CODESCRIPT

Working with empty values (na)

An indicator cannot produce a number on every bar: when there is not enough history behind it, the result stays empty and CodeScript calls that na. This page shows where empty values come from, how to test for one, and why they break your line.

An empty value is not an error. It is the language's way of saying "I have nothing to report on this bar". A 20-bar average cannot give you a number before 20 bars have piled up behind it, so it returns na on the early bars.

What an empty value is

na is not zero. Zero is a real measurement; na says the measurement could never be taken. Confusing the two is where most of the later trouble starts.

  • na is not a number, and any arithmetic that touches it comes back as na.
  • An empty condition counts as false; it raises no error and quietly takes the other branch.
  • When plot meets an empty value on a bar it draws nothing there, leaving a hole in the line.
CODESCRIPT
ortalama = sma(close, 20)
// ilk 19 barda geride 20 bar yok, sonuc bos kalir
plot(ortalama, "SMA20", "#2962ff")
plot(close, "fiyat", "#787b86")

The grey price line starts on the very first bar, while the blue average appears only from bar 20 onward; before that there is not a single blue point on the chart.

NOTE

The warm-up depends on the indicator's length. sma(close, 20) leaves 19 bars empty, sma(close, 200) leaves 199. Choosing a long period means a long silence at the start of the chart.

Why an indicator returns nothing on the first bars

An indicator computes by looking back. sma(close, 50) wants a fifty-bar window, and no average can be taken until that window is full. The same holds for every function that looks backwards.

  • In windowed indicators such as sma, ema and stdev the first length-1 bars are empty.
  • prev(close, 1) is empty on the first bar, because nothing comes before it.
  • change(close, 1) is empty on the first bar too, since there is no second value to subtract from.
  • barssince(condition) stays empty while the condition has never yet been true.
  • Functions like sqrt and log return empty on undefined input; sqrt(-1) gives na.
CODESCRIPT
kisa = sma(close, 10)
uzun = sma(close, 50)
// yesil cizgi 10. bardan, kirmizi cizgi 50. bardan itibaren dolar
plot(kisa, "SMA10", "#26a69a")
plot(uzun, "SMA50", "#ef5350")

The green line starts on bar 10 and the red one on bar 50, so for forty bars the chart carries only the green line. A rule that waits for the two to cross cannot fire at all before bar 50.

CAUTION

Your rule starts as late as your longest indicator does. If you wonder why the first trade in a backtest opens so late, look at your longest period first.

Why comparing against na never works

An empty value equals nothing at all, not even itself. So writing value == na comes out false every time and never catches a single empty bar. The way to test is the na() function.

CODESCRIPT
ortalama = sma(close, 50)
// YANLIS: bos deger kendisine bile esit degildir, bu satir hep false doner
yanlis = ortalama == na
// DOGRU: na() bir degerin bos olup olmadigini sinar
dogru = na(ortalama)
plot(iff(yanlis, 1, 0), "yanlis kontrol", "#ef5350", "kontrol")
plot(iff(dogru, 1, 0), "dogru kontrol", "#26a69a", "kontrol")

In the lower panel the red line sits flat at 0 the whole way and never notices an empty bar. The green line reads 1 for the first 49 bars and drops to 0 from bar 50, marking the empty stretch exactly.

na(deger)

true when the given value is empty, false when it holds something. Written on its own, na is the empty value itself.

deger
series
The value or series to be tested for emptiness.
CAUTION

Never handle na like a number. Comparisons such as average > na or average != na raise no error, yet they are never true either; your code just misbehaves in silence.

An empty value spreads through the maths

Any arithmetic involving na produces na again. A gap that starts in one place spreads to every calculation that touches it. If the line at the end of a chain is empty, look for the cause at the beginning.

CODESCRIPT
uzun = sma(close, 200)
// uzun bos oldugu surece fark da bostur, close dolu olsa bile
fark = close - uzun
oran = fark / uzun
plot(oran, "ortalamaya uzaklik", "#2962ff", "uzaklik")

In the lower panel the line is absent for the first 199 bars and then simply begins on bar 200. Even though close is filled on every bar the line stays empty, because the 200-bar average is what carries the gap.

TIP

When you are tracking down an empty line, plot the chain one step at a time. Draw the raw indicator, then the difference, then the ratio, and you will see for yourself which step the gap begins at.

Turning an empty value into a number with nz

nz puts a constant of your choosing in place of empty values, defaulting to 0, and leaves the filled bars untouched. Where a single empty bar would ruin an entire running total, this is the right tool.

nz(source, replacement=0)

A series of the same length in which every empty value has been swapped for replacement.

