ADX System-DI-übergreifende Strategie
Überblick
Die ADX-Systemstrategie ist die StockSharp-Konvertierung des MetaTrader 4-Experten ADX_System.mq4. Das Original EA vergleicht die
Durchschnittlicher Richtungsindex (ADX) mit seinen +DI- und -DI-Komponenten für die beiden zuletzt abgeschlossenen Kerzen. Wenn die +DI-Leitung
steigt über den ADX-Wert, den das System lang halten möchte; Wenn die -DI-Linie über den ADX-Wert steigt, möchte sie kurz sein. Die
Der Port StockSharp reproduziert dieses Verhalten, indem er die Indikatorwerte der beiden vorherigen fertigen Kerzen speichert, also die Logik
spiegelt die iADX(..., shift=1/2)-Aufrufe wider, die im MetaTrader-Code verwendet werden.
Es kann immer nur eine Position offen sein. Die Strategie übermittelt Marktaufträge für Ein- und Ausstiege, passend zum Einzelticket
Logik von MetaTrader Netting-Konten. Das Risikomanagement spiegelt den ursprünglichen Expertenberater wider: feste Take-Profit- und Stop-Loss-Werte
Die Niveaus werden in Punkten im Verhältnis zum durchschnittlichen Einstiegspreis ausgedrückt, und ein optionaler Trailing-Stop kann Gewinne sichern, sobald der Kurs erreicht ist
Position bewegt sich günstig.
Handelslogik
- Abonnieren Sie den konfigurierten Zeitrahmen (
CandleType) und verarbeiten Sie nur fertige Kerzen, um Entscheidungen innerhalb des Balkens zu vermeiden.
- Füttern Sie einen
AverageDirectionalIndex-Indikator mit den Kerzendaten und warten Sie, bis der Indikator seine Werte ADX, +DI und -DI bereitstellt
Werte.
- Speichern Sie die Indikatorwerte der beiden zuletzt abgeschlossenen Kerzen, damit die Strategie auf die „aktuellen“ und „aktuellen“ Werte verweisen kann
„vorherige“ Werte genau wie die MetaTrader-Implementierung.
- Langer Eintrag: Wenn der ältere ADX (
shift = 2) unter dem neueren ADX (shift = 1) liegt, liegt der ältere +DI darunter
ADX und der neuere +DI über dem neueren ADX liegt, senden Sie eine Marktkauforder.
- Kurzeintrag: Wenn die gleichen Bedingungen für die -DI-Komponente auftreten (alter -DI unter altem ADX, neuer -DI über neuem ADX), senden Sie eine
Marktverkaufsauftrag.
- Long Exit: Schließen Sie die Long-Position, wenn der ADX zu fallen beginnt und +DI wieder unter diesen Wert fällt, wenn die Konfiguration erfolgt
Take-Profit oder Stop-Loss erreicht wird oder wenn der Trailing Stop durchbrochen wird.
- Kurzer Exit: Spiegeln Sie die Long-Exit-Logik mithilfe von -DI zusammen mit den Risikokontrollen wider.
- Aktualisieren Sie den zwischengespeicherten Indikatorverlauf nach jeder Kerze, sodass das nächste Signal das neueste
shift = 1/2-Paar verwendet.
Risikomanagement
TakeProfitPoints und StopLossPoints beschreiben Entfernungen in Punkten im MetaTrader-Stil. Sie werden in tatsächliche Preiseinheiten umgerechnet
Verwendung von Security.PriceStep, sofern verfügbar; andernfalls wird der Rohwert als absolutes Preisdelta behandelt.
- Der Trailing Stop (
TrailingStopPoints) wird erst aktiviert, nachdem die Position mindestens den konfigurierten Abstand vom erreicht hat
Eintrittspreis. Sobald es aktiv ist, bewegt es sich in Richtung Gewinn und schließt die Position, wenn der Preis das nachlaufende Niveau überschreitet.
- Alle Exits (Indikatorumkehr, Take-Profit, Stop-Loss, Trailing Stop) verwenden Marktaufträge, sodass die Position abgeflacht wird
sofort und ahmt das Verhalten von
OrderClose aus der Quelle EA nach.
Parameter
| Name |
Typ |
Standard |
Beschreibung |
CandleType |
DataType |
Zeitrahmen von 1 Minute |
Primärer Zeitrahmen, der von der Strategie verarbeitet wird. |
AdxPeriod |
int |
14 |
Anzahl der Kerzen, die zur Berechnung der ADX- und DI-Komponenten verwendet werden. |
TradeVolume |
decimal |
1 |
Für jede Marktorder verwendete Losgröße. |
TakeProfitPoints |
decimal |
100 |
Take-Profit-Distanz in Punkten relativ zum Einstiegspreis. |
StopLossPoints |
decimal |
30 |
Stop-Loss-Distanz in Punkten relativ zum Einstiegspreis. |
TrailingStopPoints |
decimal |
0 |
Optionaler Trailing-Stop-Abstand in Punkten. Auf Null setzen, um das Nachziehen zu deaktivieren. |
- MetaTrader verwaltet einzelne Tickets, während StockSharp mit einer einzelnen Nettoposition arbeitet. Die Konvertierung schließt daher die
Überprüfen Sie die aktuelle Position, bevor Sie einen neuen Eingabebefehl erteilen, wenn das Signal wechselt.
- Das ursprüngliche EA stützte sich auf
Point, um Punkte in Preisentfernungen umzuwandeln. Der StockSharp-Port verwendet Security.PriceStep, wenn er
ist bekannt; andernfalls wird der Abstand als Rohpreiseinheit behandelt, sodass Sie möglicherweise die Standardeinstellungen für Instrumente mit anpassen müssen
unkonventionelle Preisschritte.
- MetaTrader wendet Trailing Stops an, indem es die bestehende Reihenfolge ändert. StockSharp schließt die Position mit einer Marktorder, wenn die
Der Trailing Stop wird verletzt, was im Netting-Modell funktional gleichwertig, aber einfacher ist.
Anwendungstipps
- Stellen Sie sicher, dass das Strategievolumen (
TradeVolume) mit dem Losschritt des Instruments übereinstimmt. Der Konstruktor weist diesen Wert auch zu
Strategy.Volume, daher verwenden Hilfsmethoden die erwartete Handelsgröße.
- Erhöhen Sie
TakeProfitPoints und StopLossPoints, wenn Sie Instrumente mit größeren Durchschnittsspannen oder kleineren Preisschritten handeln.
- Fügen Sie die Strategie einem Diagramm hinzu, um die Kerzen, den ADX-Indikator und ausgeführte Trades zu visualisieren, was bei der Überprüfung dieser Signale hilft
treten genau dann auf, wenn +DI oder -DI die Linie ADX überschreitet.
Indikatoren
AverageDirectionalIndex (stellt ADX zusammen mit +DI- und -DI-Komponenten bereit).
using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// ADX System DI Cross: trend-following using dual EMA crossover
/// (proxy for +DI/-DI cross) with ATR-based volatility filter.
/// </summary>
public class AdxSystemDiCrossStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _fastLength;
private readonly StrategyParam<int> _slowLength;
private readonly StrategyParam<int> _atrLength;
private readonly StrategyParam<decimal> _atrThreshold;
private decimal _prevFast;
private decimal _prevSlow;
private decimal _entryPrice;
public AdxSystemDiCrossStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(15).TimeFrame())
.SetDisplay("Candle Type", "Timeframe.", "General");
_fastLength = Param(nameof(FastLength), 10)
.SetDisplay("Fast EMA", "Fast EMA period (proxy for +DI).", "Indicators");
_slowLength = Param(nameof(SlowLength), 20)
.SetDisplay("Slow EMA", "Slow EMA period (proxy for -DI).", "Indicators");
_atrLength = Param(nameof(AtrLength), 14)
.SetDisplay("ATR Length", "ATR period for trend strength.", "Indicators");
_atrThreshold = Param(nameof(AtrThreshold), 50m)
.SetDisplay("ATR Threshold", "Min ATR value for entry.", "Indicators");
}
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int FastLength
{
get => _fastLength.Value;
set => _fastLength.Value = value;
}
public int SlowLength
{
get => _slowLength.Value;
set => _slowLength.Value = value;
}
public int AtrLength
{
get => _atrLength.Value;
set => _atrLength.Value = value;
}
public decimal AtrThreshold
{
get => _atrThreshold.Value;
set => _atrThreshold.Value = value;
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevFast = 0;
_prevSlow = 0;
_entryPrice = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var fast = new ExponentialMovingAverage { Length = FastLength };
var slow = new ExponentialMovingAverage { Length = SlowLength };
var atr = new AverageTrueRange { Length = AtrLength };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(fast, slow, atr, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, fast);
DrawIndicator(area, slow);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal fastVal, decimal slowVal, decimal atrVal)
{
if (candle.State != CandleStates.Finished)
return;
if (_prevFast == 0 || _prevSlow == 0)
{
_prevFast = fastVal;
_prevSlow = slowVal;
return;
}
var bullishCross = _prevFast <= _prevSlow && fastVal > slowVal;
var bearishCross = _prevFast >= _prevSlow && fastVal < slowVal;
// Exit on opposite cross
if (Position > 0 && bearishCross)
{
SellMarket();
_entryPrice = 0;
}
else if (Position < 0 && bullishCross)
{
BuyMarket();
_entryPrice = 0;
}
// Entry on cross + volatility filter
if (Position == 0 && atrVal >= AtrThreshold)
{
if (bullishCross)
{
_entryPrice = candle.ClosePrice;
BuyMarket();
}
else if (bearishCross)
{
_entryPrice = candle.ClosePrice;
SellMarket();
}
}
_prevFast = fastVal;
_prevSlow = slowVal;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import ExponentialMovingAverage, AverageTrueRange
from StockSharp.Algo.Strategies import Strategy
class adx_system_di_cross_strategy(Strategy):
"""
ADX System DI Cross: trend-following using dual EMA crossover
(proxy for +DI/-DI cross) with ATR-based volatility filter.
"""
def __init__(self):
super(adx_system_di_cross_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(15))) \
.SetDisplay("Candle Type", "Timeframe.", "General")
self._fast_length = self.Param("FastLength", 10) \
.SetDisplay("Fast EMA", "Fast EMA period (proxy for +DI).", "Indicators")
self._slow_length = self.Param("SlowLength", 20) \
.SetDisplay("Slow EMA", "Slow EMA period (proxy for -DI).", "Indicators")
self._atr_length = self.Param("AtrLength", 14) \
.SetDisplay("ATR Length", "ATR period for trend strength.", "Indicators")
self._atr_threshold = self.Param("AtrThreshold", 50.0) \
.SetDisplay("ATR Threshold", "Min ATR value for entry.", "Indicators")
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def FastLength(self):
return self._fast_length.Value
@FastLength.setter
def FastLength(self, value):
self._fast_length.Value = value
@property
def SlowLength(self):
return self._slow_length.Value
@SlowLength.setter
def SlowLength(self, value):
self._slow_length.Value = value
@property
def AtrLength(self):
return self._atr_length.Value
@AtrLength.setter
def AtrLength(self, value):
self._atr_length.Value = value
@property
def AtrThreshold(self):
return self._atr_threshold.Value
@AtrThreshold.setter
def AtrThreshold(self, value):
self._atr_threshold.Value = value
def OnReseted(self):
super(adx_system_di_cross_strategy, self).OnReseted()
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
def OnStarted2(self, time):
super(adx_system_di_cross_strategy, self).OnStarted2(time)
fast = ExponentialMovingAverage()
fast.Length = self.FastLength
slow = ExponentialMovingAverage()
slow.Length = self.SlowLength
atr = AverageTrueRange()
atr.Length = self.AtrLength
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(fast, slow, atr, self.ProcessCandle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, fast)
self.DrawIndicator(area, slow)
self.DrawOwnTrades(area)
def ProcessCandle(self, candle, fast_val, slow_val, atr_val):
if candle.State != CandleStates.Finished:
return
if self._prev_fast == 0 or self._prev_slow == 0:
self._prev_fast = fast_val
self._prev_slow = slow_val
return
bullish_cross = self._prev_fast <= self._prev_slow and fast_val > slow_val
bearish_cross = self._prev_fast >= self._prev_slow and fast_val < slow_val
# Exit on opposite cross
if self.Position > 0 and bearish_cross:
self.SellMarket()
self._entry_price = 0.0
elif self.Position < 0 and bullish_cross:
self.BuyMarket()
self._entry_price = 0.0
# Entry on cross + volatility filter
if self.Position == 0 and atr_val >= self.AtrThreshold:
if bullish_cross:
self._entry_price = float(candle.ClosePrice)
self.BuyMarket()
elif bearish_cross:
self._entry_price = float(candle.ClosePrice)
self.SellMarket()
self._prev_fast = fast_val
self._prev_slow = slow_val
def CreateClone(self):
"""!! REQUIRED!! Creates a new instance of the strategy."""
return adx_system_di_cross_strategy()