Ver en GitHub

Estrategia Exp Sinewave2 X2

Descripción general

Exp Sinewave2 X2 es una estrategia de seguimiento de tendencia multitemporal inspirada en el análisis Sinewave de John Ehlers. El filtro de marco temporal superior define la dirección dominante, mientras que el marco temporal inferior proporciona desencadenantes precisos de entrada y salida. Todos los cálculos usan el indicador Sinewave2 reconstruido, que internamente depende del módulo adaptativo CyclePeriod.

Indicadores

  • Sinewave2 de marco temporal superior (línea lead vs. línea sine) – detecta sesgo alcista o bajista usando el cruce de la sine lead sobre el componente sine principal.
  • Sinewave2 de marco temporal inferior – monitorea los eventos de cruce más recientes para desencadenar trades alineados con la dirección del marco temporal superior.

Lógica de trading

  1. Filtro de tendencia
    • Calcular Sinewave2 en el marco temporal superior.
    • Evaluar las líneas lead y main SignalBarHigh barras atrás.
    • La tendencia es alcista si Lead > Sine, bajista si Lead < Sine, de lo contrario neutral.
  2. Señales de entrada
    • Esperar una vela finalizada en el marco temporal inferior.
    • Recuperar los valores lead y sine en los desplazamientos definidos por SignalBarLow (actual) y SignalBarLow + 1 (anterior).
    • Entrada larga: el cruce anterior fue hacia abajo (Lead > Sine anteriormente, Lead <= Sine ahora) mientras la tendencia del marco temporal superior es alcista y EnableBuyOpen está habilitado.
    • Entrada corta: el cruce anterior fue hacia arriba (Lead < Sine anteriormente, Lead >= Sine ahora) mientras la tendencia del marco temporal superior es bajista y EnableSellOpen está habilitado.
  3. Reglas de salida
    • Los booleanos de salida del marco temporal inferior EnableBuyCloseLower y EnableSellCloseLower cierran posiciones en cruces opuestos.
    • Los booleanos de salida del marco temporal superior EnableBuyCloseTrend y EnableSellCloseTrend cierran posiciones inmediatamente siempre que la tendencia principal cambie contra la dirección abierta.
    • El stop loss protector y el take profit se evalúan en cada vela usando los máximos/mínimos intrabarra y las distancias StopLossPoints / TakeProfitPoints expresadas en pasos de precio.
  4. Gestión de riesgo
    • Los reversales de posición dimensionan las nuevas órdenes como Volume + |Position| para aplanar la posición existente antes de establecer la nueva.
    • Después de cada entrada SetRiskLevels recalcula los precios absolutos de stop/objetivo usando Security.PriceStep (respaldo 1 cuando no está disponible).

Parámetros

Nombre Descripción
AlphaHigh Factor alpha para el filtro Sinewave2 de marco temporal superior.
AlphaLow Factor alpha para el disparador Sinewave2 de marco temporal inferior.
SignalBarHigh Número de barras atrás en el marco temporal superior usadas para leer el estado de tendencia.
SignalBarLow Número de barras atrás en el marco temporal inferior usadas para leer estados de cruce.
EnableBuyOpen / EnableSellOpen Permitir entradas largas/cortas desde señales del marco temporal inferior.
EnableBuyCloseTrend / EnableSellCloseTrend Forzar salidas cuando el marco temporal superior cambia contra la posición.
EnableBuyCloseLower / EnableSellCloseLower Cerrar posiciones en cruces opuestos del marco temporal inferior.
StopLossPoints Distancia del stop-loss expresada en pasos de precio del instrumento.
TakeProfitPoints Distancia del take-profit expresada en pasos de precio del instrumento.
HigherCandleType / LowerCandleType Tipos de datos de velas (marcos temporales) para los flujos de filtro y disparador.

Notas

  • La estrategia procesa solo velas finalizadas e ignora actualizaciones parciales.
  • La implementación adaptativa de Sinewave2 usa el algoritmo CyclePeriod original para mantenerse fiel a la versión MQL.
  • Cuando los tipos de vela superior e inferior son idénticos, ambos indicadores comparten una sola suscripción de velas para evitar solicitudes de datos redundantes.
  • Ajuste Volume en la Strategy base para controlar el tamaño de trade antes del despliegue.
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>
/// Ehlers Sinewave X2 strategy (simplified). Uses CCI oscillator for entries.
/// </summary>
public class ExpSinewave2X2Strategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _cciLength;
	private readonly StrategyParam<int> _emaLength;

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

	public int CciLength
	{
		get => _cciLength.Value;
		set => _cciLength.Value = value;
	}

	public int EmaLength
	{
		get => _emaLength.Value;
		set => _emaLength.Value = value;
	}

	public ExpSinewave2X2Strategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
			.SetDisplay("Candle Type", "Candles", "General");

		_cciLength = Param(nameof(CciLength), 14)
			.SetGreaterThanZero()
			.SetDisplay("CCI Length", "CCI period", "Indicators");

		_emaLength = Param(nameof(EmaLength), 30)
			.SetGreaterThanZero()
			.SetDisplay("EMA Length", "Trend filter EMA", "Indicators");
	}

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

		var cci = new CommodityChannelIndex { Length = CciLength };
		var ema = new ExponentialMovingAverage { Length = EmaLength };

		decimal prevCci = 0;
		bool hasPrev = false;

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(cci, ema, (ICandleMessage candle, decimal cciValue, decimal emaValue) =>
			{
				if (candle.State != CandleStates.Finished)
					return;

				if (!hasPrev)
				{
					prevCci = cciValue;
					hasPrev = true;
					return;
				}

				if (!IsFormedAndOnlineAndAllowTrading())
				{
					prevCci = cciValue;
					return;
				}

				// CCI crosses above -100 with price above EMA
				if (prevCci < -100 && cciValue >= -100 && candle.ClosePrice > emaValue && Position <= 0)
				{
					BuyMarket();
				}
				// CCI crosses below 100 with price below EMA
				else if (prevCci > 100 && cciValue <= 100 && candle.ClosePrice < emaValue && Position >= 0)
				{
					SellMarket();
				}

				prevCci = cciValue;
			})
			.Start();

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