Auf GitHub ansehen

Äquidistanzkanal-Strategie

Überblick

Die Äquidistanzkanal-Strategie portiert den ursprünglichen MQL4 Expert Advisor "Equidistant Channel" auf die High-Level-API von StockSharp. Die Strategie analysiert Kreuzungen der MACD-Linie und verwaltet bestehende Positionen über Berührungen der Bollinger Bands, Breakeven-Logik und geldbasierte Trailing-Ziele.

Wenn die MACD-Linie ihre Signallinie nach oben kreuzt, eröffnet die Strategie Long-Positionen; wenn sie die Signallinie nach unten kreuzt, eröffnet sie Short-Positionen. Während ein Trade aktiv ist, überwacht die Strategie Ausstiege, wenn der Preis Bollinger Bands erreicht, wenn schwebender Gewinn konfigurierbare monetäre oder prozentuale Ziele erreicht oder wenn ein Trailing-Drawdown-Schwellenwert verletzt wird. Ein Breakeven-Modus spiegelt die MetaTrader-Implementierung, indem er den Schutz-Stop verschiebt, sobald der Gewinn eine konfigurierbare Anzahl von Preisschritten überschreitet.

Indikatoren

  • MACD (12, 26, 9) - erzeugt Einstiegssignale bei Kreuzungen zwischen der MACD-Linie und ihrer Signallinie.
  • Bollinger Bands (20, 2) - liefern Ausstiegsniveaus, sobald der Kerzenschluss das obere oder untere Band trifft.

Positionsverwaltung

  • Optionale Stop-Loss-, Take-Profit- und Trailing-Stop-Distanzen, die über StartProtection in Preispunkten ausgedrückt werden.
  • Geldbasierte Take-Profit- und Trailing-Logik, die schwebenden Gewinn anhand der Preis-/Schrittgrößenmetadaten des Instruments verfolgt.
  • Prozentualer Take-Profit, berechnet aus dem Startwert des Portfolios.
  • Breakeven-Modus, der den Stop auf Einstieg plus Offset verschiebt, sobald der Gewinn einen definierten Trigger erreicht.

Parameter

Gruppe Name Standard Beschreibung
Handel Volumen 1 Ordervolumen für neue Einstiege.
Allgemein Kerzentyp 5 Minuten Für Berechnungen verwendete Kerzenserie.
Indikatoren MACD Schnell 12 Länge der schnellen EMA für MACD.
Indikatoren MACD Langsam 26 Länge der langsamen EMA für MACD.
Indikatoren MACD Signal 9 Länge der Signallinie für MACD.
Indikatoren BB-Periode 20 Rückblickperiode der Bollinger Bands.
Indikatoren BB-Abweichung 2 Breite der Bollinger Bands in Standardabweichungen.
Risiko Stop Loss 20 Stop-Loss-Distanz in Preispunkten.
Risiko Take Profit 50 Take-Profit-Distanz in Preispunkten.
Risiko Trailing Stop 40 Trailing-Stop-Distanz in Preispunkten.
Risiko TP verwenden (Geld) false Schließt, wenn schwebender Gewinn ein absolutes Geldziel erreicht.
Risiko TP Geld 10 Absoluter Take-Profit-Wert in Kontowährung.
Risiko TP verwenden (%) false Schließt, wenn schwebender Gewinn einen Prozentsatz des Anfangskapitals erreicht.
Risiko TP Prozent 10 Prozentsatz des Anfangskapitals für den prozentualen Take-Profit.
Risiko Trailing aktivieren true Aktiviert Trailing-Logik auf schwebendem Gewinn.
Risiko Trailing aktivieren ab 40 Gewinnniveau (Währung), das die Trailing-Logik scharf schaltet.
Risiko Trailing-Schritt 10 Maximal zulässiger Drawdown vom Gewinnhoch (Währung).
Risiko BB Stop verwenden true Aktiviert Ausstiege, wenn der Preis Bollinger Bands berührt.
Risiko Breakeven verwenden true Aktiviert das Breakeven-Verhalten.
Risiko Breakeven-Trigger 10 Gewinn (Preisschritte), der zum Scharfschalten des Breakeven-Stops erforderlich ist.
Risiko Breakeven-Offset 5 Offset (Preisschritte), der auf das Breakeven-Niveau angewendet wird.

