← Back to blog

Platform Mechanics · Backtest vs Live

The request.security() Value That Isn't There Yet

"Profitable in the Strategy Tester, losing money live" usually gets blamed on slippage. One specific, mechanically checkable cause is worth ruling out first — and it's documented behavior, not a rare edge case.

2026-08-29

This one isn't from a client audit — it's a platform mechanic every Pine Script strategy that pulls in a higher timeframe should be checked against, because it's easy to introduce by accident and TradingView's own documentation explicitly warns about it. If your backtest and your live or paper results have quietly stopped agreeing and you've already ruled out fees and slippage, this is the next thing to check.

What request.security() actually does

request.security() pulls a value computed on a different timeframe (or symbol) into your script's current context — the standard way to check, say, the 1-hour trend from a 15-minute chart. It takes a lookahead parameter that controls how it fills in values on historical bars. As of the current Pine Script version, its documented default is barmerge.lookahead_off — meaning out of the box, it does not leak information from the future into the past.

The bug shows up when someone explicitly sets lookahead=barmerge.lookahead_on. People usually do this on purpose, not by accident — it removes what looks like an annoying one-bar lag on the higher-timeframe value, and plenty of forum answers recommend it for exactly that reason. TradingView's own docs carry a direct warning about this setting:

"When using barmerge.lookahead_on without an offset, ensure that it does not
compromise the integrity of the script's logic by leaking future data into
historical chart bars."

The naive pattern

//@version=6
strategy("HTF trend filter")
htfClose = request.security(syminfo.tickerid, "60", close,
     lookahead=barmerge.lookahead_on)

if close > htfClose
    strategy.entry("Long", strategy.long)

On historical bars, this compares the current price against the closed 1-hour value — including, for intraday bars still inside that hour, a close that in a live sense hasn't happened yet. The backtest engine has the full historical record, so it fills in that value without complaint. Every entry signal in the Strategy Tester is quietly using information that wasn't actually available at the moment a live bot would have had to act on it.

This is one failure shape out of several I check for when a bot's live results stop matching its backtest. The full checklist — entry-price path and exit/risk-limit path together — is on one page, or I can walk through it against your script directly.

Get the safety-net checklist →

Why it doesn't show up while you're watching it live

This is the part that makes the bug hard to catch by eyeballing the chart. TradingView's docs describe exactly this: on the currently-forming realtime bar, a lookahead series and a no-lookahead series plot the same value — there's no future data to leak yet, because the bar hasn't closed. The divergence only appears retroactively, once that realtime bar becomes historical and gets recalculated with the full record available. The docs call this repainting: the value you watched happen live and the value the same bar shows after a reload are two different numbers, and only the second one is what your backtest actually ran on.

So a live paper-trading session can look like it's confirming the strategy works — the signals you watch fire in real time match what the backtest predicted — right up until you reload the chart and the historical bars quietly repaint into a different story.

A second, easy-to-miss variant

The same function has a related but separate gotcha when the requested timeframe is at or below your chart's own resolution — for example, requesting 1-minute data on a 1-minute chart, or any case where the "higher" timeframe you're pulling isn't actually higher. TradingView's docs are specific about what you get back in that case:

"When calling this function to access a lower timeframe, it will evaluate
the expression from the LTF context. However, it returns the results from
only a single intrabar (LTF bar) on each chart bar."

Which intrabar you get depends on the same lookahead setting — the first intrabar of the period with lookahead_on, the last with lookahead_off. It's a different mechanism from the repainting issue above, but the practical effect is the same shape of problem: the value your logic reacts to in a backtest isn't necessarily the value a live bot would have seen at that moment, and the mismatch is invisible unless you go looking for it.

What to check in your own script


None of this requires an exotic setup — a higher-timeframe trend filter is one of the most common things people add to a strategy, and lookahead_on is a documented, legitimate parameter with real uses. The failure isn't in wanting the feature; it's that the difference between "correct on historical bars" and "correct at the moment a live bot has to decide" is easy to miss unless you know specifically where to look. It's the same underlying lesson as the audit bugs I've written about before: what a bot's numbers show and what was actually knowable at the time are two separate claims, and a backtest alone won't tell you which one you're looking at.

Contact

Get in touch

Not investment advice. Honest Backtest provides technical code review and backtest recalculation only — an honest read on what the code and the numbers actually show, not a recommendation to trade.
Photography via Unsplash.