
The Multi-Indicator Breakout and Reversal Trading Strategy is a quantitative trading approach that combines technical analysis indicators with price action to capture two primary trading opportunities in the market: price reversals and trend breakouts. This strategy cleverly integrates multiple technical indicators including moving averages, Relative Strength Index (RSI), Average True Range (ATR), and Volume Weighted Average Price (VWAP), while also incorporating an Opening Range Breakout (ORB) mechanism to enhance entry signal reliability. The strategy employs a dual target profit-taking design and features an automatic risk management mechanism that adjusts the stop loss to breakeven, making it particularly suitable for short timeframes (such as 2-minute charts), with parameter adjustments allowing for application to higher timeframes as well.
The core principle of this strategy is to identify three potential favorable trading opportunities through multiple indicator filtering and confirmation:
Reversal Trading Signals:
Trend Breakout Signals:
Opening Range Breakout (ORB) Signals:
The strategy uses the ATR indicator to calculate dynamic stop loss positions by looking back at the lowest/highest price over a specific period (default 7) and adding/subtracting a multiple (default 0.5) of the ATR value. After entry, the strategy sets two profit targets: - First target (TP1): 0.5 times the risk (default), closing 25% of the position - Second target (TP2): 1.1 times the risk (default), closing the remaining 75% of the position
When the first profit target is achieved, the strategy automatically adjusts the stop loss to the entry price (breakeven point), effectively protecting the profit already gained.
Diversified Entry Signals: By integrating three different entry signals—reversal, breakout, and opening range breakout—the strategy can adapt to various market environments, effectively increasing trading opportunities while maintaining high signal quality.
Comprehensive Risk Management: The strategy adopts a tiered profit-taking mechanism, allowing partial profit realization while retaining potential for greater returns. When the first profit target is reached, the stop loss is automatically adjusted to breakeven, achieving “let profits run” while protecting capital.
Dynamic Stop Loss Calculation: Using the ATR indicator to calculate stop loss positions allows the stop level to dynamically adjust based on market volatility, more accurately reflecting current market conditions and avoiding overly tight or loose stop loss settings.
Volume Confirmation: A volume confirmation mechanism is introduced especially in ORB signals, requiring that breakout volume must exceed a specific multiple of the average volume in the opening range, effectively filtering low-quality breakouts.
Trend Filtering: Using the 200-period Simple Moving Average (SMA200) to determine long-term trend direction ensures that trading direction is consistent with the main trend, improving the success rate of trades.
Integrated Capital Management: The strategy has built-in capital management mechanisms, limiting the proportion of funds used for each trade (default 50% of capital), ensuring diversified capital allocation and reducing risk exposure from any single trade.
Solution: Consider adding forward-looking indicators such as price action pattern recognition, or shortening the parameters of longer-period moving averages to increase sensitivity to market changes.
Solution: Adopt appropriate parameter optimization methods, such as forward validation or Monte Carlo simulation, to avoid over-optimization; or use fixed parameters and focus on more robust rule design.
Solution: Establish a stricter signal priority system or introduce additional confirmation mechanisms to ensure trades are executed only in high-probability situations.
Solution: Consider using options hedging strategies, or increase stop loss distance in high-volatility market conditions, or even temporarily reduce position size.
Solution: Implement global risk control, limit overall position size, or diversify trades across different asset classes to reduce correlation risk.
Optimization Rationale: Traditional fixed-weight indicator combinations struggle to adapt to different market phases, while machine learning can automatically learn the optimal indicator combination patterns from historical data.
Optimization Rationale: Market sentiment significantly influences short-term price movements; integrating such indicators can capture market turning points in advance, optimizing entry and exit timing.
Optimization Rationale: Fixed risk-reward ratios may not be flexible enough in different market environments; dynamic adjustment can set more distant targets in high-volatility markets and more conservative targets in low-volatility markets.
Optimization Rationale: Market activity shows significant differences across different periods of the day; time filtering can help the strategy focus on the most advantageous trading sessions.
Optimization Rationale: Risk is directly related to market volatility; dynamic position management can maintain more consistent risk levels, improving long-term risk-adjusted returns.
The Multi-Indicator Breakout and Reversal Trading Strategy is a comprehensive quantitative trading system that integrates various technical analysis methods. By combining reversal, trend breakout, and opening range breakout signals with comprehensive risk and capital management mechanisms, it aims to capture trading opportunities across various market environments. The core advantages of the strategy lie in signal diversification, robust risk control, and strong parameter customizability, making it particularly suitable for short-term trading. Meanwhile, the strategy also faces potential risks such as indicator lag, parameter sensitivity, and signal conflicts, requiring further optimization through machine learning integration, market sentiment analysis, dynamic profit-taking settings, and other approaches. Overall, this is a comprehensively designed, clearly structured trading strategy framework that provides quantitative traders with a solid starting point. Through continuous improvement and appropriate risk management, it has the potential to become a robust and reliable trading system.
/*backtest
start: 2025-01-01 00:00:00
end: 2025-03-31 00:00:00
period: 1h
basePeriod: 1h
exchanges: [{"eid":"Futures_Binance","currency":"BTC_USDT"}]
*/
//@version=5
strategy("Reversal & Breakout Strategy with ORB", overlay=true, pyramiding=2, initial_capital=50000)
// --- Inputs ---
ema9Length = input.int(9, "9 EMA Length", minval=1)
ema20Length = input.int(20, "20 EMA Length", minval=1)
sma50Length = input.int(50, "50 SMA Length", minval=1)
sma200Length = input.int(200, "200 SMA Length", minval=1)
rsiLength = input.int(14, "RSI Length", minval=1)
rsiOverbought = input.int(70, "RSI Overbought", minval=0, maxval=100)
rsiOversold = input.int(30, "RSI Oversold", minval=0, maxval=100)
atrLength = input.int(14, "ATR Length", minval=1)
stopMulti = input.float(0.5, "Stop Loss ATR Multiplier", minval=0.1, step=0.1)
stopLookback = input.int(7, "Stop Loss Lookback", minval=1)
rr1 = input.float(0.5, "Risk:Reward Target 1", minval=0.1, step=0.1)
rr2 = input.float(1.1, "Risk:Reward Target 2", minval=0.1, step=0.1)
target1Percent = input.float(25, "Profit % Target 1", minval=0, maxval=100)
orbBars = input.int(15, "Opening Range Bars", minval=1, tooltip="Number of bars to define the opening range (e.g., 15 bars = 30 min on 2-min chart)")
volThreshold = input.float(1.5, "Volume Threshold Multiplier", minval=1.0, step=0.1, tooltip="Volume must be this multiple of the opening range average")
// --- Indicators ---
// Moving Averages
ema9 = ta.ema(close, ema9Length)
ema20 = ta.ema(close, ema20Length)
sma50 = ta.sma(close, sma50Length)
sma200 = ta.sma(close, sma200Length)
// VWAP
vwapValue = ta.vwap(close)
// RSI
rsi = ta.rsi(close, rsiLength)
// ATR
atr = ta.atr(atrLength)
// --- Opening Range Breakout ---
var float openingRangeHigh = na
var float openingRangeLow = na
var float openingRangeAvgVol = na
if bar_index < orbBars
openingRangeHigh := na
openingRangeLow := na
openingRangeAvgVol := na
else if bar_index == orbBars
openingRangeHigh := ta.highest(high, orbBars)
openingRangeLow := ta.lowest(low, orbBars)
openingRangeAvgVol := ta.sma(volume, orbBars)
orbLong = not na(openingRangeHigh) and ta.crossover(close, openingRangeHigh) and volume > openingRangeAvgVol * volThreshold
orbShort = not na(openingRangeLow) and ta.crossunder(close, openingRangeLow) and volume > openingRangeAvgVol * volThreshold
// --- Trend Detection ---
trendUp = close > sma200
trendDown = close < sma200
// --- Reversal Conditions ---
reversalLong = ta.crossover(close, sma50) and rsi < rsiOversold and close < vwapValue and trendUp
reversalShort = ta.crossunder(close, sma50) and rsi > rsiOverbought and close > vwapValue and trendDown
// --- Range Breakout Conditions ---
breakoutLong = ta.crossover(ema9, ema20) and close > vwapValue and trendUp
breakoutShort = ta.crossunder(ema9, ema20) and close < vwapValue and trendDown
// Combine conditions
longCondition = (reversalLong or breakoutLong or orbLong)
shortCondition = (reversalShort or breakoutShort or orbShort)
// --- Calculate Position Size ---
equityPerPosition = 25000.0 // $50,000 / 2 positions
positionSizeLong = math.floor(equityPerPosition / close)
positionSizeShort = math.floor(equityPerPosition / close)
// --- Stop Loss Calculation ---
longStop = ta.lowest(low, stopLookback) - (atr * stopMulti)
shortStop = ta.highest(high, stopLookback) + (atr * stopMulti)
// --- Variables to Store Trade Levels ---
var float tradeStop = na
var float tradeTarget1 = na
var float tradeTarget2 = na
var float initialPositionSize = na
var bool breakEvenSet = false // Track if stop has been moved to break-even
var float stopLevel = na // Dedicated variable for stop loss in exits
var float target1Level = na // Dedicated variable for first take profit
var float target2Level = na // Dedicated variable for second take profit
var float qtyTotal = na // Track total quantity
// --- Reset Levels Before New Trade ---
var bool newTrade = false
if longCondition or shortCondition
newTrade := true
else
newTrade := false
if strategy.position_size == 0 and newTrade
tradeStop := na
tradeTarget1 := na
tradeTarget2 := na
stopLevel := na
target1Level := na
target2Level := na
initialPositionSize := na
qtyTotal := na
breakEvenSet := false
// --- Strategy Entries ---
if longCondition and strategy.position_size == 0
strategy.entry("Long", strategy.long, qty=positionSizeLong * 2)
tradeStop := longStop
stopLevel := longStop
stopDistance = close - tradeStop
tradeTarget1 := close + (stopDistance * rr1)
tradeTarget2 := close + (stopDistance * rr2)
target1Level := tradeTarget1
target2Level := tradeTarget2
initialPositionSize := positionSizeLong * 2
qtyTotal := positionSizeLong * 2
breakEvenSet := false // Reset break-even flag
if shortCondition and strategy.position_size == 0
strategy.entry("Short", strategy.short, qty=positionSizeShort * 2)
tradeStop := shortStop
stopLevel := shortStop
stopDistance = tradeStop - close
tradeTarget1 := close - (stopDistance * rr1)
tradeTarget2 := close - (stopDistance * rr2)
target1Level := tradeTarget1
target2Level := tradeTarget2
initialPositionSize := positionSizeShort * 2
qtyTotal := positionSizeShort * 2
breakEvenSet := false // Reset break-even flag
// --- Trade Exits ---
if strategy.position_size > 0
qty_tp1 = qtyTotal * (target1Percent / 100)
qty_tp2 = qtyTotal * ((100 - target1Percent) / 100)
strategy.exit("Long Exit 1", "Long", qty=qty_tp1, stop=stopLevel, limit=target1Level)
strategy.exit("Long Exit 2", "Long", qty=qty_tp2, stop=stopLevel, limit=target2Level)
if strategy.position_size < 0
qty_tp1 = qtyTotal * (target1Percent / 100)
qty_tp2 = qtyTotal * ((100 - target1Percent) / 100)
strategy.exit("Short Exit 1", "Short", qty=qty_tp1, stop=stopLevel, limit=target1Level)
strategy.exit("Short Exit 2", "Short", qty=qty_tp2, stop=stopLevel, limit=target2Level)
// --- Move Stop to Break-even ---
if strategy.position_size != 0 and not na(initialPositionSize) and not breakEvenSet
if math.abs(strategy.position_size) < math.abs(initialPositionSize)
tradeStop := strategy.position_avg_price
stopLevel := strategy.position_avg_price
tradeTarget1 := na // Clear first target for plotting
breakEvenSet := true // Mark break-even as set
// --- Manual Close Fallback ---
if strategy.position_size > 0
if close >= target2Level or close <= stopLevel
strategy.close("Long", qty=qtyTotal, comment="Manual Close")
if strategy.position_size < 0
if close <= target2Level or close >= stopLevel
strategy.close("Short", qty=qtyTotal, comment="Manual Close")
// --- Reset Levels When No Position ---
if strategy.position_size == 0 and not newTrade
tradeStop := na
tradeTarget1 := na
tradeTarget2 := na
stopLevel := na
target1Level := na
target2Level := na
initialPositionSize := na
qtyTotal := na
breakEvenSet := false
// --- Plotting ---
plot(tradeStop, title="Stop Loss", color=color.red, linewidth=1, style=plot.style_linebr)
plot(tradeTarget1, title="Take Profit 1", color=color.green, linewidth=1, style=plot.style_linebr)
plot(tradeTarget2, title="Take Profit 2", color=color.blue, linewidth=1, style=plot.style_linebr)