Edgoro
Indicator · Language features

Pine Script var vs varip: persistent variables explained

var vs varip in Pine Script v6: what each keeps between bars and between live updates, a script that counts both, and when varip is the right choice.

Short answer

var initializes a variable once and keeps its value from bar to bar, but on a live bar every new update rolls it back to its value at the previous close before the script runs again. varip also initializes once and keeps the changes made on every update, so it can count or remember what happened inside the bar that is still forming.

The script

Three counters that only differ by their keyword, plus a varip count of the updates the current bar has received. Open it on a live chart with a fast timeframe to see them diverge. Paste it into a new indicator in the Pine Editor, then save and add it to the chart.

Pine Script v6
//@version=6
indicator("var vs varip", overlay = false)

// No keyword: the declaration runs on every execution, so the count starts again from 0
int plainCount = 0
plainCount += 1

// var: initialized on the first bar only, then carried from bar to bar
var int barCount = 0
barCount += 1

// varip: carried from bar to bar and from one live update to the next
varip int execCount = 0
execCount += 1

// varip reset on each new bar: the number of updates this bar has received
varip int updatesThisBar = 0
if barstate.isnew
    updatesThisBar := 0
updatesThisBar += 1

plot(plainCount, "No keyword (always 1)", color.gray)
plot(updatesThisBar, "Updates on this bar (varip)", color.orange, style = plot.style_columns)
plot(execCount - barCount, "Live updates beyond one per bar", color.blue)
plot(barCount, "Bars counted (var)", display = display.data_window)
plot(execCount, "Executions counted (varip)", display = display.data_window)

How it works

  • No keyword. int plainCount = 0 runs on every execution, so the variable restarts at 0 each time and the plot is a flat line at 1. Variables declared this way don't remember anything: to read their past, use plainCount[1].
  • var. The = 0 part runs once, on the first bar. After that only barCount += 1 runs, once per bar, so barCount counts bars (it equals bar_index + 1).
  • The rollback. On a live bar the script runs on every price update. Before each of those runs, Pine restores every variable to its state at the previous bar's close. barCount is restored and incremented again, so it still counts bars.
  • varip variables are not restored: execCount keeps every increment, so it counts executions. On historical bars there's one execution per bar and both counters agree; the blue line (execCount - barCount) only rises once the chart receives live updates.
  • barstate.isnew is true on the first execution of each bar, which makes it the place to reset per-bar varip state like updatesThisBar.

Pitfalls

  • varip state disappears on reload. When the chart reloads (another symbol or timeframe, a settings change, a page refresh), the script runs again over history with one execution per bar, and everything varip collected from live updates is gone. A signal built on it can't be backtested and changes after a refresh, which is a form of repainting.
  • var inside a block or a function. A var declared inside an if is initialized the first time that block runs, not on the first bar of the chart. Inside a function, each place the function is called keeps its own copy.
  • na without a type. var x = na doesn't compile because Pine can't tell what type x is (value with na type). Write var float x = na.
  • varip in strategies. A strategy runs once per bar, at the close, on live bars too, unless calc_on_every_tick = true. Without it, varip sees one update per bar and behaves like var.

Variations

var for state you want to remember. The close of the last bullish cross stays on the chart until the next cross replaces it. This is the everyday use of var:

//@version=6
indicator("Last signal price", overlay = true)
fast = ta.ema(close, 9)
slow = ta.ema(close, 21)
up = ta.crossover(fast, slow)
// Kept until the next cross replaces it
var float lastUpPrice = na
if up
    lastUpPrice := close
plot(lastUpPrice, "Close at the last bullish cross", color.teal, style = plot.style_stepline)

varip for what happens inside the bar. How many times price crossed its average during the live bar, a number only varip can collect:

//@version=6
indicator("Crosses within the live bar", overlay = false)
ma = ta.sma(close, 20)
above = close > ma
varip bool wasAbove = false
varip int flips = 0
if barstate.isnew
    flips := 0
    wasAbove := above
if above != wasAbove
    flips += 1
    wasAbove := above
plot(flips, "Crosses of the SMA during the bar", color.orange, style = plot.style_columns)

Questions

What is the difference between var and varip in Pine Script?

Both initialize once and keep their value across bars. On a live bar, var variables are restored to their last-close value before every update, while varip variables keep every change. On historical bars, with one execution per bar, they behave the same.

When should I use varip?

When you need to count or remember events inside the bar that is still forming: updates received, intrabar crosses, the first time a level was touched. Its values aren't rebuilt on history, so don't base backtested signals on it.

Does a var variable reset on every bar?

No. Only its initialization is limited to the first bar; the lines that change it with := or += run on every bar and their changes are kept. A variable declared without var is the one that starts over on each bar.

Every script on this page was checked with Edgoro Pine Check (Pine Script v6 rules). Pine Check is a static checker, not TradingView's compiler: TradingView compiles the script when you save it in the Pine Editor. The scripts are examples to learn from, not trading systems. Trading involves substantial risk of loss and is not suitable for every investor. Edgoro is a software tool, not a broker or financial adviser: nothing it produces is investment advice, and past or backtested performance does not guarantee future results.

Need a different version of this script?

Describe the change in plain English and Edgoro writes the Pine Script v6 for you, checked with Pine Check. For example:

“Remember the price of the last bullish and bearish EMA crosses and plot both as step lines until the next cross of each kind.”