Esta estratégia replica o expert advisor "MA Cross" do MetaTrader 5 (arquivo MA Cross.mq5) dentro do framework StockSharp. O sistema observa duas médias móveis configuráveis e emite ordens de mercado sempre que a média rápida cruzar a média lenta. A implementação mantém o nível original de flexibilidade ao expor o método da média móvel, o preço aplicado e o deslocamento do indicador para ambas as curvas.
Lógica da estratégia
Assinar um único fluxo de velas definido pelo parâmetro CandleType.
Calcular as médias móveis rápida e lenta em cada vela completa. Cada média móvel pode usar um de quatro métodos (simples, exponencial, suavizada ou ponderada linearmente) e lê um dos preços aplicados no estilo MetaTrader (fechamento, abertura, máximo, mínimo, mediana, típico ou ponderado).
Armazenar os valores mais recentes do indicador levando em conta o deslocamento configurado, de modo que os testes de cruzamento sejam realizados em valores de barras anteriores quando necessário.
Detectar um cruzamento de alta quando a média rápida se move de abaixo da média lenta deslocada para acima. Detectar um cruzamento de baixa quando o movimento oposto ocorre.
Emitir ordens de mercado apenas após ambos os indicadores estarem completamente formados e a estratégia estar online. Sinais longos fecham qualquer posição curta existente e abrem uma posição comprada de OrderVolume. Sinais curtos fecham qualquer posição comprada existente e abrem uma posição vendida do mesmo tamanho.
A estratégia opera estritamente em velas completadas e nunca inspeciona dados inacabados. A lógica de proteção é ativada através de StartProtection() para garantir que o StockSharp monitore a posição aberta em busca de condições anormais.
Parâmetros
Nome
Padrão
Descrição
FastPeriod
3
Período da média móvel rápida.
SlowPeriod
13
Período da média móvel lenta.
FastMethod
Simple
Método de média móvel para a linha rápida (simples, exponencial, suavizada ou ponderada linearmente).
SlowMethod
LinearWeighted
Método de média móvel para a linha lenta.
FastPriceType
Close
Preço aplicado usado pela linha rápida (fechamento, abertura, máximo, mínimo, mediana, típico, ponderado).
SlowPriceType
Median
Preço aplicado usado pela linha lenta.
FastShift
0
Número de barras completadas usadas para deslocar a média rápida para a esquerda.
SlowShift
0
Número de barras completadas usadas para deslocar a média lenta para a esquerda.
OrderVolume
1
Volume para cada ordem de mercado.
CandleType
Período de 1 minuto
Série de dados de velas processada pela estratégia.
Todos os parâmetros podem ser otimizados dentro do StockSharp porque o construtor os registra usando os helpers StrategyParam.
Regras de trading
Entrada comprada: Ativada quando a média rápida cruza acima da média lenta de acordo com os valores ajustados pelo deslocamento. Se a estratégia já está vendida, ela submete uma única ordem de compra a mercado para fechar a exposição vendida e abrir uma nova posição comprada. Se não há posição, compra exatamente OrderVolume.
Entrada vendida: Ativada quando a média rápida cruza abaixo da média lenta. A exposição comprada existente é revertida via uma única ordem de venda a mercado; caso contrário, a estratégia abre um novo trade vendido de OrderVolume.
Sem escalonamento adicional: Uma vez posicionado, sinais na mesma direção são ignorados até que o cruzamento oposto ocorra.
Estilo de execução: As ordens são enviadas com BuyMarket ou SellMarket. A estratégia não configura níveis de stop-loss ou take-profit; a gestão de risco pode ser adicionada através de outros módulos do StockSharp, se necessário.
Notas de conversão
A criação do indicador espelha as chamadas iMA do MetaTrader. A enumeração personalizada MovingAverageMethods mapeia MODE_SMA, MODE_EMA, MODE_SMMA e MODE_LWMA para SimpleMovingAverage, ExponentialMovingAverage, SmoothedMovingAverage e WeightedMovingAverage do StockSharp, respectivamente.
O tratamento do preço aplicado reproduz as opções ENUM_APPLIED_PRICE do MetaTrader calculando os preços mediana, típico e ponderado diretamente a partir dos dados das velas.
Os parâmetros de deslocamento reutilizam a lógica original: a estratégia armazena em buffer os valores do indicador e recupera as comparações de entrada e saída de barras anteriores quando FastShift ou SlowShift são positivos.
A lógica de gestão de posições corresponde à abordagem original onde sinais opostos primeiro fecham a posição existente e depois estabelecem uma posição na nova direção na mesma barra.
using System;
using System.Linq;
using System.Collections.Generic;
using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Moving average crossover strategy converted from MetaTrader 5 script.
/// Implements dual SMA crossover signals.
/// </summary>
public class MaCrossStrategy : Strategy
{
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevFast;
private decimal _prevSlow;
private bool _hasPrevValues;
/// <summary>
/// Fast moving average period.
/// </summary>
public int FastPeriod
{
get => _fastPeriod.Value;
set => _fastPeriod.Value = value;
}
/// <summary>
/// Slow moving average period.
/// </summary>
public int SlowPeriod
{
get => _slowPeriod.Value;
set => _slowPeriod.Value = value;
}
/// <summary>
/// Candle type used for calculations.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Initializes strategy parameters.
/// </summary>
public MaCrossStrategy()
{
_fastPeriod = Param(nameof(FastPeriod), 5)
.SetGreaterThanZero()
.SetDisplay("Fast Period", "Period for the fast moving average", "Moving Averages")
.SetOptimize(2, 20, 1);
_slowPeriod = Param(nameof(SlowPeriod), 21)
.SetGreaterThanZero()
.SetDisplay("Slow Period", "Period for the slow moving average", "Moving Averages")
.SetOptimize(5, 60, 1);
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(15).TimeFrame())
.SetDisplay("Candle Type", "Type of candles for calculations", "Data");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevFast = 0m;
_prevSlow = 0m;
_hasPrevValues = false;
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_hasPrevValues = false;
var fastEma = new ExponentialMovingAverage { Length = FastPeriod };
var slowEma = new ExponentialMovingAverage { Length = SlowPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(fastEma, slowEma, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, fastEma);
DrawIndicator(area, slowEma);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal fast, decimal slow)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (_hasPrevValues)
{
var crossUp = _prevFast <= _prevSlow && fast > slow;
var crossDown = _prevFast >= _prevSlow && fast < slow;
if (crossUp && Position <= 0)
{
BuyMarket(Volume + Math.Abs(Position));
}
else if (crossDown && Position >= 0)
{
SellMarket(Volume + Math.Abs(Position));
}
}
_prevFast = fast;
_prevSlow = slow;
_hasPrevValues = 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, Unit, UnitTypes
from StockSharp.Algo.Indicators import ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class ma_cross_strategy(Strategy):
def __init__(self):
super(ma_cross_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 5)
self._slow_period = self.Param("SlowPeriod", 21)
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(15)))
self._prev_fast = 0.0
self._prev_slow = 0.0
self._has_prev_values = False
@property
def FastPeriod(self):
return self._fast_period.Value
@FastPeriod.setter
def FastPeriod(self, value):
self._fast_period.Value = value
@property
def SlowPeriod(self):
return self._slow_period.Value
@SlowPeriod.setter
def SlowPeriod(self, value):
self._slow_period.Value = value
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
def OnStarted2(self, time):
super(ma_cross_strategy, self).OnStarted2(time)
self._has_prev_values = False
self._prev_fast = 0.0
self._prev_slow = 0.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.ProcessCandle).Start()
def ProcessCandle(self, candle, fast_val, slow_val):
if candle.State != CandleStates.Finished:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
fast = float(fast_val)
slow = float(slow_val)
if self._has_prev_values:
cross_up = self._prev_fast <= self._prev_slow and fast > slow
cross_down = self._prev_fast >= self._prev_slow and fast < slow
if cross_up and self.Position <= 0:
self.BuyMarket()
elif cross_down and self.Position >= 0:
self.SellMarket()
self._prev_fast = fast
self._prev_slow = slow
self._has_prev_values = True
def OnReseted(self):
super(ma_cross_strategy, self).OnReseted()
self._prev_fast = 0.0
self._prev_slow = 0.0
self._has_prev_values = False
def CreateClone(self):
return ma_cross_strategy()