Стратегия DT RSI EXP1
Порт воспроизводит советник MT4 DT-RSI-EXP1. Алгоритм анализирует колебания RSI на 15-минутных свечах, чтобы найти двойные вершины и впадины около уровней 60/40. Лонг открывается, когда две последовательные вершины RSI удовлетворяют условиям, между ними нет впадин ниже 40, а фильтр тренда на 4-часовом графике направлен вниз. Для шорта условия зеркальные: две впадины, отсутствие вершин выше 60 и восходящий фильтр. К каждой позиции привязывается фиксированный стоп-лосс и тейк-профит, дополнительно можно включить трейлинг-стоп. Как и в оригинале, позиции принудительно закрываются при достижении RSI экстремумов 70/30.
Подробности
- Вход в рынок:
- Лонг: две вершины RSI, вторая выше 60, между ними нет впадин ниже 40; EMA на таймфрейме 240 минут (замена RFTL) ниже предыдущего закрытия; RSI(1) пересекает прогнозируемую линию шеи вверх, RSI(2) остаётся ниже, RSI(2) < 50 и RSI(0) < 55.
- Шорт: две впадины RSI, вторая ниже 40, между ними нет вершин выше 60; EMA на 240-минутном графике выше предыдущего закрытия; RSI(1) пробивает линию шеи вниз, RSI(2) > 50 и RSI(0) > 47.
- Направление: обе стороны.
- Выход:
- Экстремумы RSI (RSI > 70 для лонгов, RSI < 30 для шортов).
- Срабатывание стоп-лосса или тейк-профита, рассчитанных в шагах цены.
- Опциональный трейлинг-стоп после прохождения
TrailingStopPoints.
- Стопы: фиксированные стоп-лосс и тейк-профит + трейлинг по желанию.
- Значения по умолчанию:
CandleType = 15 минут.
TrendCandleType = 240 минут (EMA-фильтр).
RsiPeriod = 47.
StopLossPoints = 26.
TakeProfitPoints = 76.
TrailingStopPoints = 0 (выключен).
- Фильтры:
- Категория: трендовые входы по структурам RSI.
- Направление: обе.
- Индикаторы: RSI, EMA тренда.
- Стопы: есть.
- Сложность: средняя (много условий на свинги).
- Таймфрейм: внутридневной (M15 + H4).
- Сезонность: нет.
- Нейросети: нет.
- Дивергенция: нет.
- Риск: средний.
Параметры
| Имя |
Значение |
Описание |
Оптимизация |
CandleType |
15 минут |
Базовый поток свечей для RSI и сигналов. |
Да |
TrendCandleType |
240 минут |
Старший таймфрейм для EMA (аналог MT4 RFTL). |
Да |
RsiPeriod |
47 |
Период RSI на основном таймфрейме. |
Да |
StopLossPoints |
26 |
Дистанция стоп-лосса в шагах цены. |
Да |
TakeProfitPoints |
76 |
Дистанция тейк-профита в шагах цены. |
Да |
TrailingStopPoints |
0 |
Шаг трейлинг-стопа в шагах цены (0 отключает). |
Да |
Заметки
- Индикатор MT4
RFTL заменён EMA с периодом 10 на 240-минутном графике. При необходимости измените таймфрейм или период EMA, чтобы ближе воспроизвести оригинал.
- Убедитесь, что у инструмента корректно настроены
PriceStep и StepPrice, иначе значения в пунктах не совпадут с брокером.
- Трейлинг активируется только после прохождения цены дальше
TrailingStopPoints от входа и никогда не расширяет исходный риск.
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>
/// DT RSI EXP1 strategy - RSI overbought/oversold with EMA trend filter.
/// Buys when RSI crosses above oversold level while above EMA trend.
/// Sells when RSI crosses below overbought level while below EMA trend.
/// </summary>
public class DtRsiExp1Strategy : Strategy
{
private readonly StrategyParam<int> _rsiPeriod;
private readonly StrategyParam<int> _emaPeriod;
private readonly StrategyParam<decimal> _oversold;
private readonly StrategyParam<decimal> _overbought;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevRsi;
private bool _hasPrev;
public int RsiPeriod { get => _rsiPeriod.Value; set => _rsiPeriod.Value = value; }
public int EmaPeriod { get => _emaPeriod.Value; set => _emaPeriod.Value = value; }
public decimal Oversold { get => _oversold.Value; set => _oversold.Value = value; }
public decimal Overbought { get => _overbought.Value; set => _overbought.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public DtRsiExp1Strategy()
{
_rsiPeriod = Param(nameof(RsiPeriod), 14)
.SetDisplay("RSI Period", "RSI period", "Indicators");
_emaPeriod = Param(nameof(EmaPeriod), 20)
.SetDisplay("EMA Period", "EMA trend filter period", "Indicators");
_oversold = Param(nameof(Oversold), 30m)
.SetDisplay("Oversold", "RSI oversold level", "Indicators");
_overbought = Param(nameof(Overbought), 70m)
.SetDisplay("Overbought", "RSI overbought level", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities() => [(Security, CandleType)];
protected override void OnReseted() { base.OnReseted(); _prevRsi = 0m; _hasPrev = false; }
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_hasPrev = false;
var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
var ema = new ExponentialMovingAverage { Length = EmaPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(rsi, ema, ProcessCandle)
.Start();
StartProtection(
takeProfit: new Unit(2, UnitTypes.Percent),
stopLoss: new Unit(1, UnitTypes.Percent)
);
}
private void ProcessCandle(ICandleMessage candle, decimal rsi, decimal ema)
{
if (candle.State != CandleStates.Finished)
return;
var close = candle.ClosePrice;
if (!_hasPrev)
{
_prevRsi = rsi;
_hasPrev = true;
return;
}
// RSI crosses above oversold + bullish trend
if (_prevRsi <= Oversold && rsi > Oversold && close > ema && Position == 0)
{
BuyMarket();
}
// RSI crosses below overbought + bearish trend
else if (_prevRsi >= Overbought && rsi < Overbought && close < ema && Position == 0)
{
SellMarket();
}
_prevRsi = rsi;
}
}
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 RelativeStrengthIndex, ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
from StockSharp.Messages import Unit, UnitTypes
class dt_rsi_exp1_strategy(Strategy):
def __init__(self):
super(dt_rsi_exp1_strategy, self).__init__()
self._rsi_period = self.Param("RsiPeriod", 14) \
.SetDisplay("RSI Period", "RSI period", "Indicators")
self._ema_period = self.Param("EmaPeriod", 20) \
.SetDisplay("EMA Period", "EMA trend filter period", "Indicators")
self._oversold = self.Param("Oversold", 30.0) \
.SetDisplay("Oversold", "RSI oversold level", "Indicators")
self._overbought = self.Param("Overbought", 70.0) \
.SetDisplay("Overbought", "RSI overbought level", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))) \
.SetDisplay("Candle Type", "Candle timeframe", "General")
self._prev_rsi = 0.0
self._has_prev = False
@property
def rsi_period(self):
return self._rsi_period.Value
@property
def ema_period(self):
return self._ema_period.Value
@property
def oversold(self):
return self._oversold.Value
@property
def overbought(self):
return self._overbought.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(dt_rsi_exp1_strategy, self).OnReseted()
self._prev_rsi = 0.0
self._has_prev = False
def OnStarted2(self, time):
super(dt_rsi_exp1_strategy, self).OnStarted2(time)
self._has_prev = False
rsi = RelativeStrengthIndex()
rsi.Length = self.rsi_period
ema = ExponentialMovingAverage()
ema.Length = self.ema_period
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(rsi, ema, self.process_candle).Start()
self.StartProtection(
takeProfit=Unit(2, UnitTypes.Percent),
stopLoss=Unit(1, UnitTypes.Percent)
)
def process_candle(self, candle, rsi, ema):
if candle.State != CandleStates.Finished:
return
close = float(candle.ClosePrice)
rsi_val = float(rsi)
ema_val = float(ema)
if not self._has_prev:
self._prev_rsi = rsi_val
self._has_prev = True
return
if self._prev_rsi <= self.oversold and rsi_val > self.oversold and close > ema_val and self.Position == 0:
self.BuyMarket()
elif self._prev_rsi >= self.overbought and rsi_val < self.overbought and close < ema_val and self.Position == 0:
self.SellMarket()
self._prev_rsi = rsi_val
def CreateClone(self):
return dt_rsi_exp1_strategy()