Auf GitHub ansehen

Crossover-2-EMA-Strategie

Die Strategie repliziert den MetaTrader-Expert-Advisor "Crossover_2EMA", indem sie die Beziehung zwischen einer schnellen und einer langsamen exponentiellen gleitenden Durchschnittslinie (EMA) auf Schlusskursen handelt. Wenn die schnelle EMA über die langsame steigt, geht der Algorithmus long. Fällt sie wieder darunter, kehrt der Algorithmus in eine Short-Position um. Der Ansatz hält die Position stets am aktuellen Fast/Slow-Trendzustand ausgerichtet und funktioniert daher als vollständig reversibles System.

Handelslogik

  1. Die konfigurierte Kerzenserie abonnieren und zwei EMAs mit benutzerdefinierten Perioden berechnen.
  2. Den Spread zwischen schneller und langsamer EMA auf jeder abgeschlossenen Kerze verfolgen.
  3. Ein Aufwärtskreuzen erkennen, wenn der Spread von nicht positiv zu positiv wechselt. Jede Short-Exposure schließen und eine Long-Position mit dem konfigurierten Handelsvolumen eröffnen.
  4. Ein Abwärtskreuzen erkennen, wenn der Spread von nicht negativ zu negativ wechselt. Jede Long-Exposure schließen und eine Short-Position mit dem konfigurierten Handelsvolumen eröffnen.
  5. Orders werden als Marktausführungen gesendet, um sofort auf das Crossover zu reagieren. Das Volumen wird bei Umkehr automatisch erhöht, damit die bestehende Position zuerst glattgestellt und danach eine neue eröffnet wird.

Risikomanagement

  • Die Strategie ruft beim Start StartProtection() auf, sodass StockSharps Standardschutzmechanismen konfiguriert werden können (z. B. Drawdown-Schutz, Handelszeitlimits oder Circuit Breaker).
  • Positionsumkehrungen verwenden eine einzelne kombinierte Marktorder und reduzieren dadurch die Latenz gegenüber sequenziellem Ausstieg und Wiedereinstieg.

Parameter

  • Candle Type: Datenserie für EMA-Berechnungen.
  • Fast EMA Period: Periode der schnellen EMA. Muss kleiner als die langsame EMA-Periode sein.
  • Slow EMA Period: Periode der langsamen EMA. Muss größer als die schnelle EMA-Periode sein.

Zusätzliche Hinweise

  • Beide EMAs müssen vollständig gebildet sein, bevor der Handel beginnt, um vorzeitige Signale zu verhindern.
  • Die Standardkonfiguration verwendet 12/24-Perioden-EMAs auf Ein-Minuten-Kerzen und spiegelt den ursprünglichen MQL-Expert-Advisor wider.
  • Die Parameter sind als optimierbar markiert und erlauben Batch-Optimierung in StockSharp.
using System;

using Ecng.Common;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Crossover 2 EMA strategy: Fast/slow EMA crossover.
/// Buys when fast EMA crosses above slow EMA.
/// Sells when fast EMA crosses below slow EMA.
/// </summary>
public class Crossover2EmaStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;

	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	public int FastPeriod
	{
		get => _fastPeriod.Value;
		set => _fastPeriod.Value = value;
	}

	public int SlowPeriod
	{
		get => _slowPeriod.Value;
		set => _slowPeriod.Value = value;
	}

	public Crossover2EmaStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(15).TimeFrame())
			.SetDisplay("Candle Type", "Candle timeframe", "General");

		_fastPeriod = Param(nameof(FastPeriod), 20)
			.SetGreaterThanZero()
			.SetDisplay("Fast EMA", "Fast EMA period", "Indicators");

		_slowPeriod = Param(nameof(SlowPeriod), 50)
			.SetGreaterThanZero()
			.SetDisplay("Slow EMA", "Slow EMA period", "Indicators");
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		var fast = new ExponentialMovingAverage { Length = FastPeriod };
		var slow = new ExponentialMovingAverage { Length = SlowPeriod };

		decimal? prevFast = null;
		decimal? prevSlow = null;

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(fast, slow, (candle, fastVal, slowVal) =>
			{
				if (candle.State != CandleStates.Finished)
					return;

				if (!IsFormedAndOnlineAndAllowTrading())
					return;

				if (prevFast.HasValue && prevSlow.HasValue)
				{
					var crossUp = prevFast.Value <= prevSlow.Value && fastVal > slowVal;
					var crossDown = prevFast.Value >= prevSlow.Value && fastVal < slowVal;

					if (crossUp && Position <= 0)
						BuyMarket();
					else if (crossDown && Position >= 0)
						SellMarket();
				}

				prevFast = fastVal;
				prevSlow = slowVal;
			})
			.Start();

		var area = CreateChartArea();
		if (area != null)
		{
			DrawCandles(area, subscription);
			DrawIndicator(area, fast);
			DrawIndicator(area, slow);
			DrawOwnTrades(area);
		}
	}
}