La estrategia Lbs V12 es una conversión del asesor experto MetaTrader LBS_V12.mq4. Abre un par de órdenes de parada de ruptura alrededor de la vela anterior de 15 minutos cuando comienza la hora de activación configurada. Ambas órdenes se compensan con el valor actual del rango verdadero promedio (ATR) para tener en cuenta la volatilidad a corto plazo. La estrategia intenta captar el primer impulso de la sesión de negociación y gestiona las salidas mediante reglas virtuales de stop-loss, take-profit y trailing evaluadas en cada vela terminada.
Lógica de trading
La estrategia monitorea las velas terminadas del período de tiempo seleccionado (15 minutos por defecto).
Cuando aparece una nueva vela con el minuto 00 en el TriggerHour configurado, la vela anterior se convierte en el rango de referencia.
Si no hay posiciones abiertas ni órdenes de trabajo para el día actual, se envían dos órdenes de parada:
Stop de compra por encima del máximo de referencia más el diferencial del instrumento, un paso de precio y el último valor ATR.
Parada de venta por debajo del mínimo de referencia menos los mismos amortiguadores.
Los niveles de precios de protección para cada lado se almacenan internamente:
El stop-loss se coloca más allá del extremo opuesto de la vela de referencia.
La toma de ganancias se calcula utilizando la distancia de puntos estilo MetaTrader.
Un trailing stop se activa una vez que la operación se mueve más allá de la distancia configurada.
Cuando se abre una posición larga o corta, se cancela la orden stop opuesta. Toda la protección se aplica virtualmente: los máximos y mínimos de las velas se comparan con los valores de stop/take almacenados y la posición se cierra con órdenes de mercado cuando se alcanzan los límites.
La estrategia se ejecuta solo una vez al día. Todas las órdenes pendientes y el estado interno se borran al comienzo de una nueva fecha de negociación.
Parámetros
Nombre
Descripción
Predeterminado
Volume
Volumen de negociación en lotes.
1
TriggerHour
Hora del día (zona horaria de la terminal) en la que se deben enviar las órdenes de ruptura.
9
TakeProfitPoints
Puntos de estilo MetaTrader entre el precio de entrada y el objetivo de obtención de beneficios.
100
TrailingStopPoints
Puntos de estilo MetaTrader utilizados para el trailing stop después de que la operación genera ganancias.
20
AtrPeriod
Periodo del indicador ATR que compensa las órdenes pendientes.
3
CandleType
Tipo de vela utilizado para cálculos de señales. El valor predeterminado son velas con un marco de tiempo de 15 minutos.
15m timeframe
Gestión del riesgo
Las salidas se ejecutan a través de órdenes de mercado cuando los extremos de las velas tocan los niveles virtuales de stop-loss o take-profit.
El trailing stop aumenta (para largos) o disminuye (para cortos) el nivel de protección siempre que la operación gana más que la distancia configurada.
El reinicio diario garantiza que la estrategia no acumule múltiples posiciones u órdenes pendientes obsoletas.
Notas
Las actualizaciones precisas de oferta y demanda mejoran la compensación del diferencial que se agrega a los precios de ruptura. Si no se dispone de datos sobre diferenciales, la estrategia retrocede a un escalón de precio.
La conversión mantiene los valores predeterminados originales de MetaTrader pero adapta el manejo de la obtención de ganancias para posiciones cortas de modo que el objetivo siempre se coloque en la dirección rentable.
using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// LBS V12 strategy - ATR channel breakout with EMA trend.
/// Buys when close breaks above EMA + ATR.
/// Sells when close breaks below EMA - ATR.
/// </summary>
public class LbsV12Strategy : Strategy
{
private readonly StrategyParam<int> _emaPeriod;
private readonly StrategyParam<int> _atrPeriod;
private readonly StrategyParam<decimal> _atrMultiplier;
private readonly StrategyParam<int> _cooldownCandles;
private readonly StrategyParam<DataType> _candleType;
private int _cooldownRemaining;
public int EmaPeriod { get => _emaPeriod.Value; set => _emaPeriod.Value = value; }
public int AtrPeriod { get => _atrPeriod.Value; set => _atrPeriod.Value = value; }
public decimal AtrMultiplier { get => _atrMultiplier.Value; set => _atrMultiplier.Value = value; }
public int CooldownCandles { get => _cooldownCandles.Value; set => _cooldownCandles.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public LbsV12Strategy()
{
_emaPeriod = Param(nameof(EmaPeriod), 50)
.SetDisplay("EMA Period", "EMA lookback", "Indicators");
_atrPeriod = Param(nameof(AtrPeriod), 14)
.SetDisplay("ATR Period", "ATR lookback", "Indicators");
_atrMultiplier = Param(nameof(AtrMultiplier), 3m)
.SetDisplay("ATR Multiplier", "Channel width multiplier", "Indicators");
_cooldownCandles = Param(nameof(CooldownCandles), 100)
.SetDisplay("Cooldown", "Candles between signals", "General");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_cooldownRemaining = default;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_cooldownRemaining = 0;
var ema = new ExponentialMovingAverage { Length = EmaPeriod };
var atr = new AverageTrueRange { Length = AtrPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(ema, atr, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal ema, decimal atr)
{
if (candle.State != CandleStates.Finished) return;
if (_cooldownRemaining > 0)
{
_cooldownRemaining--;
return;
}
var close = candle.ClosePrice;
var mult = AtrMultiplier;
if (close > ema + atr * mult && Position <= 0)
{
if (Position < 0) BuyMarket();
BuyMarket();
_cooldownRemaining = CooldownCandles;
}
else if (close < ema - atr * mult && Position >= 0)
{
if (Position > 0) SellMarket();
SellMarket();
_cooldownRemaining = CooldownCandles;
}
}
}
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, AverageTrueRange
from StockSharp.Algo.Strategies import Strategy
class lbs_v12_strategy(Strategy):
def __init__(self):
super(lbs_v12_strategy, self).__init__()
self._ema_period = self.Param("EmaPeriod", 50) \
.SetDisplay("EMA Period", "EMA lookback", "Indicators")
self._atr_period = self.Param("AtrPeriod", 14) \
.SetDisplay("ATR Period", "ATR lookback", "Indicators")
self._atr_multiplier = self.Param("AtrMultiplier", 3.0) \
.SetDisplay("ATR Multiplier", "Channel width multiplier", "Indicators")
self._cooldown_candles = self.Param("CooldownCandles", 100) \
.SetDisplay("Cooldown", "Candles between signals", "General")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))) \
.SetDisplay("Candle Type", "Candle timeframe", "General")
self._cooldown_remaining = 0
@property
def ema_period(self):
return self._ema_period.Value
@property
def atr_period(self):
return self._atr_period.Value
@property
def atr_multiplier(self):
return self._atr_multiplier.Value
@property
def cooldown_candles(self):
return self._cooldown_candles.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(lbs_v12_strategy, self).OnReseted()
self._cooldown_remaining = 0
def OnStarted2(self, time):
super(lbs_v12_strategy, self).OnStarted2(time)
self._cooldown_remaining = 0
ema = ExponentialMovingAverage()
ema.Length = self.ema_period
atr = AverageTrueRange()
atr.Length = self.atr_period
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(ema, atr, self.process_candle).Start()
def process_candle(self, candle, ema, atr):
if candle.State != CandleStates.Finished:
return
if self._cooldown_remaining > 0:
self._cooldown_remaining -= 1
return
close = float(candle.ClosePrice)
ema_val = float(ema)
atr_val = float(atr)
mult = float(self.atr_multiplier)
if close > ema_val + atr_val * mult and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
self._cooldown_remaining = self.cooldown_candles
elif close < ema_val - atr_val * mult and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._cooldown_remaining = self.cooldown_candles
def CreateClone(self):
return lbs_v12_strategy()