Ver no GitHub

MACD + Stochastic Estratégia de filtro de tendências

Esta estratégia recria o comportamento do consultor especialista MetaTrader da pasta MQL/7604. O script original dependia de um oscilador personalizado que produzia buffers verdes e vermelhos. Na prática, os números (15, 3, 3) correspondem a um oscilador estocástico clássico, portanto, a porta StockSharp usa o indicador Stochastic integrado para a confirmação do sinal enquanto MACD e um filtro de tendência EMA gerenciam a direção.

A estratégia é negociada tanto longa quanto curta. Ele espera por um cruzamento estocástico na direção da negociação, exige que o histograma MACD cruze sua linha de sinal com distância suficiente de zero e exige que a inclinação EMA esteja de acordo com a entrada. O gerenciamento de risco reflete a versão MQL: um stop-loss fixo, um take-profit e um trailing stop baseado em pontos que estreita o nível de proteção assim que a negociação passa para o lucro.

Indicadores

  • MovingAverageConvergenceDivergenceSignal com parâmetros fast = 12, slow = 26, signal = 9. O histograma MACD deve cruzar sua linha de sinal enquanto permanece abaixo de zero para configurações longas e acima de zero para configurações curtas. Limites adicionais (MacdOpenLevel, MacdCloseLevel) impõem uma distância absoluta mínima da linha zero.
  • Stochastic oscilador com (Length = 15, KPeriod = 3, DPeriod = 3). A linha %K desempenha o papel de buffer "verde" e deve estar acima de %D para negociações longas (abaixo para negociações curtas). O mesmo cruzamento é usado para sair de posições.
  • ExponentialMovingAverage com período 26. O EMA fornece um filtro direcional: para uma negociação longa, o valor atual de EMA deve estar acima do EMA da barra anterior e, inversamente, para uma negociação curta.

Lógica de entrada

  1. Configuração longa
    • Stochastic %K > %D na vela fechada atual.
    • MACD histograma < 0 e > linha de sinal na barra atual.
    • MACD histograma <linha de sinal na barra anterior (ou seja, cruzamento de alta agora).
    • |MACD| > MacdOpenLevel * price_step.
    • EMA aumentando (atual EMA > anterior EMA).
  2. Configuração curta
    • Stochastic %K <%D na vela atual.
    • MACD histograma > 0 e < linha de sinal na barra atual.
    • MACD histograma > linha de sinal na barra anterior (cruzamento de baixa agora).
    • MACD > MacdOpenLevel * price_step.
    • EMA caindo (atual EMA < anterior EMA).

Se a conta já tiver uma posição, nenhuma nova ordem será gerada até que a negociação aberta seja fechada.

Sair da lógica

Enquanto uma posição está aberta, a estratégia impõe continuamente:

  • Saída do indicador
    • As posições longas fecham quando %K < %D, MACD > 0, MACD < sinal, o anterior MACD estava acima de seu sinal e o histograma absoluto excede MacdCloseLevel * price_step.
    • As posições curtas fecham quando %K > %D, MACD < 0, MACD > sinal, o anterior MACD estava abaixo de seu sinal e |MACD| > MacdCloseLevel * price_step.
  • Stop-loss: configurado por StopLossPoints, convertido em unidades de preço através do PriceStep do instrumento.
  • Realização de lucro: TakeProfitPoints multiplicado por PriceStep.
  • Trailing Stop: quando o lucro excede TrailingStopPoints * PriceStep, o nível de stop é aumentado (para posições compradas) ou diminuído (para posições vendidas) para que a negociação sempre bloqueie pelo menos esse valor de lucro.

Parâmetros

Nome Descrição Padrão
TradeVolume Tamanho do pedido em lotes 0.1
TakeProfitPoints Distância de lucro em pontos 10
StopLossPoints Distância de stop-loss em pontos 50
TrailingStopPoints Distância da parada final em pontos 5
MacdOpenLevel Valor absoluto mínimo MACD para entradas 3
MacdCloseLevel Valor absoluto mínimo MACD para saídas 2
MacdFastPeriod Comprimento EMA rápido dentro de MACD 12
MacdSlowPeriod Comprimento EMA lento dentro de MACD 26
MacdSignalPeriod MACD comprimento do sinal EMA 9
EmaPeriod EMA período para o filtro de tendência 26
StochasticLength Stochastic janela de retrospectiva 15
StochasticKPeriod Suavização %K 3
StochasticDPeriod Suavização %D 3
CandleType Prazo usado para cálculos 15m

Notas

  • Todos os cálculos usam apenas velas finalizadas, correspondendo ao loop start() no EA original.
  • O PriceStep fornecido pelo instrumento define um ponto. Quando a segurança não expõe uma etapa, a estratégia volta para 1.
  • O código depende puramente do API de alto nível de StockSharp: os indicadores são vinculados por meio de SubscribeCandles().BindEx(...), nenhum buffer de histórico manual é criado e os pedidos usam BuyMarket/SellMarket como na versão MQL.
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>
/// MACD strategy with stochastic confirmation and EMA trend filter.
/// Buy when MACD crosses above signal with stochastic K > D and price above EMA.
/// Sell when MACD crosses below signal with stochastic K < D and price below EMA.
/// </summary>
public class MacdStochasticFilterStrategy : Strategy
{
	private readonly StrategyParam<int> _macdFastPeriod;
	private readonly StrategyParam<int> _macdSlowPeriod;
	private readonly StrategyParam<int> _macdSignalPeriod;
	private readonly StrategyParam<int> _emaPeriod;
	private readonly StrategyParam<int> _stochKLength;
	private readonly StrategyParam<int> _stochDLength;
	private readonly StrategyParam<DataType> _candleType;

