//@version=5 // ===================================================================== // SPX Module 3 — Opening Range Breakout (Long Only) // // What it plots: // • Background tint — daily regime // • Aqua / fuchsia line — 15-min OR high / low (drawn after OR completes) // • Green ▲ "LONG" — first break above OR high, only when filters pass // • Status label — regime, gap, OR levels, setup status // // Filter rules built in: // • Regime must be StrongUp (above 20 / 50 / 200 daily SMA) // • Gap must NOT be a big gap-down (gapPct ≥ -0.5%) // • "High-conviction" tag if today's open prints above prior-day high // // Best used on a 5-min SPX chart. // ===================================================================== indicator("SPX Module 3 — ORB Long", overlay=true, max_labels_count=10) // === Inputs === orMinutes = input.int(15, "Opening Range minutes", minval=5, maxval=60, step=5) sessStart = input.session("0930-1600", "Cash session (exchange time)") showRegime = input.bool(true, "Tint background by regime") showOR = input.bool(true, "Show OR high/low") showEntry = input.bool(true, "Show breakout entry") // === Session detection === inSession = not na(time(timeframe.period, sessStart)) isFirstBar = inSession and not inSession[1] orBars = math.max(1, math.floor(orMinutes / math.max(timeframe.multiplier, 1))) inOR = inSession and ta.barssince(isFirstBar) < orBars // === OR state machine === var float orHigh = na var float orLow = na var bool orDone = false var bool brokeUp = false var float entryPx = na var int entryBar = na var float todayOpen = na if isFirstBar orHigh := high orLow := low orDone := false brokeUp := false entryPx := na entryBar := na todayOpen := open if inOR and not isFirstBar orHigh := math.max(orHigh, high) orLow := math.min(orLow, low) if inSession and not inOR and not orDone orDone := true // First break above OR high after OR completes trigger = false if orDone and inSession and not brokeUp and high > orHigh brokeUp := true entryPx := orHigh entryBar := bar_index trigger := true // === Daily regime + gap (from daily timeframe) === priorClose = request.security(syminfo.tickerid, "D", close[1], lookahead=barmerge.lookahead_on) priorHigh = request.security(syminfo.tickerid, "D", high[1], lookahead=barmerge.lookahead_on) dSMA20 = request.security(syminfo.tickerid, "D", ta.sma(close, 20)[1], lookahead=barmerge.lookahead_on) dSMA50 = request.security(syminfo.tickerid, "D", ta.sma(close, 50)[1], lookahead=barmerge.lookahead_on) dSMA200 = request.security(syminfo.tickerid, "D", ta.sma(close, 200)[1], lookahead=barmerge.lookahead_on) aboveAll = priorClose > dSMA20 and priorClose > dSMA50 and priorClose > dSMA200 belowAll = priorClose < dSMA20 and priorClose < dSMA50 and priorClose < dSMA200 gapPct = (todayOpen - priorClose) / priorClose * 100 filterOK = aboveAll and gapPct > -0.5 strongFilter = filterOK and todayOpen > priorHigh regimeColor = aboveAll ? color.new(color.green, 92) : belowAll ? color.new(color.red, 92) : color.new(color.gray, 95) bgcolor(showRegime ? regimeColor : na) // === Plots === plot(showOR and orDone ? orHigh : na, "OR High", color=color.new(color.aqua, 0), linewidth=2, style=plot.style_linebr) plot(showOR and orDone ? orLow : na, "OR Low", color=color.new(color.fuchsia, 0), linewidth=2, style=plot.style_linebr) validTrigger = trigger and filterOK plotshape(showEntry and validTrigger, title="ORB Long Entry", style=shape.triangleup, location=location.belowbar, color=color.new(color.green, 0), size=size.normal, text="LONG") // === Status label on latest bar === var label statusLbl = na if barstate.islast label.delete(statusLbl) regimeStr = aboveAll ? "StrongUp" : belowAll ? "StrongDown" : "Mixed" setupTxt = filterOK ? (strongFilter ? "✅ HIGH-CONVICTION (open above PDH)" : "✅ STANDARD long-only setup") : "🚫 SKIP — filters failed" statusTxt = brokeUp ? ("📈 ENTERED at " + str.tostring(entryPx, "#.##") + " — exit MOC, stop OR Low") : (orDone ? "⏳ Waiting for break above OR High..." : "⏳ OR forming...") fullText = "Module 3 — ORB Long\n" + "─────────────────\n" + "Regime: " + regimeStr + "\n" + "Gap: " + str.tostring(gapPct, "#.##") + "%\n" + "OR Hi: " + str.tostring(orHigh, "#.##") + "\n" + "OR Lo: " + str.tostring(orLow, "#.##") + "\n" + "─────────────────\n" + setupTxt + "\n" + statusTxt statusLbl := label.new(bar_index, high, text=fullText, style=label.style_label_down, color=color.new(color.black, 20), textcolor=color.white, size=size.normal) // === Alerts === alertcondition(validTrigger, "M3: ORB Long Entry", "M3: ORB break above OR high in StrongUp regime — long entry, exit MOC")