Analyzing Afternoon vs. Morning Ranges in Pine Script
This lesson explores a script I made to validate a hypothesis posed by a trader at SMB Capital regarding morning/afternoon ranges and trend-continuation.
Check out my other free lessons!Source Code
// This Pine Script™ code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/ // © ZenAndTheArtOfTrading // @version=5 indicator("RANGE CONTINUATION TEST", overlay=true) // Get user input Session1 = input.session(title="First Session", defval="0930-1200", display=display.none) Session2 = input.session(title="Second Session", defval="1200-1600", display=display.none) StartDate = input.time(timestamp("1 January 2000")) EndDate = input.time(timestamp("1 January 2030")) // InSession() determines if a price bar falls inside the specified session on the given weekdays InSession(sess) => na(time(timeframe.period, sess + ":1234567")) == false // Highlight sessions bgcolor(InSession(Session1) ? color.new(color.green, 90) : na) bgcolor(InSession(Session2) ? color.new(color.red, 90) : na) // Get higher timeframe data float yesterdayHigh = request.security(syminfo.tickerid, "D", high [barstate.isrealtime ? 1 : 0])[barstate.isrealtime ? 0 : 1] float yesterdayLow = request.security(syminfo.tickerid, "D", low [barstate.isrealtime ? 1 : 0])[barstate.isrealtime ? 0 : 1] // Detect session start bool startSession1 = not InSession(Session1)[1] and InSession(Session1) and time >= StartDate bool startSession2 = not InSession(Session2)[1] and InSession(Session2) and time >= StartDate // Analysis variables var int bullishRangeExpansionCount = 0 var int bearishRangeExpansionCount = 0 var int bullishRangeContinuation = 0 var int bearishRangeContinuation = 0 // First session variables var int sessionIndex1 = na var float dayOpenPrice = na var float sessionLow1 = na var float sessionHigh1 = na // Second session variables var int sessionIndex2 = na var float sessionLow2 = na var float sessionHigh2 = na var bool rangeExpansion = false var bool checkContinuation = false // Analysis variables var bool yesterdayWasBullish = false var bool monitoring1stSession = false // 1. Detect start of day's first session // 2. Save previously monitored session's range // 3. Save yesterday's close and today's open // 4. Reset and start monitoring today's first session // 5. Start of day's first session is also end of yesterday's second session, so analyze data if startSession1 bool bullishClose = close[1] > dayOpenPrice line.new(sessionIndex1, dayOpenPrice, bar_index - 1, close[1], color=bullishClose ? color.green : color.red) line.new(sessionIndex2, sessionHigh2 + (sessionHigh1 - sessionHigh2), sessionIndex2, sessionLow2 + (sessionHigh1 - sessionHigh2), color=color.red, width=2) if (sessionHigh2 - sessionLow2) >= (sessionHigh1 - sessionLow1) rangeExpansion := true label.new(bar_index - 1, high[1], (bullishClose ? "BULLISH" : "BEARISH") + " RANGE\nEXPANSION!", textcolor=color.white) else rangeExpansion := false sessionIndex1 := bar_index sessionLow1 := na sessionHigh1 := na monitoring1stSession := true dayOpenPrice := open if checkContinuation // We had range expansion yesterday - check if we continued in trend if yesterdayWasBullish // Yesterday was a bullish day - check for bullish continuation bool bullishContinuation = close[1] > yesterdayHigh bullishRangeExpansionCount := bullishRangeExpansionCount + 1 line.new(bar_index, yesterdayHigh, bar_index - 20, yesterdayHigh, color=bullishContinuation ? color.green : color.gray) if bullishContinuation bullishRangeContinuation := bullishRangeContinuation + 1 label.new(bar_index - 1, high[1], "BULLISH CONTINUATION!", color=color.green, textcolor=color.white) else bool bearishContinuation = close[1] < yesterdayLow bearishRangeExpansionCount := bearishRangeExpansionCount + 1 line.new(bar_index, yesterdayLow, bar_index - 20, yesterdayLow, color=bearishContinuation ? color.red : color.gray) if bearishContinuation bearishRangeContinuation := bearishRangeContinuation + 1 label.new(bar_index - 1, high[1], "BEARISH CONTINUATION!", color=color.red, textcolor=color.white) checkContinuation := false yesterdayWasBullish := close[1] > dayOpenPrice[1] // Track first session's range if monitoring1stSession if na(sessionLow1) or low < sessionLow1 sessionLow1 := low if na(sessionHigh1) or high > sessionHigh1 sessionHigh1 := high // 1. Detect start of day's second session // 2. Reset and start monitoring today's second session if startSession2 line.new(bar_index - 1, sessionHigh1, bar_index - 1, sessionLow1, color=color.green, width=2) monitoring1stSession := false sessionLow2 := na sessionHigh2 := na sessionIndex2 := bar_index checkContinuation := rangeExpansion // Track second session's range if not monitoring1stSession if na(sessionLow2) or low < sessionLow2 sessionLow2 := low if na(sessionHigh2) or high > sessionHigh2 sessionHigh2 := high // Analysis of range expansion data int totalRangeExpansionCount = bullishRangeExpansionCount + bearishRangeExpansionCount float totalExpansionChance = ((bullishRangeContinuation + bearishRangeContinuation) / totalRangeExpansionCount) * 100 float bullishExpansionChance = (bullishRangeContinuation / bullishRangeExpansionCount) * 100 float bearishExpansionChance = (bearishRangeContinuation / bearishRangeExpansionCount) * 100 // Debug data window plots plot(yesterdayWasBullish ? 1 : 0, title="BULLISH DAY?", display=display.data_window) plotshape(rangeExpansion ? 1 : na, "PREVIOUS EXPANSION?", shape.square, location.top, color=yesterdayWasBullish ? color.green : color.red) plot(na, title="-----------", display=display.data_window) plot(totalRangeExpansionCount, title="TOTAL RANGE EXPANSION", display=display.data_window) plot(bullishRangeExpansionCount, title="TOTAL BULLISH RANGE EXP", display=display.data_window) plot(bullishRangeContinuation, title="TOTAL BULLISH RANGE CNT", display=display.data_window) plot(bearishRangeExpansionCount, title="TOTAL BEARISH RANGE EXP", display=display.data_window) plot(bearishRangeContinuation, title="TOTAL BEARISH RANGE CNT", display=display.data_window) plot(na, title="-----------", display=display.data_window) plot(totalExpansionChance, title="Total Continuation Chance", display=display.data_window) plot(bullishExpansionChance, title="Bullish Continuation Chance", display=display.data_window) plot(bearishExpansionChance, title="Bearish Continuation Chance", display=display.data_window) // Create stat display table if barstate.islast var table myTable = table.new(position.top_right, 5, 2, border_width=1) txt1 = "Total Range Expansion\n" + str.tostring(totalRangeExpansionCount) txt2 = "Total Continuation Chance\n" + str.tostring(totalExpansionChance, "#.##") + "%" txt3 = "Bullish Days w/ Expansion\n" + str.tostring(bullishRangeExpansionCount) txt4 = "Bullish Continuation Chance\n" + str.tostring(bullishExpansionChance, "#.##") + "%" txt5 = "Bearish Days w/ Expansion\n" + str.tostring(bearishRangeExpansionCount) txt6 = "Bearish Continuation Chance\n" + str.tostring(bearishExpansionChance, "#.##") + "%" table.cell(myTable, 0, 0, text=txt1, bgcolor=color.black, text_color=color.white) table.cell(myTable, 0, 1, text=txt2, bgcolor=color.black, text_color=color.white) table.cell(myTable, 1, 0, text=txt3, bgcolor=color.black, text_color=color.white) table.cell(myTable, 1, 1, text=txt4, bgcolor=color.black, text_color=color.white) table.cell(myTable, 2, 0, text=txt5, bgcolor=color.black, text_color=color.white) table.cell(myTable, 2, 1, text=txt6, bgcolor=color.black, text_color=color.white)