Auf GitHub ansehen

Roboter ADX + 2 MA-Strategie

Überblick

Die Robot ADX + 2 MA-Strategie ist eine StockSharp-Portierung des MetaTrader-Experten Robot_ADX+2MA. Das System kombiniert ein schnelles und ein langsames exponentieller gleitender Durchschnitt mit den +DI/-DI-Komponenten des Average Directional Index (ADX). Bestellungen werden erst geöffnet, wenn die Die vorherige Kerze zeigt einen ausreichend großen Abstand von EMA und die aktuelle Kerze bestätigt die Dynamik durch den Richtungsindex. Die Bei der Konvertierung bleibt das ursprüngliche Verhalten erhalten, bei dem jeweils höchstens eine Marktposition eröffnet und Exits an Stop-Loss- und Stop-Loss-Positionen delegiert werden Take-Profit-Schutz.

Handelslogik

  1. Abonnieren Sie die über CandleType konfigurierte primäre Kerzenserie und verarbeiten Sie nur fertige Kerzen.
  2. Füttere zwei exponentielle gleitende Durchschnitte (Perioden 5 und 12) mit den Schlusskursen der Kerze. Ihre Werte von der vorherigen Kerze emulieren den in MetaTrader verwendeten shift = 1-Lookback.
  3. Füttern Sie einen AverageDirectionalIndex-Indikator (Periode 6) mit denselben Kerzen. Speichern Sie sowohl den aktuellen als auch den vorherigen +DI/-DI Messwerte zur Replikation der EA-Filter.
  4. Berechnen Sie den absoluten EMA-Abstand von der vorherigen Kerze und vergleichen Sie ihn mit DifferenceThreshold, umgerechnet aus Punkten in Preiseinheiten (Point in MetaTrader entspricht Security.PriceStep in StockSharp).
  5. Bulsischer Einstieg: nur zulässig, wenn keine Position offen ist und die folgenden Bedingungen erfüllt sind:
    • Der vorherige schnelle EMA liegt unter dem vorherigen langsamen EMA.
    • Der vorherige +DI liegt unter 5, der aktuelle +DI liegt über 10 und +DI ist stärker als -DI.
    • Die Entfernung EMA liegt über dem konfigurierten Schwellenwert.
  6. Bearischer Einstieg: symmetrisch zu den langen Regeln, erfordert, dass das vorherige schnelle EMA über dem langsamen EMA liegt, die -DI-Filter zufrieden und -DI, um +DI zu dominieren.
  7. Wenn ein Trade eröffnet wird, verlassen Sie sich darauf, dass das von StartProtection gestartete Risikomodul über Take-Profit oder Stop-Loss aussteigt. Kein Handbuch Exit-Regeln werden hinzugefügt, die dem ursprünglichen Experten entsprechen.

Parameter

Name Typ Standard Beschreibung
CandleType DataType Zeitrahmen von 1 Minute Von der Strategie verarbeitete primäre Kerzenserie.
TakeProfitPoints int 4700 Abstand des Take-Profit-Ziels, ausgedrückt in Preisschritten. Zum Deaktivieren auf Null setzen.
StopLossPoints int 2400 Abstand des Stop-Loss-Ziels in Preisschritten. Zum Deaktivieren auf Null setzen.
TradeVolume decimal 0.1 Nettovolumen, das für jede Marktorder verwendet wird.
DifferenceThreshold int 10 Mindestentfernung EMA (in Preisschritten), die erforderlich ist, bevor ein Signal akzeptiert wird.

Risikomanagement

  • Die StockSharp-Version ruft StartProtection mit UnitTypes.Step auf, also sind die konfigurierten Stop-Loss- und Take-Profit-Abstände automatisch auf die Preisstufe des Brokers umgerechnet.
  • Schutzaufträge werden als Marktaustritte (useMarketOrders = true) generiert und reproduzieren das unmittelbare Schlussverhalten des MQL Hilfsfunktion.

Details zur Implementierung

  • Indikatorbindungen verwenden das übergeordnete SubscribeCandles(...).Bind(...).BindEx(...) API, sodass keine manuellen Datenschleifen erforderlich sind.
  • EMA-Werte der vorherigen Kerze werden zwischengespeichert, um die iMA(..., shift = 1)-Aufrufe im ursprünglichen EA zu reproduzieren.
  • ADX-Daten werden über AverageDirectionalIndexValue verbraucht und ermöglichen so den direkten Zugriff auf die +DI- und -DI-Komponenten ohne Aufruf verbotene GetValue Helfer.
  • Ein Schutz pro Kerze (_lastProcessedTime) stellt sicher, dass Signale nur einmal ausgewertet werden, auch wenn sowohl die Bindungen EMA als auch ADX ausgelöst werden Rückrufe für dieselbe Kerze.

