La estrategia reacciona a velas alcistas y bajistas fuertes y abre posiciones de mercado en la misma dirección. Usa una secuencia martingala independiente para cada lado: las posiciones largas escalan volumen con el Bull Multiplier, mientras que las cortas usan el Bear Multiplier. Las distancias protectoras de stop-loss y take-profit también se configuran por separado para cada dirección, permitiendo control preciso del comportamiento asimétrico que expone el experto MQL original.
Lógica de negociación
Suscribirse al tipo de vela configurado (por defecto, 1 minuto) y esperar solo velas completadas.
Cuando no hay posición abierta:
Configuración alcista: si Close > Open y el tamaño del cuerpo de vela supera el filtro alcista, comprar a mercado.
Configuración bajista: si Close < Open y el tamaño del cuerpo supera el filtro bajista, vender a mercado.
Cada entrada establece órdenes de stop-loss y take-profit convertidas desde distancias en pips al paso de precio del instrumento.
Cuando una posición se cierra, el PnL realizado se compara con la referencia previa:
Un resultado negativo multiplica el volumen martingala correspondiente.
Un resultado positivo o break-even reinicia ese lado al volumen inicial.
Se ignoran señales nuevas mientras una posición está abierta, reproduciendo el comportamiento de una sola operación del EA fuente.
Gestión monetaria
Los ciclos martingala largos y cortos se siguen de forma independiente, por lo que una racha perdedora larga no afectará la siguiente operación corta, y viceversa.
Los volúmenes se alinean con VolumeStep del instrumento para evitar rechazos.
StartProtection(useMarketOrders: true) habilita el manejo de órdenes protectoras de StockSharp para los niveles stop y take adjuntos.
Parámetros
Parámetro
Descripción
Initial Volume
Volumen base que inicia cada ciclo martingala en ambas direcciones.
Bull Multiplier
Multiplicador aplicado a la siguiente operación alcista después de una posición larga perdedora.
Bear Multiplier
Multiplicador aplicado a la siguiente operación bajista después de una posición corta perdedora.
Bull Stop Loss
Distancia de stop-loss en pips para operaciones alcistas. Se convierte a precio usando el paso del instrumento.
Bull Take Profit
Distancia de take-profit en pips para operaciones alcistas.
Bear Stop Loss
Distancia de stop-loss en pips para operaciones bajistas.
Bear Take Profit
Distancia de take-profit en pips para operaciones bajistas.
Bull Body Filter
Cuerpo mínimo de vela alcista en pips requerido para disparar una compra.
Bear Body Filter
Cuerpo mínimo de vela bajista en pips requerido para disparar una venta.
Candle Type
Marco temporal usado para generar señales (por defecto, 1 minuto).
Notas de uso
Asegúrese de que el instrumento conectado exponga valores válidos de PriceStep y VolumeStep. La estrategia usa 0.0001 por defecto cuando no se proporciona PriceStep.
La lógica martingala depende del PnL realizado, por lo que el cierre manual de posiciones seguirá actualizando correctamente la secuencia.
La optimización puede centrarse en filtros de cuerpo y combinaciones de multiplicadores para equilibrar capacidad de respuesta frente a 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()