Стратегия Multi Indicator Trend Following
Стратегия пересечения EMA с фильтрацией RSI и объёмом. Использует стоп-лосс и тейк-профит на основе ATR.
Детали
- Вход: быстрое EMA пересекает медленное при подтверждении RSI и повышенном объёме
- Длинная/Короткая: Оба направления
- Выход: стоп-лосс и тейк-профит по ATR
- Стопы: Да, по ATR
- Значения по умолчанию:
CandleType= 5 минутFastMaLength= 10SlowMaLength= 30RsiLength= 14VolumeMaLength= 20VolumeMultiplier= 1.5AtrPeriod= 14StopLossAtrMultiplier= 2TakeProfitAtrMultiplier= 3
- Фильтры:
- Категория: Следование тренду
- Направление: Оба
- Индикаторы: EMA, RSI, ATR, Объём
- Стопы: Да
- Сложность: Средняя
- Таймфрейм: Внутридневной
- Сезонность: Нет
- Нейросети: Нет
- Дивергенция: Нет
- Уровень риска: Средний
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>
/// EMA crossover with RSI confirmation trend following strategy.
/// </summary>
public class MultiIndicatorTrendFollowingStrategy : Strategy
{
private readonly StrategyParam<int> _fastMaLength;
private readonly StrategyParam<int> _slowMaLength;
private readonly StrategyParam<int> _rsiLength;
private readonly StrategyParam<decimal> _longRsiLevel;
private readonly StrategyParam<decimal> _shortRsiLevel;
private readonly StrategyParam<int> _signalCooldownBars;
private readonly StrategyParam<DataType> _candleType;
public int FastMaLength { get => _fastMaLength.Value; set => _fastMaLength.Value = value; }
public int SlowMaLength { get => _slowMaLength.Value; set => _slowMaLength.Value = value; }
public int RsiLength { get => _rsiLength.Value; set => _rsiLength.Value = value; }
public decimal LongRsiLevel { get => _longRsiLevel.Value; set => _longRsiLevel.Value = value; }
public decimal ShortRsiLevel { get => _shortRsiLevel.Value; set => _shortRsiLevel.Value = value; }
public int SignalCooldownBars { get => _signalCooldownBars.Value; set => _signalCooldownBars.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public MultiIndicatorTrendFollowingStrategy()
{
_fastMaLength = Param(nameof(FastMaLength), 10)
.SetGreaterThanZero()
.SetDisplay("Fast MA", "Fast EMA period", "Indicators");
_slowMaLength = Param(nameof(SlowMaLength), 30)
.SetGreaterThanZero()
.SetDisplay("Slow MA", "Slow EMA period", "Indicators");
_rsiLength = Param(nameof(RsiLength), 14)
.SetGreaterThanZero()
.SetDisplay("RSI Length", "RSI period", "Indicators");
_longRsiLevel = Param(nameof(LongRsiLevel), 55m)
.SetDisplay("Long RSI", "Minimum RSI for long entries", "Indicators");
_shortRsiLevel = Param(nameof(ShortRsiLevel), 45m)
.SetDisplay("Short RSI", "Maximum RSI for short entries", "Indicators");
_signalCooldownBars = Param(nameof(SignalCooldownBars), 6)
.SetGreaterThanZero()
.SetDisplay("Signal Cooldown", "Bars to wait after each crossover trade", "Trading");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(15).TimeFrame())
.SetDisplay("Candle Type", "Type of candles", "General");
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var fastEma = new ExponentialMovingAverage { Length = FastMaLength };
var slowEma = new ExponentialMovingAverage { Length = SlowMaLength };
var rsi = new RelativeStrengthIndex { Length = RsiLength };
var prevFast = 0m;
var prevSlow = 0m;
var initialized = false;
var cooldownRemaining = 0;
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(fastEma, slowEma, rsi, (candle, fastVal, slowVal, rsiVal) =>
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (cooldownRemaining > 0)
cooldownRemaining--;
if (!initialized)
{
prevFast = fastVal;
prevSlow = slowVal;
initialized = true;
return;
}
var crossUp = prevFast <= prevSlow && fastVal > slowVal;
var crossDown = prevFast >= prevSlow && fastVal < slowVal;
if (cooldownRemaining == 0 && crossUp && rsiVal > LongRsiLevel && Position <= 0)
{
BuyMarket();
cooldownRemaining = SignalCooldownBars;
}
else if (cooldownRemaining == 0 && crossDown && rsiVal < ShortRsiLevel && Position >= 0)
{
SellMarket();
cooldownRemaining = SignalCooldownBars;
}
prevFast = fastVal;
prevSlow = slowVal;
})
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, fastEma);
DrawIndicator(area, slowEma);
DrawOwnTrades(area);
}
}
}
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, RelativeStrengthIndex
from StockSharp.Algo.Strategies import Strategy
class multi_indicator_trend_following_strategy(Strategy):
def __init__(self):
super(multi_indicator_trend_following_strategy, self).__init__()
self._fast_ma_length = self.Param("FastMaLength", 10) \
.SetGreaterThanZero() \
.SetDisplay("Fast MA", "Fast EMA period", "Indicators")
self._slow_ma_length = self.Param("SlowMaLength", 30) \
.SetGreaterThanZero() \
.SetDisplay("Slow MA", "Slow EMA period", "Indicators")
self._rsi_length = self.Param("RsiLength", 14) \
.SetGreaterThanZero() \
.SetDisplay("RSI Length", "RSI period", "Indicators")
self._long_rsi_level = self.Param("LongRsiLevel", 55.0) \
.SetDisplay("Long RSI", "Minimum RSI for long entries", "Indicators")
self._short_rsi_level = self.Param("ShortRsiLevel", 45.0) \
.SetDisplay("Short RSI", "Maximum RSI for short entries", "Indicators")
self._signal_cooldown_bars = self.Param("SignalCooldownBars", 6) \
.SetGreaterThanZero() \
.SetDisplay("Signal Cooldown", "Bars to wait after each crossover trade", "Trading")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(15))) \
.SetDisplay("Candle Type", "Type of candles", "General")
self._prev_fast = 0.0
self._prev_slow = 0.0
self._initialized = False
self._cooldown_remaining = 0
@property
def candle_type(self):
return self._candle_type.Value
@candle_type.setter
def candle_type(self, value):
self._candle_type.Value = value
def OnReseted(self):
super(multi_indicator_trend_following_strategy, self).OnReseted()
self._prev_fast = 0.0
self._prev_slow = 0.0
self._initialized = False
self._cooldown_remaining = 0
def OnStarted2(self, time):
super(multi_indicator_trend_following_strategy, self).OnStarted2(time)
self._prev_fast = 0.0
self._prev_slow = 0.0
self._initialized = False
self._cooldown_remaining = 0
self._fast_ema = ExponentialMovingAverage()
self._fast_ema.Length = self._fast_ma_length.Value
self._slow_ema = ExponentialMovingAverage()
self._slow_ema.Length = self._slow_ma_length.Value
self._rsi = RelativeStrengthIndex()
self._rsi.Length = self._rsi_length.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(self._fast_ema, self._slow_ema, self._rsi, self.OnProcess).Start()
def OnProcess(self, candle, fast_val, slow_val, rsi_val):
if candle.State != CandleStates.Finished:
return
fv = float(fast_val)
sv = float(slow_val)
rv = float(rsi_val)
if self._cooldown_remaining > 0:
self._cooldown_remaining -= 1
if not self._initialized:
self._prev_fast = fv
self._prev_slow = sv
self._initialized = True
return
cross_up = self._prev_fast <= self._prev_slow and fv > sv
cross_down = self._prev_fast >= self._prev_slow and fv < sv
long_rsi = float(self._long_rsi_level.Value)
short_rsi = float(self._short_rsi_level.Value)
if self._cooldown_remaining == 0 and cross_up and rv > long_rsi and self.Position <= 0:
self.BuyMarket()
self._cooldown_remaining = self._signal_cooldown_bars.Value
elif self._cooldown_remaining == 0 and cross_down and rv < short_rsi and self.Position >= 0:
self.SellMarket()
self._cooldown_remaining = self._signal_cooldown_bars.Value
self._prev_fast = fv
self._prev_slow = sv
def CreateClone(self):
return multi_indicator_trend_following_strategy()