Esta estratégia é uma versão StockSharp do consultor especialista MQL4 "EA - Média Móvel" (arquivo EA - Moving Average.mq4).
Ele negocia um único instrumento reagindo aos cruzamentos de médias móveis que são detectados na abertura de cada nova vela.
Ideia Central
Use uma média móvel exponencial rápida e lenta (EMA) calculada na série de velas selecionada.
Aguarde até que uma nova vela esteja disponível e avalie os valores EMA das duas velas concluídas mais recentemente, replicando as chamadas iMA(..., shift=1/2) do código original.
Abra uma posição longa quando o EMA rápida tiver cruzado acima do EMA lenta na vela anterior, enquanto a vela anterior ainda tinha o EMA rápida abaixo do EMA lenta.
Abra uma posição curta quando o EMA rápida cruzou abaixo do EMA lenta na vela anterior, enquanto a vela anterior ainda tinha o EMA rápida acima do EMA lenta.
Apenas uma posição pode ser aberta por vez. A estratégia ignora novos sinais até que todas as ordens sejam fechadas.
Gerenciamento de ordens
Antes de fazer um pedido, o spread atual é verificado. Se o melhor pedido e o melhor lance estiverem disponíveis, o spread é convertido em pontos de instrumento e comparado com MaxSpreadPoints. Os sinais que excedem o limite são ignorados, assim como a proteção MarketInfo(..., MODE_SPREAD) original.
Após o envio de uma ordem de mercado, a estratégia reflete níveis de proteção em torno do preço de entrada:
O stop loss é colocado no valor EMA lenta da vela anterior mais/menos o StopLossPoints configurado.
O take-profit é definido à mesma distância do preço de entrada que o stop-loss, criando uma meta simétrica como na implementação MQL (Ask + (Ask - StopLoss) / Bid - (StopLoss - Bid)).
Todas as distâncias de preços expressas em pontos são traduzidas em preços absolutos por meio do instrumento PriceStep, portanto, o comportamento corresponde à configuração baseada em pontos de MetaTrader.
Notas de conversão
O especialista original permite escolher diferentes modos de média móvel, mas seus padrões usam EMA (MAMode = 1). A versão StockSharp concentra-se em EMA para manter a implementação concisa; diferentes algoritmos de suavização podem ser adicionados, se necessário.
O volume de negociação é fornecido por meio do parâmetro TradeVolume e mapeado para Strategy.Volume durante OnStarted.
A estratégia depende exclusivamente de dados de velas fornecidos por meio de CandleType. Não há coleções de indicadores adicionais ou buffers históricos além do histórico EMA de dois valores necessário para detectar cruzamentos.
Parâmetros
CandleType – tipo de dados da vela e período de assinatura.
FastPeriod – comprimento do EMA rápido (o padrão é 21).
SlowPeriod – duração da lentidão EMA (o padrão é 84).
StopLossPoints – distância de stop-loss nos pontos do instrumento em relação à lentidão EMA.
MaxSpreadPoints – spread máximo permitido em pontos antes que um novo pedido seja negado.
TradeVolume – tamanho do lote utilizado no envio de ordens de mercado.
Dicas de uso
Selecione o símbolo e o período da vela antes de iniciar a estratégia para que os valores EMA correspondam ao gráfico pretendido em MetaTrader.
Forneça dados de nível 1 (melhor bid/ask) se desejar que o filtro de spread funcione em tempo real; caso contrário, a estratégia assume que o spread é aceitável.
Certifique-se de que a segurança tenha um PriceStep válido. Sem isso, a estratégia não poderá traduzir distâncias baseadas em pontos em preços absolutos e ignorará a colocação de ordens de proteção.
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Moving average crossover strategy using two EMAs.
/// Enters long on golden cross, short on death cross.
/// </summary>
public class MovingAverageCrossoverSpreadStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int FastPeriod
{
get => _fastPeriod.Value;
set => _fastPeriod.Value = value;
}
public int SlowPeriod
{
get => _slowPeriod.Value;
set => _slowPeriod.Value = value;
}
public MovingAverageCrossoverSpreadStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
.SetDisplay("Candle Type", "Candle type", "General");
_fastPeriod = Param(nameof(FastPeriod), 20)
.SetDisplay("Fast EMA", "Fast EMA period", "Indicators");
_slowPeriod = Param(nameof(SlowPeriod), 50)
.SetDisplay("Slow EMA", "Slow EMA period", "Indicators");
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var fastMa = new ExponentialMovingAverage { Length = FastPeriod };
var slowMa = new ExponentialMovingAverage { Length = SlowPeriod };
decimal? prevFast = null;
decimal? prevSlow = null;
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(fastMa, slowMa, (candle, fastValue, slowValue) =>
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (prevFast.HasValue && prevSlow.HasValue)
{
var crossUp = prevFast.Value <= prevSlow.Value && fastValue > slowValue;
var crossDown = prevFast.Value >= prevSlow.Value && fastValue < slowValue;
if (crossUp && Position <= 0)
BuyMarket();
else if (crossDown && Position >= 0)
SellMarket();
}
prevFast = fastValue;
prevSlow = slowValue;
})
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, fastMa);
DrawIndicator(area, slowMa);
DrawOwnTrades(area);
}
}
}