Unterschiede zum MetaTrader-Experten

  • Der redundante direkte OrderSend-Aufruf im Verkaufszweig des MQL-Codes wurde entfernt; Beide Richtungen verwenden ein einziges BuyMarket/SellMarket Helfer.
  • MetaTrader prüft die freie Marge, bevor Orders gesendet werden. Der StockSharp-Port delegiert Risikokontrollen an die Hosting-Umgebung und setzt ausreichendes Gleichgewicht voraus.
  • Die Schutzlogik wird über den Risikomanager von StockSharp anstelle von benutzerdefinierten Schleifen implementiert, die OrderSend wiederholt aufrufen.

Anwendungstipps

  • Passen Sie TradeVolume an, um den Losschritt des ausgewählten Wertpapiers zu berücksichtigen, bevor Sie mit dem Live-Handel beginnen.
  • Wenn der Markt eine andere Preisskala verwendet, passen Sie DifferenceThreshold zusammen mit den Stopp-/Zielentfernungen an, sodass die EMA Die Trennung ist vergleichbar mit der MetaTrader-Konfiguration.
  • Der Standardzeitrahmen beträgt eine Minute, aber der Parameter CandleType ermöglicht den Wechsel zu jeder anderen von den Daten unterstützten Serie Quelle.

Indikatoren

  • ExponentialMovingAverage(5) berechnet auf Grundlage der Schlusskurse.
  • ExponentialMovingAverage(12) berechnet auf Grundlage der Schlusskurse.
  • AverageDirectionalIndex(6) bietet +DI/-DI- und ADX-Stärkefilter.
using System;

using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;

namespace StockSharp.Samples.Strategies;

/// <summary>
/// RobotADX2MA: Dual EMA crossover with RSI confirmation and ATR stops.
/// </summary>
public class RobotAdxTwoMaStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _fastEmaLength;
	private readonly StrategyParam<int> _slowEmaLength;
	private readonly StrategyParam<int> _rsiLength;
	private readonly StrategyParam<int> _atrLength;

	private decimal _prevFast;
	private decimal _prevSlow;
	private decimal _entryPrice;

	public RobotAdxTwoMaStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe.", "General");
		_fastEmaLength = Param(nameof(FastEmaLength), 5)
			.SetDisplay("Fast EMA Length", "Fast EMA period.", "Indicators");
		_slowEmaLength = Param(nameof(SlowEmaLength), 12)
			.SetDisplay("Slow EMA Length", "Slow EMA period.", "Indicators");
		_rsiLength = Param(nameof(RsiLength), 14)
			.SetDisplay("RSI Length", "RSI period.", "Indicators");
		_atrLength = Param(nameof(AtrLength), 14)
			.SetDisplay("ATR Length", "ATR period.", "Indicators");
	}

	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
	public int FastEmaLength { get => _fastEmaLength.Value; set => _fastEmaLength.Value = value; }
	public int SlowEmaLength { get => _slowEmaLength.Value; set => _slowEmaLength.Value = value; }
	public int RsiLength { get => _rsiLength.Value; set => _rsiLength.Value = value; }
	public int AtrLength { get => _atrLength.Value; set => _atrLength.Value = value; }

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();

		_prevFast = 0; _prevSlow = 0; _entryPrice = 0;
	}

		protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_prevFast = 0; _prevSlow = 0; _entryPrice = 0;
		var fastEma = new ExponentialMovingAverage { Length = FastEmaLength };
		var slowEma = new ExponentialMovingAverage { Length = SlowEmaLength };
		var rsi = new RelativeStrengthIndex { Length = RsiLength };
		var atr = new AverageTrueRange { Length = AtrLength };
		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(fastEma, slowEma, rsi, atr, ProcessCandle).Start();
		var area = CreateChartArea();
		if (area != null) { DrawCandles(area, subscription); DrawIndicator(area, fastEma); DrawIndicator(area, slowEma); DrawOwnTrades(area); }
	}

	private void ProcessCandle(ICandleMessage candle, decimal fastVal, decimal slowVal, decimal rsiVal, decimal atrVal)
	{
		if (candle.State != CandleStates.Finished) return;
		if (_prevFast == 0 || _prevSlow == 0 || atrVal <= 0) { _prevFast = fastVal; _prevSlow = slowVal; return; }
		var close = candle.ClosePrice;

		if (Position > 0)
		{
			if ((fastVal < slowVal && _prevFast >= _prevSlow) || close <= _entryPrice - atrVal * 2m) { SellMarket(); _entryPrice = 0; }
		}
		else if (Position < 0)
		{
			if ((fastVal > slowVal && _prevFast <= _prevSlow) || close >= _entryPrice + atrVal * 2m) { BuyMarket(); _entryPrice = 0; }
		}

		if (Position == 0)
		{
			if (fastVal > slowVal && _prevFast <= _prevSlow && rsiVal > 50) { _entryPrice = close; BuyMarket(); }
			else if (fastVal < slowVal && _prevFast >= _prevSlow && rsiVal < 50) { _entryPrice = close; SellMarket(); }
		}
		_prevFast = fastVal; _prevSlow = slowVal;
	}
}