The RSI Slowdown strategy reacts to extreme readings of the Relative Strength Index that show signs of weakening momentum. When RSI approaches overbought or oversold zones and its change between bars drops below one point, the strategy assumes the market is ready for a reversal.
A long position opens when RSI meets or exceeds the upper level and the indicator's growth slows. A short position opens when RSI falls to the lower level with a similar slowdown. Any existing opposite position is closed before entering a new trade.
The default configuration uses 6-hour candles and a 2-period RSI with thresholds of 90 and 10. These values mimic the original MetaTrader implementation.
Details
Entry Criteria:
Long: RSI >= LevelMax and |RSI - prev RSI| < 1 (when slowdown is enabled)
Short: RSI <= LevelMin and |RSI - prev RSI| < 1 (when slowdown is enabled)
Long/Short: Both sides.
Exit Criteria:
Long: Opposite signal or short entry.
Short: Opposite signal or long entry.
Stops: No automatic stops.
Default Values:
RsiPeriod = 2
LevelMax = 90
LevelMin = 10
SeekSlowdown = true
CandleType = TimeSpan.FromHours(6)
Filters:
Category: Reversal
Direction: Both
Indicators: RSI
Stops: No
Complexity: Basic
Timeframe: Intraday to swing
Seasonality: No
Neural networks: No
Divergence: Yes (slowdown)
Risk Level: Medium
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;
/// <summary>
/// RSI slowdown strategy.
/// Opens long when RSI reaches the upper level and slows down.
/// Opens short when RSI reaches the lower level and slows down.
/// </summary>
public class RsiSlowdownStrategy : Strategy
{
private readonly StrategyParam<int> _rsiPeriod;
private readonly StrategyParam<decimal> _levelMax;
private readonly StrategyParam<decimal> _levelMin;
private readonly StrategyParam<bool> _seekSlowdown;
private readonly StrategyParam<DataType> _candleType;
private decimal _previousRsi;
/// <summary>
/// RSI period length.
/// </summary>
public int RsiPeriod
{
get => _rsiPeriod.Value;
set => _rsiPeriod.Value = value;
}
/// <summary>
/// Upper RSI level.
/// </summary>
public decimal LevelMax
{
get => _levelMax.Value;
set => _levelMax.Value = value;
}
/// <summary>
/// Lower RSI level.
/// </summary>
public decimal LevelMin
{
get => _levelMin.Value;
set => _levelMin.Value = value;
}
/// <summary>
/// Enable slowdown condition.
/// </summary>
public bool SeekSlowdown
{
get => _seekSlowdown.Value;
set => _seekSlowdown.Value = value;
}
/// <summary>
/// The type of candles to use for calculations.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public RsiSlowdownStrategy()
{
_rsiPeriod = Param(nameof(RsiPeriod), 2)
.SetGreaterThanZero()
.SetDisplay("RSI Period", "RSI calculation period", "RSI")
.SetOptimize(2, 14, 1);
_levelMax = Param(nameof(LevelMax), 90m)
.SetDisplay("Upper Level", "Overbought RSI level", "RSI")
.SetOptimize(50m, 100m, 5m);
_levelMin = Param(nameof(LevelMin), 10m)
.SetDisplay("Lower Level", "Oversold RSI level", "RSI")
.SetOptimize(0m, 50m, 5m);
_seekSlowdown = Param(nameof(SeekSlowdown), true)
.SetDisplay("Seek Slowdown", "Check RSI change below 1", "RSI");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(6).TimeFrame())
.SetDisplay("Candle Type", "Type of candles for the strategy", "General");
_previousRsi = decimal.MinValue;
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_previousRsi = decimal.MinValue;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_previousRsi = decimal.MinValue;
var rsi = new RelativeStrengthIndex
{
Length = RsiPeriod
};
var subscription = SubscribeCandles(CandleType);
subscription.Bind(rsi, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal rsiValue)
{
if (candle.State != CandleStates.Finished)
return;
if (_previousRsi == decimal.MinValue)
{
_previousRsi = rsiValue;
return;
}
if (!IsFormedAndOnlineAndAllowTrading())
{
_previousRsi = rsiValue;
return;
}
var isSlowdown = !SeekSlowdown || Math.Abs(_previousRsi - rsiValue) < 1m;
if (isSlowdown)
{
if (rsiValue >= LevelMax && Position <= 0)
{
BuyMarket();
}
else if (rsiValue <= LevelMin && Position >= 0)
{
SellMarket();
}
}
_previousRsi = rsiValue;
}
}