Auf GitHub ansehen

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

  1. Abonnieren Sie den konfigurierten Zeitrahmen (CandleType) und verarbeiten Sie nur fertige Kerzen, um Entscheidungen innerhalb des Balkens zu vermeiden.
  2. Füttern Sie einen AverageDirectionalIndex-Indikator mit den Kerzendaten und warten Sie, bis der Indikator seine Werte ADX, +DI und -DI bereitstellt Werte.
  3. 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.
  4. 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.
  5. 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.
  6. 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.
  7. Kurzer Exit: Spiegeln Sie die Long-Exit-Logik mithilfe von -DI zusammen mit den Risikokontrollen wider.
  8. 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.

Unterschiede zum ursprünglichen MetaTrader-Experten

  • 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;
	}
}