Skip to content
ChartTailor
WorkServicesPricingField NotesAbout Start a build
← Pine Discoveries

na, empty, and zero are three different states

Pine scripts get easier to debug when unavailable values, empty arrays, and real zeroes are kept separate.

Pine gives you several ways for “nothing” to appear, and they do not mean the same thing. na means no usable value. An empty array means no elements. Zero is a real value. Treating those three states as interchangeable is one of the fastest ways to make a script appear random.

The reason this matters in real scripts is that the problem often starts small. A level has not been found yet, an array has not been populated, or a calculation returns na during warm-up. Later, the script compares that state to a number, draws a line, or sends an alert, and the original meaning is gone.

Why this catches people

The trap is using truthiness in your head even though Pine is more explicit than that. A price of zero may be unlikely on many markets, but it is still a value. An array with size zero cannot be read with array.get(). A variable equal to na cannot be compared as if it were a normal number.

This shows up in arrays because arrays feel like collections from other languages. People ask for a max, min, or first value without checking whether the array has anything inside it. When the script returns na, the visual output can look like a plotting issue even though the real problem is state design.

The Pine bit

The first improvement is to name the state. hasLevel, hasItems, and valueReady are not glamorous variables, but they prevent accidental reads. If the state is unavailable, show nothing or show a clear placeholder. If the state is empty, skip the loop. If the state is zero, let it be zero.

I like to initialize deliberately. A variable that starts as na tells the next reader that it is not ready yet. A variable that starts as 0.0 says zero is a valid starting value. Those are different stories.

var float[] levels = array.new_float()

hasLevels = array.size(levels) > 0
nearest = hasLevels ? array.get(levels, 0) : na

plot(not na(nearest) ? nearest : na)

How I handle it in builds

For indicators with drawings, this discipline prevents many object bugs. If there is no level, do not create a line. If there is a level but it is disabled by settings, hide or delete the line intentionally. If there is a zero value because the instrument or calculation permits it, do not confuse that with “not found.”

It also makes alerts safer. A webhook should not send a numeric field that secretly means unavailable. If the value is unavailable, either omit the event or include a state that says why it is unavailable.

Where this shows up

The most useful convention is to decide what the chart should show for each state. If a level is unavailable, maybe the plot is hidden. If the level list is empty, maybe a table cell says “No active zones.” If the value is zero, maybe the plot shows zero because that is the correct value. Those choices make the visual output self-explanatory.

This also improves testing. When a script has a clear unavailable state, a tester can distinguish “the condition did not occur” from “the script did not have enough data to check.” That difference matters in backtests, dashboards, and alert logic. Silent na values make everything harder to audit.

This is especially important when values feed a table. A blank cell, a zero cell, and a muted “waiting” cell should mean different things. Users read tables quickly. If the table turns unavailable data into ordinary-looking zeroes, the dashboard can quietly lie without any Pine error being raised.

How I test it

I test state-heavy code by plotting the state before and after the update step. That shows whether the script is carrying information forward intentionally or simply leaving old values alive. If a value, array, or object ID changes at the wrong time, the debug plot usually reveals it before the finished visual does.

Checks before I trust it

  • Use not na(value) before treating a value as ready.
  • Use array.size() before reading array elements.
  • Do not use zero as a placeholder unless zero is impossible and documented.
  • Separate disabled-by-settings from unavailable-by-data.
  • Avoid sending unavailable numeric values in webhook payloads.

The thing worth preserving is that nothing is not one thing. Once the script keeps its empty states separate, many strange chart behaviours become ordinary bugs with ordinary fixes.