A Estratégia Demarker Martingale recria o expert advisor do MetaTrader "Demarker Martingale" usando a API de alto nível do StockSharp. O sistema combina um sinal do oscilador DeMarker de médio prazo com um filtro de tendência MACD de período maior. As entradas são seguidas por dimensionamento de posição estilo martingale, níveis fixos de stop-loss e take-profit, proteção de break-even e um trailing stop que imita o conjunto de ferramentas de gestão monetária do expert original.
Lógica de negociação principal
Feeds de dados – a estratégia assina um período de negociação definido pelo usuário (padrão de velas de 15 minutos) para geração de sinais e uma série de período maior (padrão de velas mensais) para calcular o filtro MACD.
Gatilho DeMarker – quando o valor do DeMarker excede o limite neutro DemarkerThreshold (padrão 0.5) e a ação de preço recente forma uma sobreposição altista (Low[2] < High[1]), uma configuração longa é considerada. Por outro lado, uma sobreposição baixista com DeMarker abaixo do limiar prepara um curto.
Confirmação MACD – o MACD de período maior deve concordar com a direção. Um sinal altista requer que a linha principal do MACD esteja acima de sua linha de sinal, enquanto um sinal baixista espera a relação oposta. Isso reproduz o filtro MACD mensal do expert MQL.
Execução de ordens – sinais válidos colocam ordens de mercado com o volume ajustado pelo martingale atual. Apenas uma posição direcional é mantida por vez.
Monitoramento de posição – enquanto uma posição está aberta, a estratégia avalia cada vela concluída para detectar gatilhos de stop-loss, take-profit, break-even ou trailing stop. Eventos de violação fecham a posição completa via ordens de mercado.
Gestão monetária
Dimensionamento inicial – as ordens começam com InitialVolume alinhado ao VolumeStep do instrumento e limitado por VolumeMin/VolumeMax.
Escalada martingale – após um trade perdedor, o próximo volume é multiplicado por MartingaleMultiplier (DoubleLotSize = true) ou incrementado por LotIncrement. Trades lucrativos resetam a escada para o volume base. A profundidade de escalada é limitada por MaxMartingaleSteps para evitar exposição descontrolada.
Stop-loss e take-profit – as distâncias são expressas em pips no estilo MetaTrader. O tamanho do pip adapta-se automaticamente às cotações Forex de 3/5 dígitos, correspondendo à lógica ticksize original.
Break-even – uma vez que o lucro não realizado atinge BreakEvenTriggerPips, o stop-loss é deslocado para a entrada mais BreakEvenOffsetPips (longo) ou menos o offset (curto).
Trailing stop – lucros além de TrailingStopPips movem um limite de trailing interno que se aperta a cada vela, replicando o comportamento TrailingStop do EA.
Parâmetros
Nome
Descrição
CandleType
Período de negociação usado para sinais DeMarker.
MacdCandleType
Período maior usado para calcular o filtro de tendência MACD.
DemarkerPeriod
Período de lookback do DeMarker.
DemarkerThreshold
Limite neutro entre configurações altistas e baixistas.
MacdFast / MacdSlow / MacdSignal
Comprimentos EMA do MACD.
InitialVolume
Tamanho de ordem base antes dos ajustes martingale.
MartingaleMultiplier
Fator de multiplicação quando DoubleLotSize está habilitado.
LotIncrement
Incremento aditivo quando a duplicação está desabilitada.
DoubleLotSize
Alternar entre martingale multiplicativo e aditivo.
MaxMartingaleSteps
Número máximo de escaladas consecutivas.
StopLossPips
Distância de stop-loss em pips.
TakeProfitPips
Distância de take-profit em pips.
TrailingStopPips
Distância de trailing stop em pips.
UseBreakEven
Habilitar ou desabilitar a lógica de break-even.
BreakEvenTriggerPips
Limiar de lucro (em pips) antes de mudar para break-even.
BreakEvenOffsetPips
Buffer aplicado ao stop de break-even.
Notas de conversão
A conversão de pip espelha o EA MQL (ticksize == 0.00001 ou 0.001 implica uma escala de pip 10x). Isso preserva distâncias de risco consistentes em cotações de 3/5 dígitos.
O filtro de tendência MACD usa MovingAverageConvergenceDivergenceSignal com os comprimentos EMA originais e processa uma série de velas separada para emular a lógica do gráfico mensal.
A contabilidade do martingale rastreia preços médios ponderados de entrada e PnL realizado para decidir se o próximo trade deve escalar ou resetar.
Todas as ações protetoras (stop-loss, take-profit, break-even, trailing) são executadas via saídas de mercado porque a API de alto nível desencoraja modificações diretas de ordens sob a guarda StartProtection.
Dicas de uso
Certifique-se de que o instrumento atribuído expõe PriceStep, VolumeStep, VolumeMin e VolumeMax para alinhar os cálculos de pip e o arredondamento de volume com as restrições da bolsa.
Experimente com MacdCandleType (por exemplo, velas semanais) para ajustar o filtro de tendência para mercados mais rápidos.
Ao otimizar, ajuste conjuntamente DemarkerThreshold, TrailingStopPips e os parâmetros martingale para manter os drawdowns sob controle.
Combine a estratégia com controles de risco no nível do portfólio ou filtros de sessão de negociação ao implantar ao vivo, já que as sequências martingale inerentemente aumentam a exposição após perdas.
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 DemarkerMartingaleStrategy : 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 DemarkerMartingaleStrategy()
{
_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;
}
}
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 ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class demarker_martingale_strategy(Strategy):
def __init__(self):
super(demarker_martingale_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 14) \
.SetDisplay("Fast Period", "Fast MA period", "Indicator")
self._slow_period = self.Param("SlowPeriod", 50) \
.SetDisplay("Slow Period", "Slow MA period", "Indicator")
self._stop_loss_points = self.Param("StopLossPoints", 200) \
.SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk")
self._take_profit_points = self.Param("TakeProfitPoints", 400) \
.SetDisplay("Take Profit", "Take-profit in price steps", "Risk")
self._fast = None
self._slow = None
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._cooldown = 0
@property
def fast_period(self):
return self._fast_period.Value
@property
def slow_period(self):
return self._slow_period.Value
@property
def stop_loss_points(self):
return self._stop_loss_points.Value
@property
def take_profit_points(self):
return self._take_profit_points.Value
def OnReseted(self):
super(demarker_martingale_strategy, self).OnReseted()
self._fast = None
self._slow = None
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._cooldown = 0
def OnStarted2(self, time):
super(demarker_martingale_strategy, self).OnStarted2(time)
self._fast = ExponentialMovingAverage()
self._fast.Length = self.fast_period
self._slow = ExponentialMovingAverage()
self._slow.Length = self.slow_period
subscription = self.SubscribeCandles(DataType.TimeFrame(TimeSpan.FromMinutes(5)))
subscription.Bind(self._fast, self._slow, self._process_candle)
subscription.Start()
def _process_candle(self, candle, fast_value, slow_value):
if candle.State != CandleStates.Finished:
return
fast_val = float(fast_value)
slow_val = float(slow_value)
if not self._fast.IsFormed or not self._slow.IsFormed:
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self._cooldown > 0:
self._cooldown -= 1
self._prev_fast = fast_val
self._prev_slow = slow_val
return
close = float(candle.ClosePrice)
step = float(self.Security.PriceStep) if self.Security is not None and self.Security.PriceStep is not None else 1.0
if self.Position > 0 and self._entry_price > 0:
if self.stop_loss_points > 0 and close <= self._entry_price - self.stop_loss_points * step:
self.SellMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self.take_profit_points > 0 and close >= self._entry_price + self.take_profit_points * step:
self.SellMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
elif self.Position < 0 and self._entry_price > 0:
if self.stop_loss_points > 0 and close >= self._entry_price + self.stop_loss_points * step:
self.BuyMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self.take_profit_points > 0 and close <= self._entry_price - self.take_profit_points * step:
self.BuyMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self._prev_fast <= self._prev_slow and fast_val > slow_val and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
self._entry_price = close
self._cooldown = 100
elif self._prev_fast >= self._prev_slow and fast_val < slow_val and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._entry_price = close
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
def CreateClone(self):
return demarker_martingale_strategy()