AGAIG MTF OPENING RANGE BREAKOUT TRADE INDICATOR
In this indicator I am using 15 minute breakout lines and the indicator will only show one breakout each trading session and I must remind you that all breakouts don’t continue for long runs. Sometimes support and resistance is merely being tested
In this indicator I am using 15 minute breakout lines and the indicator will only show one breakout each trading session and I must remind you that all breakouts don’t continue for long runs. Sometimes support and resistance is merely being tested
Chart Look:
Setup
Apply to a 5-minute chart, RTH only doesn't matter for chart display — extended hours can be on or off since the study itself already ignores pre/post-market for triggering new entries.
Key inputs to check per symbol: strikeIncrement (set to match how that name's option chain is spaced — 1 for most, 2.5/5 for higher-priced names), openingRangeMinutes (15 is a reasonable default; tighten to 5 for a more aggressive/faster read, widen to 30 for a more conservative range), holdBars (2 is a solid starting filter against single-bar fakeouts).
Reading the chart
Dashed red/green lines = resistance/support from the opening range. These freeze once the window closes (e.g. 9:45am with the 15-min default) and hold for the rest of the day.
A white OBB-Long or OBB-Short bubble is your entry signal — it only fires once per day, whichever direction triggers first. It shows the ATM strike, T1, T2, and stop.
Once triggered, a dotted stop line and two dashed target lines (light green/red, T1 thinner, T2 thicker) track the trade while it's open.
The corner label always tells you the current state at a glance: which side is active, bars elapsed, and the live stop/target numbers — or "DAILY SIGNAL USED" once the day's shot is spent.
How I'd actually trade it
Wait for the bubble, not just the lines — the lines alone aren't a signal, they're just the levels being watched.
Stop is fixed at entry (prior bar's low/high) and doesn't trail — that's a deliberate simplicity choice, so you decide manually whether to tighten it as price moves toward T1.
T1/T2 are pure price-based math (2x/3x the entry-to-stop distance) — they're a reference for where R-multiples land on the stock, not a guarantee the option will track 1:1 with the underlying's move given theta/IV.
Known limits worth remembering
No live option chain access — always double check the actual weekly contract and its bid/ask before entering, this only tells you where ATM sits.
One signal per day means if you get stopped out early, it won't re-arm even if price re-breaks later that same session.
Backtest holdBars and openingRangeMinutes against your usual watchlist before trusting it live — both were reasonable defaults, not tuned to any specific name.
Indicator Link: http://tos.mx/!f91fu06F
Code:
# AGAIG Opening Bell Breakouts
# ------------------------------------------------------------
# Opening-range breakout indicator for use on an individual
# stock's 5-minute chart.
#
# Logic:
# - Support/Resistance = high/low of the first N minutes of
# regular trading hours (RTH), starting at 9:30am ET
# - Long trigger: close holds above resistance for `holdBars`
# consecutive RTH bars
# - Short trigger: close holds below support for `holdBars`
# consecutive RTH bars
# - Signals only evaluate during RTH (9:30am-4:00pm ET) -- no
# triggers on pre-market or after-hours bars
# - Stop loss = low (long) / high (short) of the bar immediately
# preceding the trigger bar
# - Profit targets: T1 = 2x the entry-to-stop distance,
# T2 = 3x the entry-to-stop distance
# - One signal per day, either direction
# - Entry bubble (white background) shows the ATM strike, T1,
# T2, and stop; a status label in the corner shows trade
# state, bars elapsed, and current stop/targets
#
# NOTE: ThinkScript chart studies cannot query the live option
# chain. The "strike" shown is a calculated ATM price reference
# based on the underlying's price and your chosen strike
# increment -- you still select the actual weekly contract
# manually.
# ------------------------------------------------------------
declare upper;
input holdBars = 2; # consecutive closes required beyond level to confirm breakout
input openingRangeMinutes = 15; # window from market open used to build support/resistance
input strikeIncrement = 1.0; # option strike spacing for this underlying (e.g. 1, 2.5, 5)
input showBubbles = yes;
input showLevels = yes;
input showStatusLabel = yes;
# ---------- Regular Trading Hours flag ----------
# Everything that can trigger a NEW signal is gated by this so pre-market
# and after-hours prints against the opening range can't fire an entry.
def isRTH = SecondsFromTime(0930) >= 0 and SecondsFromTime(1600) < 0;
# ---------- Opening Range (first N minutes of RTH) ----------
def orStart = SecondsFromTime(0930) == 0;
def orWindow = SecondsFromTime(0930) >= 0 and SecondsFromTime(0930) < openingRangeMinutes * 60;
rec orHigh = if orStart then high
else if orWindow then Max(if IsNaN(orHigh[1]) then high else orHigh[1], high)
else orHigh[1];
rec orLow = if orStart then low
else if orWindow then Min(if IsNaN(orLow[1]) then low else orLow[1], low)
else orLow[1];
def resistanceLevel = orHigh;
def supportLevel = orLow;
plot Resistance = if showLevels then resistanceLevel else Double.NaN;
plot Support = if showLevels then supportLevel else Double.NaN;
Resistance.SetDefaultColor(Color.RED);
Support.SetDefaultColor(Color.GREEN);
Resistance.SetLineWeight(2);
Support.SetLineWeight(2);
Resistance.SetStyle(Curve.SHORT_DASH);
Support.SetStyle(Curve.SHORT_DASH);
# ---------- New day reset ----------
def newDay = GetDay() <> GetDay()[1];
# ---------- Breakout hold confirmation (RTH bars only) ----------
# Outside RTH, counts hold steady (frozen) rather than accumulating,
# so a pre-market or after-hours print can never build toward a trigger.
rec aboveCount = if newDay then 0
else if !isRTH then aboveCount[1]
else if close > resistanceLevel then aboveCount[1] + 1
else 0;
rec belowCount = if newDay then 0
else if !isRTH then belowCount[1]
else if close < supportLevel then belowCount[1] + 1
else 0;
def longTriggerRaw = isRTH and aboveCount == holdBars;
def shortTriggerRaw = isRTH and belowCount == holdBars;
# ---------- One-signal-per-day cap ----------
# Once either a long or short signal has fired, no further signals
# (of either direction) are allowed until the next session.
rec dailySignalUsed = if newDay then 0
else if longTriggerRaw or shortTriggerRaw then 1
else if IsNaN(dailySignalUsed[1]) then 0
else dailySignalUsed[1];
def longTrigger = longTriggerRaw and (dailySignalUsed[1] == 0 or IsNaN(dailySignalUsed[1]));
def shortTrigger = shortTriggerRaw and (dailySignalUsed[1] == 0 or IsNaN(dailySignalUsed[1]));
# ---------- Stop loss + entry price (captured once at trigger) ----------
rec entryStopLong = if newDay then Double.NaN
else if longTrigger then low[1]
else entryStopLong[1];
rec entryStopShort = if newDay then Double.NaN
else if shortTrigger then high[1]
else entryStopShort[1];
rec entryPriceLong = if newDay then Double.NaN
else if longTrigger then close
else entryPriceLong[1];
rec entryPriceShort = if newDay then Double.NaN
else if shortTrigger then close
else entryPriceShort[1];
# ---------- Trade state (one trade tracked at a time, resets each session) ----------
# Once a trade is open, the stop is monitored on every bar (including
# after-hours), since a real open position can still be stopped out
# outside RTH -- only NEW entries are restricted to RTH above.
rec inLong = if newDay then 0
else if longTrigger then 1
else if inLong[1] == 1 and low <= entryStopLong then 0
else inLong[1];
rec inShort = if newDay then 0
else if shortTrigger then 1
else if inShort[1] == 1 and high >= entryStopShort then 0
else inShort[1];
# ---------- Bars elapsed in active move (used for status label) ----------
rec barsInLong = if longTrigger then 1
else if inLong == 1 then barsInLong[1] + 1
else 0;
rec barsInShort = if shortTrigger then 1
else if inShort == 1 then barsInShort[1] + 1
else 0;
# ---------- ATM strike suggestion ----------
def atmStrike = Round(close / strikeIncrement, 0) * strikeIncrement;
def suggestedCallStrike = atmStrike;
def suggestedPutStrike = atmStrike;
# ---------- Profit targets (T1 = 2x stop distance, T2 = 3x stop distance) ----------
def longRiskDistance = entryPriceLong - entryStopLong;
def shortRiskDistance = entryStopShort - entryPriceShort;
def longTarget1 = entryPriceLong + (2 * longRiskDistance);
def longTarget2 = entryPriceLong + (3 * longRiskDistance);
def shortTarget1 = entryPriceShort - (2 * shortRiskDistance);
def shortTarget2 = entryPriceShort - (3 * shortRiskDistance);
# ---------- Entry bubbles ----------
AddChartBubble(showBubbles and longTrigger, low,
"OBB-Long\nCall " + suggestedCallStrike + " - ATM"
+ "\nT1 " + Round(longTarget1, 2) + " T2 " + Round(longTarget2, 2)
+ "\nStop " + Round(entryStopLong, 2),
Color.WHITE, no);
AddChartBubble(showBubbles and shortTrigger, high,
"OBB-Short\nPut " + suggestedPutStrike + " - ATM"
+ "\nT1 " + Round(shortTarget1, 2) + " T2 " + Round(shortTarget2, 2)
+ "\nStop " + Round(entryStopShort, 2),
Color.WHITE, yes);
# ---------- Stop loss markers while trade active ----------
plot LongStop = if inLong == 1 then entryStopLong else Double.NaN;
LongStop.SetDefaultColor(Color.DARK_GREEN);
LongStop.SetStyle(Curve.POINTS);
LongStop.SetLineWeight(3);
plot ShortStop = if inShort == 1 then entryStopShort else Double.NaN;
ShortStop.SetDefaultColor(Color.DARK_RED);
ShortStop.SetStyle(Curve.POINTS);
ShortStop.SetLineWeight(3);
# ---------- Target markers while trade active ----------
plot LongT1 = if inLong == 1 then longTarget1 else Double.NaN;
LongT1.SetDefaultColor(Color.LIGHT_GREEN);
LongT1.SetStyle(Curve.SHORT_DASH);
LongT1.SetLineWeight(1);
plot LongT2 = if inLong == 1 then longTarget2 else Double.NaN;
LongT2.SetDefaultColor(Color.LIGHT_GREEN);
LongT2.SetStyle(Curve.SHORT_DASH);
LongT2.SetLineWeight(2);
plot ShortT1 = if inShort == 1 then shortTarget1 else Double.NaN;
ShortT1.SetDefaultColor(Color.LIGHT_RED);
ShortT1.SetStyle(Curve.SHORT_DASH);
ShortT1.SetLineWeight(1);
plot ShortT2 = if inShort == 1 then shortTarget2 else Double.NaN;
ShortT2.SetDefaultColor(Color.LIGHT_RED);
ShortT2.SetStyle(Curve.SHORT_DASH);
ShortT2.SetLineWeight(2);
# ---------- Status label ----------
AddLabel(showStatusLabel,
if inLong == 1 then "LONG ACTIVE bars:" + barsInLong + " stop:" + Round(entryStopLong, 2) + " T1:" + Round(longTarget1, 2) + " T2:" + Round(longTarget2, 2)
else if inShort == 1 then "SHORT ACTIVE bars:" + barsInShort + " stop:" + Round(entryStopShort, 2) + " T1:" + Round(shortTarget1, 2) + " T2:" + Round(shortTarget2, 2)
else if dailySignalUsed == 1 then "DAILY SIGNAL USED - no more trades today"
else "NO ACTIVE SIGNAL",
if inLong == 1 then Color.GREEN
else if inShort == 1 then Color.RED
else if dailySignalUsed == 1 then Color.GRAY
else Color.LIGHT_GRAY);
AddLabel(showLevels, "OR(" + openingRangeMinutes + "m) R: " + Round(resistanceLevel, 2) + " S: " + Round(supportLevel, 2), Color.LIGHT_GRAY);
# ---------- Alerts ----------
Alert(longTrigger, "Opening Bell Breakout LONG", Alert.BAR, Sound.Ring);
Alert(shortTrigger, "Opening Bell Breakout SHORT", Alert.BAR, Sound.Ring);
Last edited by a moderator: