Ver no GitHub

Estratégia Simple MACD

Simple MACD replica a lógica do assessor MQL5 Simple_MACD.mq5 no StockSharp. A estratégia segue a inclinação da linha principal do MACD calculada em velas completadas e continua adicionando à posição sempre que a inclinação permanecer na mesma direção.

Visão Geral

  • Mercado: qualquer instrumento com dados de velas e horários de trading contínuos.
  • Indicador principal: Convergência/Divergência de Médias Móveis (MACD) usando médias móveis exponenciais 12/26 e sinal 9.
  • Abordagem: seguimento de momentum. A estratégia compara as duas leituras de MACD completadas mais recentes e vai comprado quando a linha sobe, ou vendido quando a linha cai.
  • Tipo de ordem: apenas ordens de mercado. Cada sinal agrega a quantidade necessária para fechar a posição oposta e adiciona o volume de trading configurado em cima, espelhando o assessor especialista original.

Notas de Conversão

  • O bot MQL5 acionava uma vez por nova barra comparando MACD(1) e MACD(2) (as duas barras completadas anteriores). No StockSharp, a mesma comparação é executada quando uma vela termina, antes da próxima barra começar.
  • A versão MQL dependia de enumeração explícita de posições e verificações manuais de volume. A versão StockSharp agrega o volume automaticamente com chamadas BuyMarket/SellMarket e o parâmetro TradeVolume da estratégia.
  • As verificações de hedge do código MQL não são necessárias porque o StockSharp rastreia a posição líquida diretamente.

Regras de Trading

Entrada e Escalonamento

  1. Calcular a linha principal do MACD em cada vela terminada.
  2. Armazenar os dois últimos valores do MACD e compará-los:
    • Se MACD(1) > MACD(2), a inclinação é de alta. A estratégia compra um volume igual a TradeVolume + max(0, -Posição) para fechar vendidos e adicionar novos comprados.
    • Se MACD(1) < MACD(2), a inclinação é de baixa. A estratégia vende TradeVolume + max(0, Posição) para fechar comprados e adicionar novos vendidos.
  3. Se ambos os valores são iguais, nenhuma nova ordem é enviada.

Gestão de Posições

  • A estratégia continua empilhando ordens na direção atual enquanto a inclinação do MACD não mudar de sinal, assim como o assessor original que enviava uma compra ou venda em cada barra qualificada.
  • Sinais opostos eliminam qualquer exposição aberta antes de construir a nova posição.
  • Não há níveis de stop-loss ou take profit incorporados; o controle de risco depende de regras externas de gestão de dinheiro ou supervisão manual.

Salvaguardas Adicionais

  • O trading é ignorado até que o indicador MACD esteja completamente formado.
  • Apenas velas completadas (CandleStates.Finished) são processadas, prevenindo ações prematuras em dados parciais.
  • As mensagens de log rastreiam cada negociação e mostram os dois valores do MACD usados para tomar a decisão para uma análise de backtesting mais fácil.

Parâmetros

Parâmetro Valor padrão Descrição
FastPeriod 12 Comprimento da EMA rápida para o cálculo do MACD.
SlowPeriod 26 Comprimento da EMA lenta para o cálculo do MACD.
SignalPeriod 9 Período da EMA de sinal retido por compatibilidade com as configurações originais.
TradeVolume 0.1 Volume adicionado em cada sinal antes de contabilizar a reversão de posição.
CandleType Período de 1 minuto Tipo de vela usado para alimentar o indicador. Ajustável para qualquer período desejado.

Todos os parâmetros são expostos como parâmetros de estratégia e marcados como otimizáveis onde relevante.

Visualização

  • A estratégia cria automaticamente uma área de gráfico (quando disponível) com as velas de preço e sobrepõe a saída do indicador MACD.
  • As negociações próprias são desenhadas no gráfico para mostrar com que frequência a estratégia escala posições em condições de tendência.

Uso Recomendado

  • Aplicar em instrumentos com tendência onde o momentum persiste por várias barras; mercados em range causarão reversões frequentes e negociações whipsaw.
  • Combinar com gestão de risco em nível de portfólio já que a lógica base não tem mecanismo de stop intrínseco.
  • Considerar otimizar o TradeVolume e os períodos do MACD para o instrumento e período alvo.

Arquivos

  • CS/SimpleMacdStrategy.cs – implementação em StockSharp da lógica da estratégia.
  • README.md, README_ru.md, README_zh.md – documentação detalhada em três idiomas.
using System;
using System.Linq;
using System.Collections.Generic;

using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;

using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Simple MACD slope-following strategy converted from MQL5 Simple_MACD.mq5.
/// The strategy evaluates the MACD main line on completed candles and builds positions accordingly.
/// </summary>
public class SimpleMacdStrategy : Strategy
{
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private readonly StrategyParam<int> _signalPeriod;
	private readonly StrategyParam<decimal> _tradeVolume;
	private readonly StrategyParam<DataType> _candleType;

	private MovingAverageConvergenceDivergence _macd = null!;
	private decimal? _previousMacdValue;
	private decimal? _prePreviousMacdValue;
	private int? _previousSlope;

