Support Resistance Breakout Strategy with Trend-ADX Filter Quantitative Trading System
FMZQuant

FMZQuant @fmzquant

Joined:
Apr 25, 2024

Support Resistance Breakout Strategy with Trend-ADX Filter Quantitative Trading System

Publish Date: Jun 4
2 1

Image description

Image description

Overview
The Support Resistance Breakout Strategy with Trend-ADX Filter Quantitative Trading System is a comprehensive trading strategy that combines support/resistance level identification, trend confirmation, and market strength validation from technical analysis. This strategy is based on price breakout behavior at key price levels and uses moving averages and Average Directional Index (ADX) as filters to improve the reliability of trading signals. The system operates on a 1-hour timeframe, identifies dynamic support and resistance zones through pivot highs and lows, generates trading signals when prices break through these zones, and implements fixed percentage take-profit and stop-loss mechanisms to control risk.

Strategy Principles
The core principle of this strategy is based on price breakout behavior at key support and resistance levels, combined with trend direction and market strength filtering, forming a complete trading system. The specific implementation principles include:

Support/Resistance Level Identification: The system uses the Pivot Points method to identify important price levels. Through the ta.pivothigh and ta.pivotlow functions, pivot highs and lows are calculated with a default parameter of 5 periods, and these points serve as potential resistance and support levels.

Dynamic Zone Management: The system uses array structures supportLevels and resistanceLevels to store support and resistance levels, and intelligently manages these price levels through the custom function f_add_level. This function ensures that newly added levels are sufficiently distant from existing levels (default 2%), preventing overcrowding of zones while limiting storage to a maximum of 5 most recent levels.

Trend Confirmation Filter: The strategy uses a 50-period Simple Moving Average (SMA) as a trend direction indicator. Long positions are only considered when price is above the moving average, and short positions when price is below, thus aligning with the overall market trend.

Market Strength Validation: Market strength is evaluated through a custom ADX (Average Directional Index) function. The ADX value must be above a set threshold (default 25) to ensure trades are only entered when the market has sufficient strength, avoiding false breakouts in weak market environments.

Entry Signal Generation:

  • Long signal: Triggered when price breaks above a support level (low is below the support but closing price is above), while price is above the 50-period moving average and ADX is above the threshold.
  • Short signal: Triggered when price breaks below a resistance level (high is above the resistance but closing price is below), while price is below the 50-period moving average and ADX is above the threshold.

Risk Management Mechanism: The strategy employs fixed percentage take-profit and stop-loss settings, with default settings of 15% take-profit and 10% stop-loss for long positions, and 10% take-profit and 10% stop-loss for short positions. Once price reaches these levels, the system automatically closes positions and resets the trading state.

Strategy Advantages
Based on deep analysis of the code, this strategy has the following significant advantages:

  1. Multiple Confirmation Mechanism: By combining support/resistance breakouts, trend direction, and ADX strength as a triple confirmation, the risk of false breakouts is effectively reduced. Compared to single indicators, this multiple confirmation mechanism improves the reliability of trading signals.

  2. Dynamic Support/Resistance Zones: The system dynamically identifies and manages support and resistance levels, adapting to different market environments. By keeping at most 5 of the most recent support/resistance levels, the strategy ensures focus on the most relevant price levels.

  3. Intelligent Zone Clustering: Through the maximum zone width percentage parameter (maxZoneWidthPct), the strategy avoids redundant calculation of support/resistance levels that are too close to each other, reducing redundant signals.

  4. Custom ADX Calculation: The strategy uses a custom ADX function, ensuring accuracy and flexibility of the indicator calculation through direct computation of true range, directional movement, and smoothing.

  5. Flexible Parameter Configuration: The strategy provides multiple adjustable parameters, including pivot length, lookback period, maximum zone width, take-profit/stop-loss percentages, and ADX threshold, allowing users to optimize according to different market conditions and trading preferences.

  6. Clear Risk Control: Through preset take-profit and stop-loss percentages, the strategy provides a clear risk management framework for each trade, preventing excessive losses on single trades while securing reasonable profits.

  7. Intuitive Visualization: The strategy marks support/resistance levels and trading signals on the chart, providing intuitive visual feedback through color coding (green for support, red for resistance) and labels (LONG, SHORT, EXIT), facilitating backtesting analysis and real-time monitoring.

