Strategy · Pine Script v5 · On the chart

Range Breakout Strategy

by nidhinninan

An intraday strategy that builds a range from the first fifteen minutes after a configurable start time, then trades breakouts of that range until a set end time.

View on GitHub

GitHub stars1on the repository
Pine versionv5runs as is
Lines of code162
Settings5inputs
LicenceMIT
Last update12 months ago3 Nov 2025

Add It to Your TradingView Chart

  1. 1Copy the scriptPress Copy script above, or the copy button on the code below.
  2. 2Open the Pine EditorOpen a TradingView chart and choose Pine Editor at the bottom of the screen.
  3. 3Paste over the templateCreate a new strategy, select all of the template text and paste. Press Save and give it a name.
  4. 4Add it to the chartPress Add to chart. The trades and results appear in the Strategy Tester tab; adjust the settings with the gear icon.

Source Code

162 lines of Pine Script v5 from Pinescripts/Custom_BreakoutRange.pine, published under MIT. Keep the author's credit and licence lines when you reuse it.

Custom_BreakoutRange.pine
//@version=5
strategy("Range Breakout Strategy", overlay=true, initial_capital=1000000, default_qty_type=strategy.percent_of_equity, default_qty_value=1, pyramiding=10)

// Add this with your other inputs
riskRewardRatio = input.float(2.0, "Risk/Reward 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)

// 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

Targets use a risk-to-reward ratio setting, and position size is a small percentage of equity. The strategy allows many stacked entries in the same direction, which raises exposure. It is the simpler counterpart of a related script in the same repository.

Details

Published by

nidhinninan on GitHub

Type

Strategy, Pine Script v5

Draws

On the price chart

Category

Breakout, Sessions & time

Markets

Stocks

Timeframes

M15-H1

Risk Notes

  • The strategy can add several entries in the same direction

Settings

The inputs you can change from the gear icon on the chart. Defaults are the author's.

SettingTypeDefaultVariable
Risk/Reward Ratiofloat2.0riskRewardRatio
Start Hourint9startHour
Start Minuteint30startMinute
End Hourint16endHour
End Minuteint0endMinute
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.

Similar Pine Scripts

106 stars

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

Strategy v4 Screeners & dashboardsBreakout Repaints
Updated 2 years ago · GPL-3.0 GitHub repository of 1St Bar GAP+BkOut Screener v2 by RM
53 stars

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

Strategy v6 TrendOscillators & momentum
Updated 2 months ago · MPL-2.0 GitHub repository of BTCUSD 5M Optimized Strategy

Turtle MACD Time-Zone Filter

by skywalker0803r
42 stars

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

Strategy v5 BreakoutOscillators & momentum
Updated 2 months ago · None stated GitHub repository of Turtle MACD Time-Zone Filter
39 stars

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

Strategy v6 BreakoutSessions & time Repaints
Updated 5 days ago · MIT GitHub repository of Futures Intraday Pro (ES/NQ) Strategy

Morning Scalp

by benso87
24 stars

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

Strategy v5 Sessions & timeBreakout
Updated 4 years ago · MPL-2.0 GitHub repository of Morning Scalp
23 stars

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

Strategy v6 TrendVolume Repaints
Updated 3 weeks ago · Custom licence GitHub repository of TradingAlpha Point-Clip Strategy

More strategys

Trade Your Charts With a Regulated Broker

Compare brokers that connect to TradingView, with spreads, minimum deposits and leverage side by side.

Compare brokers