A estratégia Lbs V12 é uma conversão do consultor especialista MetaTrader LBS_V12.mq4. Ele abre um par de ordens de stop breakout em torno da vela anterior de 15 minutos quando a hora de disparo configurada começa. Ambas as ordens são compensadas pelo valor atual do Average True Range (ATR) para levar em conta a volatilidade de curto prazo. A estratégia tenta capturar o primeiro impulso da sessão de negociação e gerencia as saídas por meio de regras virtuais de stop-loss, take-profit e trailing avaliadas em cada vela finalizada.
Lógica de negociação
A estratégia monitora as velas finalizadas do período selecionado (15 minutos por padrão).
Quando uma nova vela com minuto 00 aparece no TriggerHour configurado, a vela anterior se torna o intervalo de referência.
Se não houver posições abertas nem ordens de trabalho para o dia atual, serão enviadas duas ordens de stop:
Parada de compra acima da máxima de referência mais o spread do instrumento, uma etapa de preço e o valor mais recente de ATR.
Sell stop abaixo do mínimo de referência menos os mesmos buffers.
Os níveis de preços de proteção para cada lado são armazenados internamente:
O stop loss é colocado além do extremo oposto da vela de referência.
O take-profit é calculado usando a distância de pontos no estilo MetaTrader.
Um trailing stop é ativado quando a negociação se move além da distância configurada.
Quando uma posição longa ou curta é aberta, a ordem stop oposta é cancelada. Toda a proteção é aplicada virtualmente: os máximos e mínimos das velas são comparados com os valores de stop/take armazenados e a posição é fechada com ordens de mercado quando os limites são atingidos.
A estratégia é executada apenas uma vez por dia. Todas as ordens pendentes e estados internos são eliminados no início de uma nova data de negociação.
Parâmetros
Nome
Descrição
Padrão
Volume
Volume de negociação em lotes.
1
TriggerHour
Hora do dia (fuso horário terminal) em que as ordens de breakout devem ser enviadas.
9
TakeProfitPoints
Pontos estilo MetaTrader entre o preço de entrada e a meta de lucro.
100
TrailingStopPoints
Pontos estilo MetaTrader usados para o trailing stop depois que a negociação passa para o lucro.
20
AtrPeriod
Período do indicador ATR que compensa as ordens pendentes.
3
CandleType
Tipo de vela usado para cálculos de sinal. O padrão são velas de período de 15 minutos.
15m timeframe
Gestão de risco
As saídas são executadas por meio de ordens de mercado quando os extremos das velas tocam os níveis virtuais de stop-loss ou take-profit.
O trailing stop aumenta (para posições compradas) ou diminui (para posições vendidas) o nível de proteção sempre que a negociação ganha mais que a distância configurada.
A reinicialização diária garante que a estratégia não acumule múltiplas posições ou ordens pendentes desatualizadas.
Notas
Atualizações precisas de compra/venda melhoram a compensação de spread que é adicionada aos preços de breakout. Se os dados de spread não estiverem disponíveis, a estratégia volta para uma etapa de preço.
A conversão mantém os padrões originais MetaTrader, mas adapta o tratamento do take-profit para posições curtas para que o alvo seja sempre colocado na direção lucrativa.
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()