	/// <summary>
	/// Fast EMA period used for the MACD main line.
	/// </summary>
	public int FastPeriod
	{
		get => _fastPeriod.Value;
		set => _fastPeriod.Value = value;
	}

	/// <summary>
	/// Slow EMA period used for the MACD main line.
	/// </summary>
	public int SlowPeriod
	{
		get => _slowPeriod.Value;
		set => _slowPeriod.Value = value;
	}

	/// <summary>
	/// Signal EMA period used by the MACD indicator.
	/// </summary>
	public int SignalPeriod
	{
		get => _signalPeriod.Value;
		set => _signalPeriod.Value = value;
	}

	/// <summary>
	/// Trading volume applied when new orders are sent.
	/// </summary>
	public decimal TradeVolume
	{
		get => _tradeVolume.Value;
		set => _tradeVolume.Value = value;
	}

	/// <summary>
	/// Candle type used to feed the MACD indicator.
	/// </summary>
	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	/// <summary>
	/// Initialize Simple MACD strategy with default parameters.
	/// </summary>
	public SimpleMacdStrategy()
	{
		_fastPeriod = Param(nameof(FastPeriod), 12)
			.SetDisplay("MACD Fast Period", "Fast EMA length for MACD calculation", "Indicators")
			
			.SetOptimize(6, 18, 2);

		_slowPeriod = Param(nameof(SlowPeriod), 26)
			.SetDisplay("MACD Slow Period", "Slow EMA length for MACD calculation", "Indicators")
			
			.SetOptimize(20, 40, 2);

		_signalPeriod = Param(nameof(SignalPeriod), 9)
			.SetDisplay("MACD Signal Period", "Signal EMA length maintained for compatibility", "Indicators")
			
			.SetOptimize(6, 18, 1);

		_tradeVolume = Param(nameof(TradeVolume), 0.1m)
			.SetDisplay("Trade Volume", "Order volume used for each signal", "Risk")
			
			.SetOptimize(0.1m, 1m, 0.1m);

		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe for MACD calculations", "General");
	}

	/// <inheritdoc />
	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		return [(Security, CandleType)];
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();

		_previousMacdValue = null;
		_prePreviousMacdValue = null;
		_previousSlope = null;
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		// Configure MACD indicator to match the source MQL strategy settings.
		_macd = new MovingAverageConvergenceDivergence
		{
			ShortMa = { Length = FastPeriod },
			LongMa = { Length = SlowPeriod },
		};

		// Subscribe to candle data and bind the MACD indicator.
		var subscription = SubscribeCandles(CandleType);
		subscription
			.BindEx(_macd, ProcessCandle)
			.Start();

		// Prepare visual elements when charts are available.
		var area = CreateChartArea();
		if (area != null)
		{
			DrawCandles(area, subscription);
			DrawIndicator(area, _macd);
			DrawOwnTrades(area);
		}
	}

	private void ProcessCandle(ICandleMessage candle, IIndicatorValue macdValue)
	{
		// React only to completed candles to avoid premature decisions.
		if (candle.State != CandleStates.Finished)
			return;

		// Ensure the indicator produced a valid value.
		if (!_macd.IsFormed || !macdValue.IsFinal)
			return;

		if (!IsFormedAndOnlineAndAllowTrading())
			return;

		var macdLine = macdValue.ToDecimal();

		// Accumulate historical MACD values for slope calculations.
		if (_previousMacdValue is null)
		{
			_previousMacdValue = macdLine;
			return;
		}

		if (_prePreviousMacdValue is null)
		{
			_prePreviousMacdValue = _previousMacdValue;
			_previousMacdValue = macdLine;
			return;
		}

		var macdPrev = _previousMacdValue.Value;
		var macdPrevPrev = _prePreviousMacdValue.Value;

		var currentSlope = macdPrev > macdPrevPrev ? 1 : macdPrev < macdPrevPrev ? -1 : 0;

		if (currentSlope == 0)
		{
			_prePreviousMacdValue = _previousMacdValue;
			_previousMacdValue = macdLine;
			return;
		}

		if (_previousSlope == currentSlope)
		{
			_prePreviousMacdValue = _previousMacdValue;
			_previousMacdValue = macdLine;
			return;
		}

		if (currentSlope > 0)
		{
			// Close shorts and open (or add to) longs when the MACD slope turns positive.
			var volumeToBuy = TradeVolume + Math.Max(0m, -Position);
			if (volumeToBuy > 0m)
			{
				BuyMarket(volumeToBuy);
				LogInfo($"Bullish slope detected. MACD(1)={macdPrev:F5}, MACD(2)={macdPrevPrev:F5}. Buying {volumeToBuy}.");
			}
		}
		else
		{
			// Close longs and open (or add to) shorts when the MACD slope turns negative.
			var volumeToSell = TradeVolume + Math.Max(0m, Position);
			if (volumeToSell > 0m)
			{
				SellMarket(volumeToSell);
				LogInfo($"Bearish slope detected. MACD(1)={macdPrev:F5}, MACD(2)={macdPrevPrev:F5}. Selling {volumeToSell}.");
			}
		}

		// Update stored values so the next candle compares the two previous MACD readings.
		_previousSlope = currentSlope;
		_prePreviousMacdValue = _previousMacdValue;
		_previousMacdValue = macdLine;
	}
}