An intraday strategy that builds a range from the first fifteen minutes after a configurable start time, then looks for breakouts of that range until a set end time.
//@version=5
strategy("Range Breakout Strategy_UCMO Research", overlay=true, initial_capital=1000000, default_qty_type=strategy.percent_of_equity, default_qty_value=10, pyramiding=2)
// Add this with your other inputs
riskRewardRatio = input.float(2.0, "Reward/Risk Ratio", minval=0.1, step=0.1)
// Input time parameters
startHour = input.int(9, "Start Hour", minval=0, maxval=23)
startMinute = input.int(30, "Start Minute", minval=0, maxval=59)
endHour = input.int(16, "End Hour", minval=0, maxval=23) // Market close at 16:00 (4:00 PM)
endMinute = input.int(0, "End Minute", minval=0, maxval=59) // 00 minutes
// Get current time
currentHour = hour(time)
currentMinute = minute(time)
// Calculate time in minutes
currentTimeInMinutes = currentHour * 60 + currentMinute
startTimeInMinutes = startHour * 60 + startMinute
endTimeInMinutes = endHour * 60 + endMinute
// Variables for range calculation
var float rangeHigh = na
var float rangeLow = na
var float rangeSize = na
var bool inRangeBuilding = false
var bool rangeEstablished = false
// Variables to track daily trades
var bool longTakenToday = false
var bool shortTakenToday = false
var bool longStoppedOut = false
var bool shortStoppedOut = false
// Define range building period (first 15 minutes)
rangeBuildEndMinutes = startTimeInMinutes + 14
inRangeBuildingPeriod = currentTimeInMinutes >= startTimeInMinutes and currentTimeInMinutes <= rangeBuildEndMinutes
inTradingPeriod = currentTimeInMinutes > rangeBuildEndMinutes and currentTimeInMinutes <= endTimeInMinutes
// Reset values at the start of each day
if dayofmonth != dayofmonth[1] or (not inRangeBuildingPeriod[1] and inRangeBuildingPeriod)
rangeHigh := high
rangeLow := low
rangeEstablished := false
inRangeBuilding := true
longTakenToday := false
shortTakenToday := false
longStoppedOut := false
shortStoppedOut := false
// Readout of open positions from previous day (if positions carried over)
// (strategy.position_size is the net position; positive means long, negative means short)
openLong = strategy.position_size > 0 ? strategy.position_size : 0
openShort = strategy.position_size < 0 ? math.abs(strategy.position_size) : 0
label.new(bar_index, high, text = "Open Positions\nLong: " + str.tostring(openLong) + "\nShort: " + str.tostring(openShort), color = color.yellow, textcolor = color.black, style = label.style_label_down)
// Update range values during building period
if inRangeBuildingPeriod and inRangeBuilding
rangeHigh := math.max(rangeHigh, high)
rangeLow := math.min(rangeLow, low)
// Establish range when building period ends
if inRangeBuildingPeriod[1] and not inRangeBuildingPeriod
rangeSize := rangeHigh - rangeLow
// Validate range size
minRangeSize = 0 //syminfo.mintick * 10 // Minimum acceptable range
maxRangeSize = 1e100 //ta.atr(14) * 2 // Maximum acceptable range based on ATR
if rangeSize >= minRangeSize and rangeSize <= maxRangeSize
rangeEstablished := true
inRangeBuilding := false
// label.new(bar_index, high, text="Range Established\n" + "High: " + str.tostring(rangeHigh) + "\n" + "Low: " + str.tostring(rangeLow) + "\n" + "Size: " + str.tostring(rangeSize) + "\n" + "R/R Ratio: " + str.tostring(riskRewardRatio), color=color.blue, textcolor=color.white,style=label.style_label_down)
else
// Invalid range - reset and skip this day
rangeEstablished := false
inRangeBuilding := false
label.new(bar_index, high,text="Invalid Range Size\n" +"Size: " + str.tostring(rangeSize) + "\n" +"Min: " + str.tostring(minRangeSize) + "\n" +"Max: " + str.tostring(maxRangeSize),color=color.red,textcolor=color.white)
// Add near the top with other inputs
debugInfo = input.bool(false, "Show Debug Info")
// Add after your trade entry sections
if debugInfo and strategy.position_size != 0
label.new(bar_index, high + (5 * syminfo.mintick), text="Bar Range: " + str.tostring(high - low, format.mintick) + "\nTarget Distance: " + str.tostring(riskRewardRatio * rangeSize, format.mintick), color=color.purple, style=label.style_label_down, textcolor=color.white)
// Initialize temporary flags for trades closed today in the current bar
var bool newLongStoppedOut = false
var bool newShortStoppedOut = false
// Calculate the number of trades closed in the current 15-min bar
closedTradesDelta = strategy.closedtrades - strategy.closedtrades[1]
// Only process if one or more trades closed in this bar
if closedTradesDelta > 0
// Loop over the newly closed trades in this bar.
// (For example, if 2 trades closed, we iterate over both.)
for i = strategy.closedtrades - closedTradesDelta to strategy.closedtrades - 1
// Check if this trade was initiated today by comparing its entry day with the current day.
if dayofmonth(strategy.closedtrades.entry_time(i)) == dayofmonth(time)
// Get the exit price for this trade
exit_price = strategy.closedtrades.exit_price(i)
// If the exit price is less than or equal to the rangeLow, then assume it was a long stop out.
if exit_price <= rangeLow
newLongStoppedOut := true
// If the exit price is greater than or equal to the rangeHigh, then assume it was a short stop out.
if exit_price >= rangeHigh
newShortStoppedOut := true
// Update the stop out flags based on any qualifying trades closed in the current bar.
if newLongStoppedOut
longStoppedOut := true
if newShortStoppedOut
shortStoppedOut := true
// // Check if trades hit stop loss
// if strategy.position_size == 0 and strategy.closedtrades > 0
// last_trade = strategy.closedtrades - 1
// exit_price = strategy.closedtrades.exit_price(last_trade)
// // Check if long position was stopped out (price moved below stop)
// if exit_price <= rangeLow
// longStoppedOut := true
// // Check if short position was stopped out (price moved above stop)
// if exit_price >= rangeHigh
// shortStoppedOut := true
// Trading logic - After range is established and during trading period
if rangeEstablished and inTradingPeriod
// Long Entry
longCondition = not longTakenToday or (shortStoppedOut and not longTakenToday)
if longCondition and close >= rangeHigh
strategy.entry("Long", strategy.long)
strategy.exit("Long Exit", "Long", stop=rangeLow, limit=rangeHigh + (riskRewardRatio * rangeSize))
longTakenToday := true
// label.new(bar_index, low, text="LONG ENTRY\nTP: " + str.tostring(rangeHigh + (riskRewardRatio * rangeSize)) + "\nSL: " + str.tostring(rangeLow), color=color.green, style=label.style_label_up)
// Short Entry
shortCondition = not shortTakenToday or (longStoppedOut and not shortTakenToday)
if shortCondition and close <= rangeLow
strategy.entry("Short", strategy.short)
strategy.exit("Short Exit", "Short", stop=rangeHigh, limit=rangeLow - (riskRewardRatio * rangeSize))
shortTakenToday := true
// label.new(bar_index, high, text="SHORT ENTRY\nTP: " + str.tostring(rangeLow - (riskRewardRatio * rangeSize)) + "\nSL: " + str.tostring(rangeHigh), color=color.red, style=label.style_label_down)
// Create plotting condition
var bool shouldPlot = false
if currentTimeInMinutes > startTimeInMinutes + 15 // Only plot after range building period
shouldPlot := true
// Plot lines for visualization with time offset
plot(shouldPlot and rangeEstablished ? rangeHigh : na, color=color.blue, linewidth=2, style=plot.style_stepline, title="Range High")
plot(shouldPlot and rangeEstablished ? rangeLow : na, color=color.blue, linewidth=2, style=plot.style_stepline, title="Range Low")
plot(shouldPlot and rangeEstablished ? rangeHigh + rangeSize : na, color=color.green, linewidth=1, style=plot.style_stepline, title="Range High +1")
plot(shouldPlot and rangeEstablished ? rangeHigh + (riskRewardRatio * rangeSize) : na, color=color.green, linewidth=1, style=plot.style_stepline, title="Range High +R/R")
plot(shouldPlot and rangeEstablished ? rangeLow - rangeSize : na, color=color.red, linewidth=1, style=plot.style_stepline, title="Range Low -1")
plot(shouldPlot and rangeEstablished ? rangeLow - (riskRewardRatio * rangeSize) : na, color=color.red, linewidth=1, style=plot.style_stepline, title="Range Low -R/R")
// // Plot lines for visualization
// plot(rangeEstablished ? rangeHigh : na, color=color.blue, linewidth=2, style=plot.style_line, title="Range High")
// plot(rangeEstablished ? rangeLow : na, color=color.blue, linewidth=2, style=plot.style_line, title="Range Low")
// plot(rangeEstablished ? rangeHigh + rangeSize : na, color=color.green, linewidth=1, style=plot.style_line, title="Range High +1")
// plot(rangeEstablished ? rangeHigh + (2 * rangeSize) : na, color=color.green, linewidth=1, style=plot.style_line, title="Range High +2")
// plot(rangeEstablished ? rangeLow - rangeSize : na, color=color.red, linewidth=1, style=plot.style_line, title="Range Low -1")
// plot(rangeEstablished ? rangeLow - (2 * rangeSize) : na, color=color.red, linewidth=1, style=plot.style_line, title="Range Low -2")
Overview
Range Breakout Strategy UCMO Research tracks whether a long or short has been taken or stopped out each day and sizes positions as a percentage of equity. Targets use a reward-to-risk ratio setting. It allows up to two entries in the same direction and prints a label showing open positions.
The inputs you can change from the gear icon on the chart. Defaults are the author's.
Setting
Type
Default
Variable
Reward/Risk Ratio
float
2.0
riskRewardRatio
Start Hour
int
9
startHour
Start Minute
int
30
startMinute
End Hour
int
16
endHour
End Minute
int
0
endMinute
Show Debug Info
bool
false
debugInfo
Third-party code. ForexR did not write, test or endorse this script, and the summary above was generated automatically from its code and README. Indicators describe the past, and a strategy's backtest can look better than live trading, especially when a script repaints. Check it in the Strategy Tester and on a demo account before you rely on it.
This script monitors opening gap conditions and breakout behavior relative to the first candle's range across up to twenty configurable stock tickers. It detects whether following bars remain inside the opening range before breaking out, displaying the status
This strategy enters long or short on the price chart when price is on the correct side of a 200-period EMA, MACD agrees, RSI is not at the opposing extreme, ADX exceeds a threshold, volume beats a 20-bar average, and close breaks the recent high or low. A tim
This strategy enters long when price closes above the prior Donchian high and short when it closes below the prior Donchian low, only while flat and inside a Taipei-hour window. It exits on a MACD histogram reversal or through an ATR stop and a percentage take
This intraday strategy implements Mark Fisher's Opening Range Breakout (ORB) methodology tailored for index futures like ES and NQ. It calculates session opening ranges, volume z-scores, and VWAP bands to plot support, resistance, and confirmation levels on th
This strategy tracks an opening session time range to establish directional bias and triggers pullback trades using Stochastic RSI. Once price breaks out of the initial range, it establishes a directional bias and enters when the Stochastic RSI crosses over in
This strategy evaluates breakout and trend opportunities on the price chart using a weighted composite score of volume, trend, and candlestick structure. It tracks volume spikes, fast and slow EMAs, higher-timeframe EMA trend alignment, opening ranges, and ses