Esta estrategia replica al experto en "obtención de beneficios" MetaTrader al buscar cuatro velas consecutivas con máximos y aperturas estrictamente monótonos. Cuando la vela actual se completa con máximos crecientes y se abre, el algoritmo trata la secuencia como un impulso alcista y envía una compra de mercado. Una condición reflejada con máximos descendentes y aperturas produce una venta en el mercado. Las órdenes se gestionan con un objetivo de ganancias a nivel de cuenta, un trailing stop que puede cerrar parcialmente la exposición y un stop loss fijo opcional definido en pasos de precio.
La configuración predeterminada opera con velas de un minuto. La estrategia se puede ajustar para diferentes instrumentos ajustando el tipo de vela, los índices de desplazamiento que controlan qué velas se comparan, la distancia de seguimiento, la distancia de stop-loss, el objetivo de ganancias y el modo de tamaño de la posición. Admite un tamaño de lote fijo o un volumen dinámico calculado a partir del capital de la cartera y el porcentaje de riesgo definido por el usuario. Cuando el trailing stop avanza, el algoritmo puede opcionalmente cerrar la mitad de la posición restante para asegurar ganancias mientras se mantiene activo al corredor.
Alcanzar el objetivo de beneficio configurado medido sobre el capital de la cartera liquida inmediatamente la posición actual y cancela cualquier orden de trabajo. Esto refleja al experto MQL original que cerró todas las operaciones cuando el capital de la cuenta excedía el saldo más la ganancia deseada. La rama de gestión de riesgos valida el porcentaje de riesgo configurado y garantiza que el volumen solicitado respete el paso del volumen de seguridad.
Detalles
Lógica de entrada:
Largo: las cuatro velas monitoreadas muestran máximos estrictamente crecientes y aperturas estrictamente crecientes.
Corto: las cuatro velas monitoreadas muestran máximos estrictamente decrecientes y aperturas estrictamente decrecientes.
Gestión de Puestos:
Stop-loss opcional colocado al precio de entrada menos/más el número configurado de pasos de precio.
El trailing stop sigue el precio de cierre una vez que se mueve más que la distancia de seguimiento desde la entrada.
La salida parcial (50% del volumen restante) se ejecuta cada vez que se mueve el trailing stop, sujeto al paso de volumen de seguridad y al lote mínimo negociable.
Objetivo de cuenta: cierra toda exposición y cancela órdenes activas cuando portfolio equity ≥ initial equity + ProfitTarget.
Gestión de riesgos:
El modo de lote fijo utiliza el parámetro Lots configurado (o Volume de la base de estrategia si se especifica).
El modo de porcentaje de riesgo dimensiona el pedido como equity * RiskPercent / max(stopDistance, price) y normaliza el resultado por paso de volumen.
Parámetros predeterminados:
Shift1 = 0, Shift2 = 1, Shift3 = 2, Shift4 = 3.
TrailingStopPoints = 1, StopLossPoints = 0, ProfitTarget = 1 (unidades monetarias de la cuenta).
Lots = 1, RiskPercent = 1, MaxOrders = 1.
CandleType = período de tiempo de 1 minuto.
Mejores mercados: futuros de tendencia, principales divisas y pares de criptomonedas líquidos donde el impulso a corto plazo persiste en múltiples velas.
Fortalezas: detección rápida del impulso, objetivo de capital configurable, ampliación parcial y controles de riesgo simples.
Debilidades: sensible a rangos ruidosos, depende del tamaño de paso correcto y asume el modo de red (posición agregada única).
Parámetros
Nombre
Descripción
Shift1 – Shift4
Índices de las velas comparados para la secuencia de ruptura.
TrailingStopPoints
Distancia de seguimiento en pasos de precio.
StopLossPoints
Distancia de parada inicial en pasos de precio; cero desactiva el stop-loss.
ProfitTarget
Objetivo de ganancias aplicado al capital de la cartera antes de cerrar todas las operaciones.
Lots
Volumen de operaciones fijo cuando la gestión de riesgos está deshabilitada.
RiskManagement
Habilita el dimensionamiento basado en riesgos usando RiskPercent.
RiskPercent
Porcentaje del capital de la cartera arriesgado en cada operación cuando la gestión de riesgos está activa.
PartialClose
Si está habilitado, cierra la mitad de la posición cada vez que se mueve el trailing stop.
MaxOrders
Número máximo de unidades base permitidas simultáneamente (límite de posición neta).
CandleType
Marco de tiempo utilizado para la generación de la señal.
Consejos de uso
Alinee los parámetros Shift con la volatilidad del instrumento. Los cambios más grandes analizan secuencias de impulso más largas.
Establezca TrailingStopPoints en relación con el paso del precio del valor; valores demasiado pequeños pueden generar salidas parciales rápidas.
Utilice el tamaño del porcentaje de riesgo con un StopLossPoints explícito para que el tamaño de la posición refleje el riesgo monetario real por operación.
Monitoree la curva de acciones: una vez que se alcanza el objetivo global, la estrategia deja de operar hasta que se reinicia, imitando el EA original.
using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Take Profit Breakout: Consecutive candle breakout with EMA filter and ATR stops.
/// </summary>
public class TakeProfitBreakoutStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _fastEmaLength;
private readonly StrategyParam<int> _slowEmaLength;
private readonly StrategyParam<int> _atrLength;
private decimal _prevFast;
private decimal _prevSlow;
private decimal _entryPrice;
public TakeProfitBreakoutStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Timeframe.", "General");
_fastEmaLength = Param(nameof(FastEmaLength), 10)
.SetDisplay("Fast EMA Length", "Fast EMA period.", "Indicators");
_slowEmaLength = Param(nameof(SlowEmaLength), 30)
.SetDisplay("Slow EMA Length", "Slow EMA period.", "Indicators");
_atrLength = Param(nameof(AtrLength), 14)
.SetDisplay("ATR Length", "ATR period.", "Indicators");
}
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int FastEmaLength { get => _fastEmaLength.Value; set => _fastEmaLength.Value = value; }
public int SlowEmaLength { get => _slowEmaLength.Value; set => _slowEmaLength.Value = value; }
public int AtrLength { get => _atrLength.Value; set => _atrLength.Value = value; }
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevFast = 0; _prevSlow = 0; _entryPrice = 0;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevFast = 0; _prevSlow = 0; _entryPrice = 0;
var fastEma = new ExponentialMovingAverage { Length = FastEmaLength };
var slowEma = new ExponentialMovingAverage { Length = SlowEmaLength };
var atr = new AverageTrueRange { Length = AtrLength };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(fastEma, slowEma, atr, ProcessCandle).Start();
var area = CreateChartArea();
if (area != null) { DrawCandles(area, subscription); DrawIndicator(area, fastEma); DrawIndicator(area, slowEma); DrawOwnTrades(area); }
}
private void ProcessCandle(ICandleMessage candle, decimal fastVal, decimal slowVal, decimal atrVal)
{
if (candle.State != CandleStates.Finished) return;
if (_prevFast == 0 || _prevSlow == 0 || atrVal <= 0) { _prevFast = fastVal; _prevSlow = slowVal; return; }
var close = candle.ClosePrice;
if (Position > 0)
{
if ((fastVal < slowVal && _prevFast >= _prevSlow) || close <= _entryPrice - atrVal * 2m) { SellMarket(); _entryPrice = 0; }
}
else if (Position < 0)
{
if ((fastVal > slowVal && _prevFast <= _prevSlow) || close >= _entryPrice + atrVal * 2m) { BuyMarket(); _entryPrice = 0; }
}
if (Position == 0)
{
if (fastVal > slowVal && _prevFast <= _prevSlow) { _entryPrice = close; BuyMarket(); }
else if (fastVal < slowVal && _prevFast >= _prevSlow) { _entryPrice = close; SellMarket(); }
}
_prevFast = fastVal; _prevSlow = slowVal;
}
}
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.Strategies import Strategy
from StockSharp.Algo.Indicators import ExponentialMovingAverage, AverageTrueRange
class take_profit_breakout_strategy(Strategy):
def __init__(self):
super(take_profit_breakout_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))) \
.SetDisplay("Candle Type", "Timeframe.", "General")
self._fast_ema_length = self.Param("FastEmaLength", 10) \
.SetDisplay("Fast EMA Length", "Fast EMA period.", "Indicators")
self._slow_ema_length = self.Param("SlowEmaLength", 30) \
.SetDisplay("Slow EMA Length", "Slow EMA period.", "Indicators")
self._atr_length = self.Param("AtrLength", 14) \
.SetDisplay("ATR Length", "ATR period.", "Indicators")
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
@property
def CandleType(self):
return self._candle_type.Value
@property
def FastEmaLength(self):
return self._fast_ema_length.Value
@property
def SlowEmaLength(self):
return self._slow_ema_length.Value
@property
def AtrLength(self):
return self._atr_length.Value
def OnStarted2(self, time):
super(take_profit_breakout_strategy, self).OnStarted2(time)
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._fast_ema = ExponentialMovingAverage()
self._fast_ema.Length = self.FastEmaLength
self._slow_ema = ExponentialMovingAverage()
self._slow_ema.Length = self.SlowEmaLength
self._atr = AverageTrueRange()
self._atr.Length = self.AtrLength
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(self._fast_ema, self._slow_ema, self._atr, self.ProcessCandle).Start()
def ProcessCandle(self, candle, fast_val, slow_val, atr_val):
if candle.State != CandleStates.Finished:
return
fv = float(fast_val)
sv = float(slow_val)
av = float(atr_val)
if self._prev_fast == 0 or self._prev_slow == 0 or av <= 0:
self._prev_fast = fv
self._prev_slow = sv
return
close = float(candle.ClosePrice)
if self.Position > 0:
if (fv < sv and self._prev_fast >= self._prev_slow) or close <= self._entry_price - av * 2.0:
self.SellMarket()
self._entry_price = 0.0
elif self.Position < 0:
if (fv > sv and self._prev_fast <= self._prev_slow) or close >= self._entry_price + av * 2.0:
self.BuyMarket()
self._entry_price = 0.0
if self.Position == 0:
if fv > sv and self._prev_fast <= self._prev_slow:
self._entry_price = close
self.BuyMarket()
elif fv < sv and self._prev_fast >= self._prev_slow:
self._entry_price = close
self.SellMarket()
self._prev_fast = fv
self._prev_slow = sv
def OnReseted(self):
super(take_profit_breakout_strategy, self).OnReseted()
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
def CreateClone(self):
return take_profit_breakout_strategy()