Convertido do consultor especialista MetaTrader 4 "Template_M5_Envelopes.mq4". A estratégia rastreia um envelope de média móvel ponderada linear (LWMA) em velas de cinco minutos e ordens de stop de rompimento de armas sempre que o preço se afasta o suficiente do canal. As ordens pendentes são reavaliadas dinamicamente para acompanhar o mercado, e as posições preenchidas são protegidas por lógica configurável de stop-loss, take-profit e trailing-stop.
Lógica de negociação
Um LWMA baseado no preço médio da vela é calculado com o EnvelopePeriod configurado. As faixas superior e inferior do envelope são derivadas aplicando-se a porcentagem EnvelopeDeviation.
Cada vela finalizada de cinco minutos armazena seus valores de envelope junto com a máxima e a mínima. Os sinais só são avaliados quando um conjunto completo de valores "anteriores" estiver disponível, correspondendo à implementação MetaTrader que referenciou iEnvelopes(..., shift = 1) e a barra anterior.
Uma configuração de compra aparece quando:
A mínima da vela anterior fica pelo menos DistancePoints abaixo do envelope inferior anterior, e
O preço de oferta atual permanece pelo menos DistancePoints abaixo do mesmo valor do envelope.
Uma configuração de venda reflete a lógica com a máxima anterior e o envelope superior.
Quando uma configuração está ativa, apenas uma ordem stop é permitida (o EA original também se restringiu a um único mercado ou ordem pendente). O pedido é feito na oferta/oferta atual mais a distância de EntryOffsetPoints.
Enquanto a ordem pendente permanece ativa, a estratégia monitora o mercado. Se a diferença entre o preço da ordem e o preço de compra/venda atual exceder EntryOffsetPoints + SlippagePoints, a ordem é cancelada e imediatamente registrada novamente no novo preço de referência, mantendo o stop-loss e o take-profit anexados alinhados com as compensações desejadas.
Se o spread atual exceder MaxSpreadPoints, todas as entradas pendentes serão canceladas para evitar negociações em condições de liquidez desfavoráveis.
Gerenciamento de pedidos
Após a ativação da ordem de entrada, a estratégia registra o preço de execução e registra ordens de proteção stop e take-profit em compensações de StopLossPoints e TakeProfitPoints, respectivamente. Se um dos valores for zero, a proteção correspondente será ignorada.
O módulo de trailing stop (habilitado com UseTrailingStop) rastreia o melhor lance/venda. Sempre que o preço se move a favor da posição aberta em mais de TrailingStopPoints, a ordem stop é reavaliada mais perto do mercado usando ReRegisterOrder. As paradas longas apenas seguem para cima, enquanto as paradas curtas apenas seguem para baixo.
Quando a posição estiver totalmente fechada, todas as ordens de proteção serão canceladas e o estado interno será redefinido. Nenhuma nova ordem de entrada será considerada até que a posição retorne à estabilidade.
Parâmetros
Parâmetro
Descrição
MaxSpreadPoints
Spread máximo permitido antes do cancelamento de ordens pendentes.
TakeProfitPoints
Distância de take-profit aplicada às posições preenchidas.
StopLossPoints
Distância de stop-loss aplicada a posições pendentes e preenchidas.
EntryOffsetPoints
Compensação (em pontos) do bid/ask onde as entradas stop são colocadas.
UseTrailingStop
Permite o gerenciamento de trailing stop para posições abertas.
TrailingStopPoints
Distância (em pontos) mantida pelo trailing stop.
FixedVolume
Volume de negociação enviado com cada ordem de entrada.
EnvelopePeriod
Comprimento do LWMA usado como base do envelope.
EnvelopeDeviation
Largura do envelope em porcentagem.
DistancePoints
Diferença mínima entre preço e envelope necessária para um sinal.
SlippagePoints
Tolerância extra (em pontos) adicionada ao limite de reprecificação.
CandleType
Prazo usado para calcular o envelope LWMA (padrão M5).
Notas
A estratégia assina velas e cotações de nível 1. Se os dados de compra/venda não estiverem disponíveis, as condições de entrada não serão acionadas porque os cálculos de spread e trailing stop dependem disso.
As ordens protetoras de stop e take-profit são recriadas com o volume mais recente sempre que a lógica móvel ajusta o preço do stop-loss.
Todos os comentários dentro do código são escritos em inglês e tabulações são usadas para recuo para corresponder às convenções do projeto.
namespace StockSharp.Samples.Strategies;
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
/// <summary>
/// Template M5 Envelopes strategy: WMA envelope breakout.
/// Buys above upper envelope, sells below lower envelope.
/// </summary>
public class TemplateM5EnvelopesStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _wmaPeriod;
private readonly StrategyParam<decimal> _deviation;
private bool _wasAboveUpper;
private bool _wasBelowLower;
private bool _hasPrevSignal;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int WmaPeriod { get => _wmaPeriod.Value; set => _wmaPeriod.Value = value; }
public decimal Deviation { get => _deviation.Value; set => _deviation.Value = value; }
public TemplateM5EnvelopesStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_wmaPeriod = Param(nameof(WmaPeriod), 50)
.SetGreaterThanZero()
.SetDisplay("WMA Period", "Weighted MA period", "Indicators");
_deviation = Param(nameof(Deviation), 0.3m)
.SetDisplay("Deviation %", "Envelope deviation percent", "Indicators");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_wasAboveUpper = false;
_wasBelowLower = false;
_hasPrevSignal = false;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_hasPrevSignal = false;
var wma = new WeightedMovingAverage { Length = WmaPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(wma, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal wmaValue)
{
if (candle.State != CandleStates.Finished) return;
var close = candle.ClosePrice;
var upper = wmaValue * (1 + Deviation / 100m);
var lower = wmaValue * (1 - Deviation / 100m);
var aboveUpper = close > upper;
var belowLower = close < lower;
if (_hasPrevSignal)
{
if (aboveUpper && !_wasAboveUpper && Position <= 0)
BuyMarket();
else if (belowLower && !_wasBelowLower && Position >= 0)
SellMarket();
}
_wasAboveUpper = aboveUpper;
_wasBelowLower = belowLower;
_hasPrevSignal = true;
}
}
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 WeightedMovingAverage
from StockSharp.Algo.Strategies import Strategy
class template_m5_envelopes_strategy(Strategy):
def __init__(self):
super(template_m5_envelopes_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(30)))
self._wma_period = self.Param("WmaPeriod", 50)
self._deviation = self.Param("Deviation", 0.3)
self._was_above_upper = False
self._was_below_lower = False
self._has_prev_signal = False
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def WmaPeriod(self):
return self._wma_period.Value
@WmaPeriod.setter
def WmaPeriod(self, value):
self._wma_period.Value = value
@property
def Deviation(self):
return self._deviation.Value
@Deviation.setter
def Deviation(self, value):
self._deviation.Value = value
def OnReseted(self):
super(template_m5_envelopes_strategy, self).OnReseted()
self._was_above_upper = False
self._was_below_lower = False
self._has_prev_signal = False
def OnStarted2(self, time):
super(template_m5_envelopes_strategy, self).OnStarted2(time)
self._has_prev_signal = False
wma = WeightedMovingAverage()
wma.Length = self.WmaPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(wma, self._process_candle).Start()
def _process_candle(self, candle, wma_value):
if candle.State != CandleStates.Finished:
return
close = float(candle.ClosePrice)
wma_val = float(wma_value)
upper = wma_val * (1 + float(self.Deviation) / 100.0)
lower = wma_val * (1 - float(self.Deviation) / 100.0)
above_upper = close > upper
below_lower = close < lower
if self._has_prev_signal:
if above_upper and not self._was_above_upper and self.Position <= 0:
self.BuyMarket()
elif below_lower and not self._was_below_lower and self.Position >= 0:
self.SellMarket()
self._was_above_upper = above_upper
self._was_below_lower = below_lower
self._has_prev_signal = True
def CreateClone(self):
return template_m5_envelopes_strategy()