Auf GitHub ansehen

Crossover-Spread-Strategie mit gleitendem Durchschnitt

Diese Strategie ist eine StockSharp-Portierung des Expertenberaters MQL4 "EA - Moving Average" (Datei EA - Moving Average.mq4). Es handelt mit einem einzelnen Instrument, indem es auf Überkreuzungen des gleitenden Durchschnitts reagiert, die beim Öffnen jeder neuen Kerze erkannt werden.

Kernidee

  • Verwenden Sie einen schnellen und einen langsamen exponentiellen gleitenden Durchschnitt (EMA), der für die ausgewählte Kerzenserie berechnet wird.
  • Warten Sie, bis eine neue Kerze verfügbar ist, und werten Sie die EMA-Werte der beiden zuletzt abgeschlossenen Kerzen aus, indem Sie die iMA(..., shift=1/2)-Aufrufe aus dem Originalcode replizieren.
  • Eröffnen Sie eine Long-Position, wenn der schnelle EMA den langsamen EMA der vorherigen Kerze überschritten hat, während bei der Kerze davor der schnelle EMA noch unter dem langsamen EMA lag.
  • Eröffnen Sie eine Short-Position, wenn der schnelle EMA den langsamen EMA der vorherigen Kerze unterschritten hat, während die Kerze davor noch den schnellen EMA über dem langsamen EMA hatte.
  • Es kann jeweils nur eine Position offen sein. Die Strategie ignoriert neue Signale, bis alle Aufträge geschlossen sind.

Orderverwaltung

  • Vor der Auftragserteilung wird der aktuelle Spread überprüft. Wenn der beste Brief und das beste Geld verfügbar sind, wird der Spread in Instrumentenpunkte umgerechnet und mit MaxSpreadPoints verglichen. Signale, die das Limit überschreiten, werden übersprungen, genau wie der ursprüngliche MarketInfo(..., MODE_SPREAD)-Guard.
  • Nachdem eine Marktorder übermittelt wurde, spiegelt die Strategie Schutzniveaus um den Einstiegspreis herum wider:
    • Der Stop-Loss wird auf den langsamen EMA-Wert der vorherigen Kerze plus/minus dem konfigurierten StopLossPoints gesetzt.
    • Der Take-Profit wird im gleichen Abstand vom Einstiegspreis festgelegt wie der Stop-Loss, wodurch ein symmetrisches Ziel wie in der MQL-Implementierung (Ask + (Ask - StopLoss) / Bid - (StopLoss - Bid)) entsteht.
  • Alle in Punkten ausgedrückten Preisabstände werden über das Instrument PriceStep in absolute Preise übersetzt, sodass das Verhalten der punktbasierten Konfiguration aus MetaTrader entspricht.

Konvertierungshinweise

  • Der ursprüngliche Expert erlaubt die Auswahl verschiedener Modi für den gleitenden Durchschnitt, seine Standardeinstellungen verwenden jedoch EMA (MAMode = 1). Die StockSharp-Version konzentriert sich auf EMA, um die Implementierung prägnant zu halten; Bei Bedarf können verschiedene Glättungsalgorithmen hinzugefügt werden.
  • Das Handelsvolumen wird über den Parameter TradeVolume bereitgestellt und während OnStarted Strategy.Volume zugeordnet.
  • Die Strategie basiert ausschließlich auf Kerzendaten, die über CandleType bereitgestellt werden. Außer dem zweiwertigen EMA-Verlauf, der zum Erkennen von Überschneidungen erforderlich ist, gibt es keine zusätzlichen Indikatorsammlungen oder historischen Puffer.

Parameter

  • CandleType – Kerzendatentyp und Zeitrahmen zum Abonnieren.
  • FastPeriod – Länge des schnellen EMA (standardmäßig 21).
  • SlowPeriod – Länge des langsamen EMA (Standard: 84).
  • StopLossPoints – Stop-Loss-Distanz in Instrumentenpunkten relativ zum langsamen EMA.
  • MaxSpreadPoints – maximal zulässiger Spread in Punkten, bevor eine neue Bestellung abgelehnt wird.
  • TradeVolume – Losgröße, die beim Senden von Marktaufträgen verwendet wird.

Nutzungstipps

  1. Wählen Sie vor Beginn der Strategie das Symbol und den Kerzenzeitrahmen aus, damit die EMA-Werte mit dem beabsichtigten Diagramm in MetaTrader übereinstimmen.
  2. Stellen Sie Level-1-Daten (bester Geld-/Briefkurs) bereit, wenn Sie möchten, dass der Spread-Filter in Echtzeit funktioniert. andernfalls geht die Strategie davon aus, dass der Spread akzeptabel ist.
  3. Stellen Sie sicher, dass die Sicherheit über einen gültigen PriceStep verfügt. Ohne sie kann die Strategie punktbasierte Distanzen nicht in absolute Preise umwandeln und wird die Platzierung von Schutzaufträgen überspringen.
using System;

using Ecng.Common;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Moving average crossover strategy using two EMAs.
/// Enters long on golden cross, short on death cross.
/// </summary>
public class MovingAverageCrossoverSpreadStrategy : 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 MovingAverageCrossoverSpreadStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
			.SetDisplay("Candle Type", "Candle type", "General");

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

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

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		var fastMa = new ExponentialMovingAverage { Length = FastPeriod };
		var slowMa = new ExponentialMovingAverage { Length = SlowPeriod };

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

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(fastMa, slowMa, (candle, fastValue, slowValue) =>
			{
				if (candle.State != CandleStates.Finished)
					return;

				if (!IsFormedAndOnlineAndAllowTrading())
					return;

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

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

				prevFast = fastValue;
				prevSlow = slowValue;
			})
			.Start();

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