How to Access and Use Previous Day’s High and Low in TradingView Pine Script?

Welcome, fellow traders and Pine Script enthusiasts. As experienced developers, we understand the critical role historical data plays in building robust trading indicators and strategies. Among the most fundamental pieces of historical data are the previous day’s high and low prices. These levels are widely recognized as significant points of interest, often acting as potential support or resistance zones.

Importance of Previous Day’s High/Low in Trading

The previous day’s high and low represent the price extremes reached during the last trading session. Their importance stems from several factors:

  • Psychological Significance: They mark clear boundaries from recent price action, serving as reference points for market participants.
  • Support and Resistance: Prices often react upon reaching these levels. A break above the previous day’s high or below the previous day’s low is a common signal watched by many traders.
  • Volatility Measurement: The range between the previous day’s high and low provides a simple measure of recent volatility, informing position sizing and stop-loss placement.
  • Basis for Strategies: Numerous trading strategies, particularly breakout and reversal systems, are built around price interaction with these specific historical levels.

Integrating these levels into your Pine Script indicators or strategies allows you to align your analysis and execution with widely observed market dynamics.

Overview of Pine Script and Its Limitations

Pine Script is a powerful language designed for creating technical indicators and strategies on TradingView. Its strengths lie in its conciseness and direct access to bar data (open, high, low, close, volume, time). However, by default, Pine Script operates strictly on the timeframe of the chart it’s applied to.

Accessing data from different timeframes or periods (like the previous calendar day, regardless of the current chart’s timeframe) requires specific functions. Simply using high[1] on a 15-minute chart gives you the high of the previous 15-minute bar, not the previous day’s high.

Challenges in Accessing Historical Data

The primary challenge in accessing historical data from a higher timeframe, such as the previous day’s high or low, within a lower timeframe script is synchronizing the data. A daily bar contains information for an entire trading session, while a 1-minute bar only contains data for that specific minute.

The system needs a way to:;

  1. Request data specifically from the ‘Daily’ timeframe.
  2. Identify which ‘Daily’ bar corresponds to the ‘previous day’ relative to the current bar on the lower timeframe chart.
  3. Retrieve the high and low values from that specific ‘Daily’ bar.
  4. Make these values available for every bar within the current day on the lower timeframe.

Pine Script provides the request.security() function precisely for this purpose.

Methods for Retrieving Previous Day’s High and Low

The most reliable and idiomatic way to access previous period data, including the previous day’s high and low, in Pine Script is through the request.security() function.

Using the security() Function with timeframe.period

The request.security() function allows you to request data from a different symbol and/or timeframe than the one the script is currently running on. Its basic syntax is request.security(symbol, timeframe, expression, lookahead, gaps). For accessing the previous day’s high/low on the same symbol but a different timeframe, we use syminfo.tickerid for the symbol, 'D' for the daily timeframe, and specify the data we want.

To get the previous day’s high and low, we need the high and low from the previous daily bar. The index [1] refers to the previous bar on its own timeframe.

// Get previous day's high and low using security()
prevDayHigh = request.security(syminfo.tickerid, 'D', high[1], barmerge.lookahead_off)
prevDayLow  = request.security(syminfo.tickerid, 'D', low[1], barmerge.lookahead_off)

// The 'prevDayHigh' and 'prevDayLow' variables will hold the previous day's
// high and low values, respectively. These values will be constant for all
// bars within the current calendar day on the lower timeframe chart.

The critical arguments here are:

  • syminfo.tickerid: Ensures you are requesting data for the same symbol as the chart.
  • 'D': Specifies the Daily timeframe.
  • high[1] and low[1]: Requests the high and low values from the bar previous to the one currently being processed by security on the ‘D’ timeframe. This correctly fetches the previous day’s data.
  • barmerge.lookahead_off: Crucially, set lookahead to barmerge.lookahead_off. This prevents the script from potentially accessing data from the current daily bar before it has closed, avoiding repainting issues. For historical data like the previous day’s close, barmerge.lookahead_off is the standard and safest setting.

Implementing Custom Functions for Day Calculation

While request.security() is the recommended approach for previous period data like the previous day, it’s worth noting that for finding specific events within a period or iterating through bars based on time changes, custom functions or logic involving built-in time variables (time, dayofmonth, month, year, etc.) can be used.

