Esta estratégia é uma versão StockSharp do MetaTrader 4 especialista AG.mq4. O robô opera com dois cálculos de média móvel, convergência e divergência (MACD) que usam conjuntos de parâmetros diferentes. O MACD primário produz gatilhos de entrada, enquanto o MACD secundário (escalado) atua como um filtro direcional para evitar negociações contra-tendência e controlar saídas. A lógica reflete o especialista MQL4 original, avaliando apenas velas fechadas e reutilizando as verificações de sinal da linha de sinal que bloquearam os pedidos originais.
Lógica de negociação
Indicadores
Primário MACD: EMA rápida = FastEmaLength, EMA lenta = SlowEmaLength, sinal SMA = SignalSmaLength.
Secundário MACD: EMA rápida = SlowEmaLength * 2, EMA lenta = FastEmaLength * 2, sinal SMA = SignalSmaLength * 2.
Entrada longa
A linha principal MACD primária está acima de sua linha de sinal.
A linha de sinal primária MACD é negativa (abaixo da linha d'água).
A linha principal secundária MACD está acima de sua linha de sinal.
A linha de sinal secundária MACD é negativa.
Entrada curta
A linha principal MACD primária está abaixo de sua linha de sinal.
A linha de sinal primária MACD é positiva.
A linha principal secundária MACD está abaixo de sua linha de sinal.
A linha de sinal secundária MACD é positiva.
Regras de saída
Feche as posições longas quando o secundário MACD ficar em baixa enquanto a linha de sinal primária permanecer acima de zero.
Feche as posições vendidas quando o secundário MACD se tornar otimista enquanto a linha de sinal primária permanecer abaixo de zero.
A estratégia reage apenas às velas acabadas e ignora as barras inacabadas para evitar a repintura.
Gerenciamento de posição
Todas as ordens são ordens de mercado com volume fixo definido por OrderVolume.
MaxOpenOrders espelha a entrada original ORDER e limita o número total de pedidos ativos mais posições abertas. Defina-o como 0 para remover a tampa.
StartProtection() é ativado assim que a estratégia é iniciada para que o gerente de risco StockSharp possa monitorar a exposição aberta.
Parâmetros
Nome
Descrição
OrderVolume
Tamanho base do lote para novas negociações.
FastEmaLength
Período EMA rápido do MACD primário.
SlowEmaLength
Período EMA lento do MACD primário.
SignalSmaLength
Período de suavização de sinal para ambos os MACDs.
MaxOpenOrders
Número máximo de ordens ativas e posições abertas combinadas. Defina 0 como ilimitado.
CandleType
Período usado para construir velas para ambos os indicadores.
Notas
O MACD secundário mantém a mesma ordem rápido/lento do EA original, mesmo que o período rápido se torne maior que o lento, para preservar os cálculos do autor.
A estratégia não coloca ordens pendentes; ele abre ou fecha no mercado assim que as condições aparecem.
Nenhum nível adicional de stop-loss ou take-profit é adicionado porque o especialista original confiou exclusivamente em reversões de sinal.
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>
/// AG MACD Dual strategy - MACD histogram crossover with EMA trend filter.
/// Buys when MACD histogram crosses above zero while price is above EMA.
/// Sells when MACD histogram crosses below zero while price is below EMA.
/// </summary>
public class AgMacdDualStrategy : Strategy
{
private readonly StrategyParam<int> _emaPeriod;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevMacd;
private decimal _prevSignal;
private bool _hasPrev;
private decimal _currentEma;
public int EmaPeriod { get => _emaPeriod.Value; set => _emaPeriod.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public AgMacdDualStrategy()
{
_emaPeriod = Param(nameof(EmaPeriod), 50)
.SetDisplay("EMA Period", "EMA trend filter", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities() => [(Security, CandleType)];
protected override void OnReseted() { base.OnReseted(); _prevMacd = 0m; _prevSignal = 0m; _hasPrev = false; _currentEma = 0m; }
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_hasPrev = false;
var macd = new MovingAverageConvergenceDivergenceSignal();
var ema = new ExponentialMovingAverage { Length = EmaPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(macd, ProcessMacd)
.Bind(ema, ProcessEma)
.Start();
}
private void ProcessEma(ICandleMessage candle, decimal ema)
{
if (candle.State != CandleStates.Finished)
return;
_currentEma = ema;
}
private void ProcessMacd(ICandleMessage candle, IIndicatorValue value)
{
if (candle.State != CandleStates.Finished)
return;
if (!value.IsFinal || value.IsEmpty)
return;
var macdVal = value as MovingAverageConvergenceDivergenceSignalValue;
if (macdVal == null)
return;
var macdLine = macdVal.Macd;
var signalLine = macdVal.Signal;
if (macdLine == null || signalLine == null)
return;
var histogram = macdLine.Value - signalLine.Value;
if (!_hasPrev)
{
_prevMacd = macdLine.Value;
_prevSignal = signalLine.Value;
_hasPrev = true;
return;
}
var prevHist = _prevMacd - _prevSignal;
var close = candle.ClosePrice;
if (prevHist <= 0 && histogram > 0 && close > _currentEma && Position <= 0)
{
if (Position < 0)
BuyMarket();
BuyMarket();
}
else if (prevHist >= 0 && histogram < 0 && close < _currentEma && Position >= 0)
{
if (Position > 0)
SellMarket();
SellMarket();
}
_prevMacd = macdLine.Value;
_prevSignal = signalLine.Value;
}
}
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 MovingAverageConvergenceDivergenceSignal, ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class ag_macd_dual_strategy(Strategy):
def __init__(self):
super(ag_macd_dual_strategy, self).__init__()
self._ema_period = self.Param("EmaPeriod", 50).SetDisplay("EMA Period", "EMA trend filter", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))).SetDisplay("Candle Type", "Candle timeframe", "General")
self._prev_macd = 0.0; self._prev_signal = 0.0; self._has_prev = False; self._current_ema = 0.0
@property
def ema_period(self): return self._ema_period.Value
@property
def candle_type(self): return self._candle_type.Value
def OnReseted(self):
super(ag_macd_dual_strategy, self).OnReseted()
self._prev_macd = 0.0; self._prev_signal = 0.0; self._has_prev = False; self._current_ema = 0.0
def OnStarted2(self, time):
super(ag_macd_dual_strategy, self).OnStarted2(time)
self._has_prev = False
macd = MovingAverageConvergenceDivergenceSignal()
ema = ExponentialMovingAverage(); ema.Length = self.ema_period
sub = self.SubscribeCandles(self.candle_type)
sub.BindEx(macd, self.process_macd).Bind(ema, self.process_ema).Start()
def process_ema(self, candle, ema):
if candle.State != CandleStates.Finished: return
self._current_ema = float(ema)
def process_macd(self, candle, value):
if candle.State != CandleStates.Finished: return
if not value.IsFinal or value.IsEmpty: return
if value.Macd is None or value.Signal is None: return
ml = float(value.Macd); sl = float(value.Signal); hist = ml - sl
if not self._has_prev: self._prev_macd = ml; self._prev_signal = sl; self._has_prev = True; return
prev_hist = self._prev_macd - self._prev_signal; close = float(candle.ClosePrice)
if prev_hist <= 0 and hist > 0 and close > self._current_ema and self.Position <= 0:
if self.Position < 0: self.BuyMarket()
self.BuyMarket()
elif prev_hist >= 0 and hist < 0 and close < self._current_ema and self.Position >= 0:
if self.Position > 0: self.SellMarket()
self.SellMarket()
self._prev_macd = ml; self._prev_signal = sl
def CreateClone(self): return ag_macd_dual_strategy()