How Pine Script Runs: Bars, Series and the History Operator

Advanced7 min read
A strip of film with its frames lined up one after another
Image by Clipoemsart on Wikimedia Commons, CC0

How Does Pine Script Run on Each Bar?

A Pine script does not run once. TradingView runs it again for every bar on the chart, from the oldest to the newest. On finished bars it runs once each. On the live bar, the one still forming, it runs again on every price tick. Almost every confusing result in Pine traces back to this one fact.

Row of bars from bar 1 to the live bar n, with close, close[1] and close[2] pointing to the current and two earlier bars, and a var variable that keeps its value across bars
Illustration: the script runs once for each closed bar from the oldest, then again on every tick of the live bar. On bar 3, close is that bar, close[1] the one before and close[2] two before. A var variable keeps its value.

If you have written a few scripts (see Pine Script basics), this guide explains what is really happening underneath. Read it before you trust a signal you cannot reproduce.

What Is the Difference Between Historical and Realtime Bars?

TradingView’s documentation splits the run into two kinds of bar. A historical bar is one that has already closed when the script loads. The script runs on it once, with that bar’s final open, high, low and close, and then commits the results to the chart’s record. A realtime bar is the open bar on the right edge.

On the realtime bar the script runs again on every new tick, which is a single price update. Each run starts from the last committed state. Before it begins, the runtime resets the script’s data and updates close, high and low to the latest values. This reset is called a rollback. Only the final tick’s results are kept when the bar closes.

That is why repainting exists. History is calculated once from final numbers. The live bar is calculated many times from unfinished numbers, and the two can disagree.

What Is a Series, and How Does the History Operator [] Work?

A series is a value that has one entry per bar. close is a series: it holds a different number on every bar. When your script runs on a bar, a series name gives you that bar’s value. To reach older entries you use the history operator [].

float c0 = close
float c1 = close[1]
float c2 = close[2]
float fromHigh = high[1] - low[1]

close[1] is the close one bar ago, close[2] two bars ago, and close[0] is the same as close. Use one offset per value: write close[3] rather than stacking brackets.

This is also why the same line of code gives a different answer on each bar. A script is not a list of steps done once. It is a recipe applied bar after bar, and each series carries its own past.

What Are na and nz(), and Why Do Early Bars Return Nothing?

On the first bar there is no bar before it, so close[1] has nothing to return. Pine gives na, short for not available. TradingView’s documentation says close[3] returns na on the first bars because no bar exists in that position. Any calculation that touches na usually gives na too, so one missing value can blank a whole line.

float safe = nz(close[1], open)
bool hasValue = not na(close[5])

nz() swaps an na for a value of your choice (zero if you give none), and na() tests for it. Use them where a missing value would otherwise spread. Do not use them to hide a real bug: if a line is blank on every bar, find out why.

What Do var and varip Do?

A normal variable starts fresh on every bar. Put var in front and it is set once, on the first bar, and keeps its value from bar to bar. That is how you keep a running total, a session high, or a counter.

The live bar adds a twist. Because each tick starts from the last committed state, a var variable that changes during a tick is rolled back before the next tick of the same bar. varip (var, intrabar persist) skips the rollback and keeps its value across every tick, including ticks on the open bar.

Use varip sparingly. After a reload the old ticks of the bar are gone, so a varip value built from them cannot be rebuilt. TradingView’s documentation warns that this can repaint.

How Do You Read barstate.isconfirmed, isrealtime and islast?

The barstate variables tell your script where it is in the run. These are the ones this guide uses:

  • barstate.ishistory: true on bars that closed before the script loaded.
  • barstate.isrealtime: true on bars that close after the script loaded.
  • barstate.isconfirmed: true on the final execution of a bar, when it has closed. TradingView’s documentation suggests it for detecting closed bars.
  • barstate.isnew: true when a realtime bar opens, and false on later ticks of that bar.

There is also barstate.islast, which is true on the most recent bar. It is mostly used to draw once at the end of the chart rather than on every bar.

Why Can a Signal Appear and Vanish on the Live Bar?

Run this complete indicator on a chart and watch the right edge.

//@version=6
indicator("Execution demo", overlay = true)
var int barsSeen = 0
varip int ticksSeen = 0
barsSeen += 1
ticksSeen += 1
float prevClose = nz(close[1], open)
bool rising = close > prevClose
plotshape(rising, "Rising now", shape.triangleup, location.belowbar, color.orange)
plotshape(rising and barstate.isconfirmed, "Rising, confirmed", shape.triangledown, location.abovebar, color.green)
bgcolor(barstate.isrealtime ? color.new(color.blue, 85) : na)
plot(barsSeen, "Bars seen", display = display.data_window)
plot(ticksSeen, "Ticks seen", display = display.data_window)

The orange triangle uses the unconfirmed rule close > prevClose. On the live bar it can appear when price ticks up and disappear when it ticks down, because the script reruns each tick. The green triangle adds barstate.isconfirmed, so it prints only once the bar has closed, and it stays. The blue shading marks realtime bars. In the Data Window, “Bars seen” counts one per bar, while “Ticks seen” counts every execution, including each tick of the live bar.

The green signal is later by up to one bar. That is the trade-off: confirmed signals are honest but slower, unconfirmed ones are fast but can disappear. For the ForexR Library’s view of the same problem, see its Pine Script Library flags for repainting.

What Does calc_on_every_tick Change in a Strategy?

Indicators run on every realtime tick by default. Strategies do not: unless you say otherwise, a strategy runs only at the bar’s closing tick. Setting calc_on_every_tick = true in the declaration makes it run on every realtime tick like an indicator.

