Auf GitHub ansehen

Hedging Martingale-Strategie

Übersicht

Diese Strategie ist ein StockSharp-Port des MetaTrader-Expertenberaters "Hedging Martingale" (Ordner MQL/23693). Sie hält eine ausgeglichene Hedge aufrecht, indem sie bei jeder neuen Bar sowohl eine Long- als auch eine Short-Position eröffnet, und wendet dann ein Martingal-Averaging-Schema an. Wenn sich der Preis um eine konfigurierbare Pip-Distanz ungünstig bewegt, fügt die Strategie eine neue Position auf der Verlustseite mit erhöhtem Volumen hinzu, während die entgegengesetzte Hedge bestehen bleibt. Der schwebende Gewinn wird mit geld- und prozentbasierten Zielen zusammen mit einer optionalen Trailing-Sperre verwaltet.

Trading-Logik

  • Anfängliche Hedge: Wann immer die Strategie flat ist und eine neue Kerze schließt, kauft und verkauft sie gleichzeitig mit demselben Basisvolumen.
  • Martingal-Schritte: Wenn sich der Preis um Pip Step Pips gegen eine Seite bewegt, wird auf dieser Seite eine zusätzliche Order eröffnet. Das Volumen wird mit dem Volume Multiplier multipliziert, was die progressive Lot-Größenbestimmung aus der MQL-Version emuliert. Die entgegengesetzte Seite bleibt offen, um die Hedge aufrechtzuerhalten.
  • Take-Profit pro Trade: Jeder offene Eintrag hat eine individuelle Take-Profit-Distanz, die durch Take Profit (pips) definiert ist. Wenn sich der Markt um diese Distanz zugunsten eines Beins bewegt, wird das Bein durch eine Gegenbuchung reduziert.
  • Korb-Ausstiege: Das gesamte Positionsset kann geschlossen werden, wenn der schwebende Gewinn ein Geldziel, einen Prozentsatz des Anfangskapitals erreicht oder nachdem eine Trailing-Sperre mehr als den erlaubten Rückzug zurückgibt. Diese Verhaltensweisen replizieren Take_Profit_In_Money, Take_Profit_In_percent und TRAIL_PROFIT_IN_MONEY2 aus dem ursprünglichen Experten.
  • Trade-Limits: Der Parameter Max Trades beschränkt die Anzahl der aktiven Martingal-Schritte. Wenn Close On Max aktiviert ist, wird der Korb liquidiert, sobald das Limit überschritten wird.

Parameter

Name Beschreibung
Candle Type Zeitrahmen, der die Logik antreibt. Jede abgeschlossene Kerze kann neue Hedging-Aktionen auslösen.
Use Money TP / Money Take Profit Aktivieren und den schwebenden Gewinn (in Währungseinheiten) definieren, der alle Positionen schließt.
Use Percent TP / Percent Take Profit Korb schließen, wenn der schwebende Gewinn einen Prozentsatz des anfänglichen Portfoliowerts erreicht.
Enable Trailing / Trailing Start / Trailing Step Geldbasierte Trailing-Sperre für den Korb aktivieren und Triggerniveau zusammen mit dem erlaubten Gewinnrückzug konfigurieren.
Take Profit (pips) Distanz in Pips für Take-Profit-Ausstiege pro Bein.
Pip Step Ungünstige Preisbewegung (in Pips) erforderlich, bevor eine weitere Martingal-Order hinzugefügt wird.
Base Volume Anfangsvolumen für beide Buy- und Sell-Beine.
Volume Multiplier Multiplikator beim größten Positionsvolumen, wenn Martingal-Einstiege hinzugefügt werden.
Max Trades Maximale Anzahl gleichzeitig offener Einstiege (in beiden Richtungen).
Close On Max Ob alle Positionen liquidiert werden sollen, sobald die maximale Trade-Anzahl überschritten wird.

Hinweise

  • Die Strategie verwendet BuyMarket und SellMarket für alle Orderplatzierungen und spiegelt das Market-Execution-Modell des Quell-Experten wider.
  • Volumenwerte werden auf den Lot-Schritt des Instruments normalisiert, um abgelehnte Orders zu vermeiden.
  • Wenn die Strategie flat wird, wird die Trailing-Sperre zurückgesetzt, damit neue Körbe mit einer sauberen Gewinnreferenz beginnen.

Dateien

  • CS/HedgingMartingaleStrategy.cs – Implementierung der konvertierten Strategie (C#).
  • README.md – diese Dokumentation (Englisch).
  • README_zh.md – Chinesische Übersetzung.
  • README_ru.md – Russische Übersetzung.
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 HedgingMartingaleStrategy : 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 HedgingMartingaleStrategy()
	{
		_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;
	}
}