What it does
The opening range is the high and low price reached in the first minutes of a session. Many intraday traders treat a close beyond that range as a sign of the day's early direction. This indicator draws the range, signals the first close above or below it, and projects two targets as multiples of the range height.
How it works
- At the first candle of the session, the range starts at that candle's high and low.
- For every candle that opens within the first N minutes, the range high and low expand to include it. After N minutes the range is locked.
- Long breakout: a closed candle finishes above the range high after previously closing at or below it. Short breakout: a close below the range low after previously closing at or above it. With "only the first breakout per side" on, each side can signal once per session.
- Targets: range height = high − low. Long targets = range high + height × multiple. Short targets = range low − height × multiple.
Illustrative example: if the first 15 minutes of an index session make a high of 5,020 and a low of 5,000, the height is 20 points. A long breakout projects targets at 5,040 (1×) and 5,060 (2×).
Lines are plots, so no drawing objects build up on the chart. A warning appears if your chart timeframe is longer than the opening range.
How to use it
- Use a chart timeframe that divides the range length evenly, such as M1 or M5 for a 15-minute range, so the range is built from several candles.
- Stock index and US stock sessions are the classic use. For forex, try the London open (for example 0800-1700 Europe/London) or the New York open.
- Many traders place the stop on the opposite side of the range or at its midpoint. Check that the target distance is worth the risk with the Risk-Reward Calculator.
- A narrow opening range compared with recent days may lead to a cleaner breakout; a very wide one leaves less room for the targets.
Alerts: breakout up, breakout down. Both fire on candle close.
Settings
| Input | Default | What it changes |
|---|---|---|
| Session hours | 0930-1600 | Session used for the range |
| Session time zone | America/New_York | Clock used for the hours |
| Opening range length | 15 minutes | Range-building period |
| Only the first breakout per side | On | One signal per side per session |
| Show breakout markers | On | Triangles on signals |
| Show targets after a breakout | On | Target lines |
| Target 1 / Target 2 | 1.0 / 2.0 | Target distance in range heights |
Limitations
Breakouts from the opening range often fail and return inside, especially on quiet days or before scheduled news. The targets are simple projections, not forecasts. Signals require a candle close, so on M15 the entry can come well after the actual break. Forex has no single opening bell, so results depend heavily on the session you pick. Spreads are often wider in the first minutes of a session.
Pine Script source
In TradingView open Pine Editor, paste the code, click Save and then Add to chart.
FXP_OpeningRangeBreakout.pine
90 lines
// © FXPIPS ONLINE — https://fxpips.online/tradingview-indicators/opening-range-breakout/
// License: MIT. Educational tool — not financial advice. Trading involves substantial risk.
//@version=6
// Measures the high and low of the first N minutes of a session (the opening range),
// then flags the first close above / below it and projects targets as multiples of the
// range height. Signals are confirmed on bar close.
indicator("FXP Opening Range Breakout", shorttitle = "FXP ORB", overlay = true)
// ── Inputs ─────────────────────────────────────────────────────────────
grpS = "Session"
sess = input.session("0930-1600", "Session hours", group = grpS)
tzIn = input.string("America/New_York", "Session time zone", options = ["America/New_York", "Europe/London", "Europe/Berlin", "Asia/Tokyo", "Asia/Kolkata", "Australia/Sydney", "UTC", "Exchange"], group = grpS)
orMinutes = input.int(15, "Opening range length (minutes)", minval = 1, maxval = 480, group = grpS)
grpSig = "Signals"
oneSignal = input.bool(true, "Only the first breakout per side each session", group = grpSig)
showSig = input.bool(true, "Show breakout markers", group = grpSig)
grpT = "Targets"
showTgt = input.bool(true, "Show targets after a breakout", group = grpT)
t1Mult = input.float(1.0, "Target 1 (x range)", minval = 0.1, step = 0.1, group = grpT)
t2Mult = input.float(2.0, "Target 2 (x range)", minval = 0.1, step = 0.1, group = grpT)
grpC = "Colors"
colHi = input.color(#26a69a, "Range high / long", group = grpC)
colLo = input.color(#ef5350, "Range low / short", group = grpC)
colFill = input.color(color.new(#2962ff, 90), "Range fill while forming", group = grpC)
// ── Opening range ──────────────────────────────────────────────────────
string tz = tzIn == "Exchange" ? syminfo.timezone : tzIn
bool inSess = timeframe.isintraday and not na(time(timeframe.period, sess, tz))
bool newSess = inSess and not inSess[1]
var int orEnd = na
var float orHigh = na
var float orLow = na
var bool longDone = false
var bool shortDone = false
if newSess
orEnd := time + orMinutes * 60000
orHigh := high
orLow := low
longDone := false
shortDone := false
else if inSess and time < orEnd
orHigh := math.max(orHigh, high)
orLow := math.min(orLow, low)
bool building = inSess and time < orEnd
bool ready = inSess and time >= orEnd and not na(orHigh)
float rng = orHigh - orLow
// ── Breakouts (closed bars) ────────────────────────────────────────────
bool longBreak = barstate.isconfirmed and ready and close > orHigh and close[1] <= orHigh and (not oneSignal or not longDone)
bool shortBreak = barstate.isconfirmed and ready and close < orLow and close[1] >= orLow and (not oneSignal or not shortDone)
if longBreak
longDone := true
if shortBreak
shortDone := true
// ── Plots ──────────────────────────────────────────────────────────────
pHi = plot(building or ready ? orHigh : na, "Opening range high", color = colHi, linewidth = 2, style = plot.style_linebr)
pLo = plot(building or ready ? orLow : na, "Opening range low", color = colLo, linewidth = 2, style = plot.style_linebr)
fill(pHi, pLo, color = building ? colFill : na, title = "Opening range fill")
bool showLongT = showTgt and longDone and inSess
bool showShortT = showTgt and shortDone and inSess
plot(showLongT ? orHigh + rng * t1Mult : na, "Long target 1", color = color.new(colHi, 30), style = plot.style_linebr)
plot(showLongT ? orHigh + rng * t2Mult : na, "Long target 2", color = color.new(colHi, 55), style = plot.style_linebr)
plot(showShortT ? orLow - rng * t1Mult : na, "Short target 1", color = color.new(colLo, 30), style = plot.style_linebr)
plot(showShortT ? orLow - rng * t2Mult : na, "Short target 2", color = color.new(colLo, 55), style = plot.style_linebr)
plotshape(showSig and longBreak, "Long breakout", shape.triangleup, location.belowbar, colHi, size = size.small)
plotshape(showSig and shortBreak, "Short breakout", shape.triangledown, location.abovebar, colLo, size = size.small)
// ── Timeframe warning ──────────────────────────────────────────────────
var table warn = table.new(position.bottom_right, 1, 1)
if barstate.islast
if timeframe.isintraday and timeframe.in_seconds() > orMinutes * 60
table.cell(warn, 0, 0, "Chart timeframe is longer than the opening range. Use a lower timeframe.", text_color = color.white, bgcolor = color.new(color.red, 20), text_size = size.small)
else if not timeframe.isintraday
table.cell(warn, 0, 0, "Opening range breakout needs an intraday chart.", text_color = color.white, bgcolor = color.new(color.red, 20), text_size = size.small)
// ── Alerts ─────────────────────────────────────────────────────────────
alertcondition(longBreak, "Opening range breakout up", "{{ticker}} {{interval}}: closed above the opening range at {{close}}")
alertcondition(shortBreak, "Opening range breakout down", "{{ticker}} {{interval}}: closed below the opening range at {{close}}")

