Auf GitHub ansehen

Wave Power EA-Strategie

Die Wave Power EA-Strategie ist eine C#-Portierung des MQL4-Expertenberaters „Wave Power EA1“. Der Originalroboter baut eine Position ein Richtung eines stochastischen oder MACD-Signals und fügt dann bei jeder festgelegten Anzahl von Pips zusätzliche Marktaufträge hinzu, während die angepasst wird gemeinsame Take-Profit-Ebene. Die StockSharp-Version reproduziert dieses Verhalten mithilfe der High-Level-Strategie API, Indikatorbindung und integrierte Ordnungshelfer. Alle Kommentare bleiben nach Bedarf auf Englisch.

Wie die Strategie funktioniert

  1. Signalauswahl – der erste Trade wird nur eröffnet, wenn einer der Indikatorfilter eine Richtung generiert:

    • Stochastic – %K überschreitet %D innerhalb überverkaufter/überkaufter Regionen.
    • MacdSlope – Die Linie MACD steigt über oder unter ihren vorherigen Wert.
    • CciLevels – CCI fällt unter –120 oder steigt über +120.
    • AwesomeBreakout – Fantastischer Oszillator, der das adaptive historische Tief/Hoch durchbricht, das während der Initialisierung erfasst wurde.
    • RsiMa – schnelles SMA kreuzt langsames SMA, während RSI den Schwung bestätigt (über/unter 50).
    • SmaTrend – ein 15/20/25/50 SMA-Fächer, der in die gleiche Richtung zeigt, mit einem minimalen Neigungsunterschied.
  2. Netzerweiterung – nachdem die erste Marktorder ausgeführt wurde, merkt sich die Strategie den Ausführungspreis. Immer wenn sich der Markt bewegt um GridStepPips gegenüber der aktuellen Position und die maximale Orderanzahl wird nicht überschritten, übermittelt die Strategie einen neuen Markt Reihenfolge in der gleichen Richtung. Jede neue Ebene multipliziert das Volumen mit dem Parameter Multiplier.

  3. Gemeinsame Ziele – bei jeder neuen Order wird ein gemeinsamer Take-Profit- und (optional) Stop-Loss-Preis neu berechnet. Wenn die Anzahl der Wenn sich aktive Bestellungen dem Schwellenwert von OrdersToProtect nähern, wird die Take-Profit-Distanz durch ReboundProfitPrimary ersetzt. Nachdem der Schwellenwert überschritten wurde, wechselt die Distanz auf ReboundProfitSecondary, um eine schnellere Wiederherstellung zu fördern.

  4. Korbüberwachung – bei jedem Kerzenschluss wandelt die Strategie den offenen Gewinn und Verlust in Pips pro Lot um. Wenn der Rebound-Gewinn bzw Bei Erreichen der Verlustschutzschwellen wird der gesamte Warenkorb mittels Marktaufträgen liquidiert. Das gleiche passiert, wenn der Älteste Handel ist älter als OrdersTimeAliveSeconds oder wenn der Handel am Freitag deaktiviert ist.

  5. Lebenszyklus – sobald der Korb flach ist, werden alle internen Zähler zurückgesetzt, sodass das nächste Signal eine neue Mittelwertbildung starten kann Zyklus.

Im Vergleich zum ursprünglichen EA vermeidet dieser Port absichtlich die Eröffnung entgegengesetzter (Absicherungs-)Positionen nach einer bestimmten Anzahl von Rastern Schichten. Alle weiteren Einträge folgen der ursprünglichen Richtung. Der Rest der Geldverwaltungsregeln, Schutzlogik und Indikatorfilter bleiben mit der Referenzimplementierung MQL4 kompatibel.

Parameter

Parameter Beschreibung
EntryLogic Indikatormodus, der für die allererste Bestellung verwendet wird.
CandleType Zeitrahmen, der alle Indikatoren speist (Standard: 1 Stunde).
InitialVolume Volumen der ersten Bestellung in Losen/Kontrakten.
GridStepPips Minimaler Abstand in Pips zwischen Gitterschichten.
MaxOrders Maximale Anzahl gleichzeitiger Bestellungen im Warenkorb.
TakeProfitPips Gemeinsame Take-Profit-Distanz in Pips (0 deaktiviert das Ziel).
StopLossPips Gemeinsamer Stop-Loss-Abstand in Pips (0 deaktiviert den Stop).
Multiplier Auf jede weitere Bestellung wird ein Volumenmultiplikator angewendet.
SecureProfitProtection Aktiviert die Rebound-Gewinnlogik.
OrdersToProtect Anzahl der erforderlichen Bestellungen, bevor der Rebound-Schutz beginnt.
ReboundProfitPrimary Gewinn pro Los (in Pips) für die erste Schutzstufe.
ReboundProfitSecondary Gewinn pro Lot (in Pips), sobald die geschützte Orderanzahl überschritten wird.
LossProtection Aktiviert den Floating-Loss-Schutz.
LossThreshold Verlust pro Los (in Pips), der die Wache auslöst, wenn der Korb voll ist.
ReverseCondition Kehrt Kauf-/Verkaufssignale um.
TradeOnFriday Ermöglicht die Eröffnung neuer Bestellungen freitags.
OrdersTimeAliveSeconds Maximale Lebensdauer der neuesten Bestellung in Sekunden (0 deaktiviert den Timer).
TrendSlopeThreshold Minimale Steigungsdifferenz von SMA, die von der SmaTrend-Logik verwendet wird.

