Ver en GitHub

Estrategia de Operador de Divergencia

Esta estrategia compara dos medias móviles simples (SMA) y opera basándose en la divergencia entre ellas.

Utiliza la diferencia entre la SMA rápida y la SMA lenta de la vela anterior como medida de divergencia. Si esta divergencia es positiva pero dentro de un rango especificado, la estrategia abre una posición larga. Si la divergencia es negativa y dentro del rango espejado, abre una posición corta. El riesgo se gestiona mediante niveles opcionales de stop-loss y take-profit.

Detalles

  • Criterios de entrada:
    • Largo: SMA rápida anterior - SMA lenta anterior >= DvBuySell y <= DvStayOut.
    • Corto: SMA rápida anterior - SMA lenta anterior <= -DvBuySell y >= -DvStayOut.
  • Criterios de salida: Las posiciones se cierran mediante stop-loss o take-profit si están configurados.
  • Stops: Soportados a través de StartProtection con desplazamientos de precio absolutos.
  • Valores predeterminados:
    • FastPeriod = 7
    • SlowPeriod = 88
    • DvBuySell = 0.0011
    • DvStayOut = 0.0079
  • Filtros:
    • Categoría: Seguimiento de tendencia
    • Dirección: Ambos
    • Indicadores: SMA
    • Stops: Opcional
    • Complejidad: Básico
    • Marco temporal: Corto plazo
    • 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>
/// Strategy based on divergence between fast and slow EMA.
/// </summary>
public class DivergenceTraderStrategy : Strategy
{
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _prevFast;
	private decimal _prevSlow;
	private bool _hasPrev;

	public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
	public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public DivergenceTraderStrategy()
	{
		_fastPeriod = Param(nameof(FastPeriod), 12)
			.SetGreaterThanZero()
			.SetDisplay("Fast Period", "Fast EMA length", "Parameters");

		_slowPeriod = Param(nameof(SlowPeriod), 50)
			.SetGreaterThanZero()
			.SetDisplay("Slow Period", "Slow EMA length", "Parameters");

		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Type of candles", "General");
	}

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
		=> [(Security, CandleType)];

	protected override void OnReseted()
	{
		base.OnReseted();
		_prevFast = 0;
		_prevSlow = 0;
		_hasPrev = false;
	}

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

		var fastEma = new ExponentialMovingAverage { Length = FastPeriod };
		var slowEma = new ExponentialMovingAverage { Length = SlowPeriod };

		SubscribeCandles(CandleType)
			.Bind(fastEma, slowEma, ProcessCandle)
			.Start();
	}

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

		if (!_hasPrev)
		{
			_prevFast = fastValue;
			_prevSlow = slowValue;
			_hasPrev = true;
			return;
		}

		var crossUp = _prevFast <= _prevSlow && fastValue > slowValue;
		var crossDown = _prevFast >= _prevSlow && fastValue < slowValue;

		if (crossUp && Position <= 0)
		{
			if (Position < 0) BuyMarket();
			BuyMarket();
		}
		else if (crossDown && Position >= 0)
		{
			if (Position > 0) SellMarket();
			SellMarket();
		}

		_prevFast = fastValue;
		_prevSlow = slowValue;
	}
}