Стратегия является портом советника «RSI trader» для MetaTrader. Она использует двойную фильтрацию тренда: скользящие средние цены и сглаженные средние RSI. Сделки открываются, когда оба фильтра показывают одно направление, и закрываются при расхождении сигналов (режим флэта). По умолчанию применяются часовые свечи, но можно выбрать любые доступные данные.
Алгоритм работы
Рассчитывается RSI с периодом RSI Period (по умолчанию 14).
Поток значений RSI сглаживается двумя простыми скользящими: Short RSI MA и Long RSI MA.
Цена закрытия сглаживается простой (Short Price MA) и линейно-взвешенной (Long Price MA) средними.
После завершения свечи формируется сигнал:
Покупка – обе короткие средние находятся выше своих длинных.
Продажа – обе короткие средние находятся ниже своих длинных.
Флэт – средние указывают противоположные направления, текущая позиция закрывается.
При смене направления противоположная позиция сначала закрывается рыночным приказом, затем стратегия ожидает подтверждения для входа в новый тренд.
Параметры
Название
Описание
Значение по умолчанию
Оптимизация
RSI Period
Период расчёта RSI.
14
Да (7…28, шаг 1)
Short Price MA
Период короткой простой средней цены.
9
Да (5…20, шаг 1)
Long Price MA
Период длинной линейно-взвешенной средней цены.
45
Да (30…90, шаг 5)
Short RSI MA
Период короткой сглаживающей средней RSI.
9
Да (5…20, шаг 1)
Long RSI MA
Период длинной сглаживающей средней RSI.
45
Да (30…90, шаг 5)
Candle Type
Тип свечей для анализа, по умолчанию 1H.
H1
Нет
Дополнительно
Сделки совершаются только после формирования всех индикаторов.
Размер заявки берётся из свойства Volume. Управление проскальзыванием выполняется на уровне торгового адаптера.
Фиксированные стопы и тейк-профиты не заданы; выход осуществляется по сигналу флэта. При необходимости добавьте внешние ограничения риска.
При доступном сервисе графиков отображаются скользящие средние цены и RSI, что облегчает визуальный контроль сигналов.
using System;
using System.Collections.Generic;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// RSI Trader strategy combining price SMA crossover with RSI trend confirmation.
/// Buy when short SMA crosses above long SMA with RSI above 50.
/// Sell when short SMA crosses below long SMA with RSI below 50.
/// </summary>
public class RsiTraderAlignedAveragesStrategy : Strategy
{
private readonly StrategyParam<int> _rsiPeriod;
private readonly StrategyParam<int> _shortMaPeriod;
private readonly StrategyParam<int> _longMaPeriod;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevShort;
private decimal _prevLong;
private bool _hasPrev;
public int RsiPeriod { get => _rsiPeriod.Value; set => _rsiPeriod.Value = value; }
public int ShortMaPeriod { get => _shortMaPeriod.Value; set => _shortMaPeriod.Value = value; }
public int LongMaPeriod { get => _longMaPeriod.Value; set => _longMaPeriod.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public RsiTraderAlignedAveragesStrategy()
{
_rsiPeriod = Param(nameof(RsiPeriod), 14)
.SetDisplay("RSI Period", "RSI calculation period", "Indicators");
_shortMaPeriod = Param(nameof(ShortMaPeriod), 9)
.SetDisplay("Short MA", "Short moving average period", "Indicators");
_longMaPeriod = Param(nameof(LongMaPeriod), 26)
.SetDisplay("Long MA", "Long moving average period", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevShort = 0m;
_prevLong = 0m;
_hasPrev = false;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_hasPrev = false;
var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
var shortMa = new SimpleMovingAverage { Length = ShortMaPeriod };
var longMa = new SimpleMovingAverage { Length = LongMaPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(rsi, shortMa, longMa, ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal rsiValue, decimal shortMa, decimal longMa)
{
if (candle.State != CandleStates.Finished)
return;
if (!_hasPrev)
{
_prevShort = shortMa;
_prevLong = longMa;
_hasPrev = true;
return;
}
var bullCross = _prevShort <= _prevLong && shortMa > longMa;
var bearCross = _prevShort >= _prevLong && shortMa < longMa;
if (Position <= 0 && bullCross && rsiValue > 50)
{
if (Position < 0)
BuyMarket();
BuyMarket();
}
else if (Position >= 0 && bearCross && rsiValue < 50)
{
if (Position > 0)
SellMarket();
SellMarket();
}
_prevShort = shortMa;
_prevLong = longMa;
}
}
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 RelativeStrengthIndex, SimpleMovingAverage
from StockSharp.Algo.Strategies import Strategy
class rsi_trader_aligned_averages_strategy(Strategy):
"""RSI Trader combining SMA crossover with RSI trend confirmation.
Buy when short SMA crosses above long SMA with RSI above 50.
Sell when short SMA crosses below long SMA with RSI below 50."""
def __init__(self):
super(rsi_trader_aligned_averages_strategy, self).__init__()
self._rsi_period = self.Param("RsiPeriod", 14) \
.SetDisplay("RSI Period", "RSI calculation period", "Indicators")
self._short_ma_period = self.Param("ShortMaPeriod", 9) \
.SetDisplay("Short MA", "Short moving average period", "Indicators")
self._long_ma_period = self.Param("LongMaPeriod", 26) \
.SetDisplay("Long MA", "Long moving average period", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Candle timeframe", "General")
self._prev_short = 0.0
self._prev_long = 0.0
self._has_prev = False
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def RsiPeriod(self):
return self._rsi_period.Value
@property
def ShortMaPeriod(self):
return self._short_ma_period.Value
@property
def LongMaPeriod(self):
return self._long_ma_period.Value
def OnReseted(self):
super(rsi_trader_aligned_averages_strategy, self).OnReseted()
self._prev_short = 0.0
self._prev_long = 0.0
self._has_prev = False
def OnStarted2(self, time):
super(rsi_trader_aligned_averages_strategy, self).OnStarted2(time)
self._has_prev = False
rsi = RelativeStrengthIndex()
rsi.Length = self.RsiPeriod
short_ma = SimpleMovingAverage()
short_ma.Length = self.ShortMaPeriod
long_ma = SimpleMovingAverage()
long_ma.Length = self.LongMaPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(rsi, short_ma, long_ma, self._process_candle).Start()
def _process_candle(self, candle, rsi_value, short_ma, long_ma):
if candle.State != CandleStates.Finished:
return
rsi_val = float(rsi_value)
short_val = float(short_ma)
long_val = float(long_ma)
if not self._has_prev:
self._prev_short = short_val
self._prev_long = long_val
self._has_prev = True
return
bull_cross = self._prev_short <= self._prev_long and short_val > long_val
bear_cross = self._prev_short >= self._prev_long and short_val < long_val
if self.Position <= 0 and bull_cross and rsi_val > 50:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif self.Position >= 0 and bear_cross and rsi_val < 50:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_short = short_val
self._prev_long = long_val
def CreateClone(self):
return rsi_trader_aligned_averages_strategy()