Anwendungstipps

  1. Hängen Sie die Strategie an ein Wertpapier mit einem konfigurierten Preisschritt an, damit die Pip-Umrechnung korrekt funktioniert.
  2. Passen Sie GridStepPips, Multiplier und MaxOrders entsprechend der Instrumentenvolatilität und der Broker-Margin-Richtlinie an.
  3. Aktivieren Sie die Schutzblöcke, wenn Sie auf einem Live-Konto laufen, um unkontrollierte Verluste bei längeren Trends zu verhindern.
  4. Die Strategie basiert auf geschlossenen Kerzen; Wählen Sie einen Zeitrahmen, der den gewünschten Handelsrhythmus widerspiegelt (das ursprüngliche EA verwendet M30 und H1-Kombinationen, aber die Standard-H1-Kerzen funktionieren gut).
  5. Da eine Absicherung nach der fünften Ebene nicht implementiert ist, sollten Sie eine Senkung von MaxOrders in Betracht ziehen, wenn Sie das exakte Original benötigen Verhalten.

Dateien

  • CS/WavePowerEAStrategy.cs – StockSharp-Implementierung der Wave Power EA-Gitterlogik.
  • README.md / README_ru.md / README_zh.md – Dokumentation in Englisch, Russisch und Chinesisch.

Die Python-Version wird gemäß den Aufgabenanforderungen absichtlich weggelassen.

using System;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Wave Power strategy using RSI + EMA crossover for entry
/// with grid-like averaging on drawdown.
/// </summary>
public class WavePowerEAStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private readonly StrategyParam<int> _rsiPeriod;
	private readonly StrategyParam<decimal> _gridStepPercent;
	private readonly StrategyParam<int> _maxGridOrders;

	private decimal _prevFast;
	private decimal _prevSlow;
	private decimal _entryPrice;
	private int _gridCount;

	public WavePowerEAStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe.", "General");

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

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

		_rsiPeriod = Param(nameof(RsiPeriod), 14)
			.SetDisplay("RSI Period", "RSI period.", "Indicators");

		_gridStepPercent = Param(nameof(GridStepPercent), 0.5m)
			.SetDisplay("Grid Step %", "Price move % to add to position.", "Grid");

		_maxGridOrders = Param(nameof(MaxGridOrders), 5)
			.SetDisplay("Max Grid Orders", "Maximum averaging orders.", "Grid");
	}

	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 int RsiPeriod
	{
		get => _rsiPeriod.Value;
		set => _rsiPeriod.Value = value;
	}

	public decimal GridStepPercent
	{
		get => _gridStepPercent.Value;
		set => _gridStepPercent.Value = value;
	}

	public int MaxGridOrders
	{
		get => _maxGridOrders.Value;
		set => _maxGridOrders.Value = value;
	}

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

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

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

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

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(fast, slow, rsi, 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 rsiVal)
	{
		if (candle.State != CandleStates.Finished)
			return;

		if (_prevFast == 0 || _prevSlow == 0)
		{
			_prevFast = fastVal;
			_prevSlow = slowVal;
			return;
		}

		var close = candle.ClosePrice;
		var bullishCross = _prevFast <= _prevSlow && fastVal > slowVal;
		var bearishCross = _prevFast >= _prevSlow && fastVal < slowVal;

		// Exit on opposite cross
		if (Position > 0 && bearishCross)
		{
			SellMarket();
			_gridCount = 0;
			_entryPrice = 0;
		}
		else if (Position < 0 && bullishCross)
		{
			BuyMarket();
			_gridCount = 0;
			_entryPrice = 0;
		}

		// Grid averaging: add to position if price moved against us
		if (Position > 0 && _entryPrice > 0 && _gridCount < MaxGridOrders)
		{
			var dropPercent = (_entryPrice - close) / _entryPrice * 100;
			if (dropPercent >= GridStepPercent * (_gridCount + 1))
			{
				BuyMarket();
				_gridCount++;
			}
		}
		else if (Position < 0 && _entryPrice > 0 && _gridCount < MaxGridOrders)
		{
			var risePercent = (close - _entryPrice) / _entryPrice * 100;
			if (risePercent >= GridStepPercent * (_gridCount + 1))
			{
				SellMarket();
				_gridCount++;
			}
		}

		// New entry
		if (Position == 0)
		{
			if (bullishCross && rsiVal > 50)
			{
				_entryPrice = close;
				_gridCount = 0;
				BuyMarket();
			}
			else if (bearishCross && rsiVal < 50)
			{
				_entryPrice = close;
				_gridCount = 0;
				SellMarket();
			}
		}

		_prevFast = fastVal;
		_prevSlow = slowVal;
	}
}