Strategy Risks
Despite its reasonable design, the strategy still has the following potential risks and limitations:

  1. False Breakouts in Volatile Markets: In highly volatile market environments, prices may frequently break through support/resistance levels only to return to the original range, leading to an increase in false breakout signals. Solution: Consider adding confirmation periods, requiring price to maintain for a certain time or form specific patterns after a breakout before confirming signals.

  2. Overreliance on Historical Support/Resistance Levels: The strategy is based on historically formed support/resistance levels, which may become ineffective when market structure undergoes fundamental changes (such as major news events). Solution: Consider adding dynamic adjustment mechanisms to automatically adjust the validity period of support/resistance levels based on market volatility.

  3. Limitations of Fixed Percentage Take-Profit/Stop-Loss: Fixed percentage take-profit/stop-loss may not be suitable for all market environments, potentially being too large in low-volatility markets and too small in high-volatility markets. Solution: Consider dynamically adjusting take-profit/stop-loss levels based on ATR (Average True Range).

  4. Trend Reversal Risk: Using a 50-period SMA as a trend indicator may lag in the initial stages of trend reversal, leading to trend-following entries even as the trend is about to end. Solution: Consider adding more sensitive short-term trend indicators or momentum indicators as auxiliary judgments.

  5. Computation-Intensive Strategy: The strategy requires real-time calculation and maintenance of multiple arrays and indicators, which may face performance challenges in high-frequency trading or resource-limited environments. Solution: Optimize algorithm efficiency, reduce unnecessary calculations, or consider reducing update frequency.

  6. Parameter Sensitivity: Strategy performance is sensitive to parameter settings (such as pivot length, ADX threshold), and improper parameter selection may lead to overtrading or missed opportunities. Solution: Establish a parameter optimization framework by backtesting parameter performance under different market conditions.

Strategy Optimization Directions
Based on deep analysis of the strategy code, here are potential optimization directions:

  1. Adaptive Parameter Mechanism: Introduce mechanisms to automatically adjust key parameters based on market volatility. For example, increase ADX threshold or support/resistance zone width during high volatility periods and decrease these parameters during low volatility periods, allowing the strategy to better adapt to different market environments. This can reduce erroneous trades under unsuitable market conditions.

  2. Multi-Timeframe Analysis: Add confirmation of support/resistance levels from higher timeframes. By checking whether support/resistance levels on daily or weekly charts align with levels on the current 1-hour chart, stronger key price areas recognized across multiple timeframes can be identified, improving signal quality.

  3. Volume Confirmation: Incorporate volume analysis to validate the effectiveness of breakouts. Truly effective breakouts are usually accompanied by significant increases in trading volume. By adding volume filtering conditions, the risk of false breakouts due to low trading volume can be reduced.

  4. Dynamic Take-Profit/Stop-Loss: Set take-profit/stop-loss levels dynamically based on market volatility (such as ATR) rather than fixed percentages. This makes risk management more flexible, automatically adjusting protection levels according to current market conditions, setting looser stop-losses in high-volatility markets and tighter ones in low-volatility markets.

  5. Partial Profit Locking Mechanism: Introduce a segmented profit-taking mechanism, allowing movement of stop-loss to break-even or locking in partial profits after reaching certain profit levels. This approach can reduce drawdown risk while maintaining high profit potential.

  6. Integrate Sentiment Indicators: Consider integrating market sentiment indicators (such as VIX or relative strength indicators) as additional filtering conditions. Market sentiment often affects the sustainability of breakouts; adding a sentiment analysis dimension can improve the strategy's understanding of market states.

  7. Support/Resistance Strength Grading: Introduce a strength assessment mechanism for support/resistance levels, rating each level based on factors such as historical test frequency and formation time length. This allows prioritization of stronger price levels that are more likely to produce effective reactions.

  8. Machine Learning Optimization: Consider using machine learning methods to optimize parameter selection and signal generation. By analyzing patterns of successful and failed trades in historical data, machine learning algorithms can help identify the most effective parameter combinations and market conditions.

