5min RSI Qualified — это порт MetaTrader-советника «5min_rsi_qual_01a». Изначально робот анализировал пятиминутные свечи с помощью RSI (28) и открывал контртрендовую позицию, если индикатор оставался в экстремальной зоне заданное количество баров. После входа стоп-лосс подтягивался к закрытию предыдущей свечи. Версия на StockSharp полностью сохраняет алгоритм подтверждения сигналов, дистанции стопов и ограничение на единственную сделку, используя высокоуровневый API подписки на свечи.
По умолчанию стратегия работает с пятиминутными свечами, однако параметр CandleType допускает любой другой таймфрейм, поддерживаемый инструментом. Все пороговые значения индикатора и стопы задаются в «пунктах» MetaTrader, что позволяет без пересчётов перенести оптимизированные настройки из MT4.
Торговая логика
Расчёт RSI. Индикатор с периодом 28 пересчитывается на каждой завершённой свече. Используются только закрытые свечи, чтобы соответствовать обращению к Close[1] в MQL4.
Счётчики квалификации. Два счётчика фиксируют, сколько подряд свечей RSI находится выше уровня перекупленности (UpperThreshold) или ниже уровня перепроданности (LowerThreshold). Это повторяет цикл из MQL, который проверял последние 12 баров.
Условия входа. При отсутствии открытой позиции и достижении счётчиком перекупленности значения QualificationLength выполняется продажа по рынку. Аналогично, при выполнении условия перепроданности открывается покупка. Таким образом, в любой момент активна только одна позиция.
Трейлинг-стоп. Пока позиция открыта, стоп-уровень пересчитывается на каждой завершённой свече: берётся закрытие предыдущей свечи и вычитается/прибавляется StopLossPoints, конвертированный в абсолютное ценовое смещение. Стоп двигается только в сторону прибыли, как и в исходных вызовах OrderModify.
Первичный стоп. После исполнения ордера выставляется начальный стоп в соответствии с InitialStopPoints. Если он оказывается ближе, чем трейлинг, последний не будет его «расширять», что повторяет поведение MetaTrader.
Управление рисками
Дистанции стопов заданы в пунктах MetaTrader и при каждом расчёте переводятся в абсолютную цену через PriceStep (или MinStep, если основной шаг не задан).
Стратегия не наращивает позицию и дожидается полного закрытия перед поиском нового сигнала.
В OnStarted вызывается StartProtection(), чтобы защитные механизмы StockSharp отслеживали вручную управляемые стоп-уровни.
Параметры
Параметр
Описание
Значение по умолчанию
RsiPeriod
Период RSI.
28
QualificationLength
Количество последовательных свечей, в течение которых RSI должен оставаться в экстремальной зоне.
12
UpperThreshold
Уровень RSI для квалификации сигнала на продажу.
55
LowerThreshold
Уровень RSI для квалификации сигнала на покупку.
45
StopLossPoints
Дистанция трейлинг-стопа в пунктах MetaTrader. При значении 0 трейлинг отключается.
21
InitialStopPoints
Начальный стоп в пунктах MetaTrader, выставляемый сразу после входа. Значение 0 отменяет первичный стоп.
11
CandleType
Тип свечей для анализа (по умолчанию 5 минут).
5-минутный таймфрейм
Рекомендации по использованию
Убедитесь, что шаг цены инструмента соответствует размеру пункта, использованному при оптимизации в MT4. Для пятизнаковых FX-пар один пункт равен 0.00010, поэтому стандартные значения 11/21 повторяют оригинальную схему.
Поскольку стратегия контртрендовая, она эффективнее на боковых участках. Для трендовых инструментов увеличьте QualificationLength или расширьте пороги RSI.
Объём берётся из свойства Volume базового класса. Настройте его перед запуском стратегии.
Параметры отмечены SetCanOptimize(), поэтому их можно подбирать через оптимизатор StockSharp.
Особенности конверсии
Алгоритм обработки свечей, вычисление RSI и ограничение на единственную позицию полностью соответствуют коду MetaTrader.
Трейлинг-стоп обновляется по закрытию предыдущей свечи, что гарантирует идентичные уровни выхода при развороте рынка.
Проверки на количество баров и свободную маржу убраны: в StockSharp подготовка данных и доступность портфеля контролируются платформой.
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>
/// 5-minute RSI qualified strategy.
/// Counts consecutive candles in RSI extreme zones.
/// Buys after sustained oversold, sells after sustained overbought.
/// </summary>
public class FiveMinRsiQualifiedStrategy : Strategy
{
private readonly StrategyParam<int> _rsiPeriod;
private readonly StrategyParam<int> _qualificationLength;
private readonly StrategyParam<decimal> _upperThreshold;
private readonly StrategyParam<decimal> _lowerThreshold;
private readonly StrategyParam<DataType> _candleType;
private int _overboughtCount;
private int _oversoldCount;
public int RsiPeriod { get => _rsiPeriod.Value; set => _rsiPeriod.Value = value; }
public int QualificationLength { get => _qualificationLength.Value; set => _qualificationLength.Value = value; }
public decimal UpperThreshold { get => _upperThreshold.Value; set => _upperThreshold.Value = value; }
public decimal LowerThreshold { get => _lowerThreshold.Value; set => _lowerThreshold.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public FiveMinRsiQualifiedStrategy()
{
_rsiPeriod = Param(nameof(RsiPeriod), 14)
.SetDisplay("RSI Period", "RSI lookback", "Indicators");
_qualificationLength = Param(nameof(QualificationLength), 3)
.SetDisplay("Qual Length", "Consecutive candles in extreme zone", "Indicators");
_upperThreshold = Param(nameof(UpperThreshold), 65m)
.SetDisplay("Upper", "RSI overbought threshold", "Indicators");
_lowerThreshold = Param(nameof(LowerThreshold), 35m)
.SetDisplay("Lower", "RSI oversold threshold", "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();
_overboughtCount = 0;
_oversoldCount = 0;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_overboughtCount = 0;
_oversoldCount = 0;
var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(rsi, ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal rsiValue)
{
if (candle.State != CandleStates.Finished)
return;
// Track consecutive overbought candles
if (rsiValue >= UpperThreshold)
_overboughtCount++;
else
_overboughtCount = 0;
// Track consecutive oversold candles
if (rsiValue <= LowerThreshold)
_oversoldCount++;
else
_oversoldCount = 0;
// After qualified oversold period, buy (contrarian)
if (_oversoldCount >= QualificationLength && Position <= 0)
{
if (Position < 0)
BuyMarket();
BuyMarket();
_oversoldCount = 0;
}
// After qualified overbought period, sell (contrarian)
else if (_overboughtCount >= QualificationLength && Position >= 0)
{
if (Position > 0)
SellMarket();
SellMarket();
_overboughtCount = 0;
}
}
}