	private decimal? _prevMacd;
	private decimal? _prevSignal;

	/// <summary>
	/// Fast EMA period inside MACD.
	/// </summary>
	public int MacdFastPeriod
	{
		get => _macdFastPeriod.Value;
		set => _macdFastPeriod.Value = value;
	}

	/// <summary>
	/// Slow EMA period inside MACD.
	/// </summary>
	public int MacdSlowPeriod
	{
		get => _macdSlowPeriod.Value;
		set => _macdSlowPeriod.Value = value;
	}

	/// <summary>
	/// Signal line period for MACD.
	/// </summary>
	public int MacdSignalPeriod
	{
		get => _macdSignalPeriod.Value;
		set => _macdSignalPeriod.Value = value;
	}

	/// <summary>
	/// Trend EMA period used as directional filter.
	/// </summary>
	public int EmaPeriod
	{
		get => _emaPeriod.Value;
		set => _emaPeriod.Value = value;
	}

	/// <summary>
	/// Stochastic %K length.
	/// </summary>
	public int StochKLength
	{
		get => _stochKLength.Value;
		set => _stochKLength.Value = value;
	}

	/// <summary>
	/// Stochastic %D length.
	/// </summary>
	public int StochDLength
	{
		get => _stochDLength.Value;
		set => _stochDLength.Value = value;
	}

	/// <summary>
	/// Type of candles used by the strategy.
	/// </summary>
	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	public MacdStochasticFilterStrategy()
	{
		_macdFastPeriod = Param(nameof(MacdFastPeriod), 12)
			.SetDisplay("MACD Fast", "Fast EMA period for MACD", "Indicators");

		_macdSlowPeriod = Param(nameof(MacdSlowPeriod), 26)
			.SetDisplay("MACD Slow", "Slow EMA period for MACD", "Indicators");

		_macdSignalPeriod = Param(nameof(MacdSignalPeriod), 9)
			.SetDisplay("MACD Signal", "Signal EMA period for MACD", "Indicators");

		_emaPeriod = Param(nameof(EmaPeriod), 26)
			.SetDisplay("Trend EMA", "EMA period for trend filter", "Indicators");

		_stochKLength = Param(nameof(StochKLength), 14)
			.SetDisplay("Stochastic K", "Look-back length for stochastic K", "Indicators");

		_stochDLength = Param(nameof(StochDLength), 3)
			.SetDisplay("Stochastic D", "Smoothing for D line", "Indicators");

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

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

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

		_prevMacd = null;
		_prevSignal = null;
	}

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

		_prevMacd = null;
		_prevSignal = null;

		var macd = new MovingAverageConvergenceDivergenceSignal
		{
			Macd =
			{
				ShortMa = { Length = MacdFastPeriod },
				LongMa = { Length = MacdSlowPeriod }
			},
			SignalMa = { Length = MacdSignalPeriod }
		};

		var stochastic = new StochasticOscillator
		{
			K = { Length = StochKLength },
			D = { Length = StochDLength }
		};

		var ema = new ExponentialMovingAverage { Length = EmaPeriod };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.BindEx(macd, stochastic, ema, ProcessCandle)
			.Start();
	}

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

		if (!macdValue.IsFinal || !stochValue.IsFinal || !emaValue.IsFinal)
			return;

		if (macdValue is not MovingAverageConvergenceDivergenceSignalValue macdData)
			return;

		if (macdData.Macd is not decimal macd || macdData.Signal is not decimal signal)
			return;

		if (stochValue is not StochasticOscillatorValue stochData)
			return;

		if (stochData.K is not decimal kVal || stochData.D is not decimal dVal)
			return;

		var emaVal = emaValue.ToDecimal();

		if (_prevMacd is not decimal prevMacd || _prevSignal is not decimal prevSignal)
		{
			_prevMacd = macd;
			_prevSignal = signal;
			return;
		}

		// MACD crossover signals
		var macdBullishCross = prevMacd <= prevSignal && macd > signal;
		var macdBearishCross = prevMacd >= prevSignal && macd < signal;

		// Long: MACD bullish cross + stochastic K > D + price above EMA
		if (Position <= 0 && macdBullishCross && kVal > dVal && candle.ClosePrice > emaVal)
		{
			if (Position < 0)
				BuyMarket();
			BuyMarket();
		}
		// Short: MACD bearish cross + stochastic K < D + price below EMA
		else if (Position >= 0 && macdBearishCross && kVal < dVal && candle.ClosePrice < emaVal)
		{
			if (Position > 0)
				SellMarket();
			SellMarket();
		}

		_prevMacd = macd;
		_prevSignal = signal;
	}
}