A Estratégia Reversing Martingale é um port direto em C# do expert advisor "Reversing Martingale EA" do MetaTrader. Ela mantém continuamente uma única posição a mercado e alterna a direção da operação após cada negócio fechado. Operações perdedoras disparam uma progressão martingale de volume, enquanto operações lucrativas reiniciam o ciclo para o tamanho de lote inicial. Todas as posições são protegidas por níveis simétricos de stop-loss e take-profit expressos em pontos de preço.
A estratégia não depende de indicadores ou estrutura de mercado. Ela simplesmente reage a posições concluídas e mantém exposição de capital ativa o tempo todo (a menos que a negociação esteja desabilitada).
Lógica central
Configuração inicial
Quando a estratégia inicia, ela envia imediatamente uma ordem a mercado usando o parâmetro Start Volume e o First Trade Side configurado.
Ordens protetoras de stop-loss e take-profit são anexadas usando a distância especificada em Target (points).
Gestão de posição
Apenas uma posição pode estar aberta por vez. A estratégia aguarda até que a posição atual seja totalmente fechada por suas ordens protetoras ou por ações externas.
Após cada saída, a estratégia inverte a direção da operação (compra -> venda ou venda -> compra).
Se a última operação realizou perda, o volume da próxima ordem equivale ao tamanho da posição anterior multiplicado por Lot Multiplier. Caso contrário, o volume volta para Start Volume.
Continuação do ciclo
Depois que novo volume e direção são determinados, a próxima ordem a mercado é enviada imediatamente, mantendo o ciclo martingale alternado em execução.
Parâmetros
Nome
Descrição
Start Volume
Volume inicial usado no começo de cada ciclo vencedor.
Lot Multiplier
Multiplicador de volume aplicado após uma operação perdedora. Deve ser maior que 1.
First Trade Side
Direção da primeira operação quando a sessão da estratégia começa.
Target (points)
Distância em passos de preço usada para ordens de stop-loss e take-profit.
Order Comment
Texto opcional atribuído a cada ordem a mercado gerada.
Notas adicionais
A distância em passos de preço é convertida para UnitTypes.Step e passada para StartProtection, portanto stop-loss e take-profit ficam sempre ativos.
Ajustes de volume respeitam passo, mínimo e máximo de volume da security por meio do helper NormalizeVolume.
A estratégia espera eventos de execução do conector; se a negociação for pausada ou o conector ficar offline, o ciclo martingale será retomado assim que a negociação voltar a ser permitida.
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()