La estrategia opera basándose en un índice de dirección promedio (ADX) de doble suavizado. Compara las líneas +DI y -DI suavizadas para detectar cambios de tendencia. Cuando la línea +DI suavizada cruza por encima de la línea -DI suavizada, la estrategia entra en una posición larga. Cuando la línea +DI suavizada cruza por debajo de la línea -DI suavizada, abre una posición corta.
Cómo Funciona
Utiliza un indicador ADX con período configurable.
Aplica dos pasadas de suavizado exponencial controladas por los parámetros Alpha1 y Alpha2.
Una señal larga ocurre cuando el +DI suavizado anterior estaba por debajo del -DI suavizado y el +DI suavizado actual está por encima.
Una señal corta ocurre en el cruce opuesto.
Parámetros opcionales permiten deshabilitar operaciones largas o cortas y controlar si las posiciones existentes pueden cerrarse cuando aparece una señal opuesta.
La gestión de riesgo incorporada establece niveles de stop-loss y take-profit en puntos.
Parámetros
Nombre
Descripción
AdxPeriod
Período para el cálculo del ADX.
Alpha1
Primer coeficiente de suavizado (0-1).
Alpha2
Segundo coeficiente de suavizado (0-1).
StopLoss
Stop-loss en puntos.
TakeProfit
Take-profit en puntos.
AllowBuy
Habilitar entradas largas.
AllowSell
Habilitar entradas cortas.
AllowCloseBuy
Permitir cerrar posiciones largas en señales de venta.
AllowCloseSell
Permitir cerrar posiciones cortas en señales de compra.
CandleType
Marco temporal utilizado para el indicador.
Notas
Solo se procesan velas finalizadas.
La estrategia usa la API de alto nivel con vinculación de indicadores.
El stop-loss y el take-profit se gestionan mediante StartProtection.
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>
/// Smoothed EMA crossover strategy (ADX-inspired directional cross concept).
/// Buys when fast EMA crosses above slow EMA, sells when below.
/// </summary>
public class AdxSmoothedCrossStrategy : Strategy
{
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private readonly StrategyParam<DataType> _candleType;
private decimal? _prevFast;
private decimal? _prevSlow;
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 AdxSmoothedCrossStrategy()
{
_fastPeriod = Param(nameof(FastPeriod), 10)
.SetGreaterThanZero()
.SetDisplay("Fast Period", "Fast EMA period", "Indicator");
_slowPeriod = Param(nameof(SlowPeriod), 25)
.SetGreaterThanZero()
.SetDisplay("Slow Period", "Slow EMA period", "Indicator");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Candle type", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevFast = null;
_prevSlow = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var fast = new ExponentialMovingAverage { Length = FastPeriod };
var slow = new ExponentialMovingAverage { Length = SlowPeriod };
SubscribeCandles(CandleType)
.Bind(fast, slow, ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal fastValue, decimal slowValue)
{
if (candle.State != CandleStates.Finished)
return;
if (_prevFast is null || _prevSlow is null)
{
_prevFast = fastValue;
_prevSlow = slowValue;
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;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Math
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class adx_smoothed_cross_strategy(Strategy):
def __init__(self):
super(adx_smoothed_cross_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 10) \
.SetDisplay("Fast Period", "Fast EMA period", "Indicator")
self._slow_period = self.Param("SlowPeriod", 25) \
.SetDisplay("Slow Period", "Slow EMA period", "Indicator")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Candle type", "General")
self._prev_fast = None
self._prev_slow = None
@property
def FastPeriod(self):
return self._fast_period.Value
@FastPeriod.setter
def FastPeriod(self, value):
self._fast_period.Value = value
@property
def SlowPeriod(self):
return self._slow_period.Value
@SlowPeriod.setter
def SlowPeriod(self, value):
self._slow_period.Value = value
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
def OnStarted2(self, time):
super(adx_smoothed_cross_strategy, self).OnStarted2(time)
fast = ExponentialMovingAverage()
fast.Length = self.FastPeriod
slow = ExponentialMovingAverage()
slow.Length = self.SlowPeriod
self.SubscribeCandles(self.CandleType) \
.Bind(fast, slow, self.ProcessCandle) \
.Start()
def ProcessCandle(self, candle, fast_value, slow_value):
if candle.State != CandleStates.Finished:
return
fast_val = float(fast_value)
slow_val = float(slow_value)
if self._prev_fast is None or self._prev_slow is None:
self._prev_fast = fast_val
self._prev_slow = slow_val
return
cross_up = self._prev_fast <= self._prev_slow and fast_val > slow_val
cross_down = self._prev_fast >= self._prev_slow and fast_val < slow_val
if cross_up and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif cross_down and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_fast = fast_val
self._prev_slow = slow_val
def OnReseted(self):
super(adx_smoothed_cross_strategy, self).OnReseted()
self._prev_fast = None
self._prev_slow = None
def CreateClone(self):
return adx_smoothed_cross_strategy()