Summary
Goal: Display the last four candles of a higher timeframe (e.g., 1‑hour or 4‑hour) in a small overlay window while the main chart remains on a 5‑minute chart.
Solution: Use Pine Script v5’s built‑in request.security() to fetch higher‑timeframe OHLC arrays, then plot them with plotcandle() inside a indicator() that draws on a separate pane.
Root Cause
- Pine scripts run on the chart’s native timeframe; without explicit calls they cannot see data from other resolutions.
- Attempting to draw higher‑timeframe candles directly on the main chart leads to misaligned bars and runtime errors.
Why This Happens in Real Systems
- Single‑resolution execution: The Pine engine evaluates the script once per bar of the chart’s timeframe.
- Security wrapper:
request.security()is the only safe bridge to request data from a different timeframe. - Array limitations: Pine v5 introduced array support, allowing us to store the last N higher‑timeframe candles for custom rendering.
Real-World Impact
- Incorrect visual cues: Without proper multi‑timeframe handling, traders may make decisions on malformed price data.
- Performance penalties: Repeated
request.security()calls per bar can degrade script execution speed, especially on lower timeframes. - User frustration: Misaligned candles or missing data cause confusion and erode trust in the indicator.
Example or Code (if necessary and relevant)
//@version=5
indicator('4‑Candle Higher‑TF Overlay', overlay=false, max_bars_back=500)
//--- Settings -------------------------------------------------
higherTF = input.timeframe('60', 'Higher Timeframe') // 1‑hour by default
candlesCnt = input.int(4, 'Number of Candles', minval=1, maxval=10)
//--- Fetch higher‑timeframe OHLC as series --------------------
[htOpen, htHigh, htLow, htClose] = request.security(syminfo.tickerid,
higherTF,
[open, high, low, close],
barmerge.gaps_off,
barmerge.lookahead_on)
//--- Store last N candles in arrays ---------------------------
var float[] oArr = array.new_float()
var float[] hArr = array.new_float()
var float[] lArr = array.new_float()
var float[] cArr = array.new_float()
if barstate.islast
// Shift arrays to keep only the most recent `candlesCnt` values
if array.size(oArr) >= candlesCnt
array.shift(oArr)
array.shift(hArr)
array.shift(lArr)
array.shift(cArr)
// Append current higher‑tf candle
array.push(oArr, htOpen)
array.push(hArr, htHigh)
array.push(lArr, htLow)
array.push(cArr, htClose)
//--- Plot the stored candles ----------------------------------
for i = 0 to array.size(oArr) - 1
plotcandle(array.get(oArr, i),
array.get(hArr, i),
array.get(lArr, i),
array.get(cArr, i),
offset = -(array.size(oArr) - 1 - i),
title = 'HT Candle ' + str.tostring(i + 1))
How Senior Engineers Fix It
- Use
barmerge.lookahead_onto align higher‑timeframe data with the current bar, ensuring the most recent completed candle is shown. - Cache values in arrays only on the last bar of the higher timeframe to avoid unnecessary re‑allocation.
- Limit
max_bars_backto the exact number of candles needed, reducing memory footprint. - Separate pane (
overlay=false) so the overlay does not clutter the main 5‑minute chart. - Add input validation (e.g., preventing
candlesCnt> 10) to keep the script within Pine’s runtime limits.
Why Juniors Miss It
- Assume
request.security()returns a series that can be plotted directly without handling bar alignment. - Forget to store values in arrays, causing the script to display only the latest higher‑timeframe candle repeatedly.
- Overlook performance costs, leading to laggy charts when the lower timeframe is very fast (e.g., 1‑minute).
- Neglect Pine’s execution model, resulting in misplaced
plotcandle()calls inside loops that run on every tick instead of once per higher‑timeframe candle.