Открыть на GitHub

Шаблон стратегии на RSI

Basic RSI EA Template Strategy — конвертация советника MetaTrader 4 «Basic Rsi EA Template.mq4» (MQL/26750). Стратегия отслеживает индекс относительной силы (RSI) на выбранной серии свечей и реагирует, когда импульс достигает настраиваемых зон перекупленности или перепроданности. В StockSharp сохранены простая работа с одной позицией и защитные стоп/тейк уровни оригинального робота, при этом используется высокоуровневый API подписки.

Логика стратегии

Индикаторы

  • RSI с настраиваемым периодом, рассчитанный по выбранному типу свечей.

Условия входа

  • Покупка: RSI падает ниже OversoldLevel, открытых позиций нет — отправляется рыночная покупка объемом OrderVolume.
  • Продажа: RSI поднимается выше OverboughtLevel, открытых позиций нет — отправляется рыночная продажа объемом OrderVolume.

Алгоритм работает в неттинговом режиме: одновременно может существовать только одна позиция. Если активна длинная позиция, стратегия ждет её закрытия перед входом в шорт (и наоборот).

Условия выхода

  • Стоп-лосс: значение StopLossPips переводится в абсолютное расстояние по цене с учетом шага тикования инструмента. При откате цены на эту величину встроенная защита закрывает позицию.
  • Тейк-профит: TakeProfitPips обрабатывается аналогично — при движении цены в прибыль на указанное расстояние позиция закрывается.

Дополнительных трейлинг-стопов или выходов по сигналу нет. Стратегия полагается только на защитные расстояния или ручное вмешательство, повторяя минимализм исходного шаблона.

Риск и объем

  • OrderVolume задает фиксированный объем каждой рыночной сделки (по умолчанию 0.01 лота, как в MQL-примере).
  • Стратегия не наращивает и не хеджирует позиции. После закрытия стопом или тейком она возвращается в ноль и ждет следующего сигнала RSI.

Параметры

  • CandleType: серия свечей для генерации сигналов (по умолчанию минутный таймфрейм).
  • RsiPeriod: количество баров в расчете RSI (по умолчанию 14).
  • OverboughtLevel: порог RSI для разрешения коротких позиций (по умолчанию 70).
  • OversoldLevel: порог RSI для разрешения длинных позиций (по умолчанию 30).
  • StopLossPips: расстояние стоп-лосса в пунктах, пересчитанное в абсолютное значение (по умолчанию 30 пунктов).
  • TakeProfitPips: расстояние тейк-профита в пунктах, пересчитанное в абсолютное значение (по умолчанию 20 пунктов).
  • OrderVolume: фиксированный объем рыночных ордеров (по умолчанию 0.01).

Особенности реализации

  • Используется цепочка SubscribeCandles(...).Bind(rsi, ProcessCandle), чтобы значения индикатора сразу попадали в обработчик без ручного буфера.
  • Метод CreateProtectionUnit воспроизводит логику MQL по пересчету пунктов: для инструментов с 3 или 5 знаками после запятой применяется множитель 10.
  • Проверки сигнала выполняются только на закрытых свечах, чтобы избежать повторных ордеров на одном баре.
  • Конверсия рассчитана на неттинговый учет, в отличие от хеджевого режима MetaTrader. Поэтому противоположные сделки закрывают текущую позицию вместо открытия новой.
  • Все комментарии и сообщения в коде написаны на английском языке для удобства сопровождения.

Рекомендации по использованию

  • Подберите CandleType под инструмент и горизонт торговли (например, переключитесь на часовые свечи для свинг-подхода).
  • Настройте StopLossPips и TakeProfitPips под волатильность инструмента — защитные расстояния критичны для управления риском.
  • При необходимости расширенного мани-менеджмента подключите портфельные или рисковые модули StockSharp поверх данного шаблона.
namespace StockSharp.Samples.Strategies;

using System;

using Ecng.Common;

using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;

/// <summary>
/// Basic RSI template: buys when RSI is oversold, sells when RSI is overbought.
/// </summary>
public class BasicRsiEaTemplateStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _rsiPeriod;
	private readonly StrategyParam<decimal> _overboughtLevel;
	private readonly StrategyParam<decimal> _oversoldLevel;

	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	public int RsiPeriod
	{
		get => _rsiPeriod.Value;
		set => _rsiPeriod.Value = value;
	}

	public decimal OverboughtLevel
	{
		get => _overboughtLevel.Value;
		set => _overboughtLevel.Value = value;
	}

	public decimal OversoldLevel
	{
		get => _oversoldLevel.Value;
		set => _oversoldLevel.Value = value;
	}

	public BasicRsiEaTemplateStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
			.SetDisplay("Candle Type", "Candle timeframe", "General");

		_rsiPeriod = Param(nameof(RsiPeriod), 14)
			.SetGreaterThanZero()
			.SetDisplay("RSI Period", "RSI calculation period", "Indicators");

		_overboughtLevel = Param(nameof(OverboughtLevel), 70m)
			.SetDisplay("Overbought Level", "RSI overbought threshold", "Indicators");

		_oversoldLevel = Param(nameof(OversoldLevel), 30m)
			.SetDisplay("Oversold Level", "RSI oversold threshold", "Indicators");
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		var rsi = new RelativeStrengthIndex { Length = RsiPeriod };

		decimal? prevRsi = null;

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(rsi, (candle, rsiValue) =>
			{
				if (candle.State != CandleStates.Finished)
					return;

				if (!IsFormedAndOnlineAndAllowTrading())
					return;

				if (prevRsi.HasValue)
				{
					var crossBelowOversold = prevRsi.Value >= OversoldLevel && rsiValue < OversoldLevel;
					var crossAboveOverbought = prevRsi.Value <= OverboughtLevel && rsiValue > OverboughtLevel;

					if (crossBelowOversold && Position <= 0)
						BuyMarket();
					else if (crossAboveOverbought && Position >= 0)
						SellMarket();
				}

				prevRsi = rsiValue;
			})
			.Start();

		var area = CreateChartArea();
		if (area != null)
		{
			DrawCandles(area, subscription);
			DrawIndicator(area, rsi);
			DrawOwnTrades(area);
		}
	}
}