Default (name = expr)
rsi = ta.rsi(close, 14)
dir = close > open ? 1 : -1
The right side is re-evaluated every bar and the name holds the new value. This is what you want for anything that depends on the current bar (indicators, bar-state booleans, derived series).
var name = expr
var hitCount = 0
var lastPrice = na
var bullColor = color.lime
The initializer runs once — the first time execution reaches the statement, which is bar 0 for a top-level declaration but can be much later for a var inside a block — and is skipped thereafter. The variable can be modified later with :=:
var hitCount = 0
if close > ta.sma(close, 20)
hitCount := hitCount + 1
plot(hitCount)
var is the right tool whenever you need a value to carry across bars without being overwritten (counters, running totals, "last X" trackers, pivots).
varip name = expr
varip tickCount = 0
if barstate.isconfirmed
tickCount := 0
else
tickCount := tickCount + 1
varip ("variable in place") behaves like var on confirmed bars but is not rolled back on intra-bar updates. It is the right tool when you need to count ticks or accumulate between updates on the forming bar.
Semantics in detail:
- On a historical bar,
varipis identical tovar. - On a live forming bar, each new tick continues updating the existing value instead of restoring the snapshot from the bar's close.
- When the bar confirms, the final value becomes the new snapshot and the next bar's forming phase continues from there.
Explicit type keywords
A declaration may start with a type keyword to pin the variable's type up front. This is required when the initializer is na (otherwise the compiler cannot infer the type):
var float peakPrice = na
var line activeLine = na
var array<float> buf = array.new<float>()
Valid type keywords: int, float, bool, string, color, any UDT name, any enum name, array<T>, map<K, V>, matrix<T>, plus the special reference types line, box, label, table, polyline, linefill.
Tuple declarations
A call that returns multiple values can be destructured in a single declaration:
[middle, upper, lower] = ta.bb(close, 20, 2)
The number of names on the left must match the arity of the returned tuple.
Reassignment (:=)
Only var and varip variables, plus locals inside the current function body, can be reassigned:
var runningMax = na
if na(runningMax) or high > runningMax
runningMax := high
Attempting to reassign a plain-= top-level variable is a compile error — those are intended as per-bar derived values and are overwritten by their initializer every bar instead.
Scope
- Top-level declarations are visible everywhere below them in the script.
- Declarations inside a block (
if/for/while/function body) are visible only inside that block. Avarinside a block still persists across bars but is only addressable from within its block.
if ta.crossover(close, ta.sma(close, 20))
var crossCount = 0
crossCount := crossCount + 1
plot(crossCount, "crosses so far")
See also
- Type system — qualifiers and when
nalocks a type - Execution model — how
var/varipinteract with the bar loop - Operators —
=vs:=
var inside a block
Because the initializer runs when the statement is reached, a var declared inside a conditional block initializes on the first bar that enters the block — the pattern TradingView scripts use for a table that only needs to exist on the last bar:
if barstate.islast
var table t = table.new(position.top_right, 2, 2) // created once, on the first "last" bar
table.cell(t, 0, 0, "close")
table.cell(t, 1, 0, str.tostring(close))
A var int count = 0 inside such a block likewise starts counting on the first bar that reaches it and keeps its value from then on.