Pine Script na(): Missing Values, Fallbacks and Valid Signals
na represents an unavailable value; na(value) checks for it. Missing numeric data usually propagates through arithmetic rather than crashing a script. A guard should express what the calculation needs, not replace every missing observation with an invented zero.

Understand where missing values arise
On the first chart bar, close[1] is unavailable. A rolling calculation can also need an initial history window, whose exact length depends on the function and valid source observations. Closed-market weekends generally produce no chart bars; they do not automatically insert na bars. Requested datasets and gap settings can create missing results separately.
In v6, booleans cannot be na, and na() does not accept boolean arguments. Avoid describing the function as accepting every type. For numeric variables initialized to an unavailable value, declare the intended type explicitly. Use na(value) rather than equality with the na constant.
Fallback values change meaning
This existing example substitutes the current close when a previous close or SMA is unavailable:
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © Pineify
//@version=6
indicator("Safe Historical Reference")
// Check if yesterday's close exists before using it
safe_previous_close = na(close[1]) ? close : close[1]
plot(safe_previous_close, title="Previous Close", color=color.blue)
// More robust approach with multiple periods
safe_sma = na(ta.sma(close, 20)) ? close : ta.sma(close, 20)
plot(safe_sma, title="Safe SMA", color=color.red)
The fallback makes a visible line during warm-up, but the replacement is neither a previous-bar close nor a completed 20-bar average. “Yesterday” in the code comment means the previous chart bar, which is a day only on a daily chart. A fallback is appropriate only when that changed meaning is acceptable.
Preserve missing observations when appropriate
This complete example leaves the first price change unavailable and uses a neutral bar color:
//@version=6
indicator("Conditional Price Change")
// Calculate price change only when both values exist
price_change = na(close[1]) ? na : close - close[1]
plot(price_change, title="Price Change", color=color.green)
// Color bars based on price change, but only when valid
bar_color = na(price_change) ? color.gray :
price_change > 0 ? color.green : color.red
barcolor(bar_color)
Subtracting an unavailable previous close already yields na; the explicit condition documents the intended policy. The remaining zero change is colored red in this example because only strictly positive changes use green.
Gate entries without claiming safety
The next existing strategy waits for both indicators to be available:
//@version=6
strategy("Safe Entry Strategy")
// Only enter trades when we have sufficient historical data
rsi_value = ta.rsi(close, 14)
sma_value = ta.sma(close, 20)
// Wait for both indicators to have valid values
can_trade = not na(rsi_value) and not na(sma_value)
// Entry conditions with NA protection
long_condition = can_trade and rsi_value < 30 and close > sma_value
short_condition = can_trade and rsi_value > 70 and close < sma_value
if long_condition
strategy.entry("Long", strategy.long)
if short_condition
strategy.entry("Short", strategy.short)
It has no independent protective exit. An opposite strategy.entry() can reverse a position. The title “Safe Entry Strategy” refers only to the missing-value gate; it is not evidence of financial safety or profitable rules.
Evaluate history-dependent functions consistently
This momentum example calculates its moving average on every bar. The previous version called the average only when raw momentum was available; unconditional calculation makes the function’s history explicit.
//@version=6
indicator("Professional Momentum Indicator", shorttitle="PMI")
// Inputs
length = input.int(14, "Length", minval=1)
smoothing = input.int(3, "Smoothing", minval=1)
// Core calculation with NA protection
raw_momentum = na(close[length]) ? na : close - close[length]
smoothed_momentum = ta.sma(raw_momentum, smoothing)
// Signal generation only when data is valid
signal_up = not na(smoothed_momentum) and smoothed_momentum > 0 and smoothed_momentum[1] <= 0
signal_down = not na(smoothed_momentum) and smoothed_momentum < 0 and smoothed_momentum[1] >= 0
// Plotting with appropriate colors
plot(smoothed_momentum, "Momentum",
color=na(smoothed_momentum) ? color.gray :
smoothed_momentum >= 0 ? color.green : color.red)
// Plot signals only when valid
plotshape(signal_up, "Buy Signal", shape.triangleup,
location.belowbar, color.green, size=size.small)
plotshape(signal_down, "Sell Signal", shape.triangledown,
location.abovebar, color.red, size=size.small)
// Add zero line for reference
hline(0, "Zero Line", color=color.gray, linestyle=hline.style_dashed)
A missing plot value has no point to color, so a gray color does not display a missing-data marker. The example’s signals are calculations, not brokerage orders or automatic alerts.
Checks versus replacements
na() answers whether a supported value is unavailable. nz() replaces an unavailable value for its supported types. Choosing zero, the current close or a previous observation is a modeling decision; these substitutes are not interchangeable.
The earlier fragments containing an empty if body, a local-scope plot(), and duplicate declarations presented as copyable fixes were removed. Likewise, an unavailable subtraction or an SMA warm-up alone is not evidence of a runtime crash. Check actual diagnostics, valid input lengths and array/history limits separately.
Sources checked October 20, 2026: Pine type system, v6 migration and plot scope.
