Code: Select all
//@version=5
indicator("Pro NY Opening Range (OR) [Advanced]", overlay=true, max_boxes_count=100, max_lines_count=200, max_labels_count=100)
// =========================================================================
// 1. SETTINGS & INPUTS
// =========================================================================
grp_time = "Session Settings"
orSession = input.session("0930-1000", title="OR Time (EST)", group=grp_time)
tradeSession = input.session("1000-1600", title="Trading Session", group=grp_time)
tz = input.string("America/New_York", title="Timezone", group=grp_time)
grp_filters = "Filters & Targets"
useVol = input.bool(true, title="Require Volume Spike for Breakouts?", group=grp_filters, tooltip="Breakout candle must have volume higher than the 20-SMA of volume.")
showTargets = input.bool(true, title="Show 1R & 2R Expansion Targets?", group=grp_filters)
grp_ui = "UI & Dashboard"
showDash = input.bool(true, title="Show Data Dashboard", group=grp_ui)
boxColor = input.color(color.new(color.gray, 85), title="OR Box Color", group=grp_ui)
// =========================================================================
// 2. CORE SESSION LOGIC & DATA
// =========================================================================
inOrSession = time(timeframe.period, orSession, tz)
inTradeSession = time(timeframe.period, tradeSession, tz)
isNewOr = inOrSession and not inOrSession[1]
isTradeStart = inTradeSession and not inTradeSession[1]
var float orHigh = na
var float orLow = na
var int orStartBar = na
// ATR for Exhaustion checking
dailyATR = request.security(syminfo.tickerid, "D", ta.atr(14))
volSMA = ta.sma(volume, 20)
volSpike = volume > volSMA
// Update Range
if isNewOr
orHigh := high
orLow := low
orStartBar := bar_index
else if inOrSession
orHigh := math.max(orHigh, high)
orLow := math.min(orLow, low)
float rangeSize = orHigh - orLow
// =========================================================================
// 3. PRO VISUALS (BOXES & LINES)
// =========================================================================
var box orBox = na
var line highLine = na
var line lowLine = na
var line t1Up = na
var line t1Dn = na
if isNewOr
// Create new drawing objects for the day
orBox := box.new(left=bar_index, top=orHigh, bottom=orLow, right=bar_index, bgcolor=boxColor, border_color=color.new(color.gray, 50))
if inOrSession
// Expand box while forming
box.set_top(orBox, orHigh)
box.set_bottom(orBox, orLow)
box.set_right(orBox, bar_index)
if isTradeStart
// Draw horizontal projection lines at the start of trade session
highLine := line.new(x1=orStartBar, y1=orHigh, x2=bar_index, y2=orHigh, color=color.green, style=line.style_solid, width=2)
lowLine := line.new(x1=orStartBar, y1=orLow, x2=bar_index, y2=orLow, color=color.red, style=line.style_solid, width=2)
if showTargets
t1Up := line.new(x1=orStartBar, y1=orHigh + rangeSize, x2=bar_index, y2=orHigh + rangeSize, color=color.new(color.green, 50), style=line.style_dashed)
t1Dn := line.new(x1=orStartBar, y1=orLow - rangeSize, x2=bar_index, y2=orLow - rangeSize, color=color.new(color.red, 50), style=line.style_dashed)
if inTradeSession
// Extend lines forward with price action
line.set_x2(highLine, bar_index)
line.set_x2(lowLine, bar_index)
if showTargets
line.set_x2(t1Up, bar_index)
line.set_x2(t1Dn, bar_index)
// =========================================================================
// 4. SIGNALS (WITH VOLUME FILTER)
// =========================================================================
// Breakouts
validBOUp = inTradeSession and close > orHigh and close[1] <= orHigh and (useVol ? volSpike : true)
validBODn = inTradeSession and close < orLow and close[1] >= orLow and (useVol ? volSpike : true)
// Sweeps / Fakeouts
validFOUp = inTradeSession and low < orLow and close > orLow and close[1] >= orLow
validFODn = inTradeSession and high > orHigh and close < orHigh and close[1] <= orHigh
plotshape(validBOUp, title="BO Up", style=shape.triangleup, location=location.belowbar, color=color.green, size=size.small)
plotshape(validBODn, title="BO Down", style=shape.triangledown, location=location.abovebar, color=color.red, size=size.small)
plotshape(validFOUp, title="Sweep Bottom", style=shape.arrowup, location=location.belowbar, color=color.blue, size=size.small)
plotshape(validFODn, title="Sweep Top", style=shape.arrowdown, location=location.abovebar, color=color.orange, size=size.small)
// =========================================================================
// 5. PROFESSIONAL DASHBOARD
// =========================================================================
var table dash = table.new(position.top_right, 2, 4, bgcolor=color.new(color.black, 20), border_width=1, border_color=color.gray)
if showDash and barstate.islast
// Calculate how much fuel is left
float rangePips = syminfo.mintick == 0.00001 ? rangeSize * 10000 : rangeSize / syminfo.mintick
float atrPips = syminfo.mintick == 0.00001 ? dailyATR * 10000 : dailyATR / syminfo.mintick
float exhaustionPct = (rangeSize / dailyATR) * 100
color exhColor = exhaustionPct > 50 ? color.red : color.green // If OR is > 50% of ATR, breakouts are dangerous
table.cell(dash, 0, 0, "NY OR Status", text_color=color.white, text_size=size.small)
table.cell(dash, 1, 0, inOrSession ? "Forming..." : inTradeSession ? "Active" : "Closed", text_color=inOrSession ? color.yellow : color.white, text_size=size.small)
table.cell(dash, 0, 1, "Range Size", text_color=color.white, text_size=size.small)
table.cell(dash, 1, 1, str.tostring(rangePips, "#.1") + " pts", text_color=color.white, text_size=size.small)
table.cell(dash, 0, 2, "Daily ATR", text_color=color.white, text_size=size.small)
table.cell(dash, 1, 2, str.tostring(atrPips, "#.1") + " pts", text_color=color.white, text_size=size.small)
table.cell(dash, 0, 3, "Exhaustion", text_color=color.white, text_size=size.small)
table.cell(dash, 1, 3, str.tostring(exhaustionPct, "#.1") + "%", text_color=exhColor, text_size=size.small)
// =========================================================================
// 6. ALERTS
// =========================================================================
alertcondition(validBOUp, "Pro OR Breakout UP", "Bullish Breakout: Valid volume and close above OR High.")
alertcondition(validBODn, "Pro OR Breakout DOWN", "Bearish Breakout: Valid volume and close below OR Low.")
alertcondition(validFOUp, "Pro OR Sweep BOTTOM", "Bullish Fakeout: Price swept the OR Low and rejected.")
alertcondition(validFODn, "Pro OR Sweep TOP", "Bearish Fakeout: Price swept the OR High and rejected.")