Hinweise

  • Die Strategie arbeitet mit einem einzelnen Instrument, das gültige PriceStep- und StepPrice-Metadaten bereitstellt, damit monetäre Berechnungen genau sind.
  • Das Trailing-Profit-Modul folgt dem MetaTrader-Verhalten: Sobald schwebender Gewinn die Aktivierungsschwelle überschreitet, zeichnet die Strategie das laufende Maximum auf und schließt den Trade, wenn der Drawdown den konfigurierten Trailing-Schritt übersteigt.
  • Die Breakeven-Logik spiegelt den ursprünglichen EA, indem sie Trigger und Offsets auf Basis von Preisschritten verwendet.
  • Alle Kommentare im Strategiecode sind gemäß den Projektrichtlinien auf Englisch geschrieben.
using System;
using System.Collections.Generic;

using Ecng.Common;

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

namespace StockSharp.Samples.Strategies;

public class EquidistantChannelStrategy : Strategy
{
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private readonly StrategyParam<int> _stopLossPoints;
	private readonly StrategyParam<int> _takeProfitPoints;

	private ExponentialMovingAverage _fast;
	private ExponentialMovingAverage _slow;

	private decimal _prevFast;
	private decimal _prevSlow;
	private decimal _entryPrice;
	private int _cooldown;

	public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
	public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
	public int StopLossPoints { get => _stopLossPoints.Value; set => _stopLossPoints.Value = value; }
	public int TakeProfitPoints { get => _takeProfitPoints.Value; set => _takeProfitPoints.Value = value; }

	public EquidistantChannelStrategy()
	{
		_fastPeriod = Param(nameof(FastPeriod), 14).SetGreaterThanZero().SetDisplay("Fast Period", "Fast EMA period", "Indicator");
		_slowPeriod = Param(nameof(SlowPeriod), 50).SetGreaterThanZero().SetDisplay("Slow Period", "Slow EMA period", "Indicator");
		_stopLossPoints = Param(nameof(StopLossPoints), 200).SetNotNegative().SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk");
		_takeProfitPoints = Param(nameof(TakeProfitPoints), 400).SetNotNegative().SetDisplay("Take Profit", "Take-profit in price steps", "Risk");
	}

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		yield return (Security, TimeSpan.FromMinutes(5).TimeFrame());
	}

	protected override void OnReseted()
	{
		base.OnReseted();
		_fast = null; _slow = null;
		_prevFast = 0; _prevSlow = 0; _entryPrice = 0; _cooldown = 0;
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_fast = new ExponentialMovingAverage { Length = FastPeriod };
		_slow = new ExponentialMovingAverage { Length = SlowPeriod };
		var subscription = SubscribeCandles(TimeSpan.FromMinutes(5).TimeFrame());
		subscription.Bind(_fast, _slow, ProcessCandle);
		subscription.Start();
	}

	private void ProcessCandle(ICandleMessage candle, decimal fastValue, decimal slowValue)
	{
		if (candle.State != CandleStates.Finished) return;
		if (!_fast.IsFormed || !_slow.IsFormed) { _prevFast = fastValue; _prevSlow = slowValue; return; }
		if (_cooldown > 0) { _cooldown--; _prevFast = fastValue; _prevSlow = slowValue; return; }

		var close = candle.ClosePrice;
		var step = Security?.PriceStep ?? 1m;

		if (Position > 0 && _entryPrice > 0)
		{
			if (StopLossPoints > 0 && close <= _entryPrice - StopLossPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
			if (TakeProfitPoints > 0 && close >= _entryPrice + TakeProfitPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
		}
		else if (Position < 0 && _entryPrice > 0)
		{
			if (StopLossPoints > 0 && close >= _entryPrice + StopLossPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
			if (TakeProfitPoints > 0 && close <= _entryPrice - TakeProfitPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
		}

		if (_prevFast <= _prevSlow && fastValue > slowValue && Position <= 0)
		{ if (Position < 0) BuyMarket(); BuyMarket(); _entryPrice = close; _cooldown = 100; }
		else if (_prevFast >= _prevSlow && fastValue < slowValue && Position >= 0)
		{ if (Position > 0) SellMarket(); SellMarket(); _entryPrice = close; _cooldown = 100; }

		_prevFast = fastValue; _prevSlow = slowValue;
	}
}