Skip to content

Types & Variables

Variable Declaration

Variables can be declared with explicit or inferred types:

pine
// Type inferred
a = 10                     // inferred as int
name = "AAPL"              // inferred as string

// Explicit type
float b = 3.14
string label = "Buy"
bool flag = true

If the type cannot be inferred, an explicit annotation is required:

pine
a = na                     // ERROR: cannot infer variable type
float a = na               // OK

Reassignment

Use := to reassign a variable. Compound assignment operators are also supported:

pine
a = 10
a := 20    // Reassignment
a += 5     // a := a + 5
a -= 1     // a := a - 1
a *= 2     // a := a * 2
a /= 3     // a := a / 3
a %= 4     // a := a % 4

Type Qualifiers

Pine Script has four type qualifiers that describe when a value is known, from most restrictive to least:

QualifierMeaning
constKnown at compile time, never changes
inputKnown at script startup (e.g., user inputs)
simpleKnown on bar 0, same value on every bar
seriesCan change on every bar
pine
const int a = 2
input int b = 10
simple int c = a + b
series float d = close

The qualifier hierarchy flows: const -> input -> simple -> series. A value can be auto-promoted up this hierarchy but not demoted.

var — Initialize Once, Persist Across Bars

Without a declaration mode, variables are re-initialized on every script execution (every bar, every tick). The var keyword changes this — the variable is initialized only once on the first bar, and retains its last assigned value on all subsequent bars:

pine
//@version=6
indicator("Green Bars Count")
var count = 0
isGreen = close >= open
if isGreen
    count := count + 1
plot(count)

Without var, count would reset to 0 on every bar, so the plot would only show 0 or 1. With var, the value accumulates across bars.

var inside if blocks

var can be used inside if blocks. The variable is initialized on the first execution that enters the block:

pine
var a = close
var b = 0.0
if close > open
    var x = close   // initialized once when this branch first executes
    b := x

var with collections

var works with all types including arrays and objects. A var array persists and can grow across bars:

pine
var a = array.new<float>(0)
array.push(a, close)       // array grows by 1 element on each bar

Real-time behavior of var

On historical bars, var and non-var behave identically because the script runs exactly once per bar. The difference is visible on real-time bars: without var, the variable resets on each tick; with var, it retains its value across ticks but is subject to rollback when the bar closes (the value reverts to what it was at the last confirmed bar, then re-executes once for the new confirmed bar).

varip — Persist Without Rollback

varip (var intrabar persist) is similar to var — initialized only once. The key difference is that varip variables are not subject to rollback on real-time bars. They retain their values across all executions, including multiple ticks within the same unconfirmed bar:

pine
//@version=6
indicator("varip demo")
varip int updateCount = na
if barstate.isnew
    updateCount := 1
else
    updateCount := updateCount + 1
plot(updateCount, style = plot.style_circles)

This is useful for tracking tick-level data. On historical bars, varip behaves identically to var.

varip on type fields

varip can be used on individual type fields to make them persist across intrabar updates while other fields still roll back:

pine
type Counter
    int       bars  = 0
    varip int ticks = 0

var Counter counter = Counter.new()
counter.bars  += 1    // subject to rollback on unconfirmed bars
counter.ticks += 1    // NOT subject to rollback

Comparison Table

BehaviorNo keywordvarvarip
InitializationEvery executionOnce (first bar)Once (first bar)
Historical barsRe-init each barPersistsPersists
Real-time ticksRe-init each tickPersists (with rollback)Persists (no rollback)

Tuple Destructuring

Functions that return tuples can be destructured with [...] syntax:

pine
[median, upperBand, lowerBand] = ta.bb(close, 20, 2.0)
plot(median)
plot(upperBand)
plot(lowerBand)

Discard (_)

Use _ to discard unwanted values. It can be used multiple times:

pine
[_, upper, _] = ta.bb(close, 20, 2.0)

_ = someFunction()       // Discard return value
_ = anotherFunction()

na — Missing Values

na represents a missing or undefined value. Many functions return na when there isn't enough data:

pine
sma5 = ta.sma(close, 5)  // na for the first 4 bars

// Check for na with na()
if not na(sma5)
    label.new(bar_index, sma5, str.tostring(sma5))

Use nz() to replace na with a default:

pine
value = nz(ta.sma(close, 5), 0.0)  // Replace na with 0

Use fixnan() to replace na with the last non-na value:

pine
value = fixnan(ta.sma(close, 5))

Next Steps

Released under the MIT License.