Ver en GitHub

Estrategia Color HMA StDev

Estrategia basada en la Media Móvil Hull con un filtro dinámico de desviación estándar.

El sistema observa cuánto se desvía el precio del HMA. Cuando el cierre supera el promedio en un múltiplo elegido de la desviación estándar, la estrategia entra en largo, y viceversa para posiciones cortas. Un multiplicador más amplio define una zona de salida para que las posiciones se cierren solo después de un retorno significativo dentro de la banda.

Este enfoque intenta capturar ráfagas rápidas de momentum evitando el ruido. La Media Móvil Hull reacciona rápidamente a los cambios de tendencia, y la desviación estándar se adapta a la volatilidad permitiendo que los umbrales se expandan durante mercados turbulentos. La estrategia opera en ambas direcciones y no usa stops fijos, confiando en cambio en la reversión a la media del precio hacia el HMA.

Detalles

  • Criterios de entrada: Cierre cruzando HMA ± K1 * StdDev.
  • Largo/Corto: Ambas direcciones.
  • Criterios de salida: Cierre cruzando HMA ± K2 * StdDev en dirección opuesta.
  • Stops: Sin stop-loss ni take-profit fijos.
  • Valores predeterminados:
    • HmaPeriod = 13
    • StdPeriod = 9
    • K1 = 1.5m
    • K2 = 2.5m
    • CandleType = TimeSpan.FromHours(4)
  • Filtros:
    • Categoría: Tendencia, Volatilidad
    • Dirección: Ambos
    • Indicadores: HMA, Desviación estándar
    • Stops: No
    • Complejidad: Intermedio
    • Marco temporal: 4h
    • Estacionalidad: No
    • Redes neuronales: No
    • Divergencia: No
    • 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 Hull Moving Average with standard deviation filter.
/// Opens positions when price deviates from the HMA by a defined multiplier.
/// </summary>
public class ColorHmaStDevStrategy : Strategy
{
	private readonly StrategyParam<int> _hmaPeriod;
	private readonly StrategyParam<int> _stdPeriod;
	private readonly StrategyParam<decimal> _k1;
	private readonly StrategyParam<DataType> _candleType;

	public int HmaPeriod { get => _hmaPeriod.Value; set => _hmaPeriod.Value = value; }
	public int StdPeriod { get => _stdPeriod.Value; set => _stdPeriod.Value = value; }
	public decimal K1 { get => _k1.Value; set => _k1.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public ColorHmaStDevStrategy()
	{
		_hmaPeriod = Param(nameof(HmaPeriod), 13)
			.SetDisplay("HMA Period", "Hull Moving Average period", "Indicators")
			.SetOptimize(5, 30, 2);

		_stdPeriod = Param(nameof(StdPeriod), 9)
			.SetDisplay("StdDev Period", "Standard deviation period", "Indicators")
			.SetOptimize(5, 20, 1);

		_k1 = Param(nameof(K1), 0.5m)
			.SetDisplay("Entry Multiplier", "Deviation multiplier for entry", "Parameters")
			.SetOptimize(0.5m, 3m, 0.5m);

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

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

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

		var hma = new HullMovingAverage { Length = HmaPeriod };
		var std = new StandardDeviation { Length = StdPeriod };

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

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

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

		if (!IsFormedAndOnlineAndAllowTrading())
			return;

		if (stdValue == 0)
			return;

		var upperEntry = hmaValue + K1 * stdValue;
		var lowerEntry = hmaValue - K1 * stdValue;

		if (candle.ClosePrice > upperEntry && Position <= 0)
			BuyMarket();
		else if (candle.ClosePrice < lowerEntry && Position >= 0)
			SellMarket();
	}
}