Summary
The Support Resistance Breakout Strategy with Trend-ADX Filter Quantitative Trading System is a well-designed comprehensive trading system that combines multiple key elements from technical analysis. The strategy creates a relatively reliable trading signal generation mechanism by dynamically identifying and monitoring support/resistance levels, combined with trend direction and market strength filtering.

The core advantages of the strategy lie in its multiple confirmation mechanisms and comprehensive risk management framework, effectively reducing false breakout risks and limiting potential losses on individual trades. At the same time, the strategy provides rich parameter configuration options, allowing traders to make flexible adjustments based on personal risk preferences and market environments.

However, the strategy also faces some challenges, such as false breakout risks in high-volatility markets, limitations of fixed take-profit/stop-loss, and parameter sensitivity. Strategy performance can be further improved through the introduction of adaptive parameter mechanisms, multi-timeframe analysis, volume confirmation, and dynamic risk management optimization measures.

Overall, this is a logically clear and reasonably designed quantitative trading strategy, suitable for traders with a certain understanding of technical analysis and market structure. Through continuous optimization and adaptation to market changes, the strategy has the potential to maintain stable performance across different market environments.

Strategy source code

/*backtest
start: 2024-05-30 00:00:00
end: 2025-05-29 00:00:00
period: 3d
basePeriod: 3d
exchanges: [{"eid":"Futures_Binance","currency":"ETH_USDT"}]
*/

//@version=6
strategy("S/R Breakout Strategy (1H) with Trend and ADX Filter", overlay=true, default_qty_type=strategy.percent_of_equity, default_qty_value=100)

// ─────────────────────────────────────────────────────────────
// INPUTS
// ─────────────────────────────────────────────────────────────
pivotLen        = input.int(5, title="Pivot Length")
lookbackBars    = input.int(300, title="Lookback Bars")
maxZoneWidthPct = input.float(2.0, title="Max Zone Width %")
tpLong          = input.float(0.15, title="Take Profit % (Long)")
slLong          = input.float(0.10, title="Stop Loss % (Long)")
tpShort         = input.float(0.10, title="Take Profit % (Short)")
slShort         = input.float(0.10, title="Stop Loss % (Short)")
allowLong       = input.bool(true, title="Allow Long Trades")
allowShort      = input.bool(true, title="Allow Short Trades")

// ADX settings
adxThreshold    = input.float(25.0, title="ADX Threshold")
adxLen          = input.int(14, title="ADX Length")

// Trend filter: 50-period moving average
ma50 = ta.sma(close, 50)

// ─────────────────────────────────────────────────────────────
// CUSTOM ADX FUNCTION
// ─────────────────────────────────────────────────────────────
// This function calculates ADX using the common method based on true range,
// directional movement and smoothing it with the RMA.
f_adx(len) =>
    // true range for the current bar
    tr = ta.tr
    // Calculate upward and downward moves
    upMove   = high - high[1]
    downMove = low[1] - low
    // Determine directional movements
    plusDM  = (upMove > downMove and upMove > 0) ? upMove : 0.0
    minusDM = (downMove > upMove and downMove > 0) ? downMove : 0.0
    // Smooth the values using RMA (running moving average)
    smPlusDM  = ta.rma(plusDM, len)
    smMinusDM = ta.rma(minusDM, len)
    smTR      = ta.rma(tr, len)
    // Calculate the directional indicators, avoid division by zero
    plusDI  = (smTR != 0) ? 100 * smPlusDM / smTR : 0.0
    minusDI = (smTR != 0) ? 100 * smMinusDM / smTR : 0.0
    diSum   = plusDI + minusDI
    dx      = (diSum != 0) ? 100 * math.abs(plusDI - minusDI) / diSum : 0.0
    // Smooth the DX to get ADX
    ta.rma(dx, len)

// Compute ADX value using the custom function
adxValue = f_adx(adxLen)

// ─────────────────────────────────────────────────────────────
// PIVOT DETECTION & SUPPORT/RESISTANCE LEVELS
// ─────────────────────────────────────────────────────────────
pivotHigh = ta.pivothigh(high, pivotLen, pivotLen)
pivotLow  = ta.pivotlow(low, pivotLen, pivotLen)

