Paste this complete indicator into Pine Editor, save it, and add it to a standard one-minute candlestick chart. It measures a weekday 09:30 New York opening range, draws its box, then plots fixed levels and one confirmed breakout per direction per day. The volume filter is off by default. This is an educational indicator, not a backtested trading system.
US cash-open example for standard one-minute charts; no orders or retest entriespinescript
//@version=6
indicator("Pineify Cash-Open ORB", overlay = true, max_boxes_count = 50)
int duration = input.int(15, "Opening range minutes", options = [5, 15, 30, 60])
bool useVolume = input.bool(false, "Require volume filter")
float volumeMultiple = input.float(1.2, "Volume multiplier", minval = 0.1, step = 0.1)
string tz = "America/New_York"
if not timeframe.isminutes or timeframe.multiplier != 1 or not chart.is_standard
runtime.error("Use a standard one-minute candlestick chart.")
int localYear = year(time, tz)
int localMonth = month(time, tz)
int localDay = dayofmonth(time, tz)
int dateKey = localYear * 10000 + localMonth * 100 + localDay
bool newDate = na(dateKey[1]) or dateKey != dateKey[1]
int rangeStart = timestamp(tz, localYear, localMonth, localDay, 9, 30)
int rangeEnd = rangeStart + duration * 60 * 1000
bool inCash = not na(time(timeframe.period, "0930-1600:23456", tz))
bool inRange = inCash and time >= rangeStart and time < rangeEnd
var float rangeHigh = na
var float rangeLow = na
var int rangeBars = 0
var bool sawStart = false
var bool longFired = false
var bool shortFired = false
var box rangeBox = na
if newDate
rangeHigh := na
rangeLow := na
rangeBars := 0
sawStart := false
longFired := false
shortFired := false
rangeBox := na
if inRange
if time == rangeStart
sawStart := true
rangeHigh := high
rangeLow := low
rangeBox := box.new(bar_index, high, bar_index, low, border_color = color.blue, bgcolor = color.new(color.blue, 88))
if sawStart
rangeBars += 1
rangeHigh := math.max(rangeHigh, high)
rangeLow := math.min(rangeLow, low)
box.set_top(rangeBox, rangeHigh)
box.set_bottom(rangeBox, rangeLow)
box.set_right(rangeBox, bar_index)
bool rangeReady = sawStart and rangeBars == duration and time >= rangeEnd
float priorVolumeAverage = ta.sma(volume, 20)[1]
bool volumeOk = not useVolume or (not na(volume) and priorVolumeAverage > 0 and volume > priorVolumeAverage * volumeMultiple)
bool eligible = rangeReady and inCash and barstate.isconfirmed and volumeOk
bool longSignal = eligible and not longFired and close > rangeHigh and close[1] <= rangeHigh
bool shortSignal = eligible and not shortFired and close < rangeLow and close[1] >= rangeLow
if longSignal
longFired := true
if shortSignal
shortFired := true
bool showLevels = rangeReady and inCash
plot(showLevels ? rangeHigh : na, "ORB High", color.green, 2, plot.style_linebr)
plot(showLevels ? rangeLow : na, "ORB Low", color.red, 2, plot.style_linebr)
plot(showLevels ? (rangeHigh + rangeLow) / 2 : na, "ORB Midpoint", color.gray, 1, plot.style_linebr)
plotshape(longSignal, "ORB Long", shape.triangleup, location.belowbar, color.green, text = "Long", size = size.small)
plotshape(shortSignal, "ORB Short", shape.triangledown, location.abovebar, color.red, text = "Short", size = size.small)
alertcondition(longSignal, "ORB Long", "Confirmed close above the opening range on {{ticker}}")
alertcondition(shortSignal, "ORB Short", "Confirmed close below the opening range on {{ticker}}")