Estrategia Avanzada de Cruce de EMA
Esta estrategia va largo cuando una EMA de corto plazo cruza por encima de una EMA de largo plazo, filtrando señales con ATR normalizado, fuerza de tendencia ADX y una verificación de dirección de SuperTrend. Los niveles de stop-loss y take-profit se adaptan en función de la fortaleza del USD inferida a partir de una EMA de 50 períodos.
Detalles
- Criterios de entrada:
- La EMA corta cruza por encima de la EMA larga.
- ATR normalizado por encima de los umbrales según la dirección de la tendencia.
- SuperTrend confirma mercado alcista o bajista.
- Criterios de salida:
- Cruce inverso de EMA o ADX por encima del umbral tras un período mínimo de mantenimiento.
- Stop-loss o take-profit alcanzado.
- Indicadores: EMA, ATR, ADX, SuperTrend, SMA (volumen).
- Stops: Stop-loss y take-profit porcentuales dinámicos.
- Tipo: Seguimiento de tendencia.
- Marco temporal: 30 minutos (predeterminado).
namespace StockSharp.Samples.Strategies;
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
/// <summary>
/// Advanced EMA Cross Strategy - uses EMA crossover with ADX filter.
/// </summary>
public class AdvancedEmaCrossStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _emaShortLength;
private readonly StrategyParam<int> _emaLongLength;
private readonly StrategyParam<int> _adxPeriod;
private readonly StrategyParam<decimal> _adxHighLevel;
private readonly StrategyParam<int> _cooldownBars;
private decimal _prevEmaShort;
private decimal _prevEmaLong;
private int _cooldownRemaining;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int EmaShortLength { get => _emaShortLength.Value; set => _emaShortLength.Value = value; }
public int EmaLongLength { get => _emaLongLength.Value; set => _emaLongLength.Value = value; }
public int AdxPeriod { get => _adxPeriod.Value; set => _adxPeriod.Value = value; }
public decimal AdxHighLevel { get => _adxHighLevel.Value; set => _adxHighLevel.Value = value; }
public int CooldownBars { get => _cooldownBars.Value; set => _cooldownBars.Value = value; }
public AdvancedEmaCrossStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
_emaShortLength = Param(nameof(EmaShortLength), 8)
.SetGreaterThanZero()
.SetDisplay("EMA Short Length", "Short EMA period", "EMA");
_emaLongLength = Param(nameof(EmaLongLength), 20)
.SetGreaterThanZero()
.SetDisplay("EMA Long Length", "Long EMA period", "EMA");
_adxPeriod = Param(nameof(AdxPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("ADX Period", "ADX calculation period", "ADX");
_adxHighLevel = Param(nameof(AdxHighLevel), 20m)
.SetDisplay("ADX Level", "ADX threshold for trending market", "ADX");
_cooldownBars = Param(nameof(CooldownBars), 10)
.SetDisplay("Cooldown Bars", "Bars between trades", "Risk");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevEmaShort = 0;
_prevEmaLong = 0;
_cooldownRemaining = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var emaShort = new ExponentialMovingAverage { Length = EmaShortLength };
var emaLong = new ExponentialMovingAverage { Length = EmaLongLength };
var adx = new AverageDirectionalIndex { Length = AdxPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(emaShort, emaLong, adx, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, emaShort);
DrawIndicator(area, emaLong);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue emaShortValue, IIndicatorValue emaLongValue, IIndicatorValue adxValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var emaShort = emaShortValue.ToDecimal();
var emaLong = emaLongValue.ToDecimal();
var adxTyped = (IAverageDirectionalIndexValue)adxValue;
if (adxTyped.MovingAverage is not decimal adx)
{
_prevEmaShort = emaShort;
_prevEmaLong = emaLong;
return;
}
if (_prevEmaShort == 0)
{
_prevEmaShort = emaShort;
_prevEmaLong = emaLong;
return;
}
if (_cooldownRemaining > 0)
{
_cooldownRemaining--;
_prevEmaShort = emaShort;
_prevEmaLong = emaLong;
return;
}
var crossover = _prevEmaShort <= _prevEmaLong && emaShort > emaLong;
var crossunder = _prevEmaShort >= _prevEmaLong && emaShort < emaLong;
var trending = adx > AdxHighLevel;
if (crossover && trending && Position <= 0)
{
if (Position < 0)
BuyMarket(Math.Abs(Position));
BuyMarket(Volume);
_cooldownRemaining = CooldownBars;
}
else if (crossunder && trending && Position >= 0)
{
if (Position > 0)
SellMarket(Math.Abs(Position));
SellMarket(Volume);
_cooldownRemaining = CooldownBars;
}
_prevEmaShort = emaShort;
_prevEmaLong = emaLong;
}
}
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, AverageDirectionalIndex, IndicatorHelper
from StockSharp.Algo.Strategies import Strategy
class advanced_ema_cross_strategy(Strategy):
def __init__(self):
super(advanced_ema_cross_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(30))) \
.SetDisplay("Candle Type", "Type of candles to use", "General")
self._ema_short_length = self.Param("EmaShortLength", 8) \
.SetGreaterThanZero() \
.SetDisplay("EMA Short Length", "Short EMA period", "EMA")
self._ema_long_length = self.Param("EmaLongLength", 20) \
.SetGreaterThanZero() \
.SetDisplay("EMA Long Length", "Long EMA period", "EMA")
self._adx_period = self.Param("AdxPeriod", 14) \
.SetGreaterThanZero() \
.SetDisplay("ADX Period", "ADX calculation period", "ADX")
self._adx_high_level = self.Param("AdxHighLevel", 20.0) \
.SetDisplay("ADX Level", "ADX threshold for trending market", "ADX")
self._cooldown_bars = self.Param("CooldownBars", 10) \
.SetDisplay("Cooldown Bars", "Bars between trades", "Risk")
self._prev_ema_short = 0.0
self._prev_ema_long = 0.0
self._cooldown_remaining = 0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(advanced_ema_cross_strategy, self).OnReseted()
self._prev_ema_short = 0.0
self._prev_ema_long = 0.0
self._cooldown_remaining = 0
def OnStarted2(self, time):
super(advanced_ema_cross_strategy, self).OnStarted2(time)
ema_short = ExponentialMovingAverage()
ema_short.Length = int(self._ema_short_length.Value)
ema_long = ExponentialMovingAverage()
ema_long.Length = int(self._ema_long_length.Value)
adx = AverageDirectionalIndex()
adx.Length = int(self._adx_period.Value)
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(ema_short, ema_long, adx, self._on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, ema_short)
self.DrawIndicator(area, ema_long)
self.DrawOwnTrades(area)
def _on_process(self, candle, ema_short_value, ema_long_value, adx_value):
if candle.State != CandleStates.Finished:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
ema_s = float(IndicatorHelper.ToDecimal(ema_short_value))
ema_l = float(IndicatorHelper.ToDecimal(ema_long_value))
adx_ma = adx_value.MovingAverage
if adx_ma is None:
self._prev_ema_short = ema_s
self._prev_ema_long = ema_l
return
adx_v = float(adx_ma)
if self._prev_ema_short == 0:
self._prev_ema_short = ema_s
self._prev_ema_long = ema_l
return
if self._cooldown_remaining > 0:
self._cooldown_remaining -= 1
self._prev_ema_short = ema_s
self._prev_ema_long = ema_l
return
cooldown = int(self._cooldown_bars.Value)
crossover = self._prev_ema_short <= self._prev_ema_long and ema_s > ema_l
crossunder = self._prev_ema_short >= self._prev_ema_long and ema_s < ema_l
trending = adx_v > float(self._adx_high_level.Value)
if crossover and trending and self.Position <= 0:
if self.Position < 0:
self.BuyMarket(Math.Abs(self.Position))
self.BuyMarket(self.Volume)
self._cooldown_remaining = cooldown
elif crossunder and trending and self.Position >= 0:
if self.Position > 0:
self.SellMarket(Math.Abs(self.Position))
self.SellMarket(self.Volume)
self._cooldown_remaining = cooldown
self._prev_ema_short = ema_s
self._prev_ema_long = ema_l
def CreateClone(self):
return advanced_ema_cross_strategy()