A estratégia reage a candles altistas e baixistas fortes e abre posições a mercado na mesma direção. Ela usa uma sequência martingale independente para cada lado: posições compradas escalam o volume com o Bull Multiplier, enquanto posições vendidas usam o Bear Multiplier. Distâncias protetoras de stop-loss e take-profit também são configuradas separadamente para cada direção, permitindo controle preciso sobre o comportamento assimétrico exposto pelo expert advisor MQL original.
Lógica de negociação
Assinar o tipo de candle configurado (padrão: 1 minuto) e aguardar apenas candles concluídos.
Quando não há posição aberta:
Setup altista: se Close > Open e o tamanho do corpo do candle excede o filtro de corpo altista, comprar a mercado.
Setup baixista: se Close < Open e o tamanho do corpo excede o filtro de corpo baixista, vender a mercado.
Cada entrada define ordens de stop-loss e take-profit convertidas de distâncias em pips para o passo de preço do instrumento.
Quando uma posição fecha, o PnL realizado é comparado com a linha de base anterior:
Um resultado negativo multiplica o volume martingale respectivo.
Um resultado positivo ou break-even redefine esse lado para o volume inicial.
Novos sinais são ignorados enquanto uma posição está aberta, reproduzindo o comportamento de operação única do EA de origem.
Gestão monetária
Ciclos martingale longos e curtos são acompanhados independentemente, então uma sequência perdedora comprada não afeta a próxima venda, e vice-versa.
Volumes são alinhados ao VolumeStep do ativo para evitar rejeições de ordens.
StartProtection(useMarketOrders: true) habilita o tratamento de ordens protetoras do StockSharp para os níveis stop e take anexados.
Parâmetros
Parâmetro
Descrição
Initial Volume
Volume base que inicia cada ciclo martingale para ambas as direções.
Bull Multiplier
Multiplicador aplicado à próxima operação altista após uma posição comprada perdedora.
Bear Multiplier
Multiplicador aplicado à próxima operação baixista após uma posição vendida perdedora.
Bull Stop Loss
Distância do stop-loss em pips para operações altistas. Convertida para preço usando o passo do instrumento.
Bull Take Profit
Distância do take-profit em pips para operações altistas.
Bear Stop Loss
Distância do stop-loss em pips para operações baixistas.
Bear Take Profit
Distância do take-profit em pips para operações baixistas.
Bull Body Filter
Corpo mínimo de candle altista em pips exigido para disparar uma compra.
Bear Body Filter
Corpo mínimo de candle baixista em pips exigido para disparar uma venda.
Candle Type
Timeframe usado para geração de sinais (padrão: timeframe de 1 minuto).
Notas de uso
Garanta que o ativo conectado exponha valores válidos de PriceStep e VolumeStep. A estratégia usa 0.0001 por padrão quando PriceStep não é fornecido.
A lógica martingale depende de PnL realizado, então o fechamento manual de posição ainda atualizará a sequência corretamente.
A otimização pode focar em filtros de corpo e combinações de multiplicadores para equilibrar responsividade contra drawdown.
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Bull/Bear Candle Martingale strategy: Bullish/bearish candle direction + EMA filter.
/// Buys after strong bullish candle when close crosses above EMA.
/// Sells after strong bearish candle when close crosses below EMA.
/// </summary>
public class BullBearCandleMartingaleStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _emaPeriod;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int EmaPeriod
{
get => _emaPeriod.Value;
set => _emaPeriod.Value = value;
}
public BullBearCandleMartingaleStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_emaPeriod = Param(nameof(EmaPeriod), 30)
.SetGreaterThanZero()
.SetDisplay("EMA Period", "EMA period", "Indicators");
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var ema = new ExponentialMovingAverage { Length = EmaPeriod };
decimal? prevClose = null;
decimal? prevEma = null;
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(ema, (candle, emaVal) =>
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var close = candle.ClosePrice;
var bullish = close > candle.OpenPrice;
var bearish = close < candle.OpenPrice;
var bodySize = Math.Abs(close - candle.OpenPrice);
var range = candle.HighPrice - candle.LowPrice;
// Require strong candle body (>50% of range)
var strongCandle = range > 0 && bodySize / range > 0.5m;
if (prevClose.HasValue && prevEma.HasValue && strongCandle)
{
var crossUp = prevClose.Value <= prevEma.Value && close > emaVal;
var crossDown = prevClose.Value >= prevEma.Value && close < emaVal;
if (bullish && crossUp && Position <= 0)
BuyMarket();
else if (bearish && crossDown && Position >= 0)
SellMarket();
}
prevClose = close;
prevEma = emaVal;
})
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, ema);
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 ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class bull_bear_candle_martingale_strategy(Strategy):
def __init__(self):
super(bull_bear_candle_martingale_strategy, self).__init__()
self._ema_period = self.Param("EmaPeriod", 30) \
.SetDisplay("EMA Period", "EMA period", "Indicators")
self._ema = None
self._prev_close = None
self._prev_ema = None
@property
def ema_period(self):
return self._ema_period.Value
def OnReseted(self):
super(bull_bear_candle_martingale_strategy, self).OnReseted()
self._ema = None
self._prev_close = None
self._prev_ema = None
def OnStarted2(self, time):
super(bull_bear_candle_martingale_strategy, self).OnStarted2(time)
self._ema = ExponentialMovingAverage()
self._ema.Length = self.ema_period
subscription = self.SubscribeCandles(DataType.TimeFrame(TimeSpan.FromHours(1)))
subscription.Bind(self._ema, self._process_candle)
subscription.Start()
def _process_candle(self, candle, ema_value):
if candle.State != CandleStates.Finished:
return
if not self._ema.IsFormed:
return
close = float(candle.ClosePrice)
open_p = float(candle.OpenPrice)
high = float(candle.HighPrice)
low = float(candle.LowPrice)
ema_val = float(ema_value)
bullish = close > open_p
bearish = close < open_p
body_size = abs(close - open_p)
range_size = high - low
strong_candle = range_size > 0 and body_size / range_size > 0.5
if self._prev_close is not None and self._prev_ema is not None and strong_candle:
cross_up = self._prev_close <= self._prev_ema and close > ema_val
cross_down = self._prev_close >= self._prev_ema and close < ema_val
if bullish and cross_up and self.Position <= 0:
self.BuyMarket()
elif bearish and cross_down and self.Position >= 0:
self.SellMarket()
self._prev_close = close
self._prev_ema = ema_val
def CreateClone(self):
return bull_bear_candle_martingale_strategy()