request.security() Lookahead in Pine Script: Defaults & Avoiding Repainting

axilon8 Avatar

In Pine Script, request.security() uses barmerge.lookahead_off by default in every modern version (v3, v4, v5 and v6). Only the legacy security() function in Pine v1 and v2 defaulted to lookahead-on behaviour, silently pulling future higher-timeframe (HTF) data onto historical bars. As of July 2026 the default is off — but off alone does not make a multi-timeframe script non-repainting. The single officially recommended non-repainting HTF pattern is request.security(syminfo.tickerid, "D", close[1], lookahead = barmerge.lookahead_on): lookahead on, and the expression offset by one bar so you always read the last confirmed HTF value.

In my 8 years coding Pine Script — and more than 7,700 strategies shipped for clients across 14+ countries — the single most common bug I’m paid to fix is a multi-timeframe indicator that backtests like a money-printer and then falls apart live. Nine times out of ten it traces back to a misunderstanding of the lookahead parameter. Let me give you the exact behaviour per version, the repainting mechanics, and the code I actually ship.

The default lookahead value, version by version

The lookahead parameter was added in Pine Script v3. Before that it did not exist. Here is the exact behaviour:

Pine version Function name Default lookahead Effect on historical bars
v1 & v2 security() No parameter — behaves like lookahead_on Leaks future HTF data (lookahead bias)
v3 & v4 security() barmerge.lookahead_off Uses last available intrabar, no future leak
v5 & v6 request.security() barmerge.lookahead_off Same as v3/v4 — off by default

So to answer the exact queries people type into Google: “pine script v2 security() default lookahead” — v2 had no explicit parameter, but it effectively ran with lookahead on, which is why so many old v2 scripts repaint. And “pine script v5 request.security default lookahead” — it is off (barmerge.lookahead_off), identical in v6.

One syntax note: the function was renamed from security() to request.security() in v5. The lookahead behaviour and defaults are identical in v5 and v6, so every code sample below runs unchanged in both. If you are porting old v3/v4 code, swap security(...) for request.security(...).

Why lookahead_on repaints (the dangerous default of the past)

When you request a higher timeframe with lookahead = barmerge.lookahead_on and no history offset, on historical bars the function returns the HTF bar’s final value from the very first chart bar inside that HTF period. That is future data your strategy could not possibly have known in real time. Backtests look incredible; live trading does not match. Do not ship this:

//@version=6
indicator("DO NOT SHIP - leaks future data", overlay = true)

// On a 1h chart requesting Daily: historical bars see the full day's close
// from the first hour of that day. Pure lookahead bias.
badClose = request.security(syminfo.tickerid, "D", close, lookahead = barmerge.lookahead_on)
plot(badClose, "Leaky daily close", color.fuchsia)

The other flavour of repaint is subtler and happens even with the default lookahead_off. With lookahead off, the developing HTF bar keeps changing tick by tick in real time, so a signal that reads the current HTF close will flicker until that HTF bar closes. It is historically honest but real-time unstable — still a repaint in the eyes of a live trader.

The one officially recommended non-repainting pattern

TradingView’s documentation is explicit: combining barmerge.lookahead_on with a [1] history offset on the expression is the only recommended method to avoid repainting. The offset rolls the request back to the previous, fully confirmed HTF bar, and lookahead-on anchors that confirmed value to the start of the period so historical and real-time results agree.

//@version=6
indicator("HTF close - non-repainting", overlay = true)

// Last CONFIRMED daily close: consistent on history and in real time.
// Data is up to one HTF bar 'late', which is exactly what makes it stable.
htfClose = request.security(syminfo.tickerid, "D", close[1], lookahead = barmerge.lookahead_on)
plot(htfClose, "Confirmed daily close", color.aqua, 2)

Need multiple series? Offset every element of the tuple by one bar — this is the exact shape I use in production libraries:

//@version=6
indicator("Confirmed HTF OHLC", overlay = true)

