ADX-Volumen-Multiplikator-Strategie
Die ADX-Volumen-Multiplikator-Strategie kombiniert die Trendstärke des Average Directional Index mit einem Volumenanstiegsfilter. Sie tritt in Trades nur ein, wenn der ADX einen Schwellenwert überschreitet, die dominante Richtungslinie in die Trendrichtung zeigt und das aktuelle Volumen einen gleitenden Durchschnitt multipliziert mit einem benutzerdefinierten Faktor überschreitet.
Details
- Einstiegskriterien:
- ADX über Schwellenwert und DI+ > DI- mit Volumen größer als SMA(Volumen) * Multiplikator → Long.
- ADX über Schwellenwert und DI- > DI+ mit Volumen größer als SMA(Volumen) * Multiplikator → Short.
- Long/Short: Beide.
- Ausstiegskriterien:
- Ein umgekehrtes Signal löst eine Positionsumkehr aus.
- Stops: Keine.
- Standardwerte:
AdxPeriod= 21AdxThreshold= 26VolumeMultiplier= 1.8VolumePeriod= 20
- Filter:
- Kategorie: Trendfolge
- Richtung: Beide
- Indikatoren: ADX, Volume SMA
- Stops: Nein
- Komplexität: Niedrig
- Zeitrahmen: Beliebig
- Saisonalität: Nein
- Neuronale Netze: Nein
- Divergenz: Nein
- Risikolevel: Mittel
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// ADX Volume Multiplier strategy.
/// When ADX is above AdxThreshold and the candle volume exceeds VolumeMultiplier times its SMA, the strategy goes long if DI+ is above
/// DI- and short if DI- is above DI+; the opposite signal reverses the position.
/// </summary>
public class AdxVolumeMultiplierStrategy : Strategy
{
private readonly StrategyParam<int> _adxPeriod;
private readonly StrategyParam<decimal> _adxThreshold;
private readonly StrategyParam<decimal> _volumeMultiplier;
private readonly StrategyParam<int> _volumePeriod;
private readonly StrategyParam<DataType> _candleType;
private SimpleMovingAverage _volumeSma;
/// <summary>
/// ADX period.
/// </summary>
public int AdxPeriod
{
get => _adxPeriod.Value;
set => _adxPeriod.Value = value;
}
/// <summary>
/// ADX level a trend must exceed.
/// </summary>
public decimal AdxThreshold
{
get => _adxThreshold.Value;
set => _adxThreshold.Value = value;
}
/// <summary>
/// Multiple of the average volume the candle volume must exceed.
/// </summary>
public decimal VolumeMultiplier
{
get => _volumeMultiplier.Value;
set => _volumeMultiplier.Value = value;
}
/// <summary>
/// Period of the volume SMA.
/// </summary>
public int VolumePeriod
{
get => _volumePeriod.Value;
set => _volumePeriod.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public AdxVolumeMultiplierStrategy()
{
_adxPeriod = Param(nameof(AdxPeriod), 21)
.SetGreaterThanZero()
.SetDisplay("ADX Period", "ADX period", "ADX");
_adxThreshold = Param(nameof(AdxThreshold), 26m)
.SetDisplay("ADX Threshold", "ADX level a trend must exceed", "ADX");
_volumeMultiplier = Param(nameof(VolumeMultiplier), 1.8m)
.SetGreaterThanZero()
.SetDisplay("Volume Multiplier", "Multiple of the average volume the candle volume must exceed", "Volume");
_volumePeriod = Param(nameof(VolumePeriod), 20)
.SetGreaterThanZero()
.SetDisplay("Volume Period", "Period of the volume SMA", "Volume");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_volumeSma = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var adx = new AverageDirectionalIndex { Length = AdxPeriod };
_volumeSma = new SimpleMovingAverage { Length = VolumePeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(adx, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
var oscillators = CreateChartArea();
if (oscillators != null)
DrawIndicator(oscillators, adx);
}
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue adxValue)
{
if (candle.State != CandleStates.Finished)
return;
var volumeAverage = _volumeSma.Process(candle.TotalVolume, candle.ServerTime, true).ToDecimal();
if (!adxValue.IsFormed || !_volumeSma.IsFormed)
return;
var adxTyped = (IAverageDirectionalIndexValue)adxValue;
if (adxTyped.MovingAverage is not decimal adx || adxTyped.Dx.Plus is not decimal diPlus || adxTyped.Dx.Minus is not decimal diMinus)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var volumeSurge = candle.TotalVolume > volumeAverage * VolumeMultiplier;
var strong = adx > AdxThreshold;
if (strong && volumeSurge && diPlus > diMinus && Position <= 0)
BuyMarket(Volume + Math.Abs(Position));
else if (strong && volumeSurge && diMinus > diPlus && Position >= 0)
SellMarket(Volume + Math.Abs(Position));
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
clr.AddReference("StockSharp.BusinessEntities")
from System import TimeSpan, Decimal
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import AverageDirectionalIndex, SimpleMovingAverage
from StockSharp.Algo.Strategies import Strategy
from indicator_extensions import *
class adx_volume_multiplier_strategy(Strategy):
"""
ADX Volume Multiplier strategy.
When ADX is above AdxThreshold and the candle volume exceeds VolumeMultiplier times its SMA, the strategy goes long if DI+ is above
DI- and short if DI- is above DI+; the opposite signal reverses the position.
"""
def __init__(self):
super(adx_volume_multiplier_strategy, self).__init__()
self._adx_period = self.Param("AdxPeriod", 21).SetGreaterThanZero().SetDisplay("ADX Period", "ADX period", "ADX")
self._adx_threshold = self.Param("AdxThreshold", 26.0).SetDisplay("ADX Threshold", "ADX level a trend must exceed", "ADX")
self._volume_multiplier = self.Param("VolumeMultiplier", 1.8).SetGreaterThanZero().SetDisplay("Volume Multiplier", "Multiple of the average volume the candle volume must exceed", "Volume")
self._volume_period = self.Param("VolumePeriod", 20).SetGreaterThanZero().SetDisplay("Volume Period", "Period of the volume SMA", "Volume")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(30))).SetDisplay("Candle Type", "Type of candles to use", "General")
self._volume_sma = None
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(adx_volume_multiplier_strategy, self).OnReseted()
self._volume_sma = None
def OnStarted2(self, time):
super(adx_volume_multiplier_strategy, self).OnStarted2(time)
adx = AverageDirectionalIndex()
adx.Length = self._adx_period.Value
self._volume_sma = SimpleMovingAverage()
self._volume_sma.Length = self._volume_period.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(adx, self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
oscillators = self.CreateChartArea()
if oscillators is not None:
self.DrawIndicator(oscillators, adx)
def _process_candle(self, candle, adx_value):
if candle.State != CandleStates.Finished:
return
volume_average = process_float(self._volume_sma, candle.TotalVolume, candle.ServerTime, True).GetValue[Decimal](None)
if not adx_value.IsFormed or not self._volume_sma.IsFormed:
return
adx = adx_value.MovingAverage
di_plus = adx_value.Dx.Plus
di_minus = adx_value.Dx.Minus
if adx is None or di_plus is None or di_minus is None:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
volume_surge = candle.TotalVolume > volume_average * Decimal(self._volume_multiplier.Value)
strong = adx > Decimal(self._adx_threshold.Value)
if strong and volume_surge and di_plus > di_minus and self.Position <= 0:
self.BuyMarket(self.Volume + abs(self.Position))
elif strong and volume_surge and di_minus > di_plus and self.Position >= 0:
self.SellMarket(self.Volume + abs(self.Position))
def CreateClone(self):
return adx_volume_multiplier_strategy()