Auf GitHub ansehen

Reversing-Martingal-Strategie

Überblick

Die Reversing-Martingal-Strategie ist ein direkter C#-Port des MetaTrader-Expert-Advisors "Reversing Martingale EA". Sie hält kontinuierlich eine einzelne Marktposition und wechselt nach jedem geschlossenen Deal die Handelsrichtung. Verlusttrades lösen eine Martingal-Volumenprogression aus, während profitable Trades den Zyklus auf die anfängliche Lotgröße zurücksetzen. Alle Positionen werden durch symmetrische Stop-Loss- und Take-Profit-Niveaus in Preispunkten geschützt.

Die Strategie verlässt sich nicht auf Indikatoren oder Marktstruktur. Sie reagiert schlicht auf abgeschlossene Positionen und hält die Kapitalexposure jederzeit aktiv (sofern Handel nicht deaktiviert ist).

Kernlogik

  1. Anfangskonfiguration
    • Beim Start sendet die Strategie sofort eine Marktorder mit dem Parameter Start Volume und der konfigurierten First Trade Side.
    • Schutzorders für Stop-Loss und Take-Profit werden mit der in Target (points) angegebenen Distanz angehängt.
  2. Positionsverwaltung
    • Es kann nur eine Position gleichzeitig offen sein. Die Strategie wartet, bis die aktuelle Position durch Schutzorders oder externe Aktionen vollständig geschlossen ist.
    • Nach jedem Ausstieg dreht die Strategie die Handelsrichtung (Kauf -> Verkauf oder Verkauf -> Kauf).
    • Wenn der letzte Trade einen Verlust realisiert hat, entspricht das nächste Ordervolumen der vorherigen Positionsgröße multipliziert mit Lot Multiplier. Andernfalls wird das Volumen auf Start Volume zurückgesetzt.
  3. Zyklusfortsetzung
    • Sobald neues Volumen und Richtung feststehen, wird die nächste Marktorder sofort gesendet, sodass der alternierende Martingal-Zyklus weiterläuft.

Parameter

Name Beschreibung
Start Volume Anfangsvolumen am Beginn jedes Gewinnzyklus.
Lot Multiplier Volumenmultiplikator nach einem Verlusttrade. Muss größer als 1 sein.
First Trade Side Richtung des allerersten Trades beim Start der Strategiesitzung.
Target (points) Distanz in Preisschritten für Stop-Loss- und Take-Profit-Orders.
Order Comment Optionaler Text-Tag, der jeder erzeugten Marktorder zugewiesen wird.

Zusätzliche Hinweise

  • Die Preisschritt-Distanz wird in UnitTypes.Step konvertiert und an StartProtection übergeben, sodass Stop-Loss und Take-Profit immer aktiv sind.
  • Volumenanpassungen respektieren Volumenschritt, Minimum und Maximum der Security über den Helper NormalizeVolume.
  • Die Strategie erwartet Ausführungsereignisse vom Connector; wenn der Handel pausiert oder der Connector offline ist, wird der Martingal-Zyklus fortgesetzt, sobald Handel wieder erlaubt ist.
using System;

using Ecng.Common;

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

namespace StockSharp.Samples.Strategies;

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

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

		_slowPeriod = Param(nameof(SlowPeriod), 30)
			.SetGreaterThanZero()
			.SetDisplay("Slow WMA", "Slow WMA period", "Indicators");
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		var fast = new WeightedMovingAverage { Length = FastPeriod };
		var slow = new WeightedMovingAverage { 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)
				{
					var crossUp = prevFast.Value <= prevSlow.Value && fastVal > slowVal;
					var crossDown = prevFast.Value >= prevSlow.Value && fastVal < slowVal;

					if (crossUp && Position <= 0)
						BuyMarket();
					else if (crossDown && 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);
		}
	}
}