Estrategia Color Zerolag Momentum X2
Estrategia de momentum en doble marco temporal que utiliza un cruce de media móvil de cero lag. El marco temporal superior define la dirección de la tendencia, mientras que el marco temporal inferior activa las entradas cuando el momentum cruza su media de cero lag en la dirección de la tendencia.
Detalles
- Criterios de entrada: el momentum cruza su media de cero lag en la dirección de la tendencia
- Largo/Corto: Ambos
- Criterios de salida: cruce opuesto o reversión de tendencia
- Stops: No
- Valores predeterminados:
TrendCandleType= 6hTrendMomentumPeriod= 34TrendMaLength= 15SignalCandleType= 30mSignalMomentumPeriod= 34SignalMaLength= 15BuyPosOpen= trueSellPosOpen= trueBuyPosClose= trueSellPosClose= true
- Filtros:
- Categoría: Seguimiento de tendencia
- Dirección: Ambos
- Indicadores: Momentum, ZeroLagEMA
- Stops: No
- Complejidad: Intermedio
- Marco temporal: Multi-marco temporal
- Estacionalidad: No
- Redes neuronales: No
- Divergencia: No
- Nivel de riesgo: Medio
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>
/// Momentum cross strategy on two timeframes using zero lag moving average.
/// </summary>
public class ColorZerolagMomentumX2Strategy : Strategy
{
private readonly StrategyParam<DataType> _trendCandleType;
private readonly StrategyParam<int> _trendMomentumPeriod;
private readonly StrategyParam<int> _trendMaLength;
private readonly StrategyParam<DataType> _signalCandleType;
private readonly StrategyParam<int> _signalMomentumPeriod;
private readonly StrategyParam<int> _signalMaLength;
private readonly StrategyParam<bool> _buyPosOpen;
private readonly StrategyParam<bool> _sellPosOpen;
private readonly StrategyParam<bool> _buyPosClose;
private readonly StrategyParam<bool> _sellPosClose;
private int _trend;
private decimal? _prevSignalMomentum;
private decimal? _prevSignalMa;
/// <summary>
/// Candle type for trend detection.
/// </summary>
public DataType TrendCandleType
{
get => _trendCandleType.Value;
set => _trendCandleType.Value = value;
}
/// <summary>
/// Momentum period on trend timeframe.
/// </summary>
public int TrendMomentumPeriod
{
get => _trendMomentumPeriod.Value;
set => _trendMomentumPeriod.Value = value;
}
/// <summary>
/// Smoothing length on trend timeframe.
/// </summary>
public int TrendMaLength
{
get => _trendMaLength.Value;
set => _trendMaLength.Value = value;
}
/// <summary>
/// Candle type for signals.
/// </summary>
public DataType SignalCandleType
{
get => _signalCandleType.Value;
set => _signalCandleType.Value = value;
}
/// <summary>
/// Momentum period on signal timeframe.
/// </summary>
public int SignalMomentumPeriod
{
get => _signalMomentumPeriod.Value;
set => _signalMomentumPeriod.Value = value;
}
/// <summary>
/// Smoothing length on signal timeframe.
/// </summary>
public int SignalMaLength
{
get => _signalMaLength.Value;
set => _signalMaLength.Value = value;
}
/// <summary>
/// Allow long entries.
/// </summary>
public bool BuyPosOpen
{
get => _buyPosOpen.Value;
set => _buyPosOpen.Value = value;
}
/// <summary>
/// Allow short entries.
/// </summary>
public bool SellPosOpen
{
get => _sellPosOpen.Value;
set => _sellPosOpen.Value = value;
}
/// <summary>
/// Close long positions on opposite signal.
/// </summary>
public bool BuyPosClose
{
get => _buyPosClose.Value;
set => _buyPosClose.Value = value;
}
/// <summary>
/// Close short positions on opposite signal.
/// </summary>
public bool SellPosClose
{
get => _sellPosClose.Value;
set => _sellPosClose.Value = value;
}
/// <summary>
/// Initializes a new instance of <see cref="ColorZerolagMomentumX2Strategy"/>.
/// </summary>
public ColorZerolagMomentumX2Strategy()
{
_trendCandleType = Param(nameof(TrendCandleType), TimeSpan.FromMinutes(15).TimeFrame())
.SetDisplay("Trend Timeframe", "Candle type for trend", "General");
_trendMomentumPeriod = Param(nameof(TrendMomentumPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("Trend Momentum Period", "Momentum length for trend", "Parameters")
;
_trendMaLength = Param(nameof(TrendMaLength), 5)
.SetGreaterThanZero()
.SetDisplay("Trend Smooth Length", "Zero lag MA length for trend", "Parameters")
;
_signalCandleType = Param(nameof(SignalCandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Signal Timeframe", "Candle type for signals", "General");
_signalMomentumPeriod = Param(nameof(SignalMomentumPeriod), 20)
.SetGreaterThanZero()
.SetDisplay("Signal Momentum Period", "Momentum length for signals", "Parameters")
;
_signalMaLength = Param(nameof(SignalMaLength), 8)
.SetGreaterThanZero()
.SetDisplay("Signal Smooth Length", "Zero lag MA length for signals", "Parameters")
;
_buyPosOpen = Param(nameof(BuyPosOpen), true)
.SetDisplay("Buy Entries", "Enable long entries", "Signals");
_sellPosOpen = Param(nameof(SellPosOpen), true)
.SetDisplay("Sell Entries", "Enable short entries", "Signals");
_buyPosClose = Param(nameof(BuyPosClose), true)
.SetDisplay("Buy Exits", "Close longs on opposite signal", "Signals");
_sellPosClose = Param(nameof(SellPosClose), true)
.SetDisplay("Sell Exits", "Close shorts on opposite signal", "Signals");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, TrendCandleType), (Security, SignalCandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_trend = 0;
_prevSignalMomentum = default;
_prevSignalMa = default;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
StartProtection(
takeProfit: new Unit(2, UnitTypes.Percent),
stopLoss: new Unit(1, UnitTypes.Percent));
var trendFast = new ExponentialMovingAverage { Length = TrendMaLength };
var trendSlow = new ExponentialMovingAverage { Length = TrendMomentumPeriod };
var trendSub = SubscribeCandles(TrendCandleType);
trendSub.Bind(trendFast, trendSlow, ProcessTrend).Start();
var signalFast = new ExponentialMovingAverage { Length = SignalMaLength };
var signalSlow = new ExponentialMovingAverage { Length = SignalMomentumPeriod };
var signalSub = SubscribeCandles(SignalCandleType);
signalSub.Bind(signalFast, signalSlow, ProcessSignal).Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, signalSub);
DrawIndicator(area, signalFast);
DrawIndicator(area, signalSlow);
DrawOwnTrades(area);
}
}
private void ProcessTrend(ICandleMessage candle, decimal fast, decimal slow)
{
if (candle.State != CandleStates.Finished)
return;
_trend = fast > slow ? 1 : -1;
}
private void ProcessSignal(ICandleMessage candle, decimal fast, decimal slow)
{
if (candle.State != CandleStates.Finished)
return;
if (_prevSignalMomentum is null || _prevSignalMa is null)
{
_prevSignalMomentum = fast;
_prevSignalMa = slow;
return;
}
var buyOpen = BuyPosOpen && _prevSignalMomentum <= _prevSignalMa && fast > slow;
var sellOpen = SellPosOpen && _prevSignalMomentum >= _prevSignalMa && fast < slow;
if (buyOpen && Position == 0)
BuyMarket();
else if (sellOpen && Position == 0)
SellMarket();
_prevSignalMomentum = fast;
_prevSignalMa = slow;
}
}
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, Unit, UnitTypes
from StockSharp.Algo.Indicators import ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class color_zerolag_momentum_x2_strategy(Strategy):
def __init__(self):
super(color_zerolag_momentum_x2_strategy, self).__init__()
self._trend_candle_type = self.Param("TrendCandleType", DataType.TimeFrame(TimeSpan.FromMinutes(15)))
self._trend_momentum_period = self.Param("TrendMomentumPeriod", 14)
self._trend_ma_length = self.Param("TrendMaLength", 5)
self._signal_candle_type = self.Param("SignalCandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5)))
self._signal_momentum_period = self.Param("SignalMomentumPeriod", 20)
self._signal_ma_length = self.Param("SignalMaLength", 8)
self._buy_pos_open = self.Param("BuyPosOpen", True)
self._sell_pos_open = self.Param("SellPosOpen", True)
self._buy_pos_close = self.Param("BuyPosClose", True)
self._sell_pos_close = self.Param("SellPosClose", True)
self._trend = 0
self._prev_signal_momentum = None
self._prev_signal_ma = None
@property
def TrendCandleType(self):
return self._trend_candle_type.Value
@TrendCandleType.setter
def TrendCandleType(self, value):
self._trend_candle_type.Value = value
@property
def TrendMomentumPeriod(self):
return self._trend_momentum_period.Value
@TrendMomentumPeriod.setter
def TrendMomentumPeriod(self, value):
self._trend_momentum_period.Value = value
@property
def TrendMaLength(self):
return self._trend_ma_length.Value
@TrendMaLength.setter
def TrendMaLength(self, value):
self._trend_ma_length.Value = value
@property
def SignalCandleType(self):
return self._signal_candle_type.Value
@SignalCandleType.setter
def SignalCandleType(self, value):
self._signal_candle_type.Value = value
@property
def SignalMomentumPeriod(self):
return self._signal_momentum_period.Value
@SignalMomentumPeriod.setter
def SignalMomentumPeriod(self, value):
self._signal_momentum_period.Value = value
@property
def SignalMaLength(self):
return self._signal_ma_length.Value
@SignalMaLength.setter
def SignalMaLength(self, value):
self._signal_ma_length.Value = value
@property
def BuyPosOpen(self):
return self._buy_pos_open.Value
@BuyPosOpen.setter
def BuyPosOpen(self, value):
self._buy_pos_open.Value = value
@property
def SellPosOpen(self):
return self._sell_pos_open.Value
@SellPosOpen.setter
def SellPosOpen(self, value):
self._sell_pos_open.Value = value
@property
def BuyPosClose(self):
return self._buy_pos_close.Value
@BuyPosClose.setter
def BuyPosClose(self, value):
self._buy_pos_close.Value = value
@property
def SellPosClose(self):
return self._sell_pos_close.Value
@SellPosClose.setter
def SellPosClose(self, value):
self._sell_pos_close.Value = value
def OnStarted2(self, time):
super(color_zerolag_momentum_x2_strategy, self).OnStarted2(time)
self._trend = 0
self._prev_signal_momentum = None
self._prev_signal_ma = None
self.StartProtection(
Unit(2.0, UnitTypes.Percent),
Unit(1.0, UnitTypes.Percent))
trend_fast = ExponentialMovingAverage()
trend_fast.Length = self.TrendMaLength
trend_slow = ExponentialMovingAverage()
trend_slow.Length = self.TrendMomentumPeriod
trend_sub = self.SubscribeCandles(self.TrendCandleType)
trend_sub.Bind(trend_fast, trend_slow, self.ProcessTrend).Start()
signal_fast = ExponentialMovingAverage()
signal_fast.Length = self.SignalMaLength
signal_slow = ExponentialMovingAverage()
signal_slow.Length = self.SignalMomentumPeriod
signal_sub = self.SubscribeCandles(self.SignalCandleType)
signal_sub.Bind(signal_fast, signal_slow, self.ProcessSignal).Start()
def ProcessTrend(self, candle, fast, slow):
if candle.State != CandleStates.Finished:
return
f = float(fast)
s = float(slow)
self._trend = 1 if f > s else -1
def ProcessSignal(self, candle, fast, slow):
if candle.State != CandleStates.Finished:
return
f = float(fast)
s = float(slow)
if self._prev_signal_momentum is None or self._prev_signal_ma is None:
self._prev_signal_momentum = f
self._prev_signal_ma = s
return
buy_open = self.BuyPosOpen and self._prev_signal_momentum <= self._prev_signal_ma and f > s
sell_open = self.SellPosOpen and self._prev_signal_momentum >= self._prev_signal_ma and f < s
if buy_open and self.Position == 0:
self.BuyMarket()
elif sell_open and self.Position == 0:
self.SellMarket()
self._prev_signal_momentum = f
self._prev_signal_ma = s
def OnReseted(self):
super(color_zerolag_momentum_x2_strategy, self).OnReseted()
self._trend = 0
self._prev_signal_momentum = None
self._prev_signal_ma = None
def CreateClone(self):
return color_zerolag_momentum_x2_strategy()