Reversing Martingale Strategy — порт советника MetaTrader «Reversing Martingale EA». Стратегия постоянно держит только одну рыночную позицию и после каждого закрытия меняет направление сделки. Убыточные сделки запускают мартингейловое увеличение объёма, а прибыльные возвращают цикл к исходному лоту. Все позиции защищаются симметричными стоп-лоссом и тейк-профитом, заданными в пунктах.
Стратегия не использует индикаторы и не анализирует рыночную структуру: она реагирует исключительно на факт закрытия позиций, сохраняя активное присутствие на рынке, пока торговля разрешена.
Логика работы
Инициализация
При старте стратегия сразу отправляет рыночный ордер с объёмом Start Volume и направлением First Trade Side.
Стоп-лосс и тейк-профит устанавливаются на расстоянии Target (points) при помощи StartProtection.
Управление позицией
Одновременно может существовать только одна позиция. Стратегия ждёт полного закрытия текущей позиции защитными ордерами или внешними действиями.
После закрытия направление следующей сделки разворачивается (buy → sell либо sell → buy).
Если последняя сделка завершилась с убытком, следующий объём равен предыдущему объёму, умноженному на Lot Multiplier. После прибыли объём сбрасывается к Start Volume.
Продолжение цикла
Как только вычислены новое направление и объём, мгновенно отправляется очередной рыночный ордер, поддерживая непрерывный цикл «реверсивного» мартингейла.
Параметры
Название
Описание
Start Volume
Исходный объём, с которого начинается каждый прибыльный цикл.
Lot Multiplier
Множитель объёма, применяемый после убыточной сделки (значение > 1).
First Trade Side
Направление первой сделки при запуске стратегии.
Target (points)
Расстояние до стоп-лосса и тейк-профита в минимальных шагах цены.
Дистанция защитных ордеров преобразуется в UnitTypes.Step и передаётся в StartProtection, поэтому стоп и тейк всегда выставляются автоматически.
Функция NormalizeVolume приводит объём в соответствие с шагом объёма инструмента и его лимитами по минимальному/максимальному размеру.
Стратегия ожидает события исполнения от коннектора. Если торговля была приостановлена, цикл автоматически продолжится после восстановления соединения и разрешения торгов.
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()