Prevent Lookahead Bias in Pine Script MTF Strategies with request.security
Adding a one-hour series to a 15-minute strategy appears to add context. But if the completed hourly close is distributed to historical 15-minute bars before that hour had ended, the strategy is using future information. If the open hourly value is used instead, it can fluctuate in real time and change after reload. This guide does not test whether an MTF idea is profitable; it audits which requested-context value becomes available on which chart bar.
Who this guide is for: Developers converting MTF indicators into strategies, users facing implausibly strong request.security results and anyone tracing higher-timeframe signals after reload
Key points to understand first
- A final higher-timeframe value does not exist for lower-timeframe logic until the higher-timeframe bar closes.
- lookahead_on without an offset can leak a completed HTF value into earlier historical chart bars.
- A representative confirmed-HTF pattern offsets the expression and aligns it with lookahead_on.
- lookahead_off can still return an unconfirmed realtime HTF value that differs after reload.
- Use one known boundary to compare historical, realtime and reload states, proving the first available LTF bar before reading performance.
The hourly close does not exist until the fourth 15-minute bar closes
BEFORE CLOSE09:00–10:00: previous confirmed HTF value
AFTER CLOSEAfter 10:00: confirmed 09:00–10:00 value
LOOKAHEAD RISKFuture leak: making the completed value appear available from 09:00
The core MTF question is when the value became knowable
The final close, high, low or indicator value of a higher-timeframe bar is not confirmed until that bar closes. At 09:00 on a 15-minute chart, code cannot know the final close of the 09:00–10:00 hourly bar. If a historical plot makes that completed value visible from 09:00, audit for future leakage.
Save symbol, requested timeframe, expression, gaps, lookahead, offset and historical/realtime behavior as one request contract. “Uses the hourly timeframe” is incomplete; state which hourly bar, confirmed or open, and from which lower-timeframe bar it becomes eligible.
In this guide, HTF means that the requested timeframe is strictly greater than the chart timeframe. A 60-minute request on a 60-minute chart, or a 15-minute request on a 60-minute chart, is outside this confirmed-HTF pattern. Convert both to seconds and stop with a runtime error unless requested > chart.
Map the HTF close boundary onto lower-timeframe bars
In a simple four-to-one mapping, the final value of the 09:00–10:00 hourly bar becomes confirmed at 10:00. Before that boundary, realtime high, low and close are fluid. A confirmed-only design holds the previous completed HTF value through the hour and switches after 10:00.
| State | What the LTF receives | After reload | Role |
|---|---|---|---|
| Previous confirmed HTF | Stable value | Usually consistent | Reproducible baseline |
| Open HTF | Changes with updates | Interim values disappear | Separate realtime design |
| Future leak | Completed value appears early | History looks unnaturally clean | Reject and fix |
Provider revisions and session differences can remain, so “usually consistent” is not an identity guarantee.
available(final HTF value) = after the HTF close boundaryconfirmed request = previous HTF expression + lookahead alignmentfuture leak = final HTF value assigned before it existedUse the real symbol session, timezone and missing-bar pattern when locating boundaries.| Condition | Required handling | Evidence |
|---|---|---|
| Requested = chart | Reject the HTF helper | Both timeframe seconds and error |
| Requested < chart | Separate as an LTF problem | Request expression and a new test ID |
| Non-integer ratio or split session | Do not infer from bar count alone | Actual open/close timestamps |
| Holiday or missing bar | Recalculate the boundary from data | Ticker ID and adjacent timestamps |
| Open HTF bar | Hold the prior value in the confirmed baseline | Realtime changes and reload value |
The arithmetic 60/15=4 does not prove that four market bars exist at the relevant boundary.
Build separate cases for four aligned bars on an ordinary session, a shortened-session endpoint and the first bar after a holiday. Record the HTF start/end plus the adjacent lower-timeframe bars, then reconcile the first appearance of the completed value in both the plot and timestamped log. Never invent a missing chart bar to make the ratio fit.
The offset changes what lookahead_on means
`barmerge.lookahead_on` is not universally safe or unsafe in isolation. Requesting the current HTF `close` can distribute a completed historical value from the start of its period. Requesting `close[1]` in the HTF context and aligning it with lookahead_on is a representative way to receive the prior confirmed HTF value consistently.
| Pattern | Historical behavior | Realtime behavior | Audit |
|---|---|---|---|
| close + lookahead_on | Can deliver future value early | Current HTF | Avoid for HTF |
| close + lookahead_off | Updates near HTF end | Can return open HTF | Test reload |
| close[1] + lookahead_on | Aligns prior confirmed HTF | Prior confirmed HTF | Confirmed baseline |
Same-timeframe and lower-timeframe requests have different semantics; validate that this is truly an HTF request.
Adding `barstate.isconfirmed` to the lower-timeframe strategy does not remove a future value already leaked by the request expression. Chart-context confirmation and requested-context confirmation are separate states.
Freeze symbol, timeframe, gaps and session together
A requested symbol can differ through session, adjustment, currency or ticker construction even when its visible name looks similar. `gaps_off` can carry a previous value while `gaps_on` exposes `na`. Holidays, extended hours, weekends and daylight-saving transitions can alter the practical alignment.
- Save the full syminfo.tickerid or explicitly constructed ticker ID.
- Reject a requested timeframe that is not truly above the chart timeframe.
- Record expression length and every history offset.
- State gaps and lookahead explicitly with a comment explaining the intent.
- Hand-check sample timestamps around a session and HTF boundary.
| Field | Recorded value | Mismatch treatment |
|---|---|---|
| Context | Chart ticker ID, session and timeframe seconds | Exclude a different context |
| Request | Requested ticker, timeframe seconds and gaps | Make implicit defaults explicit |
| Expression | Formula, length and history offset | Version every offset change |
| Alignment | Lookahead and first eligible chart bar | Classify an early value as leakage |
| Runtime | Historical, realtime and reloaded values | Retain unresolved differences |
Similar final values or matching plot colors do not prove an identical request contract.
Exercise a requested extended session, a gaps_on case that returns na, and a symbol switch that changes exchange timezone. Before counting signals, prove which series was available on which bar and whether carried-forward data was mistaken for a newly confirmed value.
Request the previous confirmed HTF expression explicitly
The Pine v6 sample requires a timeframe above the chart, evaluates `close[1]` and `ta.ema(close, 20)[1]` in the requested context, and aligns them with lookahead_on. The cross is only a timing demonstration. Confirmed data is intentionally later than the still-forming HTF value.
//@version=6
strategy("Confirmed HTF audit demo", overlay = true)
string higherTf = input.timeframe("60", "Higher timeframe")
int chartSeconds = timeframe.in_seconds()
int higherSeconds = timeframe.in_seconds(higherTf)
if higherSeconds <= chartSeconds
runtime.error("Choose a timeframe higher than the chart timeframe")
float confirmedHtfClose = request.security(
syminfo.tickerid,
higherTf,
close[1],
lookahead = barmerge.lookahead_on
)
float confirmedHtfEma = request.security(
syminfo.tickerid,
higherTf,
ta.ema(close, 20)[1],
lookahead = barmerge.lookahead_on
)
bool longCondition = ta.crossover(confirmedHtfClose, confirmedHtfEma) and barstate.isconfirmed
bool exitCondition = ta.crossunder(confirmedHtfClose, confirmedHtfEma) and barstate.isconfirmed
if longCondition
strategy.entry("L", strategy.long)
if exitCondition
strategy.close("L")
plot(confirmedHtfClose, "Confirmed HTF close", color.teal)
plot(confirmedHtfEma, "Confirmed HTF EMA", color.orange)This pattern is for confirmed HTF values. Verify symbol, session, gaps and current compiler behavior.
The EMA is calculated in the HTF context and then offset. That differs from repeating an hourly close across 15-minute bars and computing a chart-context EMA. Also review current request-count and execution limits.
Compare historical, realtime and reload states on the same boundary
- Choose a known boundary
Select lower-timeframe bars immediately before and after one HTF close.
- Record historical state
Save values, signals and markers immediately after reload.
- Observe realtime state
Timestamp whether the requested value stays fixed or changes while the HTF is open.
- Observe HTF close
Identify the first chart bar receiving the new confirmed value.
- Reload again
Diff the same bars and classify every change instead of calling all of them repainting.
Run a known unsafe and confirmed pattern over the same window, then compare first availability, signal count and trade timestamps—not only performance. Unlike BT07 overfitting, the defect here is a data-availability bug rather than parameter selection.
| Observation | Confirmed version | Unsafe version | Decision |
|---|---|---|---|
| Immediately before HTF close | Prior confirmed value held | Completed value is a failure | Availability time |
| Immediately after HTF close | Switch to new confirmed value | Record the switch bar | Explain one-bar offsets |
| While HTF is open | Stable | Fluid value is a separate design | Preserve tick changes |
| After reload | Same bar and value | Classify every difference | Reproducibility |
Freeze every setting except the expression offset and lookahead between the two versions.
Reproduce this with three evidence sets: save the historical bars and values, observe timestamped changes while that HTF bar forms, then reload after confirmation. Bind the tables with ticker ID, version ID, timezone and session. Rows that cannot distinguish data revision, session mismatch or code change remain unresolved and are excluded from release.
The release ledger keeps each LTF open and close, its HTF open and close, the predicted first-availability time and the observed switch time in separate columns. Equal values do not pass when timing is early. Holidays, shortened trading, extended sessions and different gaps settings receive distinct case IDs rather than being merged into one population.
Include an unsafe lookahead_on request without the offset as a negative control. If the audit does not flag its completed value appearing too early, the test has no detection power. The confirmed version must hold the prior value before HTF close, switch only on the first eligible bar afterward and retain that mapping after reload before its CSV can enter downstream analysis.
Send only leak-free strategy results into downstream analysis
Prove at a known boundary—and again after reload—that future data no longer enters the decision, then import the corrected Strategy Tester CSV/XLSX into the Backtest & Robustness Lab. Compare the leaking and corrected versions across performance metrics, drawdown, stress, OOS and parameter stability to isolate results created by the leak. Paid version management is appropriate when that before-and-after evidence must be retained.
When a free indicator uses MTF data, its plot is still not a strategy export. Review source visibility, requested timeframe, confirmation and alert timing; strategy conversion adds a new order and fill contract.
Estimate the HTF close wait and timeframe ratio
Use this only when the requested HTF is greater than the chart timeframe. Enter both timeframes, elapsed minutes in the HTF bar and expression offset; requested values at or below the chart are outside this HTF model.
Precondition: B>A. Ratio = B/A; wait = B when C≤0, B-C when 0
Frequently asked questions
Is lookahead_on always lookahead bias?
No. It is dangerous with an unoffset current HTF value, while the representative prior-confirmed pattern combines an expression offset with lookahead_on for alignment.
Does lookahead_off guarantee no repainting?
No. It can avoid historical future leakage yet return an unconfirmed realtime HTF value that changes after reload.
Does barstate.isconfirmed confirm the requested HTF too?
Chart-bar confirmation and requested-context confirmation are separate. Audit the request expression, offset and lookahead together.
Does using the previous confirmed HTF value make the signal late?
It is later than using an open HTF value because confirmation has a causal cost. If you use the fluid value, specify it as a separate realtime design and measure its reload difference.
Primary sources and verification links
- TradingView Pine Script | Other timeframes and dataOfficial request.security, gaps, lookahead and HTF/LTF behavior
- TradingView Pine Script | RepaintingOfficial historical/realtime requested-data differences and confirmed pattern
- TradingView Pine Script FAQ | Other data and timeframesOfficial FAQ for timeframe requests
- TradingView Pine Script | TimeframesOfficial timeframe strings, comparison and conversion
- TradingView Pine Script | LimitationsCurrent request and data-access limits
Edited and published by: SG Group · Editorial approach: We prioritize official TradingView Help Center and Pine Script documentation, then use exchange, regulator and other primary materials for market and product context. Features, data, pricing and connection terms change, so verify the current interface and linked sources before use.
Important notice: This article provides general education about TradingView interfaces, charts, alerts, screeners, paper trading and Pine Script. It is not investment advice, a trading signal, a recommendation of any instrument, data source or broker, or a guarantee of future price or profit. Features, pricing, data, exchange coverage, notifications, order integrations and Pine Script behavior vary by plan, region, connection and date and may change. Before risking money, verify current TradingView documentation and the terms of the relevant data source and connected provider, then rehearse the workflow with fictional data or paper trading.

