Ver no GitHub

MACD Quatro Cores 2 Martingale Estratégia

MACD Quatro Cores 2 Martingale

A estratégia transporta o consultor especialista "MACD Four Colors 2 Martingale" de MetaTrader para StockSharp. Ele mantém a lógica original construída em torno da interpretação de "cor" MACD e de um modelo de dimensionamento de posição martingale.

Visão geral

O indicador subjacente pinta o histograma MACD com cinco cores. No "novo" esquema de cores padrão, o histograma muda de cor dependendo se a linha MACD sobe ou desce acima/abaixo da linha zero. O Expert Advisor abre uma posição sempre que as cores transitam de prata para amarelo (negativo MACD diminuindo novamente) ou de vermelho para azul (positivo MACD rolando). A versão StockSharp reproduz esta sequência reconstruindo as cores a partir de valores MACD.

Apenas uma cesta direcional de negociações está ativa a qualquer momento. Uma nova negociação só é permitida se o seu preço melhorar a entrada média da cesta atual (preço mais baixo para posições compradas, preço mais alto para posições vendidas). Cada nova entrada multiplica o último volume preenchido por um coeficiente de lote configurável, implementando a média martingale do EA original.

Regras de negociação

  • Lógica do indicador: um indicador MovingAverageConvergenceDivergenceSignal com a configuração clássica 26/12/9 gera valores MACD.
  • Reconstrução de cores: a estratégia compara os dois valores MACD mais recentes. O negativo crescente MACD mapeia para a cor 1 (prata), o positivo crescente para a cor 2 (vermelho), o positivo decrescente para a cor 3 (azul) e o negativo descendente para a cor 4 (amarelo).
  • Entrada longa: acionada quando as cores reconstruídas se movem de 1 para 4 enquanto o MACD na barra anterior permanece abaixo de zero. A negociação é executada apenas se não houver exposição curta e o novo preço for inferior a qualquer entrada longa existente.
  • Entrada curta: acionada quando as cores passam de 2 para 3 enquanto o MACD na barra anterior permanece acima de zero. A negociação só dispara se não houver exposição longa e o novo preço for superior a qualquer entrada curta existente.
  • Gerenciamento de volume: o primeiro pedido usa InitialVolume. Cada pedido subsequente dentro da mesma cesta multiplica o último volume executado por LotCoefficient. Definir o coeficiente ≤ 0 desativa o multiplicador.
  • Controle de lucros e perdas: O PnL flutuante é avaliado em cada vela finalizada. Acertar TargetProfit fecha todas as posições e reinicia o ciclo martingale. A violação de MaxDrawdown (interpretada como um limite de perda) também fecha tudo e reinicia o ciclo. Limites negativos são suportados como no código original.
  • Saída de posição: Além das metas monetárias, não há paradas automáticas. As posições permanecem abertas até que um limite de risco seja atingido ou o usuário intervenha manualmente.

Parâmetros

  • CandleType (DataType, padrão 1h) – período para o cálculo de MACD.
  • InitialVolume (decimal, padrão 1) – volume do primeiro pedido em uma cesta.
  • LotCoefficient (decimal, padrão 2) – multiplicador aplicado ao volume anterior quando o martingale está ativo.
  • MaxDrawdown (decimal, padrão 50) – limite de perda flutuante (em dinheiro) que força a liquidação. Valores positivos observam -MaxDrawdown, valores negativos usam o valor exato.
  • TargetProfit (decimal, padrão 150) – meta de lucro flutuante (em dinheiro) que fecha a cesta. Valores negativos invertem a comparação como na versão MQL.
  • FastEmaPeriod (int, padrão 12) – comprimento do EMA rápido para MACD.
  • SlowEmaPeriod (int, padrão 26) – duração da lentidão EMA para MACD.
  • SignalPeriod (int, padrão 9) – comprimento do sinal EMA para suavização MACD.

Notas de uso

  • Funciona em qualquer instrumento que defina PriceStep e StepPrice, porque o PnL não realizado é calculado a partir das especificações da exchange.
  • O dimensionamento do martingale pode aumentar a posição rapidamente. Valide os limites de risco antes de permitir a negociação em uma conta real.
  • Para análise visual anexe a área do gráfico criada pela estratégia. Ele traça velas, o indicador MACD e as negociações executadas.
  • Categoria: Média de Tendência/Momentum
  • Direção: Ambas (cestas longas e curtas)
  • Indicadores: MACD
  • Paradas: somente saída baseada em dinheiro
  • Prazo: Configurável (padrão 1h)
  • Complexidade: Intermediário
  • Risco: Alto devido à escala de martingale
  • Automação: Totalmente automatizado depois de iniciado
using System;

