Ver no GitHub

Divergência MACD (MACD Divergence)

A Divergência MACD busca discrepâncias entre a ação do preço e o indicador MACD. Máximas mais altas no preço com máximas mais baixas no MACD sugerem enfraquecimento do momentum (divergência baixista), enquanto mínimas mais baixas no preço com mínimas mais altas no MACD apontam para uma reversão altista.

Os testes indicam um retorno anual médio de aproximadamente 70%. Funciona melhor no mercado de ações.

Após detectar a divergência, o sistema aguarda que o MACD cruze sua linha de sinal antes de entrar. A operação é fechada se o MACD cruzar na direção oposta ou o stop-loss for acionado.

Detalhes

  • Critérios de entrada: Divergência altista ou baixista mais cruzamento do MACD com a linha de sinal.
  • Comprado/Vendido: Ambos os lados.
  • Critérios de saída: O MACD cruza na direção oposta ou stop.
  • Stops: Sim.
  • Valores padrão:
    • FastMacdPeriod = 12
    • SlowMacdPeriod = 26
    • SignalPeriod = 9
    • DivergencePeriod = 5
    • CandleType = TimeSpan.FromMinutes(15)
    • StopLossPercent = 2.0m
  • Filtros:
    • Categoria: Divergência
    • Direção: Ambos
    • Indicadores: MACD
    • Stops: Sim
    • Complexidade: Intermediário
    • Período: Intradiário
    • Sazonalidade: Não
    • Redes neurais: Não
    • Divergência: Sim
    • Nível de risco: Médio
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>
/// MACD Divergence strategy.
/// Detects divergences between price and MACD for reversal signals.
/// Bullish: price falling but MACD rising.
/// Bearish: price rising but MACD falling.
/// </summary>
public class MacdDivergenceStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _cooldownBars;

	private decimal _prevPrice;
	private decimal _prevMacd;
	private int _cooldown;

	/// <summary>
	/// Candle type.
	/// </summary>
	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	/// <summary>
	/// Cooldown bars between trades.
	/// </summary>
	public int CooldownBars
	{
		get => _cooldownBars.Value;
		set => _cooldownBars.Value = value;
	}

	/// <summary>
	/// Constructor.
	/// </summary>
	public MacdDivergenceStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(1).TimeFrame())
			.SetDisplay("Candle Type", "Type of candles to use", "General");

		_cooldownBars = Param(nameof(CooldownBars), 500)
			.SetRange(1, 1000)
			.SetDisplay("Cooldown Bars", "Bars to wait between trades", "General");
	}

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

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevPrice = default;
		_prevMacd = default;
		_cooldown = default;
	}

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

		_prevPrice = 0;
		_prevMacd = 0;
		_cooldown = 0;

		var macd = new MovingAverageConvergenceDivergenceSignal();

		var subscription = SubscribeCandles(_candleType.Value);
		subscription
			.BindEx(macd, ProcessCandle)
			.Start();

		var area = CreateChartArea();
		if (area != null)
		{
			DrawCandles(area, subscription);
			DrawIndicator(area, macd);
			DrawOwnTrades(area);
		}
	}

	private void ProcessCandle(ICandleMessage candle, IIndicatorValue macdValue)
	{
		if (candle.State != CandleStates.Finished)
			return;

		if (!macdValue.IsFormed)
			return;

		var macdTyped = (MovingAverageConvergenceDivergenceSignalValue)macdValue;

		if (macdTyped.Macd is not decimal macdLine || macdTyped.Signal is not decimal signal)
			return;

		if (_prevPrice == 0)
		{
			_prevPrice = candle.ClosePrice;
			_prevMacd = macdLine;
			return;
		}

		if (_cooldown > 0)
		{
			_cooldown--;
			_prevPrice = candle.ClosePrice;
			_prevMacd = macdLine;
			return;
		}

		// Bullish divergence: price down but MACD up
		var bullishDiv = candle.ClosePrice < _prevPrice && macdLine > _prevMacd;
		// Bearish divergence: price up but MACD down
		var bearishDiv = candle.ClosePrice > _prevPrice && macdLine < _prevMacd;

		if (Position == 0 && bullishDiv && macdLine > signal)
		{
			BuyMarket();
			_cooldown = CooldownBars;
		}
		else if (Position == 0 && bearishDiv && macdLine < signal)
		{
			SellMarket();
			_cooldown = CooldownBars;
		}
		else if (Position > 0 && macdLine < signal)
		{
			SellMarket();
			_cooldown = CooldownBars;
		}
		else if (Position < 0 && macdLine > signal)
		{
			BuyMarket();
			_cooldown = CooldownBars;
		}

		_prevPrice = candle.ClosePrice;
		_prevMacd = macdLine;
	}
}