RSI Alert Strategy повторяет поведение советника MetaTrader 5 «RSI Alert» в экосистеме StockSharp. Оригинальный эксперт вычислял Relative Strength Index (RSI) на каждом новом баре, отправлял уведомление при попадании значения в глубокие зоны перепроданности (≤20) или перекупленности (≥80) и мгновенно открывал рыночные позиции. Перенос использует тот же событийный подход: подписывается на свечи, анализирует готовые значения RSI и автоматически переворачивает позицию рыночными заявками при достижении заданных уровней.
Логика торговли
Подписка на выбранный поток свечей (по умолчанию минутный таймфрейм) и передача закрытий в индикатор RelativeStrengthIndex.
Игнорирование незавершённых свечей. Проверка условий выполняется только при формировании нового бара, как и в MQL-версии.
Генерация сигналов:
Покупка — RSI ≤ OversoldLevel. Закрывается короткая позиция (если была) и открывается длинная с заданным объёмом.
Продажа — RSI ≥ OverboughtLevel. Закрывается длинная позиция и открывается короткая тем же объёмом.
Используются исключительно рыночные заявки BuyMarket/SellMarket. Стоп-лоссы и тейк-профиты не ставятся: оригинальный советник предоставлял соответствующие поля, но по умолчанию полагался на ручное сопровождение. В StockSharp-переносе управление рисками оставлено внешним модулям (например, StartProtection() или портфельным ограничениям).
При появлении встречного сигнала стратегия переворачивается, добавляя к заявке объём, необходимый для закрытия текущей позиции, — точная копия поведения MQL-бота при последовательных алертах.
Параметры
Параметр
Значение по умолчанию
Описание
OrderVolume
0.01
Объём рыночных сделок. При развороте прибавляется количество контрактов, нужное для закрытия текущей позиции.
RsiPeriod
30
Период усреднения RSI. Должен быть положительным.
OverboughtLevel
80
Уровень RSI, при достижении которого формируется сигнал на продажу.
OversoldLevel
20
Уровень RSI, при достижении которого формируется сигнал на покупку.
CandleType
Свечи TimeFrameCandle 1 минута
Источник данных для расчёта RSI. Можно заменить на более крупный таймфрейм.
Все настройки реализованы через StrategyParam<T>, поэтому доступны в дизайнере StockSharp, сохраняются в пресетах и поддерживают оптимизацию.
Особенности реализации
Используется высокоуровневый API StockSharp: данные получаются через SubscribeCandles(), индикатор обрабатывается вызовом Bind, никаких ручных копирований буферов не требуется.
Свойство Strategy.Volume синхронизировано с параметром OrderVolume, что обеспечивает корректный разворот позиций при изменении лота во время работы.
Комментарии и XML-документация выполнены на английском языке, как того требуют правила репозитория.
При запуске в дизайнере стратегия рисует свечи, собственные сделки и кривую RSI на отдельной области графика.
Рекомендации по использованию
Подключайте внешние модули сопровождения (стопы, трейлинг) при необходимости автоматического управления рисками.
Оптимизируйте пороги RSI под конкретный инструмент и волатильность.
Экспериментируйте с таймфреймом свечей: короткие интервалы подходят для скальпинга, более длинные — для свинговой торговли.
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>
/// RSI alert strategy converted from the original MetaTrader expert advisor.
/// Buys when RSI drops below the oversold threshold and sells when RSI rises above the overbought threshold.
/// </summary>
public class RsiAlertStrategy : Strategy
{
private readonly StrategyParam<decimal> _orderVolume;
private readonly StrategyParam<int> _rsiPeriod;
private readonly StrategyParam<decimal> _overboughtLevel;
private readonly StrategyParam<decimal> _oversoldLevel;
private readonly StrategyParam<DataType> _candleType;
private RelativeStrengthIndex _rsi;
/// <summary>
/// Order volume used for market trades.
/// </summary>
public decimal OrderVolume
{
get => _orderVolume.Value;
set
{
_orderVolume.Value = value;
Volume = value; // Keep the base strategy volume aligned with the parameter value.
}
}
/// <summary>
/// RSI averaging period.
/// </summary>
public int RsiPeriod
{
get => _rsiPeriod.Value;
set => _rsiPeriod.Value = value;
}
/// <summary>
/// RSI level that triggers short trades.
/// </summary>
public decimal OverboughtLevel
{
get => _overboughtLevel.Value;
set => _overboughtLevel.Value = value;
}
/// <summary>
/// RSI level that triggers long trades.
/// </summary>
public decimal OversoldLevel
{
get => _oversoldLevel.Value;
set => _oversoldLevel.Value = value;
}
/// <summary>
/// Candle type supplying prices to the RSI indicator.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Initializes a new instance of <see cref="RsiAlertStrategy"/> with default parameters.
/// </summary>
public RsiAlertStrategy()
{
_orderVolume = Param(nameof(OrderVolume), 0.01m)
.SetGreaterThanZero()
.SetDisplay("Order Volume", "Order size used for market trades", "Trading")
;
_rsiPeriod = Param(nameof(RsiPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("RSI Period", "Number of bars for RSI calculation", "Indicator")
;
_overboughtLevel = Param(nameof(OverboughtLevel), 70m)
.SetDisplay("Overbought Level", "RSI threshold that triggers short signals", "Indicator")
;
_oversoldLevel = Param(nameof(OversoldLevel), 30m)
.SetDisplay("Oversold Level", "RSI threshold that triggers long signals", "Indicator")
;
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Type of candles that feed the RSI", "General");
Volume = OrderVolume;
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_rsi = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
Volume = OrderVolume; // Ensure the strategy uses the configured volume on each start.
_rsi = new RelativeStrengthIndex
{
Length = RsiPeriod
};
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(_rsi, ProcessCandle)
.Start();
StartProtection(
takeProfit: new Unit(2, UnitTypes.Percent),
stopLoss: new Unit(1, UnitTypes.Percent));
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, _rsi);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal rsiValue)
{
if (candle.State != CandleStates.Finished)
return;
var buySignal = rsiValue <= OversoldLevel;
var sellSignal = rsiValue >= OverboughtLevel;
if (buySignal && Position == 0)
{
BuyMarket();
}
else if (sellSignal && Position == 0)
{
SellMarket();
}
}
}