Ver en GitHub

Estrategia de Indicador de Momentum de Squeeze

La estrategia Squeeze Momentum Indicator detecta contracción de volatilidad cuando las Bandas de Bollinger caen dentro de los Canales de Keltner. Se abre una posición larga cuando el squeeze se libera hacia arriba con momentum creciente y el precio por encima de la EMA de 100 períodos. Se toman cortos en una liberación hacia abajo con momentum decreciente y el precio por debajo de la EMA. Las posiciones salen cuando el momentum se revierte.

Detalles

  • Criterios de entrada:
    • Las Bandas de Bollinger se mueven fuera de los Canales de Keltner (liberación del squeeze).
    • Largo: El momentum aumenta, precio por encima del cierre anterior y EMA100, y el color del squeeze cambia de negro a gris.
    • Corto: El momentum disminuye, precio por debajo del cierre anterior y EMA100, y el color cambia de gris a negro.
  • Largo/Corto: Ambos lados.
  • Criterios de salida:
    • El momentum se revierte.
  • Stops: Ninguno.
  • Valores predeterminados:
    • BbLength = 20
    • BbMultiplier = 2
    • KcLength = 20
    • KcMultiplier = 1.5
    • EmaLength = 100
  • Filtros:
    • Categoría: Ruptura de volatilidad
    • Dirección: Ambos
    • Indicadores: Bollinger Bands, Keltner Channels, Linear Regression, EMA
    • Stops: Ninguno
    • Complejidad: Medio
    • Marco temporal: Cualquiera
    • 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>
/// Squeeze Momentum Indicator strategy using EMA crossover.
/// </summary>
public class SqueezeMomentumIndicatorStrategy : Strategy
{
	private readonly StrategyParam<int> _slowLength;
	private readonly StrategyParam<DataType> _candleType;

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

	public SqueezeMomentumIndicatorStrategy()
	{
		_slowLength = Param(nameof(SlowLength), 40)
			.SetGreaterThanZero()
			.SetDisplay("Slow Length", "Slow EMA period", "General");

		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
			.SetDisplay("Candle Type", "Candle type", "General");
	}

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

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		var fast = new ExponentialMovingAverage { Length = 14 };
		var slow = new ExponentialMovingAverage { Length = SlowLength };
		var prevF = 0m; var prevS = 0m; var init = false;
		var lastSignal = DateTimeOffset.MinValue;
		var cooldown = TimeSpan.FromMinutes(360);
		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(fast, slow, (candle, f, s) =>
		{
			if (candle.State != CandleStates.Finished) return;
			if (!fast.IsFormed || !slow.IsFormed) return;
			if (!init) { prevF = f; prevS = s; init = true; return; }
			if (candle.OpenTime - lastSignal >= cooldown)
			{
				if (prevF <= prevS && f > s && Position <= 0) { BuyMarket(); lastSignal = candle.OpenTime; }
				else if (prevF >= prevS && f < s && Position >= 0) { SellMarket(); lastSignal = candle.OpenTime; }
			}
			prevF = f; prevS = s;
		}).Start();
		var area = CreateChartArea();
		if (area != null) { DrawCandles(area, subscription); DrawIndicator(area, fast); DrawIndicator(area, slow); DrawOwnTrades(area); }
	}
}