Auf GitHub ansehen

Zwei EMA Intraday-Filterstrategien

Überblick

Diese Strategie reproduziert den MetaTrader Expert Advisor Expert_2EMA_ITF unter Verwendung des StockSharp-High-Level-API. Der Handel erfolgt am Schnittpunkt zweier exponentieller gleitender Durchschnitte und verwendet den durchschnittlichen wahren Bereich (ATR), um ausstehende Limit-Orders, Schutzstopps und Ziele festzulegen. Ein zusätzlicher Intraday-Zeitfilter blockiert Einträge in unerwünschten Minuten, Stunden oder Wochentagen.

Zusammenfassung der Logik

  • Berechnen Sie schnelle und langsame EMA-Werte für die ausgewählte Kerzenserie.
  • Erkennen Sie einen bullischen Crossover, wenn der schnelle EMA über den langsamen EMA steigt, und einen bärischen Crossover, wenn er darunter fällt.
  • Platzieren Sie bei einem zinsbullischen Crossover eine Kauf-Limit-Order, die vom langsamen EMA um LimitMultiplier * ATR plus dem aktuellen Spread versetzt ist. Platzieren Sie bei einem rückläufigen Crossover eine Verkaufs-Limit-Order mit einem Offset in die entgegengesetzte Richtung.
  • Speichern Sie Stop-Loss- und Take-Profit-Preise mit ATR-Multiplikatoren, damit sie sofort übermittelt werden können, sobald die Einstiegsorder ausgeführt ist.
  • Stornieren Sie ausstehende Bestellungen automatisch, wenn sie länger als ExpirationBars Kerzen nicht ausgeführt werden.
  • Überspringen Sie Signale, die den Intraday-Filter nicht bestehen (zulässige Minuten-, Stunden- und Tagesprüfungen). Bitmasken können mehrere Minuten, Stunden oder Tage gleichzeitig deaktivieren.

Indikatoren

  • Schnell EMA – steuert die Empfindlichkeit der Crossover-Erkennung.
  • Langsam EMA – definiert die Trendrichtung.
  • Average True Range (ATR) – misst die Marktvolatilität und skaliert Einstiegs-/Ausstiegspreis-Offsets.

Parameter

Parameter Beschreibung Standard
CandleType Für Berechnungen verwendeter Zeitrahmen. 30-Minuten-Kerzen
FastEmaPeriod Zeitraum des Fastens EMA. 5
SlowEmaPeriod Periode des langsamen EMA (muss größer sein als die schnelle Periode). 30
AtrPeriod ATR Berechnungszeitraum. 7
LimitMultiplier ATR-Multiplikator, der die Eintrittspreise verschiebt. 1.2
StopLossMultiplier ATR-Multiplikator für Stop-Loss-Platzierung. 5
TakeProfitMultiplier ATR-Multiplikator für Take-Profit-Platzierung. 8
ExpirationBars Anzahl der Balken, nach denen nicht ausgeführte Aufträge storniert werden. 4
GoodMinuteOfHour Spezifische erlaubte Minute für Einträge (-1 deaktiviert). -1
BadMinutesMask Bitmaske blockiert Minuten (Bit n blockiert Minute n). 0
GoodHourOfDay Bestimmte Stunde, die für Einträge zulässig ist (-1 deaktiviert). -1
BadHoursMask Bitmaske blockiert Stunden (Bit n blockiert Stunde n). 0
GoodDayOfWeek Bestimmter Tag für Einträge zulässig (-1 deaktiviert, 0 = Sonntag). -1
BadDaysMask Bitmaske blockiert Tage (Bit n blockiert Tag n, 0 = Sonntag). 0

Orderverwaltung

  1. Einstiegsaufträge – Limitaufträge werden mit einem vom langsamen EMA um den ATR-basierten Offset verschobenen Preis registriert. Der Kaufauftrag fügt auch den aktuellen Spread hinzu, wenn Geld-/Briefkurse verfügbar sind.
  2. Ablaufdatum – Jede ausstehende Order speichert den Kerzenindex zum Zeitpunkt ihrer Erstellung. Wenn ExpirationBars positiv ist und die Order über diese Anzahl von Balken hinaus bestehen bleibt, wird sie automatisch storniert.
  3. Schutzaufträge – Wenn eine Einstiegsorder ausgeführt wird, storniert die Strategie alle vorherigen Stop-/Target-Orders und platziert dann sofort einen Stop-Loss und einen Take-Profit, die aus dem ATR-Snapshot berechnet werden, der das Signal generiert hat. Gegenläufige Schutzanordnungen werden aufgehoben, wenn die Position flach ist.

Details des Intraday-Filters

  • Einzelne zulässige WerteGoodMinuteOfHour, GoodHourOfDay und GoodDayOfWeek beschränken den Handel auf eine bestimmte Minute, Stunde oder einen bestimmten Wochentag, wenn sie nicht negativ sind.
  • BitmaskenBadMinutesMask, BadHoursMask und BadDaysMask enthalten Bits, die mehrere Zeitfenster gleichzeitig deaktivieren. Wenn Sie beispielsweise BadMinutesMask = (1 << 0) | (1 << 30) festlegen, wird der Handel während Minute 0 und Minute 30 jeder Stunde blockiert.
  • Kombinierte Logik – Ein Eintrag ist nur zulässig, wenn die aktuelle Kerzenzeit alle Zulassungsbedingungen erfüllt und keine der Masken ihn blockiert.

Unterschiede zum ursprünglichen Expert Advisor

  • Die StockSharp-Version verwendet ausstehende Limit-Orders kombiniert mit expliziten Stop-Loss- und Take-Profit-Registrierungen, sobald der Eintrag ausgeführt wird, was die MQL-Signalberechnungen widerspiegelt.
  • Die Spread-Kompensation für Kaufaufträge verwendet die aktuellen Security.BestBid/BestAsk-Kurse, sofern diese verfügbar sind, andernfalls ist der Offset Null.
  • Die Zeitfilterung wird durch Bitmasken und direkte Vergleiche anstelle von MetaTrader spezifischen Zeitfilter-Hilfsklassen ausgedrückt.
  • Alle Handelsaktionen nutzen StockSharp High-Level-Helfer (BuyLimit, SellLimit, SellStop, BuyStop) und eine automatische Stornierungslogik anstelle manueller Order-Arrays.

Nutzungshinweise

  • Stellen Sie sicher, dass das Strategievolumen festgelegt ist, bevor Sie mit der Strategie beginnen. Andernfalls wird eine Warnung ausgegeben und es werden keine Bestellungen gesendet.
  • Für Optimierungsszenarien ermöglichen die Parametermetadaten bereits die Optimierung von EMA-Zeiträumen, ATR-Zeiträumen, Multiplikatoren und Ablauflängen.
  • Die Strategie geht davon aus, dass die Schlusszeiten der Kerzen das Ende des Balkens darstellen und verwendet diese bei der Auswertung von Intraday-Filtern.
using System;

using Ecng.Common;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Two EMA Intraday Filter strategy: EMA crossover.
/// Buys when fast EMA crosses above slow EMA. Sells on cross below.
/// </summary>
public class TwoEmaIntradayFilterStrategy : 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 TwoEmaIntradayFilterStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(15).TimeFrame())
			.SetDisplay("Candle Type", "Candle timeframe", "General");

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

		_slowPeriod = Param(nameof(SlowPeriod), 30)
			.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)
				{
					if (prevFast.Value <= prevSlow.Value && fastVal > slowVal && Position <= 0)
						BuyMarket();
					else if (prevFast.Value >= prevSlow.Value && fastVal < slowVal && 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);
		}
	}
}