Introduction to Day High and Low in Pine Script
Understanding the Importance of Day High and Low for Traders
Day high and low are fundamental price levels watched by many traders across various markets. These levels represent the extremes of price movement within a single trading day. They serve as key reference points for identifying potential support and resistance, gauging daily volatility, and recognizing possible breakout opportunities.
Institutional traders and algorithmic systems frequently incorporate daily extremes into their strategies. Understanding how price interacts with the previous day’s high and low, or breaking the current day’s high or low, can provide valuable context for intraday price action.
Why Calculate Day High and Low in Pine Script?
Calculating day high and low directly within Pine Script allows traders to automate the identification and application of these levels. Instead of manually marking charts, you can integrate these values into custom indicators, strategies, or alert systems.
Pine Script provides efficient ways to access and process historical and real-time data, making it ideal for implementing logic based on daily extremes. This enables backtesting strategy ideas, automating execution logic, and creating dynamic visual tools on your TradingView charts.
Calculating Day High and Low Using Pine Script
There are primary methods to obtain the day’s high and low within a Pine Script script. Each has its specific use cases and implications regarding calculation time and lookahead.
Method 1: Using request.security to Fetch Daily Data
The request.security function is a powerful tool in Pine Script that allows you to request data from a different symbol, resolution, or exchange context than the current chart. This is the most robust way to get a fixed daily high/low based on daily bars, regardless of your current chart’s timeframe.
// This Pine Script™ code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © YourTradingName
//@version=5
indicator("Day High/Low (Security)", overlay=true)
// Request daily OHLC data
[dailyHigh, dailyLow] = request.security(
syminfo.tickerid, // Symbol ID
"D", // Resolution (Daily)
[high[0], low[0]],// Data series to request (current bar's high and low)
lookahead=barmerge.lookahead_off // Prevent future data leakage
)
// Plot the daily high and low
plot(dailyHigh, title="Day High", color=color.green, linewidth=2)
plot(dailyLow, title="Day Low", color=color.red, linewidth=2)
// Optional: Extend lines across the day
// This requires storing the value and only updating on new day
var float dailyHighLine = na
var float dailyLowLine = na
isNewDay = timeframe.change("D")
if isNewDay
dailyHighLine := request.security(syminfo.tickerid, "D", high[0], lookahead=barmerge.lookahead_off)
dailyLowLine := request.security(syminfo.tickerid, "D", low[0], lookahead=barmerge.lookahead_off)
else
dailyHighLine := dailyHighLine[1]
dailyLowLine := dailyLowLine[1]
// Plot extended lines
// plot(dailyHighLine, title="Day High Extended", color=color.green, linewidth=2, style=plot.style_stepline)
// plot(dailyLowLine, title="Day Low Extended", color=color.red, linewidth=2, style=plot.style_stepline)
// Explanation:
// request.security fetches the high/low from the daily bar that corresponds to the current chart bar.
// We request high[0] and low[0] from the daily timeframe, effectively getting the high and low of the *current* day's daily bar.
// lookahead=barmerge.lookahead_off is crucial to ensure we are only getting data available at the start of the daily bar.
// The optional part shows how to carry the values forward to draw horizontal lines using `timeframe.change()` to detect the start of a new day.
- Pros: Provides the correct daily high/low irrespective of the chart’s timeframe. Simple and clean code. Handles session breaks automatically based on the daily bar definition.
- Cons: Incurs a security call overhead. The value obtained is the current day’s daily bar high/low, which updates throughout the day. If you need the previous day’s high/low, you’d use
high[1]andlow[1]in therequest.securitycall, and often needbarmerge.lookahead_onor careful handling if referring to the previous completed daily bar while on an intraday timeframe.
Method 2: Utilizing dayofmonth and Conditional Logic
This method calculates the daily high and low directly on the chart’s current timeframe by tracking the maximum and minimum values since the start of the trading day. It’s more resource-intensive on lower timeframes but avoids security calls.
// This Pine Script™ code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © YourTradingName
//@version=5
indicator("Day High/Low (Intraday Calc)", overlay=true)
// Check if it's a new trading day
// Note: This is sensitive to the chart's time zone and exchange session definition.
// Using `dayofmonth` is a common proxy, but `time('D')` is more robust for detecting daily session starts.
// For simplicity, we'll use dayofmonth here, assuming standard session definition.
// A more accurate approach might involve checking if the *time* of the current bar starts a new daily session.
// isNewDay = ta.change(time("D")) // More robust new day check
isNewDay = dayofmonth != dayofmonth[1]
// Initialize or update the day's high and low
var float currentDayHigh = na
var float currentDayLow = na
if isNewDay
// New day: reset high/low to current bar's price
currentDayHigh := high
currentDayLow := low
else
// Same day: update high/low with current bar's max/min
currentDayHigh := math.max(currentDayHigh[1], high)
currentDayLow := math.min(currentDayLow[1], low)
// Plot the calculated intraday daily high and low
plot(currentDayHigh, title="Calculated Day High", color=color.blue, linewidth=1)
plot(currentDayLow, title="Calculated Day Low", color=color.orange, linewidth=1)
// Explanation:
// We check if the dayofmonth has changed from the previous bar.
// If it's a new day, we reset the high and low variables to the current bar's high/low.
// If it's the same day, we update the high and low variables using math.max and math.min
// compared to the previous bar's stored value and the current bar's high/low.
// This calculation updates on every bar of the current timeframe.
- Pros: Avoids
request.security, potentially faster on higher timeframes. Calculates the intraday high/low up to the current bar. Gives a continuously updating picture. - Cons: Logic can be tricky around session boundaries, especially for non-standard trading hours or symbols with different session definitions.
dayofmonthrelies on the server’s time zone alignment with the instrument. Less robust thanrequest.securityfor fetching values based purely on the daily bar’s completion.
Handling Trading Sessions and Time Zones
Both methods can be affected by how TradingView defines trading sessions for the specific instrument. request.security using resolution “D” typically aligns with the instrument’s standard daily session. Method 2 (intraday calculation) is more susceptible to how you define a “new day”.
Using time('D') and timeframe.change('D') is generally a more reliable way to detect the start of a daily session according to TradingView’s definition for the symbol, compared to relying solely on dayofmonth. Always test your script against the specific instrument and timeframe you intend to use to ensure the daily boundaries are correctly identified.
Applying Day High and Low in Trading Strategies
Day high and low levels are versatile tools that can be incorporated into various trading strategies and indicators.
Identifying Breakouts Using Day High and Low
A common strategy involves trading breakouts above the day’s high or below the day’s low. These breaks can indicate increasing momentum and potential continuation in the direction of the breakout.
Your script can check if the current price (e.g., close) crosses above the day’s high or below the day’s low, potentially triggering an entry signal. Considerations include filtering false breakouts, confirming with volume or other indicators, and managing risk.
Setting Stop-Loss and Take-Profit Levels Based on Day High and Low
Day high and low can serve as natural levels for setting stop-loss and take-profit orders.
- Stop-Loss: For a long trade, placing a stop-loss just below the day’s low (or previous day’s low) can provide protection with a logical exit point based on daily volatility. Conversely, for a short trade, a stop just above the day’s high is common.
- Take-Profit: Targeting the day’s high after a bounce from the low (or vice-versa) can be a valid strategy. Alternatively, using multiples of the daily range (High – Low) can help project potential profit targets beyond the immediate daily extreme.
Filtering Trades Based on Proximity to Day High/Low
Daily extremes can also be used as filters.
- You might only take long trades if the price is trading above the day’s midpoint or closer to the day’s low (indicating potential support).
- Conversely, only taking short trades when the price is below the midpoint or closer to the day’s high (indicating potential resistance).
- Avoiding entries when the price is consolidating tightly between the day’s high and low might also be a valid filtering approach.
Practical Examples and Pine Script Code
Let’s look at some concrete examples using the request.security method for simplicity and robustness in fetching the daily extremes.
Example 1: Plotting Day High and Low on the Chart
This is a slightly refined version of the earlier plotting example, adding options.
// This Pine Script™ code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © YourTradingName
//@version=5
indicator("Daily H/L Plotter", shorttitle="Day H/L", overlay=true)
// --- Inputs ---
plotToday = input.bool(true, "Plot Today's H/L")
plotYesterday = input.bool(false, "Plot Yesterday's H/L")
lineStyleInput = input.string("Solid", "Line Style", options=["Solid", "Dashed", "Dotted"])
lineColorHigh = input.color(color.green, "High Color")
lineColorLow = input.color(color.red, "Low Color")
lineWidthInput = input.int(1, "Line Width", minval=1)
// Convert string style input to plot style enum
lineStyle = lineStyleInput == "Dashed" ? plot.style_dashed :
lineStyleInput == "Dotted" ? plot.style_dotted : plot.style_solid
// --- Calculation ---
// Get today's high/low using security
[todayHigh, todayLow] = request.security(syminfo.tickerid, "D", [high[0], low[0]], lookahead=barmerge.lookahead_off)
// Get yesterday's high/low using security (accessing previous daily bar [1])
[yesterdayHigh, yesterdayLow] = request.security(syminfo.tickerid, "D", [high[1], low[1]], lookahead=barmerge.lookahead_on) // lookahead_on might be needed depending on exact use case vs bar_index, use with caution
// --- Plotting ---
// Plot today's H/L
plot(plotToday ? todayHigh : na, title="Today's High", color=lineColorHigh, linewidth=lineWidthInput, style=lineStyle)
plot(plotToday ? todayLow : na, title="Today's Low", color=lineColorLow, linewidth=lineWidthInput, style=lineStyle)
// Plot yesterday's H/L
plot(plotYesterday ? yesterdayHigh : na, title="Yesterday's High", color=lineColorHigh, linewidth=lineWidthInput, style=lineStyle)
plot(plotYesterday ? yesterdayLow : na, title="Yesterday's Low", color=lineColorLow, linewidth=lineWidthLow, style=lineStyle)
// Explanation:
// We add inputs for user control.
// We use request.security for today's H/L [0] and yesterday's H/L [1]. Note the potential need for lookahead=barmerge.lookahead_on for [1] depending on how you relate it to the current bar_index.
// The plots use a conditional (plotToday ? ... : na) to only show lines if the input is true.
// The line style is handled by converting a string input to the appropriate plot.style enum.
Example 2: Creating Alerts for Day High/Low Breaches
Alerts are crucial for acting on potential breakouts without constant chart monitoring.
// This Pine Script™ code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © YourTradingName
//@version=5
indicator("Daily H/L Breakout Alerts", shorttitle="H/L Alerts", overlay=true)
// --- Inputs ---
fireAlerts = input.bool(true, "Enable Alerts")
lookbackDays = input.int(1, "Lookback Days for H/L", minval=1) // 1 for today, 2 for previous day, etc.
// --- Calculation ---
// Get the High/Low for the specified lookback day (e.g., [0] for today, [1] for yesterday)
[targetHigh, targetLow] = request.security(syminfo.tickerid, "D", [high[lookbackDays - 1], low[lookbackDays - 1]], lookahead=barmerge.lookahead_off)
// --- Alert Conditions ---
bullishBreakout = ta.crossover(close, targetHigh)
bearishBreakout = ta.crossunder(close, targetLow)
// --- Alerts ---
if fireAlerts and bullishBreakout
alert("Bullish Breakout above " + syminfo.ticker + " " + timeframe.period + " Day High (" + str.tostring(targetHigh) + ")", alert.freq_once_per_bar)
if fireAlerts and bearishBreakout
alert("Bearish Breakout below " + syminfo.ticker + " " + timeframe.period + " Day Low (" + str.tostring(targetLow) + ")", alert.freq_once_per_bar)
// Explanation:
// We get the target day's H/L using request.security with an input for the lookback period [lookbackDays - 1].
// ta.crossover and ta.crossunder detect price breaking above/below these levels.
// Alerts are triggered based on these conditions, with dynamic alert messages including symbol, timeframe, and the breached price.
Example 3: Backtesting a Simple Day High/Low Breakout Strategy
This example outlines a basic strategy framework. Note: This is a simplified model for illustration; real strategies require more complex logic, position sizing, and risk management.
// This Pine Script™ code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © YourTradingName
//@version=5
strategy("Daily H/L Breakout Strategy", shorttitle="H/L Strat", overlay=true, initial_capital=10000, process_orders_on_close=true)
// --- Inputs ---
entryLookbackDays = input.int(1, "Entry H/L Lookback (Days)", minval=1) // 1 for today, 2 for previous day, etc.
stopLossPct = input.float(1.0, "Stop Loss %", minval=0.1) / 100
profitTargetPct = input.float(2.0, "Profit Target %", minval=0.1) / 100
// --- Calculation ---
// Get the Entry High/Low for the specified lookback day
[entryHigh, entryLow] = request.security(syminfo.tickerid, "D", [high[entryLookbackDays - 1], low[entryLookbackDays - 1]], lookahead=barmerge.lookahead_off)
// --- Strategy Logic ---
bullishEntry = ta.crossover(close, entryHigh)
bearishEntry = ta.crossunder(close, entryLow)
// Calculate stop loss and take profit levels
longStopLevel = strategy.position_avg_price * (1 - stopLossPct)
longTargetLevel = strategy.position_avg_price * (1 + profitTargetPct)
shortStopLevel = strategy.position_avg_price * (1 + stopLossPct)
shortTargetLevel = strategy.position_avg_price * (1 - profitTargetPct)
// Enter Trades
if bullishEntry
strategy.entry("Long", strategy.long)
if bearishEntry
strategy.entry("Short", strategy.short)
// Exit Trades (using calculated levels)
if strategy.position_size > 0 // Currently Long
strategy.exit("Exit Long", from_entry="Long", stop=longStopLevel, limit=longTargetLevel)
if strategy.position_size < 0 // Currently Short
strategy.exit("Exit Short", from_entry="Short", stop=shortStopLevel, limit=shortTargetLevel)
// --- Plotting (Optional) ---
// plot(entryHigh, title="Entry High", color=color.green, style=plot.style_stepline)
// plot(entryLow, title="Entry Low", color=color.red, style=plot.style_stepline)
// Explanation:
// This script gets the target day's H/L for entry using request.security.
// It defines entry conditions based on crossovers/crossunders.
// It enters long on bullish breakout, short on bearish breakout.
// It sets percentage-based stop loss and take profit using strategy.exit.
// Remember to refine entry filters, position sizing, and exit logic for robustness.
Advanced Techniques and Considerations
Working with daily levels can involve more advanced concepts, especially in real-world trading scenarios.
Adjusting Day High/Low Calculation for Extended Hours Trading
For instruments that trade extended hours (pre-market, after-hours), the standard “D” resolution may or may not include these sessions depending on the symbol and exchange settings in TradingView. If you need H/L specifically for the regular trading session or the full 24-hour period, you might need to use request.security with a specific session string or use the intraday calculation method (time('D')) in conjunction with time in session checks.
Manually defining session start/end times and using time() or hour()/minute() with conditional logic can provide precise control over which bars are included in the daily H/L calculation, but adds complexity.
Combining Day High/Low with Other Indicators
Day high and low are powerful on their own, but their effectiveness can be enhanced by combining them with other indicators.
- Volume: Confirming breakouts with significant volume adds conviction.
- Moving Averages: Using MAs as filters (e.g., only taking long breakouts if above the 200-period MA).
- Oscillators: Using RSI or Stochastic to check for overbought/oversold conditions near daily extremes.
- Pivot Points: Day H/L are related to pivot point calculations and can be used in conjunction with them.
Optimizing Pine Script Code for Efficiency
When calculating day high and low, especially on lower timeframes, script performance is important.
- Minimize
request.securitycalls: While often necessary, repeated calls within tight loops or unnecessary calls can slow down your script. - Avoid
lookahead=barmerge.lookahead_onif possible: Using lookahead introduces potential repainting issues and should be understood and used cautiously. Fetching data from previous completed bars ([1],[2], etc., withlookahead_offor impliedlookahead_off) is generally safer. - Optimize intraday calculations: If using Method 2, ensure your
isNewDaylogic is efficient. Variable declaration usingvaris crucial for maintaining state across bars without redundant calculations. - Use
timeframe.change(): This built-in function is optimized for detecting resolution changes (like the start of a new day) and is generally preferred over manualdayofmonthchecks for session boundaries. Always test performance on your target assets and timeframes.calc_once_per_dayfunction can also be helpful with security calls for daily data.request.security(..., strategy.closed.entries[0], ...)can fetch data only when a trade is closed, reducing calls.
By understanding the nuances of these methods and applying them thoughtfully, you can effectively leverage day high and low levels in your Pine Script indicators and strategies.