Стратегия представляет собой порт MetaTrader 5 эксперта «Rollback system» на платформу StockSharp. Как и оригинал,
она анализирует последние 24 часовые свечи в момент начала нового торгового дня и ищет чрезмерные движения, способные дать
обратный откат.
Логика работы
Используется таймфрейм CandleType (по умолчанию 1 час).
Проверка сигналов выполняется один раз в сутки – в промежутке с 00:00 до 00:03. В понедельник и пятницу сделки не открываются.
Перед входом стратегия убеждается, что активных позиций нет.
На основании 24 последних завершённых свечей рассчитываются величины:
Open_24_minus_Close_1 – разница между ценой открытия 24 бара назад и последним закрытием.
Close_1_minus_Lowest – удалённость закрытия от минимальной цены дня.
Highest_minus_Close_1 – удалённость закрытия от максимума дня.
Сигналы (все пороги переводятся из пунктов в цену):
Покупка №1 – предыдущий день снизился (Open_24_minus_Close_1 выше ChannelOpenClosePips), а закрытие осталось возле минимума
(Close_1_minus_Lowest меньше RollbackPips - ChannelRollbackPips).
Покупка №2 – предыдущий день вырос (Close_1_minus_Open_24 выше порога), но закрылся значительно ниже максимума
(Highest_minus_Close_1 больше RollbackPips + ChannelRollbackPips).
Продажа №1 – предыдущий день вырос и закрылся возле максимума (Highest_minus_Close_1 меньше RollbackPips - ChannelRollbackPips).
Продажа №2 – предыдущий день упал, но закрытие сильно восстановилось (Close_1_minus_Lowest больше RollbackPips + ChannelRollbackPips).
Вход осуществляется рыночными ордерами BuyMarket/SellMarket с объёмом TradeVolume. Значения StopLossPips и TakeProfitPips
задают расстояние до защитных уровней (нулевые значения отключают их).
После открытия позиции стратегия на каждом завершённом баре контролирует срабатывание уровней. При пробое стопа или тейка внутри
бара позиция закрывается маркет-заявкой, что воспроизводит механику MT5-советника с жёсткими ордерами.
Конвертация пунктов
В MT5 для инструментов с 3 и 5 знаками после запятой пункт автоматически умножается на 10. Порт сохраняет это поведение:
используется PriceStep инструмента, а при количестве знаков 3 или 5 применяется десятикратный множитель. Благодаря этому
все пороговые значения и защитные уровни совпадают с исходной реализацией.
Параметры
Параметр
Описание
TradeVolume
Объём, с которым размещаются рыночные ордера.
StopLossPips
Стоп-лосс в пунктах (0 – отключён).
TakeProfitPips
Тейк-профит в пунктах (0 – отключён).
RollbackPips
Базовое требование к величине отката.
ChannelOpenClosePips
Минимальная разница между открытием и закрытием предыдущего дня.
ChannelRollbackPips
Допуск, добавляемый к условию отката.
CandleType
Рабочий таймфрейм, по умолчанию часовые свечи.
Дополнительно
В MT5-версии рисовались прямоугольники на графике; в портированной версии оставлена только торговая логика.
Управление рисками реализовано внутри стратегии, а не через реальные стоп-заявки, что соответствует высокоуровневому API 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;
public class RollbackSystemStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _rsiPeriod;
private decimal? _prevRsi;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int RsiPeriod { get => _rsiPeriod.Value; set => _rsiPeriod.Value = value; }
public RollbackSystemStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame()).SetDisplay("Candle Type", "Timeframe", "General");
_rsiPeriod = Param(nameof(RsiPeriod), 14).SetGreaterThanZero().SetDisplay("RSI Period", "RSI lookback", "Indicators");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities() => [(Security, CandleType)];
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevRsi = null;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevRsi = null;
var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(rsi, ProcessCandle).Start();
var area = CreateChartArea();
if (area != null) { DrawCandles(area, subscription); DrawOwnTrades(area); }
}
private void ProcessCandle(ICandleMessage candle, decimal rsiVal)
{
if (candle.State != CandleStates.Finished) return;
if (!IsFormedAndOnlineAndAllowTrading()) { _prevRsi = rsiVal; return; }
if (_prevRsi == null) { _prevRsi = rsiVal; return; }
if (_prevRsi.Value < 30m && rsiVal >= 30m && Position <= 0) { if (Position < 0) BuyMarket(); BuyMarket(); }
else if (_prevRsi.Value > 70m && rsiVal <= 70m && Position >= 0) { if (Position > 0) SellMarket(); SellMarket(); }
_prevRsi = rsiVal;
}
}
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
from StockSharp.Algo.Strategies import Strategy
class rollback_system_strategy(Strategy):
def __init__(self):
super(rollback_system_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))) \
.SetDisplay("Candle Type", "Timeframe", "General")
self._rsi_period = self.Param("RsiPeriod", 14) \
.SetDisplay("RSI Period", "RSI lookback", "Indicators")
self._prev_rsi = None
@property
def CandleType(self):
return self._candle_type.Value
@property
def RsiPeriod(self):
return self._rsi_period.Value
def OnReseted(self):
super(rollback_system_strategy, self).OnReseted()
self._prev_rsi = None
def OnStarted2(self, time):
super(rollback_system_strategy, self).OnStarted2(time)
self._prev_rsi = None
rsi = RelativeStrengthIndex()
rsi.Length = self.RsiPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(rsi, self._on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def _on_process(self, candle, rsi_value):
if candle.State != CandleStates.Finished:
return
rv = float(rsi_value)
if not self.IsFormedAndOnlineAndAllowTrading():
self._prev_rsi = rv
return
if self._prev_rsi is None:
self._prev_rsi = rv
return
# RSI crosses above 30 from oversold
if self._prev_rsi < 30.0 and rv >= 30.0 and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
# RSI crosses below 70 from overbought
elif self._prev_rsi > 70.0 and rv <= 70.0 and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_rsi = rv
def CreateClone(self):
return rollback_system_strategy()