Pine Script Coding & Reliability

How to Fix Repainting in Pine Script with barstate.isconfirmed

In Pine Script, repainting occurs when an indicator or strategy calculates signals using unconfirmed real-time price updates or future historical bars, causing signals that appeared in real time to disappear or shift once the chart refreshes. Using barstate.isconfirmed ensures calculations, plot shapes, and alert triggers evaluate strictly on the closing tick of a bar, producing permanent, non-repainting signals matching live trading conditions.

Fix Repainting with AI Agent

Why Pine Script indicators repaint and how barstate.isconfirmed works

When an indicator runs in TradingView, the script executes on every historical bar once (at bar close) and on every real-time price update (tick by tick). On an active, open bar, the close price constantly changes until the bar period ends. If an indicator plots a signal when close > ta.ema(close, 20), that condition might turn true midway through a 5-minute bar, draw a green buy arrow, and then turn false two minutes later if price drops before the bar closes. On historical refresh, only the final close exists, so the arrow disappears. The built-in variable barstate.isconfirmed resolves this by staying false throughout intra-bar ticks and evaluating to true exclusively on the bar closing tick.

State variableIntra-bar tick behaviorBar closing tick behaviorHistorical bar behavior
barstate.isconfirmedfalse (suppresses premature triggers)true (confirms permanent signal)true (every historical bar is confirmed)
barstate.isrealtimetruetruefalse
barstate.isnewtrue on first tick onlyfalsefalse
barstate.ishistoryfalsefalsetrue

Non-repainting signal and alert code example in Pine Script v6

The following complete Pine Script v6 indicator demonstrates how to guard signals, visual plots, and alert triggers using barstate.isconfirmed. It calculates an EMA crossover and guarantees that the signal plot and alert trigger only fire when the bar is fully confirmed.

Pine Script v6: Non-repainting EMA crossover with barstate.isconfirmedpinescript
//@version=6
indicator("Non-Repainting EMA Signal [v6]", overlay = true)

fastLen = input.int(9, "Fast EMA Length")
slowLen = input.int(21, "Slow EMA Length")

fastEma = ta.ema(close, fastLen)
slowEma = ta.ema(close, slowLen)

plot(fastEma, "Fast EMA", color = color.blue)
plot(slowEma, "Slow EMA", color = color.orange)

// Raw crossover condition
bullCross = ta.crossover(fastEma, slowEma)

// Confirm signal strictly at bar close to prevent repainting
confirmedBuy = bullCross and barstate.isconfirmed

// Plot shape only when confirmed
plotshape(confirmedBuy, title = "Confirmed Buy", style = shape.triangleup, location = location.belowbar, color = color.green, size = size.small)

// Trigger alert only when confirmed
if confirmedBuy
    alert("Buy signal confirmed at close: " + str.tostring(close), alert.freq_once_per_bar_close)

Preventing lookahead bias in request.security calls

Another common source of repainting is higher-timeframe data access using request.security(). When requesting data from a higher timeframe (like 1D data on a 1H chart), TradingView historical bars can accidentally access data from the end of the day before the daily bar closed. To guarantee non-repainting multi-timeframe scripts, always pass barmerge.lookahead_off and sample the completed previous bar using the [1] historical index.

  • Use barmerge.lookahead_off: Never set lookahead = barmerge.lookahead_on unless specifically analyzing non-trading historical distributions.
  • Request expression[1]: Requesting ta.sma(close, 50)[1] ensures the lower timeframe receives the completed daily average rather than the fluctuating current daily bar.
  • Avoid future timestamps: Do not mix time-based offsets with real-time session checks.
  • Verify with Replay tool: Use TradingView Bar Replay tick by tick to verify that printed arrows stay fixed on the chart after bars close.
Pine Script v6: Safe non-repainting multi-timeframe requestpinescript
//@version=6
indicator("Safe MTF Daily Trend [v6]", overlay = true)

// Request the daily close of the PREVIOUS completed day
dailyClosePrev = request.security(syminfo.tickerid, "D", close[1], barmerge.gaps_off, barmerge.lookahead_off)

plot(dailyClosePrev, "Previous Day Close", color = color.purple, linewidth = 2)

Common pitfalls when using barstate.isconfirmed

While barstate.isconfirmed prevents repainting, applying it incorrectly can introduce unexpected script behavior. Keep these technical rules in mind when structuring your logic:

  • Do not wrap history-dependent calculations inside if barstate.isconfirmed: Indicators like ta.ema() and ta.rsi() maintain internal state across every bar. If you place them inside a conditional block, their historical series buffer becomes corrupt, triggering Pine Script CW10003 warnings.
  • Calculate indicator values globally: Always evaluate indicator series globally on every bar, and apply barstate.isconfirmed solely to the final boolean trigger or drawing function.
  • Strategy vs Indicator alert models: In strategy() scripts, orders execute on bar close by default unless calc_on_every_tick = true is specified. In indicator() scripts, alerts require explicit freq_once_per_bar_close configuration.
  • One-bar execution latency: Because non-repainting signals wait for the bar to close, your entry occurs at the open of the subsequent bar. This latency is realistic and reflects live trade execution.
Where Pineify fits

Pine Script AI Coding Agent

Audit your existing TradingView scripts for repainting vulnerabilities, rewrite multi-timeframe request.security logic, and generate clean, non-repainting v6 code in plain English.

Also useful: Pine Script Error Lab. Troubleshoot compiler errors, variable scoping issues, and runtime execution warnings with targeted v6 fixes.

Fix Repainting with AI Agent

Frequently asked questions

Educational and programming reference only. Eliminating repainting aligns historical charts with live execution models but does not guarantee trading profitability. Past performance in backtests does not assure future results.

Sources and verification