using Ecng.Common;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// MACD histogram crossover with martingale volume scaling.
/// Based on the MACD Four Colors 2 Martingale expert advisor.
/// </summary>
public class MacdFourColors2MartingaleStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _fastEmaPeriod;
	private readonly StrategyParam<int> _slowEmaPeriod;
	private readonly StrategyParam<int> _signalPeriod;
	private readonly StrategyParam<decimal> _lotCoefficient;
	private readonly StrategyParam<int> _maxMartingale;

	private MovingAverageConvergenceDivergence _macd;
	private readonly System.Collections.Generic.Queue<decimal> _macdHistory = new();
	private decimal? _prevHistogram;
	private decimal _currentVolume;
	private int _consecutiveLosses;
	private decimal _entryPrice;

	/// <summary>
	/// Type of candles used for MACD analysis.
	/// </summary>
	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	/// <summary>
	/// Period of the fast EMA inside MACD.
	/// </summary>
	public int FastEmaPeriod
	{
		get => _fastEmaPeriod.Value;
		set => _fastEmaPeriod.Value = value;
	}

	/// <summary>
	/// Period of the slow EMA inside MACD.
	/// </summary>
	public int SlowEmaPeriod
	{
		get => _slowEmaPeriod.Value;
		set => _slowEmaPeriod.Value = value;
	}

	/// <summary>
	/// Period of the signal line.
	/// </summary>
	public int SignalPeriod
	{
		get => _signalPeriod.Value;
		set => _signalPeriod.Value = value;
	}

	/// <summary>
	/// Multiplier applied after a losing trade.
	/// </summary>
	public decimal LotCoefficient
	{
		get => _lotCoefficient.Value;
		set => _lotCoefficient.Value = value;
	}

	/// <summary>
	/// Maximum number of martingale steps before resetting.
	/// </summary>
	public int MaxMartingale
	{
		get => _maxMartingale.Value;
		set => _maxMartingale.Value = value;
	}

	/// <summary>
	/// Initialize strategy parameters.
	/// </summary>
	public MacdFourColors2MartingaleStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
			.SetDisplay("Candle Type", "Type of candles for MACD analysis", "General");

		_fastEmaPeriod = Param(nameof(FastEmaPeriod), 20)
			.SetDisplay("Fast EMA", "Fast EMA period for MACD", "Indicators")
			.SetGreaterThanZero();

		_slowEmaPeriod = Param(nameof(SlowEmaPeriod), 50)
			.SetDisplay("Slow EMA", "Slow EMA period for MACD", "Indicators")
			.SetGreaterThanZero();

		_signalPeriod = Param(nameof(SignalPeriod), 12)
			.SetDisplay("Signal Period", "Signal line smoothing period", "Indicators")
			.SetGreaterThanZero();

		_lotCoefficient = Param(nameof(LotCoefficient), 1.5m)
			.SetDisplay("Lot Coefficient", "Multiplier after a loss", "Money Management")
			.SetGreaterThanZero();

		_maxMartingale = Param(nameof(MaxMartingale), 5)
			.SetDisplay("Max Martingale", "Maximum consecutive doublings", "Money Management")
			.SetGreaterThanZero();
	}

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

		_prevHistogram = null;
		_currentVolume = Volume > 0 ? Volume : 1;
		_consecutiveLosses = 0;
		_entryPrice = 0;
		_macdHistory.Clear();

		_macd = new MovingAverageConvergenceDivergence
		{
			ShortMa = { Length = FastEmaPeriod },
			LongMa = { Length = SlowEmaPeriod }
		};

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(_macd, ProcessCandle)
			.Start();

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

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

		_macdHistory.Enqueue(macdValue);
		while (_macdHistory.Count > SignalPeriod)
			_macdHistory.Dequeue();

		if (!_macd.IsFormed || _macdHistory.Count < SignalPeriod)
		{
			_prevHistogram = null;
			return;
		}

		// Calculate signal line (SMA of MACD)
		var sum = 0m;
		var history = _macdHistory.ToArray();
		foreach (var v in history)
			sum += v;
		var signalValue = sum / history.Length;

		var histogram = macdValue - signalValue;

		if (_prevHistogram is null)
		{
			_prevHistogram = histogram;
			return;
		}

		var crossUp = _prevHistogram < 0 && histogram >= 0;
		var crossDown = _prevHistogram >= 0 && histogram < 0;

		if (crossUp)
		{
			// Check for loss on closing short
			if (Position < 0)
			{
				var pnl = _entryPrice - candle.ClosePrice;
				if (pnl < 0)
				{
					_consecutiveLosses++;
					if (_consecutiveLosses <= MaxMartingale)
						_currentVolume *= LotCoefficient;
				}
				else
				{
					_consecutiveLosses = 0;
					_currentVolume = Volume > 0 ? Volume : 1;
				}

				BuyMarket(Math.Abs(Position) + _currentVolume);
				_entryPrice = candle.ClosePrice;
			}
			else if (Position == 0)
			{
				BuyMarket(_currentVolume);
				_entryPrice = candle.ClosePrice;
			}
		}
		else if (crossDown)
		{
			// Check for loss on closing long
			if (Position > 0)
			{
				var pnl = candle.ClosePrice - _entryPrice;
				if (pnl < 0)
				{
					_consecutiveLosses++;
					if (_consecutiveLosses <= MaxMartingale)
						_currentVolume *= LotCoefficient;
				}
				else
				{
					_consecutiveLosses = 0;
					_currentVolume = Volume > 0 ? Volume : 1;
				}

				SellMarket(Math.Abs(Position) + _currentVolume);
				_entryPrice = candle.ClosePrice;
			}
			else if (Position == 0)
			{
				SellMarket(_currentVolume);
				_entryPrice = candle.ClosePrice;
			}
		}

		_prevHistogram = histogram;
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		_macd = null;
		_prevHistogram = null;
		_currentVolume = 0;
		_consecutiveLosses = 0;
		_entryPrice = 0;
		_macdHistory.Clear();

		base.OnReseted();
	}
}