[o, h, l, c] = request.security(syminfo.tickerid, "D",
     [open[1], high[1], low[1], close[1]],
     lookahead = barmerge.lookahead_on)

plot(c, "Confirmed daily close", color.aqua)

Building or debugging a multi-timeframe strategy and want a second set of eyes on the lookahead logic before it goes live? Message me on WhatsApp at +91 77352 68199 and I’ll take a look.

The confirmed-bar alternative (and a common myth)

The other legitimate approach is to request the HTF value with the default lookahead_off, then only act on it once the chart bar closes:

//@version=6
strategy("Confirmed-bar entry", overlay = true)

htfEma = request.security(syminfo.tickerid, "D", ta.ema(close, 20), lookahead = barmerge.lookahead_off)
long  = ta.crossover(close, htfEma)

// Only take the signal on a closed chart bar
if long and barstate.isconfirmed
    strategy.entry("L", strategy.long)

Here is the myth to kill: barstate.isconfirmed confirms the chart bar, not the higher-timeframe bar you pulled through request.security(). It stops your entry from flickering intrabar, but it does nothing to confirm the developing HTF value itself. If you need the HTF value to be stable, you still need the lookahead_on + [1] offset pattern above. In practice I combine them: the offset pattern for a stable HTF value, and barstate.isconfirmed to gate the actual order.

What about ta.vwap on a higher timeframe?

People searching “ta.vwap pine script v5” usually hit the same wall. ta.vwap uses hlc3 as its default source and resets at the start of each session. It is a chart-timeframe calculation — if you pull it from a higher timeframe with request.security(), the exact same repainting rules apply. Wrap it in the confirmed pattern:

//@version=6
indicator("HTF VWAP - non-repainting", overlay = true)

htfVwap = request.security(syminfo.tickerid, "D", ta.vwap(hlc3)[1], lookahead = barmerge.lookahead_on)
plot(htfVwap, "Confirmed HTF VWAP", color.orange)

If you want the whole thing done properly — audited for lookahead bias, tested on history and forward — that is exactly what my Pine Script development service is for. For traders bridging TradingView signals to a broker or MT5, see my MT4/MT5 automation work, and if you are hunting down subtle script bugs, my write-up on 10 Pine Script bugs that slow down your strategy pairs well with this one. New to the language? Start with how to learn Pine Script quickly.

Frequently asked questions

What is the default lookahead in Pine Script request.security?

In Pine v3, v4, v5 and v6 the default is barmerge.lookahead_off, meaning no future data is used on historical bars. In v1 and v2 there was no parameter and security() behaved like lookahead_on.

What is the pine script v5 request.security default lookahead?

It is barmerge.lookahead_off, exactly the same as v6. The value and behaviour did not change between v5 and v6.

What was the pine script v2 security() default lookahead?

Pine v2 had no lookahead argument. The function effectively behaved as if lookahead were on, pulling future HTF data onto historical bars — the main reason legacy v2 scripts repaint.

Does barstate.isconfirmed stop request.security from repainting?

No. barstate.isconfirmed only confirms the chart bar. To make the HTF value itself non-repainting you must use lookahead = barmerge.lookahead_on together with a [1] offset on the expression.

Why does my request.security backtest look better than live trading?

Almost always lookahead bias: lookahead_on with no history offset lets historical bars read a future HTF close. Switch to the confirmed pattern request.security(syminfo.tickerid, tf, close[1], lookahead = barmerge.lookahead_on).

Still stuck, or want your existing script audited for repainting before you risk capital? WhatsApp me at +91 77352 68199 and I’ll help you get it right.

Related guides

Repainting has more causes than lookahead alone — see the full map in why your indicator repaints and how to fix it, plus calc_on_every_tick in strategies and alert frequencies explained.

Disclaimer: Trading and algorithmic strategies carry substantial risk of loss and are not suitable for every investor. Nothing in this article is financial advice or a promise of profit. Code examples are educational; always test thoroughly on your own data before trading real money.

Leave a Reply

Your email address will not be published. Required fields are marked *