Estrategia Sidus
Esta estrategia implementa el sistema de medias móviles SIDUS. Opera usando cruces entre dos medias móviles ponderadas linealmente y una media exponencial de confirmación. Se abre una posición cuando la LWMA a corto plazo cruza la LWMA a largo plazo o cuando la LWMA larga cruza la EMA lenta. Los cruces opuestos cierran o revierten la posición. Un stop-loss y take-profit basados en porcentaje gestionan el riesgo.
Las pruebas indican una rentabilidad anual media de aproximadamente el 25%. Funciona mejor en pares de divisas.
La idea central es capturar los cambios de tendencia cuando las medias móviles rápidas y lentas se realinean. El par de LWMA reacciona rápidamente a los cambios de precio mientras que la EMA más lenta filtra el ruido. Cuando ocurre una alineación alcista o bajista, la estrategia entra en esa dirección y confía en los niveles de protección para salir durante movimientos adversos.
Detalles
- Criterios de entrada:
- Largo: la LWMA rápida cruza por encima de la LWMA lenta o la LWMA lenta cruza por encima de la EMA lenta.
- Corto: la LWMA rápida cruza por debajo de la LWMA lenta o la LWMA lenta cruza por debajo de la EMA lenta.
- Largo/Corto: Ambos.
- Criterios de salida:
- Cruce opuesto o niveles de stop de protección.
- Stops: Sí, utiliza take-profit y stop-loss basados en porcentaje mediante
StartProtection.
- Valores predeterminados:
- Longitud de EMA rápida = 18.
- Longitud de EMA lenta = 28.
- Longitud de LWMA rápida = 5.
- Longitud de LWMA lenta = 8.
- Take profit = 2%.
- Stop loss = 1%.
- Filtros: Ninguno.
using System;
using System.Linq;
using System.Collections.Generic;
using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// SIDUS strategy based on moving average crossovers.
/// Buys when fast LWMA crosses above slow LWMA or when slow LWMA crosses above slow EMA.
/// Sells on opposite crossovers.
/// </summary>
public class SidusStrategy : Strategy
{
private readonly StrategyParam<int> _fastEma;
private readonly StrategyParam<int> _slowEma;
private readonly StrategyParam<int> _fastLwma;
private readonly StrategyParam<int> _slowLwma;
private readonly StrategyParam<DataType> _candleType;
private ExponentialMovingAverage _fastEmaIndicator;
private ExponentialMovingAverage _slowEmaIndicator;
private WeightedMovingAverage _fastLwmaIndicator;
private WeightedMovingAverage _slowLwmaIndicator;
private decimal _prevFastLwma;
private decimal _prevSlowLwma;
private decimal _prevSlowEma;
private bool _isInitialized;
public int FastEma { get => _fastEma.Value; set => _fastEma.Value = value; }
public int SlowEma { get => _slowEma.Value; set => _slowEma.Value = value; }
public int FastLwma { get => _fastLwma.Value; set => _fastLwma.Value = value; }
public int SlowLwma { get => _slowLwma.Value; set => _slowLwma.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public SidusStrategy()
{
_fastEma = Param(nameof(FastEma), 18)
.SetGreaterThanZero()
.SetDisplay("Fast EMA", "Length of the fast EMA", "Sidus")
.SetOptimize(10, 30, 2);
_slowEma = Param(nameof(SlowEma), 28)
.SetGreaterThanZero()
.SetDisplay("Slow EMA", "Length of the slow EMA", "Sidus")
.SetOptimize(20, 50, 2);
_fastLwma = Param(nameof(FastLwma), 5)
.SetGreaterThanZero()
.SetDisplay("Fast LWMA", "Length of the fast LWMA", "Sidus")
.SetOptimize(3, 10, 1);
_slowLwma = Param(nameof(SlowLwma), 8)
.SetGreaterThanZero()
.SetDisplay("Slow LWMA", "Length of the slow LWMA", "Sidus")
.SetOptimize(5, 15, 1);
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Type of candles", "General");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
protected override void OnReseted()
{
base.OnReseted();
_prevFastLwma = 0;
_prevSlowLwma = 0;
_prevSlowEma = 0;
_isInitialized = false;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_fastEmaIndicator = new ExponentialMovingAverage { Length = FastEma };
_slowEmaIndicator = new ExponentialMovingAverage { Length = SlowEma };
_fastLwmaIndicator = new WeightedMovingAverage { Length = FastLwma };
_slowLwmaIndicator = new WeightedMovingAverage { Length = SlowLwma };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(_fastEmaIndicator, _slowEmaIndicator, _fastLwmaIndicator, _slowLwmaIndicator, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, _fastEmaIndicator);
DrawIndicator(area, _slowEmaIndicator);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal fastEmaValue, decimal slowEmaValue, decimal fastLwmaValue, decimal slowLwmaValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!_isInitialized)
{
_prevFastLwma = fastLwmaValue;
_prevSlowLwma = slowLwmaValue;
_prevSlowEma = slowEmaValue;
_isInitialized = true;
return;
}
var buySignal =
(fastLwmaValue > slowLwmaValue && _prevFastLwma <= _prevSlowLwma) ||
(slowLwmaValue > slowEmaValue && _prevSlowLwma <= _prevSlowEma);
var sellSignal =
(fastLwmaValue < slowLwmaValue && _prevFastLwma >= _prevSlowLwma) ||
(slowLwmaValue < slowEmaValue && _prevSlowLwma >= _prevSlowEma);
if (IsFormedAndOnlineAndAllowTrading())
{
if (buySignal && Position <= 0)
BuyMarket();
else if (sellSignal && Position >= 0)
SellMarket();
}
_prevFastLwma = fastLwmaValue;
_prevSlowLwma = slowLwmaValue;
_prevSlowEma = slowEmaValue;
}
}
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 ExponentialMovingAverage, WeightedMovingAverage
from StockSharp.Algo.Strategies import Strategy
class sidus_strategy(Strategy):
def __init__(self):
super(sidus_strategy, self).__init__()
self._fast_ema = self.Param("FastEma", 18) \
.SetDisplay("Fast EMA", "Length of the fast EMA", "Sidus")
self._slow_ema = self.Param("SlowEma", 28) \
.SetDisplay("Slow EMA", "Length of the slow EMA", "Sidus")
self._fast_lwma = self.Param("FastLwma", 5) \
.SetDisplay("Fast LWMA", "Length of the fast LWMA", "Sidus")
self._slow_lwma = self.Param("SlowLwma", 8) \
.SetDisplay("Slow LWMA", "Length of the slow LWMA", "Sidus")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Type of candles", "General")
self._prev_fast_lwma = 0.0
self._prev_slow_lwma = 0.0
self._prev_slow_ema = 0.0
self._is_initialized = False
@property
def fast_ema(self):
return self._fast_ema.Value
@property
def slow_ema(self):
return self._slow_ema.Value
@property
def fast_lwma(self):
return self._fast_lwma.Value
@property
def slow_lwma(self):
return self._slow_lwma.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(sidus_strategy, self).OnReseted()
self._prev_fast_lwma = 0.0
self._prev_slow_lwma = 0.0
self._prev_slow_ema = 0.0
self._is_initialized = False
def OnStarted2(self, time):
super(sidus_strategy, self).OnStarted2(time)
fast_ema_ind = ExponentialMovingAverage()
fast_ema_ind.Length = self.fast_ema
slow_ema_ind = ExponentialMovingAverage()
slow_ema_ind.Length = self.slow_ema
fast_lwma_ind = WeightedMovingAverage()
fast_lwma_ind.Length = self.fast_lwma
slow_lwma_ind = WeightedMovingAverage()
slow_lwma_ind.Length = self.slow_lwma
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(fast_ema_ind, slow_ema_ind, fast_lwma_ind, slow_lwma_ind, self.process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, fast_ema_ind)
self.DrawIndicator(area, slow_ema_ind)
self.DrawOwnTrades(area)
def process_candle(self, candle, fast_ema_val, slow_ema_val, fast_lwma_val, slow_lwma_val):
if candle.State != CandleStates.Finished:
return
fast_ema_val = float(fast_ema_val)
slow_ema_val = float(slow_ema_val)
fast_lwma_val = float(fast_lwma_val)
slow_lwma_val = float(slow_lwma_val)
if not self._is_initialized:
self._prev_fast_lwma = fast_lwma_val
self._prev_slow_lwma = slow_lwma_val
self._prev_slow_ema = slow_ema_val
self._is_initialized = True
return
buy_signal = (
(fast_lwma_val > slow_lwma_val and self._prev_fast_lwma <= self._prev_slow_lwma) or
(slow_lwma_val > slow_ema_val and self._prev_slow_lwma <= self._prev_slow_ema)
)
sell_signal = (
(fast_lwma_val < slow_lwma_val and self._prev_fast_lwma >= self._prev_slow_lwma) or
(slow_lwma_val < slow_ema_val and self._prev_slow_lwma >= self._prev_slow_ema)
)
if buy_signal and self.Position <= 0:
self.BuyMarket()
elif sell_signal and self.Position >= 0:
self.SellMarket()
self._prev_fast_lwma = fast_lwma_val
self._prev_slow_lwma = slow_lwma_val
self._prev_slow_ema = slow_ema_val
def CreateClone(self):
return sidus_strategy()