Convertida do especialista do MetaTrader 5 "MA Envelopes". A estratégia busca retrações de preço em direção a uma média móvel envolvida por um canal de envelopes. Quando uma vela concluída fecha entre a média móvel e uma das bandas do envelope durante a janela de trading configurada, a estratégia coloca entradas limitadas na média móvil com ordens de saída protetoras derivadas do envelope.
Lógica de trading
Uma média móvel é calculada com o método, fonte de preço e período selecionados. O mesmo valor é usado para construir bandas simétricas de envelope usando o parâmetro de desvio.
Quando uma vela concluída fecha acima da média móvil mas abaixo da banda superior do envelope e o preço ask atual permanece acima da média móvil, uma sequência escalonada de ordens de compra limitadas é preparada no preço da média móvil.
Cada compra limitada usa o envelope inferior como nível de stop-loss e o envelope superior mais um offset adicional em pips como take-profit.
Até três ordens independentes são gerenciadas, cada uma com seu próprio offset de take-profit (parâmetros SL/TP de First, Second, Third).
Quando uma vela concluída fecha abaixo da média móvil mas acima da banda inferior do envelope e o preço bid atual permanece abaixo da média móvil, a lógica é espelhada para ordens de venda limitadas.
A janela de trading é controlada por StartHour e EndHour (hora do terminal). Após a hora de fim, todas as ordens de entrada ainda ativas são canceladas.
O risco por trade é estimado através de MaximumRisk e reduzido após perdas consecutivas usando DecreaseFactor. O volume da ordem é alinhado ao passo de volume e aos limites do instrumento.
Uma vez que uma ordem de entrada está completamente preenchida, as ordens de stop-loss e take-profit protetoras são registradas imediatamente. Se uma ordem de saída for acionada, a ordem contraparte é cancelada e, se houver volume de posição restante, novas ordens protetoras são emitidas para o restante.
Parâmetros
Parâmetro
Descrição
MaximumRisk
Fração do capital disponível arriscado por posição.
DecreaseFactor
Reduz o tamanho da posição após trades perdedores consecutivos.
First/Second/ThirdStopTakeProfitPips
Distâncias em pips adicionadas às bandas do envelope para as três ordens escalonadas.
StartHour, EndHour
Limites da sessão de trading em hora do terminal (0–23).
MaPeriod, MaShift, MaMethodType, AppliedPrice
Configuração da média móvil.
EnvelopeDeviation
Largura do canal de envelope em porcentagem.
CandleType
Período das velas usadas para os cálculos.
Notas
Ordens protetoras são recriadas sempre que apenas parte de uma posição é fechada, mantendo o tamanho restante coberto.
Ordens de entrada pendentes são canceladas ao final da sessão; posições abertas continuam sendo gerenciadas por suas ordens protetoras.
A estratégia depende de atualizações do livro de ordens para capturar os últimos preços bid/ask; os valores de fechamento das velas são usados como alternativa quando os dados do livro de ordens não estão disponíveis.
using System;
using System.Collections.Generic;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
public class MaEnvelopesStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _period;
private decimal? _prevHigh, _prevLow;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int Period { get => _period.Value; set => _period.Value = value; }
public MaEnvelopesStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame()).SetDisplay("Candle Type", "Timeframe", "General");
_period = Param(nameof(Period), 15).SetGreaterThanZero().SetDisplay("Channel Period", "Channel lookback", "Indicators");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities() => [(Security, CandleType)];
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevHigh = null;
_prevLow = null;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevHigh = null; _prevLow = null;
var highest = new Highest { Length = Period };
var lowest = new Lowest { Length = Period };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(highest, lowest, ProcessCandle).Start();
var area = CreateChartArea();
if (area != null) { DrawCandles(area, subscription); DrawOwnTrades(area); }
}
private void ProcessCandle(ICandleMessage candle, decimal high, decimal low)
{
if (candle.State != CandleStates.Finished) return;
if (!IsFormedAndOnlineAndAllowTrading()) { _prevHigh = high; _prevLow = low; return; }
if (_prevHigh == null || _prevLow == null) { _prevHigh = high; _prevLow = low; return; }
if (candle.ClosePrice > _prevHigh.Value && Position <= 0) { if (Position < 0) BuyMarket(); BuyMarket(); }
else if (candle.ClosePrice < _prevLow.Value && Position >= 0) { if (Position > 0) SellMarket(); SellMarket(); }
_prevHigh = high; _prevLow = low;
}
}
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 Highest, Lowest
from StockSharp.Algo.Strategies import Strategy
class ma_envelopes_strategy(Strategy):
def __init__(self):
super(ma_envelopes_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Timeframe", "General")
self._period = self.Param("Period", 15) \
.SetDisplay("Channel Period", "Channel lookback", "Indicators")
self._prev_high = None
self._prev_low = None
@property
def CandleType(self):
return self._candle_type.Value
@property
def Period(self):
return self._period.Value
def OnReseted(self):
super(ma_envelopes_strategy, self).OnReseted()
self._prev_high = None
self._prev_low = None
def OnStarted2(self, time):
super(ma_envelopes_strategy, self).OnStarted2(time)
self._prev_high = None
self._prev_low = None
highest = Highest()
highest.Length = self.Period
lowest = Lowest()
lowest.Length = self.Period
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(highest, lowest, self._on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def _on_process(self, candle, high_value, low_value):
if candle.State != CandleStates.Finished:
return
hv = float(high_value)
lv = float(low_value)
if self._prev_high is None or self._prev_low is None:
self._prev_high = hv
self._prev_low = lv
return
close = float(candle.ClosePrice)
if close > self._prev_high and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif close < self._prev_low and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_high = hv
self._prev_low = lv
def CreateClone(self):
return ma_envelopes_strategy()