ADX-Ausbruch
Die ADX-Ausbruch-Strategie überwacht den ADX auf starke Expansionen. Wenn die Werte über ihren typischen Bereich hinausspringen, beginnt der Preis oft eine neue Bewegung.
Tests zeigen eine durchschnittliche jährliche Rendite von etwa 97%. Die Strategie funktioniert am besten im Kryptomarkt.
Eine Position wird eröffnet, sobald der Indikator ein Band durchbricht, das aus aktuellen Daten und einem Abweichungsmultiplikator abgeleitet wird. Long- und Short-Trades sind mit einem Stop möglich.
Dieses System eignet sich für Momentum-Trader, die frühe Ausbrüche suchen. Trades schließen, wenn der ADX zur Mitte zurückkehrt. Standardwerte beginnen mit ADXPeriod = 14.
Details
- Einstiegskriterien: Indikator überschreitet den Durchschnitt um den Abweichungsmultiplikator.
- Long/Short: Beide Richtungen.
- Ausstiegskriterien: Indikator kehrt zum Durchschnitt zurück.
- Stops: Ja.
- Standardwerte:
ADXPeriod= 14AvgPeriod= 20Multiplier= 0.1mCandleType= TimeSpan.FromMinutes(5)StopLoss= 2.0m
- Filter:
- Kategorie: Ausbruch
- Richtung: Beide
- Indikatoren: ADX
- Stops: Ja
- Komplexität: Mittel
- Zeitrahmen: Kurzfristig
- Saisonalität: Nein
- Neuronale Netze: Nein
- Divergenz: Nein
- Risikolevel: Mittel
using System;
using System.Linq;
using System.Collections.Generic;
using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Strategy that trades on ADX breakouts.
/// When ADX breaks out above its average, it enters position in the direction determined by price.
/// </summary>
public class ADXBreakoutStrategy : Strategy
{
private readonly StrategyParam<int> _adxPeriod;
private readonly StrategyParam<int> _avgPeriod;
private readonly StrategyParam<decimal> _multiplier;
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<decimal> _stopLoss;
private AverageDirectionalIndex _adx;
private SimpleMovingAverage _adxAverage;
private decimal _prevAdxValue;
private decimal _prevAdxAvgValue;
/// <summary>
/// ADX period.
/// </summary>
public int ADXPeriod
{
get => _adxPeriod.Value;
set => _adxPeriod.Value = value;
}
/// <summary>
/// Period for ADX average calculation.
/// </summary>
public int AvgPeriod
{
get => _avgPeriod.Value;
set => _avgPeriod.Value = value;
}
/// <summary>
/// Standard deviation multiplier for breakout detection.
/// </summary>
public decimal Multiplier
{
get => _multiplier.Value;
set => _multiplier.Value = value;
}
/// <summary>
/// Candle type for strategy.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Stop-loss percentage.
/// </summary>
public decimal StopLoss
{
get => _stopLoss.Value;
set => _stopLoss.Value = value;
}
/// <summary>
/// Initialize <see cref="ADXBreakoutStrategy"/>.
/// </summary>
public ADXBreakoutStrategy()
{
_adxPeriod = Param(nameof(ADXPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("ADX Period", "Period for ADX indicator", "Indicators")
.SetOptimize(10, 30, 2);
_avgPeriod = Param(nameof(AvgPeriod), 20)
.SetGreaterThanZero()
.SetDisplay("Average Period", "Period for ADX average calculation", "Indicators")
.SetOptimize(10, 50, 5);
_multiplier = Param(nameof(Multiplier), 0.1m)
.SetGreaterThanZero()
.SetDisplay("Multiplier", "Standard deviation multiplier for breakout detection", "Indicators")
.SetOptimize(0.0m, 1.0m, 0.1m);
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
_stopLoss = Param(nameof(StopLoss), 2.0m)
.SetGreaterThanZero()
.SetDisplay("Stop Loss %", "Stop Loss percentage", "Risk Management")
.SetOptimize(1.0m, 5.0m, 0.5m);
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevAdxValue = 0;
_prevAdxAvgValue = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
// Create indicators
_adx = new AverageDirectionalIndex { Length = ADXPeriod };
_adxAverage = new SMA { Length = AvgPeriod };
// Create subscription and bind indicators
var subscription = SubscribeCandles(CandleType);
// First bind ADX to the candle subscription
subscription
.BindEx(_adx, ProcessAdx)
.Start();
// Enable stop loss protection
StartProtection(
takeProfit: new Unit(0, UnitTypes.Absolute),
stopLoss: new Unit(StopLoss, UnitTypes.Percent)
);
// Create chart area for visualization
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, _adx);
DrawOwnTrades(area);
}
}
private void ProcessAdx(ICandleMessage candle, IIndicatorValue adxValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!adxValue.IsFinal)
return;
// Get current ADX value
if (((AverageDirectionalIndexValue)adxValue).MovingAverage is not decimal currentAdx)
{
return;
}
// Process ADX through average indicator
var adxAvgValue = _adxAverage.Process(new DecimalIndicatorValue(_adxAverage, currentAdx, candle.ServerTime));
var currentAdxAvg = adxAvgValue.ToDecimal();
// For first values, just save and skip
if (_prevAdxValue == 0)
{
_prevAdxValue = currentAdx;
_prevAdxAvgValue = currentAdxAvg;
return;
}
// Calculate standard deviation of ADX (simplified approach)
var stdDev = Math.Abs(currentAdx - currentAdxAvg) * 2; // Simplified approximation
// Check if trading is allowed
if (!IsFormedAndOnlineAndAllowTrading())
{
_prevAdxValue = currentAdx;
_prevAdxAvgValue = currentAdxAvg;
return;
}
// ADX breakout detection (ADX increases significantly above its average)
if (currentAdx > currentAdxAvg + Multiplier * stdDev)
{
// Determine direction based on price movement
var priceDirection = candle.ClosePrice > candle.OpenPrice;
// Cancel active orders before placing new ones
CancelActiveOrders();
// Trade in the direction of price movement
if (priceDirection && Position <= 0)
{
// Bullish breakout - Buy
BuyMarket(Volume + Math.Abs(Position));
}
else if (!priceDirection && Position >= 0)
{
// Bearish breakout - Sell
SellMarket(Volume + Math.Abs(Position));
}
}
// Check for exit condition - ADX returns to average
else if ((Position > 0 && currentAdx < currentAdxAvg) ||
(Position < 0 && currentAdx < currentAdxAvg))
{
// Exit position
ClosePosition();
}
// Update previous values
_prevAdxValue = currentAdx;
_prevAdxAvgValue = currentAdxAvg;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Math
from StockSharp.Messages import DataType, Unit, UnitTypes, CandleStates
from StockSharp.Algo.Indicators import AverageDirectionalIndex, SimpleMovingAverage
from StockSharp.Algo.Strategies import Strategy
from datatype_extensions import *
from indicator_extensions import *
class adx_breakout_strategy(Strategy):
"""
Strategy that trades on ADX breakouts.
When ADX breaks out above its average, it enters position in the direction determined by price.
"""
def __init__(self):
super(adx_breakout_strategy, self).__init__()
# Initialize strategy parameters
self._adx_period = self.Param("ADXPeriod", 14) \
.SetGreaterThanZero() \
.SetDisplay("ADX Period", "Period for ADX indicator", "Indicators") \
.SetCanOptimize(True) \
.SetOptimize(10, 30, 2)
self._avg_period = self.Param("AvgPeriod", 20) \
.SetGreaterThanZero() \
.SetDisplay("Average Period", "Period for ADX average calculation", "Indicators") \
.SetCanOptimize(True) \
.SetOptimize(10, 50, 5)
self._multiplier = self.Param("Multiplier", 0.1) \
.SetGreaterThanZero() \
.SetDisplay("Multiplier", "Standard deviation multiplier for breakout detection", "Indicators") \
.SetCanOptimize(True) \
.SetOptimize(0.0, 1.0, 0.1)
self._candle_type = self.Param("CandleType", tf(5)) \
.SetDisplay("Candle Type", "Type of candles to use", "General")
self._stop_loss = self.Param("StopLoss", 2.0) \
.SetGreaterThanZero() \
.SetDisplay("Stop Loss %", "Stop Loss percentage", "Risk Management") \
.SetCanOptimize(True) \
.SetOptimize(1.0, 5.0, 0.5)
# Internal indicators
self._adx = None
self._adx_average = None
self._prev_adx_value = 0
self._prev_adx_avg_value = 0
@property
def ADXPeriod(self):
"""ADX period."""
return self._adx_period.Value
@ADXPeriod.setter
def ADXPeriod(self, value):
self._adx_period.Value = value
@property
def AvgPeriod(self):
"""Period for ADX average calculation."""
return self._avg_period.Value
@AvgPeriod.setter
def AvgPeriod(self, value):
self._avg_period.Value = value
@property
def Multiplier(self):
"""Standard deviation multiplier for breakout detection."""
return self._multiplier.Value
@Multiplier.setter
def Multiplier(self, value):
self._multiplier.Value = value
@property
def CandleType(self):
"""Candle type for strategy."""
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def StopLoss(self):
"""Stop-loss percentage."""
return self._stop_loss.Value
@StopLoss.setter
def StopLoss(self, value):
self._stop_loss.Value = value
def OnReseted(self):
"""
Resets internal state when strategy is reset.
"""
super(adx_breakout_strategy, self).OnReseted()
self._prev_adx_value = 0
self._prev_adx_avg_value = 0
def OnStarted2(self, time):
"""Called when the strategy starts."""
super(adx_breakout_strategy, self).OnStarted2(time)
# Create indicators
self._adx = AverageDirectionalIndex()
self._adx.Length = self.ADXPeriod
self._adx_average = SimpleMovingAverage()
self._adx_average.Length = self.AvgPeriod
# Create subscription and bind indicators
subscription = self.SubscribeCandles(self.CandleType)
# First bind ADX to the candle subscription
subscription.BindEx(self._adx, self.ProcessAdx).Start()
# Enable stop loss protection
self.StartProtection(
takeProfit=Unit(0, UnitTypes.Absolute),
stopLoss=Unit(self.StopLoss, UnitTypes.Percent)
)
# Create chart area for visualization
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, self._adx)
self.DrawOwnTrades(area)
def ProcessAdx(self, candle, adxValue):
if candle.State != CandleStates.Finished:
return
if not adxValue.IsFinal:
return
# Get current ADX value
if adxValue.MovingAverage is None:
return
currentAdx = float(adxValue.MovingAverage)
# Process ADX through average indicator (no IsFinal, matching CS)
currentAdxAvg = float(process_float(self._adx_average, currentAdx, candle.ServerTime, True))
# For first values, just save and skip
if self._prev_adx_value == 0:
self._prev_adx_value = currentAdx
self._prev_adx_avg_value = currentAdxAvg
return
# Calculate standard deviation of ADX (simplified approach)
stdDev = Math.Abs(currentAdx - currentAdxAvg) * 2 # Simplified approximation
# Check if trading is allowed
if not self.IsFormedAndOnlineAndAllowTrading():
self._prev_adx_value = currentAdx
self._prev_adx_avg_value = currentAdxAvg
return
# ADX breakout detection (ADX increases significantly above its average)
if currentAdx > currentAdxAvg + self.Multiplier * stdDev:
# Determine direction based on price movement
priceDirection = candle.ClosePrice > candle.OpenPrice
# Cancel active orders before placing new ones
self.CancelActiveOrders()
# Trade in the direction of price movement
if priceDirection and self.Position <= 0:
# Bullish breakout - Buy
self.BuyMarket(self.Volume + Math.Abs(self.Position))
elif not priceDirection and self.Position >= 0:
# Bearish breakout - Sell
self.SellMarket(self.Volume + Math.Abs(self.Position))
# Check for exit condition - ADX returns to average
elif (self.Position > 0 and currentAdx < currentAdxAvg) or (
self.Position < 0 and currentAdx < currentAdxAvg):
# Exit position
self.ClosePosition()
# Update previous values
self._prev_adx_value = currentAdx
self._prev_adx_avg_value = currentAdxAvg
def CreateClone(self):
"""!! REQUIRED!! Creates a new instance of the strategy."""
return adx_breakout_strategy()