// Declare arrays for support and resistance levels
var float[] supportLevels    = array.new_float()
var float[] resistanceLevels = array.new_float()

// Function to add a level into the provided array if it meets the criteria.
// Always returns a float (0.0) for consistency.
f_add_level(arr, newLevel) =>
    if array.size(arr) == 0
        array.push(arr, newLevel)
    else
        shouldAdd = true
        for i = 0 to (array.size(arr) - 1)
            existing = array.get(arr, i)
            if math.abs(existing - newLevel) / newLevel * 100 <= maxZoneWidthPct
                shouldAdd := false
        if shouldAdd
            array.push(arr, newLevel)
            if array.size(arr) > 5
                array.shift(arr)
    0.0

// Update support and resistance arrays once sufficient bars have formed
if bar_index > pivotLen * 2
    if not na(pivotLow)
        f_add_level(supportLevels, pivotLow)
    if not na(pivotHigh)
        f_add_level(resistanceLevels, pivotHigh)

// ─────────────────────────────────────────────────────────────
// TRADE MANAGEMENT VARIABLES
// ─────────────────────────────────────────────────────────────
var bool   inTrade    = false
var bool   isLong     = false
var float  entryPrice = na

// Signal flags
longSignal  = false
shortSignal = false

// Detect long signal: price crosses above support level
if array.size(supportLevels) > 0
    for i = 0 to (array.size(supportLevels) - 1)
        lvl = array.get(supportLevels, i)
        if low < lvl and close > lvl
            longSignal := true

// Detect short signal: price crosses below resistance level
if array.size(resistanceLevels) > 0
    for i = 0 to (array.size(resistanceLevels) - 1)
        lvl = array.get(resistanceLevels, i)
        if high > lvl and close < lvl
            shortSignal := true

// ─────────────────────────────────────────────────────────────
// ENTRY CONDITIONS & EXECUTION
// ─────────────────────────────────────────────────────────────
if not inTrade
    // Long entry: require long signal, price above 50MA, and ADX above threshold
    if allowLong and longSignal and close > ma50 and adxValue > adxThreshold
        strategy.entry("Long", strategy.long)
        label.new(x=bar_index, y=low, text="LONG", xloc=xloc.bar_index, style=label.style_label_up, color=color.green, textcolor=color.white)
        entryPrice := close
        isLong     := true
        inTrade    := true
    // Short entry: require short signal, price below 50MA, and ADX above threshold
    else if allowShort and shortSignal and close < ma50 and adxValue > adxThreshold
        strategy.entry("Short", strategy.short)
        label.new(x=bar_index, y=high, text="SHORT", xloc=xloc.bar_index, style=label.style_label_down, color=color.red, textcolor=color.white)
        entryPrice := close
        isLong     := false
        inTrade    := true

// ─────────────────────────────────────────────────────────────
// EXIT CONDITIONS
// ─────────────────────────────────────────────────────────────
if inTrade
    ret = isLong ? (close - entryPrice) / entryPrice : (entryPrice - close) / entryPrice
    tp  = isLong ? tpLong : tpShort
    sl  = isLong ? slLong : slShort
    if ret >= tp or ret <= -sl
        strategy.close_all()
        label.new(x=bar_index, y=close, text="EXIT", xloc=xloc.bar_index, style=label.style_label_left, color=color.orange, textcolor=color.black)
        inTrade    := false
        entryPrice := na

// ─────────────────────────────────────────────────────────────
// ALERT CONDITIONS
// ─────────────────────────────────────────────────────────────
alertcondition(longSignal and allowLong, title="Long Breakout", message="🚀 Long breakout on {{ticker}} at {{close}}")
alertcondition(shortSignal and allowShort, title="Short Breakout", message="🔻 Short breakout on {{ticker}} at {{close}}")


Enter fullscreen mode Exit fullscreen mode

Strategy parameters

Image description

The original address: Support Resistance Breakout Strategy with Trend-ADX Filter Quantitative Trading System

Comments 1 total

  • Raxrb Kuech
    Raxrb KuechJun 5, 2025

    Great strategy! Combining support/resistance breakouts with ADX for trend confirmation is a robust approach. I especially like how you use ADX to filter false breakouts—this helps avoid whipsaws.

Add comment