One common pattern involves detecting the first bar of a new day using dayofmonth != dayofmonth[1]. On the first bar of a new day, you could then look back to find the high and low of the previous day’s bars on the current timeframe. This is more complex and less efficient than security('D', ...), which handles the cross-timeframe synchronization internally. Therefore, request.security('D', ...) remains the preferred method for the specific task of getting the previous day’s H/L.

Leveraging Built-in Variables for Date Comparison

Built-in time variables like dayofmonth, month, and year are primarily useful for identifying period boundaries on the current chart’s timeframe. For instance, new_day = dayofmonth(timenow) != dayofmonth(timenow[1]) (or simpler dayofmonth != dayofmonth[1]) can detect the start of a new day on the current chart’s timeframe.

You could use these variables to mark the beginning of a day and then potentially store the high and low of bars occurring since the last new_day event. However, this requires significant logic to track the maximum high and minimum low throughout the day and reset at the start of the next. Again, request.security('D', ...) handles this aggregation and lookback far more elegantly and efficiently for fetching the overall previous day’s extremes.

Pine Script Code Examples

Let’s look at practical examples demonstrating how to implement and use the previous day’s high and low in Pine Script.

Basic Script to Plot Previous Day’s High and Low

This script shows how to fetch and plot the previous day’s high and low levels on your chart, regardless of the chart’s current timeframe (as long as it’s lower than Daily).

//@version=5
indicator("Previous Day High/Low", shorttitle="PD H/L", overlay=true)

// --- Get Previous Day's Data ---
// Request previous day's high and low from the Daily timeframe
// high[1] and low[1] access the previous completed daily bar's data.
// barmerge.lookahead_off ensures no future data is used.
prevDayHigh = request.security(syminfo.tickerid, 'D', high[1], barmerge.lookahead_off)
prevDayLow  = request.security(syminfo.tickerid, 'D', low[1], barmerge.lookahead_off)

// --- Plotting ---+
// Plot the levels. Use extend=extend.right to draw them across the current day.
// Use color=na and linewidth=0 initially, then plot only when the value changes (once per day).
// A simpler approach for constant daily values is to just plot directly,
// as Pine Script handles constant series efficiently across bars.

plot(prevDayHigh, title="Previous Day High", color=color.blue, linewidth=2, style=plot.style_line, extend=extend.right)
plot(prevDayLow,  title="Previous Day Low",  color=color.red,  linewidth=2, style=plot.style_line, extend=extend.right)

// Optional: Add labels for clarity
// Only display labels on the first bar of the day to avoid clutter
var bool isNewDay = dayofmonth(time) != dayofmonth(time[1]) or barstate.isfirst

if isNewDay
    label.new(bar_index, prevDayHigh, "PDH", color=color.blue, textcolor=color.white, style=label.style_label_down)
    label.new(bar_index, prevDayLow, "PDL", color=color.red, textcolor=color.white, style=label.style_label_up)

Explanation: The script defines prevDayHigh and prevDayLow using request.security. These variables hold the previous day’s values, which remain constant for all bars within the current calendar day. The plot function draws horizontal lines at these levels, extended to the right. The optional labels are added only on the first bar of the new day (isNewDay logic) to keep the chart clean.

Advanced Script with Dynamic Timeframe Selection

While accessing the previous day specifically uses 'D', you might generalize this to access the previous value from any higher timeframe. This example shows how to make the target timeframe selectable via input.

//@version=5
indicator("Previous Period High/Low (Select TF)", shorttitle="Prev TF H/L", overlay=true)

// --- Inputs ---
// Allow user to select the target timeframe (must be higher than chart TF)
string i_timeframe = input.timeframe('D', "Target Timeframe")

// --- Get Previous Period's Data ---
// Request previous period's high and low from the selected timeframe
// high[1] and low[1] access the previous completed bar's data on the target TF.
// barmerge.lookahead_off ensures no future data is used.
prevPeriodHigh = request.security(syminfo.tickerid, i_timeframe, high[1], barmerge.lookahead_off)
prevPeriodLow  = request.security(syminfo.tickerid, i_timeframe, low[1], barmerge.lookahead_off)

