Открыть на GitHub

RsiBoosterStrategy

Обзор

RsiBoosterStrategy — порт советника MetaTrader RSI booster на платформу StockSharp. Стратегия сравнивает значение «быстрого» RSI на текущей свече с отложенным RSI, рассчитанным по предыдущей свече. Если разница превышает заданный порог, открывается рыночная позиция. Далее сделка сопровождается фиксированным стоп-лоссом, тейк-профитом, при необходимости трейлинг-стопом и цепочкой обратных заявок для отработки убытков.

Реализация использует высокоуровневый API StockSharp: подписывается на один поток свечей, применяет встроенные индикаторы RelativeStrengthIndex и оформляет все настройки через систему параметров, что позволяет оптимизировать стратегию в Designer.

Логика торговли

  1. На каждой завершённой свече обновляются два RSI.
    • Быстрый RSI использует параметры FirstRsiPeriod и FirstRsiPrice и отражает текущее значение.
    • Отложенный RSI использует SecondRsiPeriod и SecondRsiPrice, но стратегия хранит предыдущее значение, обеспечивая задержку на одну свечу.
  2. Если быстрый RSI – отложенный RSI больше Ratio, стратегия покупает (если нет открытого лонга). Если разница меньше -Ratio, открывается шорт (при отсутствии короткой позиции).
  3. Параметр OnlyOnePositionPerBar запрещает более одного входа в каждом направлении в рамках одной свечи.
  4. После закрытия каждой свечи проверяются условия стоп-лосса, тейк-профита и трейлинг-стопа. При срабатывании позиция закрывается немедленно.
  5. При фиксации убытка и включённой функции восстановления стратегия может открыть обратную позицию тем же объёмом. Количество таких попыток ограничено ReturnOrdersMax.

Управление рисками

  • Стоп-лосс — задаётся в пунктах через StopLossPips; при достижении уровня позиция закрывается.
  • Тейк-профит — задаётся через TakeProfitPips.
  • Трейлинг-стоп — активируется, если TrailingStopPips больше нуля; перемещается при улучшении цены не менее чем на TrailingStepPips.
  • Обратные сделки — включаются параметром ReturnOrderEnabled. После убыточного закрытия стратегия немедленно отправляет встречный ордер и считает количество восстановительных сделок.

Параметры

Параметр Описание
Volume Торговый объём каждой рыночной заявки (лоты или контракты).
Ratio Минимальная разница между RSI для открытия позиции.
StopLossPips Размер стоп-лосса в пунктах.
TakeProfitPips Размер тейк-профита в пунктах.
TrailingStopPips Дистанция трейлинг-стопа в пунктах.
TrailingStepPips Минимальное улучшение перед переносом трейлинг-стопа.
OnlyOnePositionPerBar Ограничивает количество входов на одну свечу.
ReturnOrderEnabled Включает логику обратных ордеров после убытка.
ReturnOrdersMax Максимальное число подряд идущих восстановительных сделок.
FirstRsiPeriod Период быстрого RSI.
FirstRsiPrice Тип цены для быстрого RSI (соответствует режимам MetaTrader).
SecondRsiPeriod Период отложенного RSI.
SecondRsiPrice Тип цены для отложенного RSI.
CandleType Тип свечей, по которым ведётся анализ.

Дополнительно

  • Конвертация пунктов в цену использует PriceStep инструмента, а при его отсутствии применяется запасное значение 0.0001.
  • Счётчик цепочки восстановительных сделок сбрасывается при прибыльной сделке или при достижении лимита ReturnOrdersMax.
  • На графике отображаются обе линии RSI и совершённые сделки для визуального контроля.
using System;
using System.Collections.Generic;

using Ecng.Common;

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

namespace StockSharp.Samples.Strategies;

public class RsiBoosterStrategy : Strategy
{
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private readonly StrategyParam<int> _stopLossPoints;
	private readonly StrategyParam<int> _takeProfitPoints;

	private ExponentialMovingAverage _fast;
	private ExponentialMovingAverage _slow;

	private decimal _prevFast;
	private decimal _prevSlow;
	private decimal _entryPrice;
	private int _cooldown;

	public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
	public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
	public int StopLossPoints { get => _stopLossPoints.Value; set => _stopLossPoints.Value = value; }
	public int TakeProfitPoints { get => _takeProfitPoints.Value; set => _takeProfitPoints.Value = value; }

	public RsiBoosterStrategy()
	{
		_fastPeriod = Param(nameof(FastPeriod), 14).SetGreaterThanZero().SetDisplay("Fast Period", "Fast EMA period", "Indicator");
		_slowPeriod = Param(nameof(SlowPeriod), 50).SetGreaterThanZero().SetDisplay("Slow Period", "Slow EMA period", "Indicator");
		_stopLossPoints = Param(nameof(StopLossPoints), 200).SetNotNegative().SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk");
		_takeProfitPoints = Param(nameof(TakeProfitPoints), 400).SetNotNegative().SetDisplay("Take Profit", "Take-profit in price steps", "Risk");
	}

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		yield return (Security, TimeSpan.FromMinutes(5).TimeFrame());
	}

	protected override void OnReseted()
	{
		base.OnReseted();
		_fast = null; _slow = null;
		_prevFast = 0; _prevSlow = 0; _entryPrice = 0; _cooldown = 0;
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_fast = new ExponentialMovingAverage { Length = FastPeriod };
		_slow = new ExponentialMovingAverage { Length = SlowPeriod };
		var subscription = SubscribeCandles(TimeSpan.FromMinutes(5).TimeFrame());
		subscription.Bind(_fast, _slow, ProcessCandle);
		subscription.Start();
	}

	private void ProcessCandle(ICandleMessage candle, decimal fastValue, decimal slowValue)
	{
		if (candle.State != CandleStates.Finished) return;
		if (!_fast.IsFormed || !_slow.IsFormed) { _prevFast = fastValue; _prevSlow = slowValue; return; }
		if (_cooldown > 0) { _cooldown--; _prevFast = fastValue; _prevSlow = slowValue; return; }

		var close = candle.ClosePrice;
		var step = Security?.PriceStep ?? 1m;

		if (Position > 0 && _entryPrice > 0)
		{
			if (StopLossPoints > 0 && close <= _entryPrice - StopLossPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
			if (TakeProfitPoints > 0 && close >= _entryPrice + TakeProfitPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
		}
		else if (Position < 0 && _entryPrice > 0)
		{
			if (StopLossPoints > 0 && close >= _entryPrice + StopLossPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
			if (TakeProfitPoints > 0 && close <= _entryPrice - TakeProfitPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
		}

		if (_prevFast <= _prevSlow && fastValue > slowValue && Position <= 0)
		{ if (Position < 0) BuyMarket(); BuyMarket(); _entryPrice = close; _cooldown = 100; }
		else if (_prevFast >= _prevSlow && fastValue < slowValue && Position >= 0)
		{ if (Position > 0) SellMarket(); SellMarket(); _entryPrice = close; _cooldown = 100; }

		_prevFast = fastValue; _prevSlow = slowValue;
	}
}