Ver en GitHub

Estrategia CVD Divergencia Volumen HMA RSI MACD

Esta estrategia combina Hull Moving Averages, RSI, MACD, filtro de volumen y divergencia del delta de volumen acumulado (CVD) para identificar oportunidades de tendencia.

Las posiciones largas se abren cuando HMA20 está por encima de HMA50, el RSI muestra momentum alcista, el histograma MACD sube, el volumen supera su media y el CVD forma divergencia alcista o aumenta. Las posiciones cortas reflejan estas condiciones de forma inversa.

Detalles

  • Criterios de entrada:
    • Largo: HMA20 > HMA50 y precio > HMA20; RSI entre 40 y RsiOverbought; línea MACD sobre señal e histograma subiendo; volumen > SMA * VolumeMultiplier; divergencia CVD alcista o CVD creciente.
    • Corto: HMA20 < HMA50 y precio < HMA20; RSI entre RsiOversold y 60; línea MACD bajo señal e histograma bajando; volumen > SMA * VolumeMultiplier; divergencia CVD bajista o CVD decreciente.
  • Largo/Corto: Ambos lados.
  • Criterios de salida:
    • Largo: Precio < HMA20 o RSI > RsiOverbought o línea MACD cruza bajo señal.
    • Corto: Precio > HMA20 o RSI < RsiOversold o línea MACD cruza sobre señal.
  • Stops: No.
  • Valores predeterminados:
    • Hma20Length = 20
    • Hma50Length = 50
    • RsiLength = 14
    • RsiOverbought = 70
    • RsiOversold = 30
    • MacdFast = 12
    • MacdSlow = 26
    • MacdSignal = 9
    • VolumeMaLength = 20
    • VolumeMultiplier = 1.5
    • CvdLength = 14
    • DivergenceLookback = 5
    • CandleType = TimeSpan.FromMinutes(5)
  • Filtros:
    • Categoría: Mixto
    • Dirección: Ambos
    • Indicadores: HMA, RSI, MACD, Volumen, CVD
    • Stops: No
    • Complejidad: Avanzado
    • Marco temporal: Intradía
    • Estacionalidad: No
    • Redes neuronales: No
    • Divergencia: Sí
    • Nivel de riesgo: Medio
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>
/// CvdDivergenceVolumeHmaRsiMacdStrategy using EMA crossover for trend timing.
/// Enters long on golden cross, short on death cross.
/// </summary>
public class CvdDivergenceVolumeHmaRsiMacdStrategy : Strategy
{
	private readonly StrategyParam<int> _fastEmaPeriod;
	private readonly StrategyParam<int> _slowEmaPeriod;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _prevFastEma;
	private decimal _prevSlowEma;

	public int FastEmaPeriod { get => _fastEmaPeriod.Value; set => _fastEmaPeriod.Value = value; }
	public int SlowEmaPeriod { get => _slowEmaPeriod.Value; set => _slowEmaPeriod.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public CvdDivergenceVolumeHmaRsiMacdStrategy()
	{
		_fastEmaPeriod = Param(nameof(FastEmaPeriod), 120)
			.SetGreaterThanZero()
			.SetDisplay("Fast EMA", "Fast EMA period", "Indicators");

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

		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(1).TimeFrame())
			.SetDisplay("Candle Type", "Type of candles to use", "General");
	}

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

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevFastEma = 0m;
		_prevSlowEma = 0m;
	}

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

		var fastEma = new ExponentialMovingAverage { Length = FastEmaPeriod };
		var slowEma = new ExponentialMovingAverage { Length = SlowEmaPeriod };

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

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

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

		if (_prevFastEma == 0m || _prevSlowEma == 0m)
		{
			_prevFastEma = fastEmaValue;
			_prevSlowEma = slowEmaValue;
			return;
		}

		if (_prevFastEma <= _prevSlowEma && fastEmaValue > slowEmaValue && Position <= 0)
		{
			BuyMarket();
		}
		else if (_prevFastEma >= _prevSlowEma && fastEmaValue < slowEmaValue && Position >= 0)
		{
			SellMarket();
		}

		_prevFastEma = fastEmaValue;
		_prevSlowEma = slowEmaValue;
	}
}