// --- Plotting ---
plot(prevPeriodHigh, title="Previous Period High", color=color.blue, linewidth=2, style=plot.style_line, extend=extend.right)
plot(prevPeriodLow,  title="Previous Period Low",  color=color.red,  linewidth=2, style=plot.style_line, extend=extend.right)

// Optional: Calculate and plot the range and midpoint
prevPeriodRange = prevPeriodHigh - prevPeriodLow
prevPeriodMid   = (prevPeriodHigh + prevPeriodLow) / 2

plot(prevPeriodMid, title="Previous Period Midpoint", color=color.gray, linewidth=1, style=plot.style_line, extend=extend.right)
// Note: Plotting the range itself as a level doesn't make visual sense, but the variable can be used for calculations.
// plotchar(prevPeriodRange, title="Prev Period Range", char='R', location=location.top, color=color.purple) // Example of using the range value

Explanation: This version introduces a timeframe input i_timeframe, defaulting to 'D'. request.security now uses this input variable. This makes the script more versatile, allowing analysis based on the previous week ('W'), previous month ('M'), or even a specific hourly timeframe relative to a lower one (e.g., previous 4-hour on a 15-minute chart). We also demonstrate calculating and plotting the midpoint and range, showing how the retrieved data can be used.

Script with Error Handling and Data Validation

request.security can return na (Not Available) in certain situations, primarily on the very first bars of the chart or if there’s a data gap on the requested timeframe. It’s good practice to check for na before using the values, especially if they are critical for calculations or strategy logic.

//@version=5
indicator("Previous Day H/L with NA Check", shorttitle="PD H/L (NA Check)", overlay=true)

// --- Get Previous Day's Data ---
prevDayHigh = request.security(syminfo.tickerid, 'D', high[1], barmerge.lookahead_off)
prevDayLow  = request.security(syminfo.tickerid, 'D', low[1], barmerge.lookahead_off)

// --- Data Validation ---
// Check if the previous day's data is available (not NA)
bool dataValid = not na(prevDayHigh) and not na(prevDayLow)

// --- Plotting ---+
// Only plot if the data is valid
plot(dataValid ? prevDayHigh : na, title="Previous Day High", color=color.blue, linewidth=2, style=plot.style_line, extend=extend.right)
plot(dataValid ? prevDayLow  : na, title="Previous Day Low",  color=color.red,  linewidth=2, style=plot.style_line, extend=extend.right)

// Example: Use the data in a strategy condition (simplified)
// This part would be in a strategy script using strategy() declaration
// longCondition = dataValid and close > prevDayHigh
// shortCondition = dataValid and close < prevDayLow

// plotshape(longCondition, style=shape.labelup, color=color.green, text="Breakout Buy", location=location.belowbar)
// plotshape(shortCondition, style=shape.labeldown, color=color.red, text="Breakout Sell", location=location.abovebar)

Explanation: We introduce a dataValid boolean variable that checks if both prevDayHigh and prevDayLow are not na. The plotting calls use the ternary operator condition ? value_if_true : value_if_false to plot the levels only if dataValid is true; otherwise, they plot na, which means nothing is drawn for that bar. This prevents visual glitches or erroneous calculations on the initial bars of the chart where previous day data might not yet be loaded.

Practical Applications and Trading Strategies

Once you have successfully accessed the previous day’s high and low, you can integrate them into various trading tools and strategies.

Identifying Support and Resistance Levels

The most straightforward application is using these levels as dynamic support and resistance. Price action around these levels can provide trading signals:

  • Bounce: Price approaches the previous day’s high and reverses downwards (resistance), or approaches the low and reverses upwards (support).
  • Breakout: Price decisively breaks above the previous day’s high or below the previous day’s low, suggesting continuation in the direction of the break.

Plotting these lines on your chart helps visualize these potential interaction zones.

Developing Breakout Trading Strategies

Previous day highs and lows are classic levels for breakout strategies. A simple strategy might enter a long position when the current price closes above the previous day’s high and a short position when it closes below the previous day’s low. More advanced strategies would incorporate:

  • Volume confirmation on the breakout.
  • Filtering breakouts based on the time of day.
  • Setting stop losses based on the previous day’s range or the breakout candle.
  • Using other indicators (like moving averages or volatility measures) to confirm the trend or market condition.