source
series
The source series that may contain gaps.
replacement
number
The constant that stands in for an empty value; 0 when you leave it out.
CODESCRIPT
degisim = change(close, 1)
// ilk barda change bostur; 0 sayarsak birikim ilk bardan itibaren calisir
birikim = cum(nz(degisim, 0))
plot(birikim, "birikimli degisim", "#2962ff", "birikim")

In the lower panel the cumulative change flows from bar one, starting at 0. Without nz the hole on the first bar would leave the entire total empty.

CAUTION

Do not sprinkle nz everywhere. Zero is a real number and it takes part in comparisons. Force an average to 0 during warm-up and price looks higher than it on every bar, breeding buy signals that were never there.

CODESCRIPT
uzun = sma(close, 200)
// YANLIS: isinma boyunca uzun=0 olur, close her zaman 0'in ustundedir
sahte = close > nz(uzun, 0)
// DOGRU: once bos mu diye sor, bossa kural hic calismasin
gercek = not na(uzun) and close > uzun
plotshape(sahte, style="circle", location="abovebar", color="#ef5350")
plotshape(gercek, style="triangleup", location="belowbar", color="#26a69a")

A red circle appears above every one of the first 199 bars, and not one of them is a real signal. The green triangle shows up below the bar only after bar 200, once the average genuinely holds a value.

TIP

The right question when writing a rule is this: do I actually have an answer for this bar? If yes, compute; if no, do nothing. nz skips the question and invents an answer, so keep it for places where an invented answer does no harm.

Carrying the last known value with fixnan

Sometimes you want to fill a gap not with a constant but with the series' own last known value. That is exactly what fixnan does: every empty bar takes the last filled value seen so far. The gap persists until the first real value, because there is nothing yet to carry.

fixnan(source)

A series of the same length in which every empty bar carries the last filled value seen up to that point.

source
series
The series to be carried forward, gaps and all.
CODESCRIPT
// yalnizca yukari kesisim barlarinda deger uret, digerlerini bos birak
sinyal = iff(crossover(close, sma(close, 20)), close, na)
// son sinyal fiyatini bir sonraki sinyale kadar tasi
tasinan = fixnan(sinyal)
plot(tasinan, "son sinyal fiyati", "#ff9800")

The orange line advances in steps: it jumps to a new level on each upward cross and lies flat there until the next one. Before the first cross it is not drawn at all.

NOTE

Keep nz and fixnan apart. nz puts the same constant on every empty bar, while fixnan puts the last value the data itself produced. One is a constant, the other is the series' own past.

Why the line breaks, and how to mend it

plot skips an empty bar. If a series has holes in the middle, the line breaks there and the chart shows an interrupted, dotted shape. Sometimes that is precisely what you want and sometimes it is a defect; you are the one who decides.

iff(condition, ifTrue, ifFalse)

For each bar, the ifTrue value when the condition holds and the ifFalse value when it does not.

condition
condition
The condition, evaluated separately on each bar.
ifTrue
series
The value taken while the condition holds; write na here to leave that bar deliberately empty.
ifFalse
series
The value taken while the condition fails.
CODESCRIPT
// yalnizca hacmi ortalamanin ustunde olan barlarda deger uret
yogun = iff(volume > sma(volume, 20), close, na)
// kopuk hali: bos barlarda cizgi kesilir
plot(yogun, "yogun barlar", "#ef5350")
// butun hali: son deger tasindigi icin cizgi kesilmez
plot(fixnan(yogun), "surekli", "#2962ff")

The red line shows up only on high-volume bars and breaks in between. The blue line uses the same values but fills the holes with the last known price, so it runs unbroken from one end to the other.

  • If you want an unbroken line, carry the last value forward with fixnan.
  • If a constant floor suits the gap, fill it with nz. For volume, 0 is a meaningful floor.
  • If the breaks are the point, leave them alone. iff(condition, price, na) is the right pattern for dotting only the signal bars.
  • If warm-up bars spoil the chart, shorten the indicator's length or open the chart on deeper data.
TIP

For discrete marks, plotshape or plotchar is cleaner than plot. They draw nothing on the bars where the condition is empty, so the broken-line problem never comes up.

Common mistakes

  • Writing value == na. That line is never true; use na(value) instead.
  • Mistaking na for 0. Zero is a real measurement; na is the absence of one.
  • Reflexively plugging every gap with nz(x, 0). That manufactures false signals during warm-up.
  • Expecting an empty condition to raise an error. It quietly counts as false: the code runs and the answer is wrong.
  • Reading a broken line as a drawing defect. Usually the source series really does have holes; look at the series first.
  • Using a long-period indicator on a chart with little history. sma(close, 200) stays empty from start to finish on a chart shorter than 200 bars.
NOTE

Empty values are part of backtesting too. Your rule cannot act before the warm-up ends, so the first trade always opens a little late; that is not a flaw, it is an honest result.