strategy("Every tick", overlay = true, calc_on_every_tick = true)

The catch is history. Past bars still run only once each, so a strategy that trades on intrabar signals live can look very different from its own backtest. The same page documents calc_on_order_fills, which reruns the strategy when an order fills; historical bars have four default ticks (open, high, low, close), so it can run up to four times per bar. Both settings are ways to make a backtest less like reality, so leave them off unless you know why you need them. The next guide, strategy orders, stops and sizing, covers how orders fill, and backtesting a Pine strategy covers reading the report.

How Does This Help You Debug a Script?

  • Signal differs after reload: it probably used unconfirmed data. Add barstate.isconfirmed or move the rule to the previous bar.
  • Line blank at the left edge: an indicator needs history; na is normal for the first bars.
  • Counter resets on the live bar: that is rollback acting on a var. Use it deliberately or switch to varip.
  • History reference error on the live bar: a history lookup can run beyond the stored buffer. The documentation points to max_bars_back() and the smallest size that works. See Pine Script errors and limits.

To practise on real code, open a few open-source scripts from the indicator category and look for var, varip and barstate lines.

Knowing the execution model explains differences; it does not make a rule profitable. A script that behaves well on history can still fail live, in ranges, or around news. Leveraged forex and CFD trading carries a high risk of loss, so test on a demo account first and only risk money you can afford to lose.

FAQ

Does a Pine Script run on every tick?

It depends on the script type and the bar. Indicators run on every tick of the live bar. On past bars, every script runs once per bar. Strategies run only at the bar’s close unless you set calc_on_every_tick to true. After the bar closes, only the final result is kept.

What does na mean in Pine Script?

na means not available: the script has no value there. It appears when you look back further than the chart’s history, such as close[1] on the first bar. Most calculations that include na return na. Use nz() to replace it with a number, or na() to test for it.

What is the difference between var and varip?

A var variable is set once and keeps its value from bar to bar, but it is rolled back between ticks of the live bar. A varip variable also keeps changes made on each tick of the live bar. That makes varip hard to reproduce after a reload, so use it with care.

Why does my indicator show different signals after I refresh the chart?

Live signals were calculated tick by tick on an unfinished bar, while after a refresh the same bar is rebuilt from its final numbers. If a rule uses the open bar’s close, the two can disagree. Test signals only after the bar has closed, for example with barstate.isconfirmed.

Next lesson Pine Script Strategy Orders: Entries, Stops and Position Size Continue

More Advanced Guides

Multi-Timeframe Analysis in Forex: A Top-Down Routine Price Action Trading: Market Structure, Zones & Liquidity Smart Money Concepts (SMC) Explained: A Practical Guide Fair Value Gap (FVG) Explained: How to Find and Trade It The Wyckoff Method: Accumulation, Distribution and Market Cycles Elliott Wave Theory Explained: The 5-3 Wave Pattern Made Simple London Breakout Strategy: Rules, Example & Backtesting Currency Correlation in Forex: Pairs That Move Together Hedging in Forex: How It Works, Strategies and Real Costs US Dollar Index (DXY) Explained: How to Read & Use It Carry Trade & Interest Rates: How Swap Shapes Forex Trades Trading the News in Forex: NFP, CPI & Rate Decisions Non-Farm Payrolls (NFP): How to Trade the US Jobs Report CPI and Forex: How Inflation Data Moves Currencies FOMC Meetings Explained: How Fed Rate Decisions Move Forex XAU/USD Explained: Contract Specs, Volatility and ATR Stops Gold Price History: 1971 to 2020 in Cycles, Not Straight Lines Gold Futures vs Spot vs CFDs: Contango, Roll and Which to Trade LBMA Gold Price and the London Fix: How Gold's Benchmark Is Set Central Bank Gold Buying: Why They Buy and What It Does to Price Gold Supply and Demand: Mines, Recycling, Jewellery and ETFs Gold Seasonality: Festivals, Weddings and What the Data Say Gold EAs and Trading Bots: Why XAU/USD Breaks Forex Robots Hedging Physical Gold With XAU/USD: A Guide for Jewellers How to Trade Silver (XAG/USD): What Moves It and How It Differs How to Trade Bitcoin (BTC/USD): A Guide for Forex Traders Forex Robots & Expert Advisors (EAs): A Practical Guide Running an EA 24/7: Forex VPS, Forward Testing & Going Live Open-Source Forex EAs on GitHub: Licences, Compiling & Editing How to Backtest a Pine Script Strategy in TradingView Pine Script Strategy Orders: Entries, Stops and Position Size Pine Script Functions, Methods and Libraries: Reuse Your Code Pine Script Drawings: Lines, Labels, Boxes and Tables Pine Script Errors and Limits: How to Fix the Common Ones How to Publish a Pine Script: Open Source, Private and Licences How to Send TradingView Alerts to MT4 or MT5 AI in Forex Trading: What It Can and Cannot Do for You Machine Learning in Forex: What Works and What Fails What Is MCP? The Model Context Protocol for Traders How to Build an AI Trading Bot: An Honest Walkthrough How to Backtest an AI Trading Strategy the Right Way Martingale and Grid Trading Explained: How They Work, Pros & Cons Backtesting & Trading Journal: Test Your Forex Strategy Prop Firm Challenges Explained: Rules, Maths & How to Pass Trading Psychology in Forex: Discipline, Bias & Routine

Choose a Regulated Broker

Put what you’ve learned to work with a regulated broker. Compare costs, platforms and licences side by side.

Compare top brokers