Ver no GitHub

Estratégia dupla AG MACD

Visão geral

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;
	}
}