Auf GitHub ansehen

Hedger Drawdown-Strategie

StockSharp-Port des MetaTrader 5 Expert Advisors hedger.mq5 (MQL #23511). Das ursprüngliche System eröffnet eine schützende Absicherung in der entgegengesetzten Richtung, wenn eine bestehende Position um eine bestimmte Anzahl von Pips in den Drawdown gerät. Sobald der Preis um einen kleineren Betrag zurückgeht, wird die Absicherung auch mit Verlust geschlossen, wodurch der ursprüngliche Trade sich erholen kann. Diese Konvertierung reproduziert das Verhalten mit der High-Level-API von StockSharp und passt die Mechanik an das Netto-Positionsmodell der Plattform an.

Trading-Logik

  1. Die Strategie überwacht den Abschluss jeder Kerze des konfigurierten Zeitrahmens.
  2. Für jede Long-Position, die keine Absicherung ist, prüft sie, ob die Distanz zwischen dem Einstiegspreis und dem aktuellen Schlusskurs größer oder gleich DrawdownOpenPips ist. Wenn keine Short-Absicherung aktiv ist, öffnet sie eine mit demselben Volumen.
  3. Für jede Short-Position, die keine Absicherung ist, wendet sie die symmetrische Regel an und öffnet eine Long-Absicherung, nachdem der Verlust den Öffnungsschwellenwert erreicht.
  4. Aktive Absicherungspositionen werden geschlossen, wenn ihr schwebender Verlust DrawdownClosePips erreicht, was der MetaTrader-Logik der Freigabe des Schutzes nach einer teilweisen Erholung entspricht.
  5. Wenn das Konto keine offenen Positionen hat und StartWithLong aktiviert ist, öffnet der Algorithmus eine initiale Long-Position, um den Zyklus zu starten.

Da StockSharp Nettopositionen verfolgt, führt die Strategie interne Bücher über Long- und Short-Einträge (einschließlich derer, die Absicherungen sind). Jede Marktorder aktualisiert die Bücher, sodass Absicherungen unabhängig geöffnet und geschlossen werden können, selbst wenn der Broker Positionen zusammenfasst.

Parameter

Parameter Beschreibung
DrawdownOpenPips Drawdown in Pips, der das Öffnen der entgegengesetzten Absicherung auslöst.
DrawdownClosePips Drawdown in Pips, der das Schließen der Absicherung erzwingt.
InitialVolume Volumen des initialen Trades beim Start des Zyklus.
StartWithLong Wenn aktiviert, öffnet eine initiale Long-Position bei flachem Konto.
EnableVerboseLogging Schreibt Absicherungsaktionen in das Strategie-Log zur Fehlersuche.
CandleType Kerzenserie zur Überwachung der Drawdowns.

Unterschiede zur MetaTrader-Version

  • Der Expert Advisor verwendete Ticket-Kommentare (hedge_buy / hedge_sell) zur Unterscheidung von Absicherungspositionen. Die Konvertierung speichert diesen Zustand im Speicher, da StockSharp Netting verwendet.
  • Margin-Prüfungen und Slippage-Einstellungen werden weggelassen; die Orderplatzierung verwendet die High-Level-Helfer BuyMarket / SellMarket.
  • Die Strategie stellt Optimierungsbereiche für die Pip-Schwellenwerte und das Volumen bereit, damit sie mit StockSharp-Optimierern abgestimmt werden können.

Verwendungshinweise

  1. Hängen Sie die Strategie an das gewünschte Symbol und Portfolio an.
  2. Passen Sie die Pip-Schwellenwerte an die Volatilität des Instruments an.
  3. Aktivieren Sie das ausführliche Logging beim Validieren der Konvertierung – das Log erfasst jede Absicherungserstellung und -entfernung mit Pip-Statistiken.
  4. Setzen Sie auf Zeitrahmen ein, die bedeutungsvolle Kerzenabschlüsse liefern (z.B. M15 bis H1), um Overtrading zu vermeiden.
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 HedgerDrawdownStrategy : 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 HedgerDrawdownStrategy()
	{
		_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;
	}
}