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.
//@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 = 0runs 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, useplainCount[1]. var. The= 0part runs once, on the first bar. After that onlybarCount += 1runs, once per bar, sobarCountcounts bars (it equalsbar_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.
barCountis restored and incremented again, so it still counts bars. varipvariables are not restored:execCountkeeps 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.isnewis true on the first execution of each bar, which makes it the place to reset per-barvaripstate likeupdatesThisBar.
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
vardeclared inside anifis 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 = nadoesn't compile because Pine can't tell what typexis (value with na type). Writevar 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,varipsees one update per bar and behaves likevar.
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.
Related pages
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.