Ver en GitHub

Divergencia MACD Stochastic Estrategia

Esta estrategia recrea el asesor experto MetaTrader 5 "Divergencia EA pip sl tp" en el marco StockSharp. El algoritmo busca divergencias clásicas entre la acción del precio y el histograma MACD, luego valida la señal con un filtro oscilador de sobrecompra/sobreventa Stochastic antes de abrir operaciones de reversión.

Lógica comercial

  1. Suscríbase a las velas de período de tiempo principales seleccionadas por el parámetro CandleType.
  2. Calcule el histograma MACD (MACD line - Signal line) y los valores Stochastic %K/%D en cada vela terminada.
  3. Realice un seguimiento de los dos últimos máximos y mínimos tanto del precio como de los valores del histograma.
  4. Divergencia bajista: un nuevo máximo de precio más alto acompañado de un pico de histograma MACD más bajo y un Stochastic %K por encima de StochasticUpperLevel activa una posición corta o revierte una posición larga existente.
  5. Divergencia alcista: un nuevo mínimo de precio más bajo con un histograma mínimo de MACD más alto y %K por debajo de StochasticLowerLevel se abre o se revierte en una posición larga.
  6. Las protecciones opcionales TakeProfitSteps y StopLossSteps se convierten en StockSharp unidades de paso y se activan una vez cuando comienza la estrategia.

Notas de implementación

  • Construido con API de alto nivel de StockSharp utilizando una única suscripción de vela vinculada a los indicadores MovingAverageConvergenceDivergenceSignal y StochasticOscillator.
  • Mantiene el estado de divergencia sin llamar a los ayudantes del indicador GetValue, cumpliendo con las pautas de conversión.
  • La integración de gráficos muestra velas de precios, MACD y Stochastic líneas cuando hay un área de gráfico disponible.
  • Las posiciones se invierten sumando el tamaño absoluto de la posición actual a la base Volume, lo que garantiza cambios de dirección inmediatos después de divergencias confirmadas.

Parámetros

Parámetro Descripción Predeterminado
CandleType Plazo utilizado para los cálculos de divergencia. velas de 1 hora
MacdFastLength, MacdSlowLength, MacdSignalLength MACD EMA longitudes que replican las entradas originales EA. 12 / 26 / 9
MacdDivergenceThreshold Diferencia mínima de histograma entre oscilaciones consecutivas requerida para confirmar la divergencia. 0.0005
StochasticLength Periodo %K rápido del oscilador Stochastic. 50
StochasticSlowK, StochasticSlowD Longitudes de suavizado %K/%D adicionales que reflejan la configuración EA. 9 / 9
StochasticUpperLevel, StochasticLowerLevel Filtros de sobrecompra y sobreventa que validan configuraciones bajistas/alcistas. 80 / 20
TakeProfitSteps, StopLossSteps Distancias de protección opcionales expresadas en pasos de precio (0 desactiva el nivel). 50

Uso

  1. Adjunte la estrategia a un conector StockSharp con un valor que admita el período de tiempo seleccionado.
  2. Configure el tamaño de la posición a través de la propiedad base Volume y ajuste la configuración del indicador como desee.
  3. Inicie la estrategia: las órdenes se generarán automáticamente cada vez que se cumplan las condiciones de divergencia y Stochastic.
using System;

