◆ New — Strategy Validator, Code Fixer & Prop Compliance Checker are live. Try one free →
Home / Indicators / Previous Day High/Low
Session & Time indicator

Previous Day High/Low

Yesterday's completed high and low plotted as fixed intraday reference lines — and a classic test case for repaint-free coding.

Illustrative diagram — not live market data.

What it is

Previous Day High/Low (PDH/PDL) plots the high and low of the most recently completed daily bar as horizontal reference lines on an intraday chart. The concept could not be simpler — yesterday's extremes are fixed, known numbers once the daily bar closes — yet PDH/PDL scripts are one of the most commonly broken indicators in circulation, because fetching higher-timeframe data in Pine Script has a well-known trap. The naive implementation requests the daily high and low with lookahead enabled and no bar offset, which makes historical bars display information (the day's final high and low) that was not knowable until that day ended. The chart then shows perfect-looking levels across history that a live trader could never have seen, and any backtest touching them peeks into the future. The correct implementation requests the prior completed daily bar — offsetting the series by one bar and keeping lookahead off — so the plotted levels on every bar are exactly what was known at that moment. The levels themselves are purely descriptive: they mark where yesterday's trading stopped, nothing about where today's will. This page is educational only, not financial advice, and trading involves risk of loss.

How it works

The mechanics of the correct version are worth spelling out. request.security(syminfo.tickerid, "D", high[1], lookahead = barmerge.lookahead_off) asks the daily timeframe for its high one completed bar back, merged without lookahead. On any intraday bar, this returns the high of the last daily bar that had already closed at that point in time — which is precisely the 'previous day high' a live trader would have known. Contrast the broken version: requesting high (no offset) with barmerge.lookahead_on returns the current day's final high on every intraday bar of that day, including bars printed at 9 a.m. when the day's high had not happened yet. On a live chart both versions look identical for today (the repainting one keeps updating), but on historical bars the broken version silently substitutes hindsight, so its history is a fiction. This is exactly the class of defect a repaint checker exists to catch: the test is whether the value plotted on a historical bar equals the value that was available in real time on that bar. There is one legitimate combination of lookahead_on with a [1] offset that older Pine versions used for the same effect, but in v6 the offset-plus-lookahead_off form is the clear, safe idiom.

How traders read it

Common settings

There is little to configure: the higher timeframe is "D" by convention, though the same pattern generalizes to previous week ("W") or previous month ("M") levels. The meaningful choice is hidden in the data: whether the daily bar comes from the exchange session or a 24-hour electronic session changes the high and low. Some traders also plot the previous day's close or the midpoint of the previous range alongside PDH/PDL. Applicable on any intraday timeframe.

Strengths

Pitfalls to watch

Pine v6 example

//@version=6
indicator("Previous Day High/Low", overlay = true)

htf = input.timeframe("D", "Higher Timeframe")

// CORRECT: prior completed HTF bar, lookahead off -> non-repainting
pdh = request.security(syminfo.tickerid, htf, high[1], lookahead = barmerge.lookahead_off)
pdl = request.security(syminfo.tickerid, htf, low[1],  lookahead = barmerge.lookahead_off)

// WRONG (do not use): request.security(..., htf, high, lookahead = barmerge.lookahead_on)
// paints the day's FINAL high onto bars before it existed.

plot(pdh, "Prev Day High", color = color.teal,   style = plot.style_linebr)
plot(pdl, "Prev Day Low",  color = color.maroon, style = plot.style_linebr)

brokeHigh = ta.crossover(close, pdh)  and barstate.isconfirmed
brokeLow  = ta.crossunder(close, pdl) and barstate.isconfirmed
plotshape(brokeHigh, "Above PDH", style = shape.triangleup,   location = location.belowbar, color = color.gray)
plotshape(brokeLow,  "Below PDL", style = shape.triangledown, location = location.abovebar, color = color.gray)

Pro tip: Test any PDH/PDL script the way a repaint checker does: note the plotted level on a live bar, then reload the chart after the day closes and confirm the historical bar still shows the same value. If the level 'improved' after the fact, the script is using future data and its history cannot be trusted for study or backtesting. The levels themselves are just yesterday's facts — useful context, never a forecast. Educational content only, not financial advice; trading involves risk of loss.

Built an indicator from this? Run it through the Validator to catch look-ahead bias and repainting, or convert a strategy to Pine Script.

Educational only — not financial advice, not a recommendation to trade. No indicator is predictive; trading involves substantial risk of loss.

Catch the bug that compiles.Run auditGet Pro