Skip to content
FactorQX
advancedpine-scriptmulti-timeframerequest-security

Multi-Timeframe Data with request.security

Pull higher-timeframe data into a Pine Script v5 chart with request.security while avoiding repainting through barmerge.lookahead_off and closed-bar offsets.

4 min read

This is educational material about programming. Nothing here is investment advice, a trading signal, or a recommendation.

request.security() lets a script read data from a different symbol or timeframe than the chart it runs on. It is the foundation of multi-timeframe (MTF) analysis in Pine Script v5 — but it is also the single biggest source of repainting bugs. This article shows how to request higher-timeframe (HTF) values correctly and how to keep them honest. If you are still learning the basics, begin with Getting Started with Pine Script.

The function signature

signature.pine
request.security(symbol, timeframe, expression, gaps, lookahead, ignore_invalid_symbol)

The three arguments you use most:

  • symbol — a ticker string, or syminfo.tickerid for the current symbol.
  • timeframe — a resolution string like "60" (60 minutes), "D", or "W".
  • expression — the series or tuple to evaluate in that context.

A minimal request for the daily close while charting an intraday symbol:

daily-close.pine
//@version=5
indicator("HTF Close", overlay = true)
 
htfClose = request.security(syminfo.tickerid, "D", close)
plot(htfClose, color = color.orange, style = plot.style_stepline)

The stepline style makes the discrete HTF updates visible: the daily value holds flat across each intraday bar until the higher timeframe advances.

How HTF data maps onto a lower chart

When the chart timeframe is lower than the requested one, a single HTF bar spans many chart bars. The critical question is: while the current HTF bar is still forming, what value does request.security return?

By default Pine returns the developing value of the in-progress HTF bar. That value is not final — the HTF high, low, and close can all still change until the HTF bar closes. If your logic compares against it, the comparison result can change retroactively when you reload the chart, because historical bars are recalculated using only closed HTF data. This mismatch between real-time and historical behavior is repainting.

Preventing lookahead bias

The lookahead parameter is the most misunderstood part of the function.

  • barmerge.lookahead_off (the default and the safe choice) — returns data that was actually available at that point in time.
  • barmerge.lookahead_on — pulls the HTF bar's value as of its open, which on historical bars leaks the future closing value into earlier chart bars. This produces unrealistically clean backtests and cannot happen in real time.

Always use barmerge.lookahead_off unless you fully understand the exception below. Using lookahead_on carelessly is how scripts appear to predict moves on history that they could never have known live.

The confirmed-value pattern

To get HTF data that is both repaint-free and references only closed HTF bars, combine lookahead_on with an offset of [1] on the expression. This idiom is deliberate and safe: the lookahead aligns the data to the HTF bar boundary, and the [1] shifts it back to the previous, fully closed HTF bar.

confirmed-htf.pine
//@version=5
indicator("Confirmed HTF EMA", overlay = true)
 
htfEma = request.security(syminfo.tickerid, "240", ta.ema(close, 50)[1], lookahead = barmerge.lookahead_on)
plot(htfEma, color = color.teal, linewidth = 2)

Here ta.ema(close, 50)[1] evaluates in the 240-minute context and is offset by one HTF bar, so every chart bar sees only the EMA from the last completed 4-hour bar. The value never changes after the fact. The trade-off is a deliberate one-bar lag — you accept slightly stale data in exchange for consistency between historical and live behavior.

If you prefer the simpler default, just omit lookahead and accept that the most recent HTF value updates intrabar:

default-safe.pine
//@version=5
indicator("Default HTF", overlay = true)
 
// Repaint-free for closed bars; current HTF bar still develops live
htfRsi = request.security(syminfo.tickerid, "D", ta.rsi(close, 14))
plot(htfRsi)

Requesting tuples and multiple series

You can request several values at once by wrapping them in a tuple, which is more efficient than separate calls:

tuple-request.pine
//@version=5
indicator("HTF OHLC", overlay = true)
 
[hOpen, hHigh, hLow, hClose] = request.security(syminfo.tickerid, "D", [open, high, low, close])
plot(hHigh, color = color.green)
plot(hLow, color = color.red)

Practical guidance

  • Never request a timeframe lower than the chart's; it forces Pine to fabricate intrabar detail and the results are unreliable.
  • Keep the number of request.security calls modest — each one adds compute and counts toward script limits.
  • When you need alerts on HTF events, pair this with the confirmation techniques in Creating Alerts in Pine Script and gate on barstate.isconfirmed.
  • Document in the script which pattern you chose, since the lookahead behavior is invisible on the chart but changes correctness.

Where to go next

With repaint-aware MTF requests in hand, you can build indicators that combine context from several resolutions while remaining faithful to what was knowable in real time. Revisit Plotting and Styling in Pine Script to present that multi-timeframe data clearly, and keep barmerge.lookahead_off as your default until a specific, well-understood reason justifies otherwise.

Educational content. This article covers software development and research methods only. It is not investment advice, a trading signal, or a recommendation. See our disclaimer.