TradingCharts

Variable Declarations

ChartScript has three declaration forms. What differs between them is *when* the initializer runs and whether the value survives from bar to bar (and from tick to tick).

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, varip is identical to var.
  • 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. A var inside 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

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.