Esta estratégia é uma porta em C# do consultor especialista MetaTrader 5 3sma.mq5 (id 21495). Segue a mesma ideia de negociar quando três médias móveis simples se separam umas das outras por um spread configurável. A implementação usa a API de alto nível do StockSharp com assinaturas de velas e vinculação de indicadores para que nenhum gerenciamento manual de séries seja necessário.
Comportamento original do MT5
O especialista MT5 baseia-se em três médias móveis simples com diferentes períodos e deslocamentos de exibição. A média rápida usa a barra atual, enquanto as médias média e lenta são deslocadas uma e duas barras para o passado. Em cada tick:
Converte o spread definido pelo usuário de pips para unidades de preço com base na precisão do símbolo.
Fecha posições compradas quando a SMA rápida cai abaixo da SMA média em pelo menos metade do spread, e fecha posições vendidas quando a SMA rápida sobe acima da SMA média em metade do spread.
Abre novas posições compradas se MA1 > MA2 + spread e MA2 > MA3 + spread enquanto nenhum outro trade comprado do especialista permanecer. Analogamente, abre posições vendidas quando todas as três médias estão alinhadas na ordem oposta.
Usa apenas ordens de mercado com um tamanho de lote fixo e não aplica níveis explícitos de stop-loss ou take-profit.
Implementação no StockSharp
Indicadores – três instâncias de SimpleMovingAverage se inscrevem na mesma fonte de velas. Buffers de histórico compactos reproduzem os parâmetros de "shift" do MT5 para que cada comparação use valores de barras terminadas com os deslocamentos solicitados.
Tratamento do spread – o parâmetro de spread é inserido em pips. A estratégia deriva um tamanho de pip de Security.PriceStep (ou Security.Step) e multiplica por dez para símbolos FX de 3/5 dígitos, coincidindo com o ajuste do MT5 para cotações fracionárias.
Fluxo de ordens – as ordens são enviadas com BuyMarket/SellMarket. Quando uma condição de reversão aparece, a estratégia adiciona o valor absoluto da posição líquida atual ao volume base para nivelar a exposição oposta e estabelecer a nova direção com uma única ordem de mercado.
Visualização – se gráficos estiverem disponíveis, a estratégia traça as velas fonte junto com as três médias móveis e trades executados.
Parâmetros
Nome
Descrição
Padrão
Volume
Volume de ordem usado para cada entrada de mercado.
0.1
FastMaPeriod
Período da SMA rápida (equivalente a MA1 no MT5).
9
FastMaShift
Número de barras terminadas usadas para deslocar a SMA rápida.
0
MiddleMaPeriod
Período da SMA média (MA2).
14
MiddleMaShift
Deslocamento em barras terminadas para a SMA média.
1
SlowMaPeriod
Período da SMA lenta (MA3).
29
SlowMaShift
Deslocamento em barras terminadas para a SMA lenta.
2
MaSpreadPips
Spread mínimo requerido entre SMAs consecutivas medido em pips.
10
CandleType
Série de velas usada para cálculos.
Período de 1 minuto
Lógica de trading
Aguardar até que todas as três médias móveis estejam formadas e os buffers de histórico contenham valores para os deslocamentos solicitados.
Converter o parâmetro de spread de pips para unidades de preço e calcular o meio-spread para filtros de saída.
Filtros de saída –
Fechar exposição comprada se a SMA rápida deslocada cair abaixo da SMA média deslocada em pelo menos metade do spread.
Fechar exposição vendida se a SMA rápida deslocada subir acima da SMA média deslocada em pelo menos metade do spread.
Condições de entrada –
Entrar comprado (ou reverter de vendido para comprado) quando a SMA rápida é maior que a SMA média mais o spread e a SMA média é maior que a SMA lenta mais o spread.
Entrar vendido (ou reverter de comprado para vendido) quando a SMA rápida é menor que a SMA média menos o spread e a SMA média é menor que a SMA lenta menos o spread.
Diferenças da versão MT5
O StockSharp trabalha com uma única posição líquida por instrumento. Quando um sinal de reversão aparece, a estratégia emite uma única ordem de mercado dimensionada para aplanar a exposição líquida anterior e estabelecer a nova direção. O especialista MT5 poderia manter posições compradas e vendidas independentes.
A conversão de pips usa os melhores metadados de Security disponíveis. Se o broker não fornecer nem PriceStep nem Step, o valor 1 é usado como fallback.
As ordens são enviadas em velas terminadas em vez de cada tick porque a API de alto nível opera em assinaturas de velas.
A estratégia não implementa os helpers de registro verboso do código MT5; o registro integrado do StockSharp pode ser usado se necessário.
Notas de uso
Garantir que a série de velas selecionada corresponda ao período usado na configuração original do MT5.
Ajustar o parâmetro de spread sempre que o instrumento usar tamanhos de pip não padrão.
Como a estratégia trabalha com velas terminadas, a execução será atrasada até que a vela atual feche.
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>
/// Triple SMA strategy that trades when three moving averages are properly aligned.
/// Enters long when fast > middle > slow, enters short when fast < middle < slow.
/// </summary>
public class TripleSmaSpreadStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _middlePeriod;
private readonly StrategyParam<int> _slowPeriod;
private int _prevSignal;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int FastPeriod
{
get => _fastPeriod.Value;
set => _fastPeriod.Value = value;
}
public int MiddlePeriod
{
get => _middlePeriod.Value;
set => _middlePeriod.Value = value;
}
public int SlowPeriod
{
get => _slowPeriod.Value;
set => _slowPeriod.Value = value;
}
public TripleSmaSpreadStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Timeframe", "General");
_fastPeriod = Param(nameof(FastPeriod), 9)
.SetGreaterThanZero()
.SetDisplay("Fast Period", "Fast SMA period", "Indicators");
_middlePeriod = Param(nameof(MiddlePeriod), 14)
.SetGreaterThanZero()
.SetDisplay("Middle Period", "Middle SMA period", "Indicators");
_slowPeriod = Param(nameof(SlowPeriod), 29)
.SetGreaterThanZero()
.SetDisplay("Slow Period", "Slow SMA period", "Indicators");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevSignal = 0;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevSignal = 0;
var fastSma = new ExponentialMovingAverage { Length = FastPeriod };
var slowSma = new ExponentialMovingAverage { Length = SlowPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(fastSma, slowSma, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, fastSma);
DrawIndicator(area, slowSma);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal fast, decimal slow)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var close = candle.ClosePrice;
var signal = 0;
if (fast > slow && close > fast)
signal = 1;
else if (fast < slow && close < fast)
signal = -1;
if (signal == _prevSignal)
return;
var oldSignal = _prevSignal;
_prevSignal = signal;
if (signal == 1 && oldSignal <= 0)
{
if (Position < 0)
BuyMarket();
if (Position <= 0)
BuyMarket();
}
else if (signal == -1 && oldSignal >= 0)
{
if (Position > 0)
SellMarket();
if (Position >= 0)
SellMarket();
}
}
}
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
from StockSharp.Algo.Strategies import Strategy
class triple_sma_spread_strategy(Strategy):
def __init__(self):
super(triple_sma_spread_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))) \
.SetDisplay("Candle Type", "Timeframe", "General")
self._fast_period = self.Param("FastPeriod", 9) \
.SetDisplay("Fast Period", "Fast SMA period", "Indicators")
self._middle_period = self.Param("MiddlePeriod", 14) \
.SetDisplay("Middle Period", "Middle SMA period", "Indicators")
self._slow_period = self.Param("SlowPeriod", 29) \
.SetDisplay("Slow Period", "Slow SMA period", "Indicators")
self._prev_signal = 0
@property
def CandleType(self):
return self._candle_type.Value
@property
def FastPeriod(self):
return self._fast_period.Value
@property
def MiddlePeriod(self):
return self._middle_period.Value
@property
def SlowPeriod(self):
return self._slow_period.Value
def OnReseted(self):
super(triple_sma_spread_strategy, self).OnReseted()
self._prev_signal = 0
def OnStarted2(self, time):
super(triple_sma_spread_strategy, self).OnStarted2(time)
self._prev_signal = 0
fast_ema = ExponentialMovingAverage()
fast_ema.Length = self.FastPeriod
slow_ema = ExponentialMovingAverage()
slow_ema.Length = self.SlowPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(fast_ema, slow_ema, self._on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, fast_ema)
self.DrawIndicator(area, slow_ema)
self.DrawOwnTrades(area)
def _on_process(self, candle, fast_value, slow_value):
if candle.State != CandleStates.Finished:
return
close = float(candle.ClosePrice)
fv = float(fast_value)
sv = float(slow_value)
signal = 0
if fv > sv and close > fv:
signal = 1
elif fv < sv and close < fv:
signal = -1
if signal == self._prev_signal:
return
old_signal = self._prev_signal
self._prev_signal = signal
if signal == 1 and old_signal <= 0:
if self.Position < 0:
self.BuyMarket()
if self.Position <= 0:
self.BuyMarket()
elif signal == -1 and old_signal >= 0:
if self.Position > 0:
self.SellMarket()
if self.Position >= 0:
self.SellMarket()
def CreateClone(self):
return triple_sma_spread_strategy()