Ver en GitHub

Estrategia dual AG MACD

Descripción general

Esta estrategia es una adaptación StockSharp del experto MetaTrader 4 AG.mq4. El robot opera con dos cálculos de convergencia y divergencia de media móvil (MACD) que utilizan diferentes conjuntos de parámetros. El MACD primario produce activadores de entrada, mientras que el MACD secundario (escalado) actúa como un filtro direccional para evitar operaciones contratendencias y controlar las salidas. La lógica refleja al experto MQL4 original al evaluar solo velas cerradas y reutilizar las comprobaciones de señales de la línea de señal que activaron las órdenes originales.

Lógica de trading

  • Indicadores
    • Primario MACD: EMA rápida = FastEmaLength, EMA lenta = SlowEmaLength, señal SMA = SignalSmaLength.
    • Secundario MACD: EMA rápida = SlowEmaLength * 2, EMA lenta = FastEmaLength * 2, señal SMA = SignalSmaLength * 2.
  • Entrada larga
    • La línea principal primaria MACD está por encima de su línea de señal.
    • La línea de señal primaria MACD es negativa (debajo de la línea de flotación).
    • La línea principal secundaria MACD está por encima de su línea de señal.
    • La línea de señal secundaria MACD es negativa.
  • Entrada corta
    • La línea principal primaria MACD está debajo de su línea de señal.
    • La línea de señal primaria MACD es positiva.
    • La línea principal secundaria MACD está debajo de su línea de señal.
    • La línea de señal secundaria MACD es positiva.
  • Reglas de salida
    • Cierre posiciones largas cuando el MACD secundario se vuelva bajista mientras la línea de señal primaria se mantiene por encima de cero.
    • Cierre posiciones cortas cuando el MACD secundario se vuelva alcista mientras la línea de señal primaria permanece por debajo de cero.
  • La estrategia sólo reacciona a las velas terminadas e ignora las barras sin terminar para evitar volver a pintarlas.

Gestión de Puestos

  • Todas las órdenes son órdenes de mercado con el volumen fijo definido por OrderVolume.
  • MaxOpenOrders refleja la entrada original ORDER y limita el número total de órdenes activas más posiciones abiertas. Configúrelo en 0 para quitar la tapa.
  • StartProtection() se habilita una vez que comienza la estrategia para que el administrador de riesgos StockSharp pueda monitorear la exposición abierta.

Parámetros

Nombre Descripción
OrderVolume Tamaño de lote base para nuevas operaciones.
FastEmaLength Período EMA rápida del MACD primario.
SlowEmaLength Período EMA lenta del MACD primario.
SignalSmaLength Período de suavizado de señal para ambos MACD.
MaxOpenOrders Número máximo de órdenes activas y posiciones abiertas combinadas. Establece 0 para ilimitado.
CandleType Marco de tiempo utilizado para construir velas para ambos indicadores.

Notas

  • El MACD secundario mantiene el mismo orden rápido/lento que en el EA original, incluso si el período rápido se vuelve más grande que el lento, para preservar los cálculos del autor.
  • La estrategia no coloca órdenes pendientes; se abre o cierra en el mercado tan pronto como aparecen las condiciones.
  • No se agregan niveles adicionales de stop-loss o take-profit porque el experto original se basó exclusivamente en las reversiones de señales.
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;
	}
}