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
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.
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.
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);
}
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import WeightedMovingAverage
from StockSharp.Algo.Strategies import Strategy
from datatype_extensions import *
from indicator_extensions import *
class reversing_martingale_strategy(Strategy):
def __init__(self):
super(reversing_martingale_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 10).SetGreaterThanZero().SetDisplay("Fast WMA", "Fast WMA period", "Indicators")
self._slow_period = self.Param("SlowPeriod", 30).SetGreaterThanZero().SetDisplay("Slow WMA", "Slow WMA period", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(15))).SetDisplay("Candle Type", "Candle timeframe", "General")
@property
def CandleType(self): return self._candle_type.Value
@CandleType.setter
def CandleType(self, value): self._candle_type.Value = value
def OnReseted(self):
super(reversing_martingale_strategy, self).OnReseted()
self._prev_fast = 0
self._prev_slow = 0
def OnStarted2(self, time):
super(reversing_martingale_strategy, self).OnStarted2(time)
self._prev_fast = 0
self._prev_slow = 0
fast = WeightedMovingAverage()
fast.Length = self._fast_period.Value
slow = WeightedMovingAverage()
slow.Length = self._slow_period.Value
sub = self.SubscribeCandles(self.CandleType)
sub.Bind(fast, slow, self.OnProcess).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, sub)
self.DrawIndicator(area, fast)
self.DrawIndicator(area, slow)
self.DrawOwnTrades(area)
def OnProcess(self, candle, fast_val, slow_val):
if candle.State != CandleStates.Finished:
return
if self._prev_fast == 0 or self._prev_slow == 0:
self._prev_fast = fast_val
self._prev_slow = slow_val
return
cross_up = self._prev_fast <= self._prev_slow and fast_val > slow_val
cross_down = self._prev_fast >= self._prev_slow and fast_val < slow_val
if cross_up and self.Position <= 0:
self.BuyMarket()
elif cross_down and self.Position >= 0:
self.SellMarket()
self._prev_fast = fast_val
self._prev_slow = slow_val
def CreateClone(self):
return reversing_martingale_strategy()