A Envelope Limit Ladder Strategy é uma porta C# do MetaTrader consultor especialista E_2_12_5min.mq4 (ID 7671). Ele reconstrói a escada original de pedidos com limite em torno de um envelope EMA em velas de 5 minutos, enquanto mantém o modelo de gerenciamento multi-alvo e de rastreamento do robô legado.
Conceito
Filtro de envelope – um envelope de média móvel (padrão EMA 144 com um desvio de 0,05%) calculado no período de tempo EnvelopeCandleType configurável fornece a linha média e as bandas superior/inferior.
Vela de sinal – os sinais de negociação são avaliados na assinatura CandleType (padrão 5 minutos). Quando a vela anterior fecha entre a linha média e a banda mais próxima, os braços estratégicos limitam as ordens na linha média.
Escada de pedidos – até três limites de compra e três limites de venda são colocados simultaneamente:
Preço de entrada: valor da linha média alinhado.
Stop-loss: banda oposta do envelope.
Take-profit: banda ± compensações definidas pelo usuário (8, 13 e 21 pontos por padrão).
Janela de negociação – ordens pendentes são criadas somente quando TradingStartHour < Hour < TradingEndHour. Todos os limites restantes serão cancelados quando o horário de funcionamento atingir TradingEndHour.
Gerenciamento de posição – cada ordem com limite preenchida imediatamente coloca sua própria ordem stop e take-profit. Um modo de rastreamento opcional move o stop para a média móvel (ou o mantém na banda oposta) quando o preço ultrapassa o envelope.
Parâmetros
Parâmetro
Padrão
Descrição
CandleType
5 minutos
Tipo vela para detecção de sinal.
EnvelopeCandleType
5 minutos
Tipo de vela usado para calcular o envelope. Use um período de tempo maior para imitar a entrada MT4 EnvTimeFrame.
EnvelopePeriod
144
Comprimento médio móvel do envelope.
MaMethod
EMA
Método de média móvel (SMA, EMA, SMMA, LWMA).
EnvelopeDeviation
0,05
Largura do envelope em porcentagem (0,05 = 0,05%).
TradingStartHour
0
Primeira hora em que podem aparecer ordens pendentes (verificação exclusiva, corresponde ao comportamento do MT4).
TradingEndHour
17
Hora em que todas as ordens pendentes são removidas (limite superior exclusivo).
FirstTakeProfitPoints
8
Deslocamento em pontos adicionados além do envelope para o primeiro degrau da escada.
SecondTakeProfitPoints
13
Deslocamento em pontos para o segundo degrau.
ThirdTakeProfitPoints
21
Deslocamento em pontos para o terceiro degrau.
UseOppositeEnvelopeTrailing
true
Mantém o stop na banda oposta (true) ou segue até a média móvel (false). Espelha a sinalização MT4 MaElineTSL.
OrderVolume
0,1
Volume por ordem pendente (substitui o dimensionamento de lote adaptativo do MT4).
Notas de comportamento
A estratégia mantém um par stop/take separado para cada ordem com limite preenchida. As saídas não interferem nos demais degraus da escada.
O trailing só é ativado após um rompimento além do envelope e apenas estreita o stop na direção lucrativa.
Quando EnvelopeCandleType difere de CandleType, os valores de envelope mais recentes da assinatura secundária são reutilizados para velas de sinal, correspondendo de perto à pesquisa de envelope de período de tempo superior MT4.
A rotina original de gerenciamento de dinheiro MT4 (LotsOptimized) é substituída pelo parâmetro explícito OrderVolume para manter a porta determinística dentro de StockSharp.
Dicas de uso
Combine o período do envelope com as entradas MT4 para reproduzir o comportamento original (por exemplo, mantenha EnvelopeCandleType em 5 minutos ou mude para 1 hora/4 horas conforme necessário).
Defina UseOppositeEnvelopeTrailing como false se desejar que o trailing stop salte para a média móvel em vez da banda oposta quando o preço sair do envelope.
Otimizar as compensações de take-profit e o desvio de envelope em conjunto; as distâncias da escada dependem da volatilidade capturada pelo envelope.
using System;
using System.Collections.Generic;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Envelope Limit Ladder strategy - Bollinger band mean reversion.
/// Buys when price touches lower band, sells when it touches upper band.
/// Exits at the middle band.
/// </summary>
public class EnvelopeLimitLadderStrategy : Strategy
{
private readonly StrategyParam<int> _bbPeriod;
private readonly StrategyParam<decimal> _bbWidth;
private readonly StrategyParam<DataType> _candleType;
public int BbPeriod { get => _bbPeriod.Value; set => _bbPeriod.Value = value; }
public decimal BbWidth { get => _bbWidth.Value; set => _bbWidth.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public EnvelopeLimitLadderStrategy()
{
_bbPeriod = Param(nameof(BbPeriod), 20)
.SetDisplay("BB Period", "Bollinger bands period", "Indicators");
_bbWidth = Param(nameof(BbWidth), 1.5m)
.SetDisplay("BB Width", "Bollinger bands deviation", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities() => [(Security, CandleType)];
protected override void OnReseted() { base.OnReseted(); }
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var bb = new BollingerBands { Length = BbPeriod, Width = BbWidth };
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(bb, ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue value)
{
if (candle.State != CandleStates.Finished)
return;
if (!value.IsFinal || value.IsEmpty)
return;
var bbVal = value as BollingerBandsValue;
if (bbVal == null)
return;
var upper = bbVal.UpBand;
var lower = bbVal.LowBand;
var middle = bbVal.MovingAverage;
if (upper == null || lower == null || middle == null)
return;
var close = candle.ClosePrice;
// Mean reversion: buy at lower band
if (close < lower.Value && Position <= 0)
{
if (Position < 0)
BuyMarket();
BuyMarket();
}
// Mean reversion: sell at upper band
else if (close > upper.Value && Position >= 0)
{
if (Position > 0)
SellMarket();
SellMarket();
}
// Exit long at middle
else if (Position > 0 && close > middle.Value)
{
SellMarket();
}
// Exit short at middle
else if (Position < 0 && close < middle.Value)
{
BuyMarket();
}
}
}
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 BollingerBands
from StockSharp.Algo.Strategies import Strategy
class envelope_limit_ladder_strategy(Strategy):
def __init__(self):
super(envelope_limit_ladder_strategy, self).__init__()
self._bb_period = self.Param("BbPeriod", 20) \
.SetDisplay("BB Period", "Bollinger bands period", "Indicators")
self._bb_width = self.Param("BbWidth", 1.5) \
.SetDisplay("BB Width", "Bollinger bands deviation", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Candle timeframe", "General")
@property
def bb_period(self):
return self._bb_period.Value
@property
def bb_width(self):
return self._bb_width.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(envelope_limit_ladder_strategy, self).OnReseted()
def OnStarted2(self, time):
super(envelope_limit_ladder_strategy, self).OnStarted2(time)
bb = BollingerBands()
bb.Length = self.bb_period
bb.Width = self.bb_width
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(bb, self.process_candle).Start()
def process_candle(self, candle, bb_value):
if candle.State != CandleStates.Finished:
return
if not bb_value.IsFinal or bb_value.IsEmpty:
return
if bb_value.UpBand is None or bb_value.LowBand is None or bb_value.MovingAverage is None:
return
upper = float(bb_value.UpBand)
lower = float(bb_value.LowBand)
middle = float(bb_value.MovingAverage)
close = float(candle.ClosePrice)
if close < lower and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif close > upper and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
elif self.Position > 0 and close > middle:
self.SellMarket()
elif self.Position < 0 and close < middle:
self.BuyMarket()
def CreateClone(self):
return envelope_limit_ladder_strategy()