Example condition logic within a strategy:

// Assuming prevDayHigh and prevDayLow are calculated as shown before
bool longCondition = close > prevDayHigh[1] // Check current close vs *previous* bar's PDH value
bool shortCondition = close < prevDayLow[1]  // Check current close vs *previous* bar's PDL value

if longCondition
    strategy.entry("Long", strategy.long)

if shortCondition
    strategy.entry("Short", strategy.short)

// Add exit conditions, stop losses, take profits, etc.

Note the use of [1] on prevDayHigh and prevDayLow in the condition. On a lower timeframe, the value of prevDayHigh is constant throughout the day. Comparing the current bar’s close to the current prevDayHigh means the signal would be true for all bars after the first one that closed above the PDH. Comparing to prevDayHigh[1] ensures you are comparing the current close to the PDH value that was valid on the previous bar, which is often the desired behavior for a breakout signal on the candle after the potential breakout occurred, or the bar on which the close happened relative to the previous bar’s PDH value.

Integrating Previous Day’s Data into Existing Indicators

The previous day’s high and low can enhance other indicators:

  • Volatility Indicators: Compare the current day’s range to the previous day’s range to assess relative volatility.
  • Pivot Points: These often use previous day’s H/L/C in their calculation. You can build custom pivot logic.
  • Relative Strength: Compare the current price’s position relative to the previous day’s range (e.g., is price in the upper or lower half?).
  • Dashboards: Display previous day’s H/L and range in a panel for quick reference.

These are just a few ideas; the key is that having reliable access to these historical levels opens up many possibilities for quantitative analysis and rule-based trading.

Conclusion: Best Practices and Further Exploration

Accessing previous day’s high and low is a fundamental skill for developing sophisticated Pine Script tools. request.security('D', ...) is the standard, efficient, and reliable method for this task.

Summary of Techniques for Accessing Historical Data

We focused on request.security with the Daily timeframe ('D') and the [1] index to retrieve the previous day’s completed data. This function handles the complexities of cross-timeframe data requests effectively. While date comparison using variables like dayofmonth can identify daily boundaries on the current timeframe, they are less suitable for directly fetching aggregated historical values like the previous day’s high/low compared to security.

Tips for Optimizing Script Performance

  • Minimize request.security Calls: While generally efficient, calling request.security repeatedly with the same arguments on every bar is handled by Pine Script’s caching. However, be mindful if you need data from many different timeframes or symbols in a single script; too many calls can impact performance. In our case, getting just the previous day’s H/L requires only two security calls, which is perfectly fine.
  • Avoid barmerge.lookahead_on: As mentioned, using barmerge.lookahead_off (or simply omitting the lookahead argument, as off is the default for historical references) is crucial for avoiding repainting and ensuring your previous day’s data is truly from the previous completed day.
  • Check for na: As shown in the examples, validating the data with not na(...) before using it in calculations or plotting prevents errors and unexpected behavior on bars where data might be temporarily unavailable.

Potential Issues and Troubleshooting

  • Data Gaps: On some instruments or during specific market events (like holidays or exchange outages), the ‘D’ timeframe might have data gaps. request.security will return na during these periods. Your script should account for this, as demonstrated with the na checks.
  • Timezone Differences: TradingView handles timezones for bars and time variables correctly within the chart context. request.security('D', ...) requests data based on the exchange’s timezone or the symbol’s primary trading hours, which aligns with how ‘daily’ bars are typically defined. Be aware of how your local time or desired analysis window aligns with the chart’s bar times.
  • First Bars of Chart: The first few bars loaded on the chart might not have a preceding ‘Daily’ bar available for request.security to reference high[1]. This is another scenario where na will be returned, reinforcing the need for na checks.

Further Learning Resources for Pine Script

To deepen your understanding of Pine Script and its capabilities, including more advanced techniques for handling historical data, refer to:

  • The official TradingView Pine Script Reference Manual.
  • The TradingView Help Center documentation on scripting.
  • Community scripts and discussions on TradingView.

Mastering functions like request.security is key to unlocking the full potential of Pine Script for developing powerful, cross-timeframe trading tools.


Leave a Reply