Skip to content

Instantly share code, notes, and snippets.

@bthaile
Created April 6, 2026 00:02
Show Gist options
  • Select an option

  • Save bthaile/27481a9cd95b157643980dc4bdb45b58 to your computer and use it in GitHub Desktop.

Select an option

Save bthaile/27481a9cd95b157643980dc4bdb45b58 to your computer and use it in GitHub Desktop.
//@version=6
strategy("30min ORB + OR Box + Gap Filter [v6]", overlay=true,
default_qty_type=strategy.percent_of_equity,
default_qty_value=100,
commission_type=strategy.commission.percent,
commission_value=0.1)
// ── Inputs ─────────────────────────────────────────────────────────────────────
orbMinutes = input.int(30, "Opening Range Minutes", minval=5, maxval=60)
gapMovePct = input.float(5.0, "Gap Threshold %", minval=0.1)
useVWAPFilter = input.bool(true, "Require VWAP Confirmation")
useConfirmBar = input.bool(true, "Require Next Bar Confirmation")
maFastLen = input.int(4, "Profit MA Fast Length")
maSlowLen = input.int(9, "Profit MA Slow Length")
maType = input.string("EMA", "MA Type", options=["SMA", "EMA"])
// ── Optional safety: built for 5m charts ──────────────────────────────────────
if timeframe.period != "5"
runtime.error("This strategy is intended for 5-minute charts only.")
// ── Session filters ────────────────────────────────────────────────────────────
bool inSession = not na(time(timeframe.period, "0930-1600"))
bool before11 = hour < 11
// ── Gap filter ─────────────────────────────────────────────────────────────────
// Note: This is an overnight gap proxy, not true after-hours move.
prevClose = request.security(syminfo.tickerid, "1D", close[1], lookahead=barmerge.lookahead_on)
gapPct = prevClose != 0 ? (open - prevClose) / prevClose * 100 : 0
isInPlay = math.abs(gapPct) >= gapMovePct
// ── New day detection ──────────────────────────────────────────────────────────
bool isNewDay = ta.change(time("1D")) != 0
// ── Opening Range state ────────────────────────────────────────────────────────
var float orHigh = na
var float orLow = na
var bool orSet = false
var int orStartBar = na
var int orEndBar = na
var box orBox = na
if isNewDay
orHigh := na
orLow := na
orSet := false
orStartBar := na
orEndBar := na
orBox := na
barsInOR = ta.barssince(isNewDay)
orBars = math.round(orbMinutes / 5)
inOrbPeriod = inSession and not orSet and barsInOR < orBars
// ── Build OR high/low ──────────────────────────────────────────────────────────
if inOrbPeriod
orStartBar := na(orStartBar) ? bar_index : orStartBar
orHigh := na(orHigh) ? high : math.max(orHigh, high)
orLow := na(orLow) ? low : math.min(orLow, low)
// ── Finalize OR after window closes ────────────────────────────────────────────
if not orSet and not inOrbPeriod and not na(orHigh) and not na(orLow)
orSet := true
orEndBar := bar_index - 1
// Create a full box covering the OR candles
orBox := box.new(
left=orStartBar,
top=orHigh,
right=orEndBar,
bottom=orLow,
border_color=color.new(color.yellow, 0),
bgcolor=color.new(color.yellow, 85)
)
// Extend the box to the right all day so you can see the breakout level
if orSet and not na(orBox)
box.set_right(orBox, bar_index)
box.set_top(orBox, orHigh)
box.set_bottom(orBox, orLow)
// ── Plot OR levels ─────────────────────────────────────────────────────────────
plot(orSet ? orHigh : na, "ORB High", color.red, 2, plot.style_linebr)
plot(orSet ? orLow : na, "ORB Low", color.lime, 2, plot.style_linebr)
// ── VWAP ───────────────────────────────────────────────────────────────────────
vwapValue = ta.vwap(hlc3)
plot(useVWAPFilter ? vwapValue : na, "VWAP", color.purple, 2)
// ── Profit MAs ─────────────────────────────────────────────────────────────────
maFast = maType == "EMA" ? ta.ema(close, maFastLen) : ta.sma(close, maFastLen)
maSlow = maType == "EMA" ? ta.ema(close, maSlowLen) : ta.sma(close, maSlowLen)
plot(maFast, "Fast MA", color.orange, 1)
plot(maSlow, "Slow MA", color.blue, 1)
// ── Breakout logic ─────────────────────────────────────────────────────────────
bullBreak = orSet and close > orHigh and close[1] <= orHigh
bearBreak = orSet and close < orLow and close[1] >= orLow
bullSignal = useConfirmBar ? (bullBreak[1] and close > orHigh) : bullBreak
bearSignal = useConfirmBar ? (bearBreak[1] and close < orLow) : bearBreak
longCondition = isInPlay and bullSignal and (not useVWAPFilter or close > vwapValue) and before11 and inSession
shortCondition = isInPlay and bearSignal and (not useVWAPFilter or close < vwapValue) and before11 and inSession
// ── Entries ────────────────────────────────────────────────────────────────────
if longCondition and strategy.position_size <= 0
strategy.entry("Long", strategy.long)
if shortCondition and strategy.position_size >= 0
strategy.entry("Short", strategy.short)
// ── Exits ──────────────────────────────────────────────────────────────────────
strategy.exit("Long Stop", "Long", stop=low[1])
strategy.exit("Short Stop", "Short", stop=high[1])
longProfit = ta.crossunder(maFast, maSlow)
shortProfit = ta.crossover(maFast, maSlow)
if longProfit and strategy.position_size > 0
strategy.close("Long")
if shortProfit and strategy.position_size < 0
strategy.close("Short")
// ── Visuals ────────────────────────────────────────────────────────────────────
plotshape(longCondition, title="Long Signal", location=location.belowbar, color=color.green, style=shape.triangleup, size=size.large, text="LONG")
plotshape(shortCondition, title="Short Signal", location=location.abovebar, color=color.red, style=shape.triangledown, size=size.large, text="SHORT")
bgcolor(isInPlay ? color.new(color.yellow, 92) : na, title="In Play Day")
// ── Debug plots ────────────────────────────────────────────────────────────────
plotchar(isInPlay, title="isInPlay", char="G", location=location.top, color=color.yellow, size=size.tiny)
plotchar(orSet, title="orSet", char="R", location=location.top, color=color.white, size=size.tiny)
plotchar(bullBreak, title="bullBreak", char="B", location=location.top, color=color.green, size=size.tiny)
plotchar(bearBreak, title="bearBreak", char="S", location=location.top, color=color.red, size=size.tiny)
// ── Alerts ─────────────────────────────────────────────────────────────────────
alertcondition(longCondition, title="Long ORB Alert", message="ORB LONG confirmed • {{ticker}} @ {{close}}")
alertcondition(shortCondition, title="Short ORB Alert", message="ORB SHORT confirmed • {{ticker}} @ {{close}}")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment