This strategy is a C# conversion of the MetaTrader 5 expert advisor "Rollback system". It keeps the original idea of
trading at the very beginning of a new trading day, evaluating the last 24 hourly candles to detect whether the market delivered
an extended move that is likely to retrace.
Trading logic
The strategy works on an hourly timeframe (CandleType, default 1 hour).
Signals are evaluated only once per day when the new day starts (00:00 – 00:03). The filter skips Monday and Friday
sessions exactly like the MQL version.
Before opening a position the algorithm ensures that no other trades are active.
For every trading day the following values are calculated from the last 24 closed candles:
Open_24_minus_Close_1 – distance between the open price 24 bars ago and the latest close.
Close_1_minus_Open_24 – inverse distance showing the net day change.
Close_1_minus_Lowest – how far the close is from the lowest low of the day.
Highest_minus_Close_1 – how far the close is from the highest high of the day.
Entry rules (expressed in price units converted from the pip parameters):
Long #1 – previous day fell (Open_24_minus_Close_1 above the ChannelOpenClosePips threshold) and the close is still
near the extreme low (Close_1_minus_Lowest below RollbackPips - ChannelRollbackPips).
Long #2 – previous day rallied (Close_1_minus_Open_24 above the channel threshold) but the market closed far below the
daily high (Highest_minus_Close_1 greater than RollbackPips + ChannelRollbackPips).
Short #1 – previous day rallied and the close finished near the daily high (Highest_minus_Close_1 below
RollbackPips - ChannelRollbackPips).
Short #2 – previous day sold off and the close recovered far above the daily low (Close_1_minus_Lowest above
RollbackPips + ChannelRollbackPips).
Orders are executed with BuyMarket/SellMarket using the configured trade volume. Stop-loss and take-profit levels are
derived from StopLossPips and TakeProfitPips (both zero disable the respective protection).
Protective levels are monitored on every finished candle. If price breaches a level intrabar the strategy closes the position
using a market order, replicating the behaviour of the original MQL expert advisor that submitted hard stops.
Parameter conversion from pips
MetaTrader 5 multiplies pip values by 10 on 3- and 5-digit symbols. The conversion logic is preserved: the strategy takes the
instrument's PriceStep and applies a tenfold multiplier when the detected number of decimal digits equals 3 or 5. This keeps the
entry thresholds, stop-loss and take-profit distances consistent with the MQL implementation across typical FX symbols.
Parameters
Parameter
Description
TradeVolume
Trade size used for market orders.
StopLossPips
Stop-loss distance in pips. Set to zero to disable.
TakeProfitPips
Take-profit distance in pips. Set to zero to disable.
RollbackPips
Base rollback requirement used by all signals.
ChannelOpenClosePips
Minimum difference between the previous day's open and close.
ChannelRollbackPips
Tolerance added/subtracted from the rollback check.
CandleType
Working candle type, defaults to hourly bars.
Notes
The MQL version painted rectangles on the chart for visual reference. The StockSharp port keeps the trading logic only.
Risk management is implemented with in-strategy monitoring instead of server-side protective orders because the high-level API
manages positions directly.
When optimising, adjust the pip thresholds and volume to suit the target instrument and broker tick size.
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()