Esta estratégia porta o consultor especializado MetaTrader 5 Simple EA MA plus MACD para a API de alto nível do StockSharp. Busca um rompimento de uma "barra de sinal" que satisfaz duas condições: uma média móvel deslocada está abaixo/acima das máximas da barra, e o histograma MACD acabou de cruzar a linha zero. Quando o próximo candle fecha além do extremo da barra de sinal, a estratégia entra na direção do rompimento.
A implementação mantém o comportamento original do EA:
Detecção de sinal – em cada candle finalizado a estratégia inspeciona a barra anterior. Uma média móvel configurável (padrão LWMA) calculada no preço aplicado escolhido deve ser menor que as máximas dos candles anterior e atual para comprados (maior para vendidos). Simultaneamente a linha principal MACD deve ter cruzado zero entre as duas barras precedentes.
Confirmação de sinal – uma vez armazenada uma barra de sinal, a estratégia aguarda o próximo candle completado. Um fechamento acima da máxima armazenada aciona um rompimento comprado; um fechamento abaixo da mínima armazenada aciona um rompimento vendido. Se o preço invalida o sinal ao fechar de volta dentro da barra de sinal, a configuração é cancelada.
Gestão de posição – novos trades herdam distâncias de stop-loss, take-profit e trailing-stop expressas em pips. Os níveis de proteção são convertidos para preços absolutos usando o PriceStep do instrumento. Instrumentos com três ou cinco decimais recebem o ajuste clássico de forex (step × 10) para imitar as definições de pip do MetaTrader.
Gestão de risco
Stop-loss / take-profit – distâncias opcionais definidas em pips são avaliadas em cada fechamento de candle. Quando o mercado imprime além do nível correspondente, a estratégia sai com uma ordem de mercado.
Trailing stop – quando o lucro supera TrailingStopPips + TrailingStepPips, uma referência de trailing é movida atrás do melhor preço alcançado. Se o preço recuar ao nível de trailing, a posição é fechada. Um passo de trailing zero reativa o stop em cada novo extremo.
Zerar na reversão – se um rompimento oposto aparecer enquanto uma posição oposta está aberta, a estratégia envia uma única ordem de mercado suficientemente grande para fechar a exposição existente e abrir o novo trade em um único movimento.
Notas de implementação
A média móvel suporta os mesmos métodos de suavização e opções de preço aplicado que o MetaTrader (Simple, Exponential, Smoothed, LinearWeighted e preços Close/Open/High/Low/Median/Typical/Weighted).
MaShift reproduz o deslocamento horizontal do indicador MetaTrader lendo valores de barras anteriores antes de avaliar as regras de rompimento.
MACD usa o indicador integrado MovingAverageConvergenceDivergence. Apenas o histograma (diferença entre EMAs rápida e lenta) é necessário; o período da linha de sinal é retido para manter paridade com as configurações do EA.
As assinaturas de candles e o processamento de indicadores dependem exclusivamente da API de alto nível do StockSharp. Nenhum tratamento manual de ticks ou buffers de indicadores são usados.
Parâmetros
Parâmetro
Padrão
Descrição
Volume
1
Tamanho da ordem para cada entrada de rompimento.
TakeProfitPips
50
Distância do alvo de lucro em pips (convertida para preço absoluto usando o passo de preço do instrumento). Definir como 0 para desativar.
StopLossPips
50
Distância do stop de proteção em pips. Definir como 0 para desativar.
TrailingStopPips
5
Distância do trailing stop em pips que é fixada quando o preço avança suficientemente.
TrailingStepPips
5
Progresso adicional mínimo (em pips) antes de o trailing stop avançar novamente.
MaPeriod
100
Comprimento da média móvil usada para validar a barra de sinal.
MaShift
0
Deslocamento horizontal aplicado à média móvil, emulando o parâmetro ma_shift do MetaTrader.
MaMethod
LinearWeighted
Método de suavização da média móvil (Simple, Exponential, Smoothed, LinearWeighted).
MaAppliedPrice
Weighted
Fonte de preço alimentada na média móvil (Close, Open, High, Low, Median, Typical, Weighted).
MacdFastPeriod
12
Período EMA rápida usado no cálculo MACD.
MacdSlowPeriod
26
Período EMA lenta usado no cálculo MACD.
MacdSignalPeriod
9
Período de suavização da linha de sinal retido para paridade com o EA original.
MacdAppliedPrice
Weighted
Preço aplicado ao alimentar valores no MACD.
CandleType
1 hour time frame
Série de candles principal analisada para sinais e gestão de trades.
Dicas de uso
Ajustar as proteções baseadas em pip para corresponder ao tamanho de tick do instrumento selecionado; valores PriceStep incorretos no lado do conector distorcerão as conversões de pip.
Para mercados altamente voláteis, considerar aumentar TrailingStepPips para reduzir saídas prematuras, ou diminuí-lo para ajustar o comportamento de trailing.
Como os trades são executados em candles fechados, o rompimento deve persistir até que a barra seja concluída; habilitar períodos menores aumenta a frequência de negociação mas pode introduzir mais ruído.
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Simple EA MA plus MACD strategy using EMA crossover.
/// Buys when fast EMA crosses above slow EMA, sells on reverse.
/// </summary>
public class SimpleEaMaPlusMacdStrategy : Strategy
{
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private readonly StrategyParam<int> _stopLossPoints;
private readonly StrategyParam<int> _takeProfitPoints;
private ExponentialMovingAverage _fast;
private ExponentialMovingAverage _slow;
private decimal _prevFast;
private decimal _prevSlow;
private decimal _entryPrice;
private int _cooldown;
public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
public int StopLossPoints { get => _stopLossPoints.Value; set => _stopLossPoints.Value = value; }
public int TakeProfitPoints { get => _takeProfitPoints.Value; set => _takeProfitPoints.Value = value; }
public SimpleEaMaPlusMacdStrategy()
{
_fastPeriod = Param(nameof(FastPeriod), 12).SetGreaterThanZero().SetDisplay("Fast Period", "Fast EMA period", "Indicator");
_slowPeriod = Param(nameof(SlowPeriod), 50).SetGreaterThanZero().SetDisplay("Slow Period", "Slow EMA period", "Indicator");
_stopLossPoints = Param(nameof(StopLossPoints), 200).SetNotNegative().SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk");
_takeProfitPoints = Param(nameof(TakeProfitPoints), 400).SetNotNegative().SetDisplay("Take Profit", "Take-profit in price steps", "Risk");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
yield return (Security, TimeSpan.FromMinutes(5).TimeFrame());
}
protected override void OnReseted()
{
base.OnReseted();
_fast = null; _slow = null;
_prevFast = 0; _prevSlow = 0; _entryPrice = 0; _cooldown = 0;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_fast = new ExponentialMovingAverage { Length = FastPeriod };
_slow = new ExponentialMovingAverage { Length = SlowPeriod };
var subscription = SubscribeCandles(TimeSpan.FromMinutes(5).TimeFrame());
subscription.Bind(_fast, _slow, ProcessCandle);
subscription.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal fastValue, decimal slowValue)
{
if (candle.State != CandleStates.Finished) return;
if (!_fast.IsFormed || !_slow.IsFormed) { _prevFast = fastValue; _prevSlow = slowValue; return; }
if (_cooldown > 0) { _cooldown--; _prevFast = fastValue; _prevSlow = slowValue; return; }
var close = candle.ClosePrice;
var step = Security?.PriceStep ?? 1m;
if (Position > 0 && _entryPrice > 0)
{
if (StopLossPoints > 0 && close <= _entryPrice - StopLossPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
if (TakeProfitPoints > 0 && close >= _entryPrice + TakeProfitPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
}
else if (Position < 0 && _entryPrice > 0)
{
if (StopLossPoints > 0 && close >= _entryPrice + StopLossPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
if (TakeProfitPoints > 0 && close <= _entryPrice - TakeProfitPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
}
if (_prevFast <= _prevSlow && fastValue > slowValue && Position <= 0)
{ if (Position < 0) BuyMarket(); BuyMarket(); _entryPrice = close; _cooldown = 100; }
else if (_prevFast >= _prevSlow && fastValue < slowValue && Position >= 0)
{ if (Position > 0) SellMarket(); SellMarket(); _entryPrice = close; _cooldown = 100; }
_prevFast = fastValue; _prevSlow = slowValue;
}
}
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
from datatype_extensions import *
from indicator_extensions import *
class simple_ea_ma_plus_macd_strategy(Strategy):
def __init__(self):
super(simple_ea_ma_plus_macd_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 12).SetGreaterThanZero().SetDisplay("Fast Period", "Fast EMA period", "Indicator")
self._slow_period = self.Param("SlowPeriod", 50).SetGreaterThanZero().SetDisplay("Slow Period", "Slow EMA period", "Indicator")
self._sl_points = self.Param("StopLossPoints", 200).SetNotNegative().SetDisplay("Stop Loss", "SL in price steps", "Risk")
self._tp_points = self.Param("TakeProfitPoints", 400).SetNotNegative().SetDisplay("Take Profit", "TP in price steps", "Risk")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))).SetDisplay("Candle Type", "Candle type", "General")
@property
def CandleType(self): return self._candle_type.Value
@CandleType.setter
def CandleType(self, value): self._candle_type.Value = value
def OnReseted(self):
super(simple_ea_ma_plus_macd_strategy, self).OnReseted()
self._prev_fast = 0
self._prev_slow = 0
self._entry_price = 0
self._cooldown = 0
def OnStarted2(self, time):
super(simple_ea_ma_plus_macd_strategy, self).OnStarted2(time)
self._prev_fast = 0
self._prev_slow = 0
self._entry_price = 0
self._cooldown = 0
self._step = 1.0
if self.Security is not None and self.Security.PriceStep is not None and self.Security.PriceStep > 0:
self._step = float(self.Security.PriceStep)
fast = ExponentialMovingAverage()
fast.Length = self._fast_period.Value
slow = ExponentialMovingAverage()
slow.Length = self._slow_period.Value
sub = self.SubscribeCandles(self.CandleType)
sub.Bind(fast, slow, self.OnProcess).Start()
def OnProcess(self, candle, fast_val, slow_val):
if candle.State != CandleStates.Finished:
return
if self._prev_fast == 0 or self._prev_slow == 0:
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self._cooldown > 0:
self._cooldown -= 1
self._prev_fast = fast_val
self._prev_slow = slow_val
return
close = float(candle.ClosePrice)
step = self._step
# Manage SL/TP
if self.Position > 0 and self._entry_price > 0:
if self._sl_points.Value > 0 and close <= self._entry_price - self._sl_points.Value * step:
self.SellMarket()
self._entry_price = 0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self._tp_points.Value > 0 and close >= self._entry_price + self._tp_points.Value * step:
self.SellMarket()
self._entry_price = 0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
elif self.Position < 0 and self._entry_price > 0:
if self._sl_points.Value > 0 and close >= self._entry_price + self._sl_points.Value * step:
self.BuyMarket()
self._entry_price = 0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self._tp_points.Value > 0 and close <= self._entry_price - self._tp_points.Value * step:
self.BuyMarket()
self._entry_price = 0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
# Crossover signals
if self._prev_fast <= self._prev_slow and fast_val > slow_val and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
self._entry_price = close
self._cooldown = 100
elif self._prev_fast >= self._prev_slow and fast_val < slow_val and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._entry_price = close
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
def CreateClone(self):
return simple_ea_ma_plus_macd_strategy()