Стратегия Color Zerolag Momentum X2
Стратегия использует два таймфрейма и пересечение индикатора Momentum с его скользящей средней Zero Lag. Старший таймфрейм определяет направление тренда, младший формирует входы при пересечении Momentum своей Zero Lag средней в сторону тренда.
Детали
- Критерий входа: пересечение Momentum со своей Zero Lag средней по направлению тренда
- Покупка/Продажа: Обе стороны
- Критерий выхода: обратное пересечение или смена тренда
- Стопы: Нет
- Значения по умолчанию:
TrendCandleType= 6чTrendMomentumPeriod= 34TrendMaLength= 15SignalCandleType= 30мSignalMomentumPeriod= 34SignalMaLength= 15BuyPosOpen= trueSellPosOpen= trueBuyPosClose= trueSellPosClose= true
- Фильтры:
- Категория: Следование тренду
- Направление: Обе
- Индикаторы: Momentum, ZeroLagEMA
- Стопы: Нет
- Сложность: Средняя
- Таймфрейм: Мульти-таймфрейм
- Сезонность: Нет
- Нейросети: Нет
- Дивергенция: Нет
- Уровень риска: Средний
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()