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
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.
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.
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.
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);
}
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import CommodityChannelIndex, ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class exp_sinewave2_x2_strategy(Strategy):
"""
Ehlers Sinewave X2 strategy (simplified). Uses CCI oscillator for entries.
CCI crosses above -100 with price above EMA to buy, CCI crosses below 100 with price below EMA to sell.
"""
def __init__(self):
super(exp_sinewave2_x2_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))) \
.SetDisplay("Candle Type", "Candles", "General")
self._cci_length = self.Param("CciLength", 14) \
.SetDisplay("CCI Length", "CCI period", "Indicators")
self._ema_length = self.Param("EmaLength", 30) \
.SetDisplay("EMA Length", "Trend filter EMA", "Indicators")
self._prev_cci = 0.0
self._has_prev = False
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(exp_sinewave2_x2_strategy, self).OnReseted()
self._prev_cci = 0.0
self._has_prev = False
def OnStarted2(self, time):
super(exp_sinewave2_x2_strategy, self).OnStarted2(time)
self._has_prev = False
cci = CommodityChannelIndex()
cci.Length = self._cci_length.Value
ema = ExponentialMovingAverage()
ema.Length = self._ema_length.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(cci, ema, self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, ema)
self.DrawOwnTrades(area)
def _process_candle(self, candle, cci_val, ema_val):
if candle.State != CandleStates.Finished:
return
cci_val = float(cci_val)
ema_val = float(ema_val)
if not self._has_prev:
self._prev_cci = cci_val
self._has_prev = True
return
if not self.IsFormedAndOnlineAndAllowTrading():
self._prev_cci = cci_val
return
close = float(candle.ClosePrice)
if self._prev_cci < -100 and cci_val >= -100 and close > ema_val and self.Position <= 0:
self.BuyMarket()
elif self._prev_cci > 100 and cci_val <= 100 and close < ema_val and self.Position >= 0:
self.SellMarket()
self._prev_cci = cci_val
def CreateClone(self):
return exp_sinewave2_x2_strategy()