using Ecng.Common;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Simplified from "Divergence MACD Stochastic" MetaTrader expert.
/// Uses MACD histogram divergence (price vs histogram) with RSI confirmation.
/// MACD is computed manually from two EMAs.
/// </summary>
public class DivergenceMacdStochasticStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _macdFast;
	private readonly StrategyParam<int> _macdSlow;
	private readonly StrategyParam<int> _rsiPeriod;

	// Manual EMA for MACD
	private decimal _fastEma;
	private decimal _slowEma;
	private bool _emaInitialized;
	private int _barCount;
	private decimal _fastMultiplier;
	private decimal _slowMultiplier;

	private readonly decimal[] _macdWindow = new decimal[DivergenceLookback];
	private readonly decimal[] _priceWindow = new decimal[DivergenceLookback];
	private int _windowCount;
	private int _windowIndex;
	private const int DivergenceLookback = 10;

	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	public int MacdFast
	{
		get => _macdFast.Value;
		set => _macdFast.Value = value;
	}

	public int MacdSlow
	{
		get => _macdSlow.Value;
		set => _macdSlow.Value = value;
	}

	public int RsiPeriod
	{
		get => _rsiPeriod.Value;
		set => _rsiPeriod.Value = value;
	}

	public DivergenceMacdStochasticStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe for divergence detection", "General");

		_macdFast = Param(nameof(MacdFast), 20)
			.SetGreaterThanZero()
			.SetDisplay("MACD Fast", "Fast EMA length", "Indicators");

		_macdSlow = Param(nameof(MacdSlow), 50)
			.SetGreaterThanZero()
			.SetDisplay("MACD Slow", "Slow EMA length", "Indicators");

		_rsiPeriod = Param(nameof(RsiPeriod), 14)
			.SetGreaterThanZero()
			.SetDisplay("RSI Period", "RSI period for confirmation", "Indicators");
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		_windowCount = 0;
		_windowIndex = 0;
		_emaInitialized = false;
		_barCount = 0;
		_fastMultiplier = 2m / (MacdFast + 1);
		_slowMultiplier = 2m / (MacdSlow + 1);

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

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

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

		var close = candle.ClosePrice;
		_barCount++;

		// Manual EMA computation
		if (!_emaInitialized)
		{
			_fastEma = close;
			_slowEma = close;
			_emaInitialized = true;
		}
		else
		{
			_fastEma = close * _fastMultiplier + _fastEma * (1 - _fastMultiplier);
			_slowEma = close * _slowMultiplier + _slowEma * (1 - _slowMultiplier);
		}

		if (_barCount < MacdSlow)
			return;

		var macdLine = _fastEma - _slowEma;

		_macdWindow[_windowIndex] = macdLine;
		_priceWindow[_windowIndex] = close;
		_windowIndex = (_windowIndex + 1) % DivergenceLookback;
		if (_windowCount < DivergenceLookback)
			_windowCount++;

		if (_windowCount < DivergenceLookback)
			return;

		var volume = Volume;
		if (volume <= 0)
			volume = 1;

		var oldestIndex = _windowIndex;
		var newestIndex = (_windowIndex + DivergenceLookback - 1) % DivergenceLookback;
		var oldMacd = _macdWindow[oldestIndex];
		var newMacd = _macdWindow[newestIndex];
		var oldPrice = _priceWindow[oldestIndex];
		var newPrice = _priceWindow[newestIndex];

		var minPriceMove = oldPrice * 0.005m;
		// Bullish divergence: price makes lower low but MACD makes higher low.
		var bullishDiv = newPrice < oldPrice - minPriceMove && newMacd > oldMacd;
		// Bearish divergence: price makes higher high but MACD makes lower high.
		var bearishDiv = newPrice > oldPrice + minPriceMove && newMacd < oldMacd;

		if (bullishDiv)
		{
			if (Position <= 0)
				BuyMarket(Position < 0 ? Math.Abs(Position) + volume : volume);
		}
		else if (bearishDiv)
		{
			if (Position >= 0)
				SellMarket(Position > 0 ? Math.Abs(Position) + volume : volume);
		}
	}

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

		_fastEma = 0;
		_slowEma = 0;
		_emaInitialized = false;
		_barCount = 0;
		_fastMultiplier = 0;
		_slowMultiplier = 0;
		Array.Clear(_macdWindow, 0, _macdWindow.Length);
		Array.Clear(_priceWindow, 0, _priceWindow.Length);
		_windowCount = 0;
		_windowIndex = 0;
	}
}