RSI Expert
Overview
The RSI Expert strategy trades using the Relative Strength Index (RSI). It waits for the RSI value to cross predefined overbought or oversold levels and enters positions in the direction of the crossing.
Logic
- Calculate RSI for each candle.
- When RSI crosses above the oversold level, a long position is opened.
- When RSI crosses below the overbought level, a short position is opened.
- Before entering a new position the opposite one is closed.
- Optional protections for take‑profit, stop‑loss and trailing stop can be enabled.
The strategy processes only finished candles and uses StockSharp's high‑level API with indicator binding.
Parameters
| Name | Description | Default |
|---|---|---|
RsiPeriod |
RSI calculation period. | 14 |
LevelUp |
Overbought level to trigger shorts. | 70 |
LevelDown |
Oversold level to trigger longs. | 30 |
TakeProfitPercent |
Take profit percentage. 0 disables. |
0 |
StopLossPercent |
Stop loss percentage. 0 disables. |
0 |
TrailingStopPercent |
Trailing stop percentage. 0 disables. |
0 |
CandleType |
Candle timeframe used for calculations. | 1 minute |
Notes
The trailing stop uses the built‑in StartProtection mechanism. When TrailingStopPercent is greater than zero it replaces the regular stop loss and automatically follows the price.
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 based strategy with overbought and oversold level cross signals.
/// Opens long when RSI crosses above oversold level, short when crosses below overbought level.
/// </summary>
public class RsiExpertStrategy : Strategy
{
private readonly StrategyParam<int> _rsiPeriod;
private readonly StrategyParam<decimal> _levelUp;
private readonly StrategyParam<decimal> _levelDown;
private readonly StrategyParam<decimal> _takeProfitPercent;
private readonly StrategyParam<decimal> _stopLossPercent;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevRsi;
public int RsiPeriod { get => _rsiPeriod.Value; set => _rsiPeriod.Value = value; }
public decimal LevelUp { get => _levelUp.Value; set => _levelUp.Value = value; }
public decimal LevelDown { get => _levelDown.Value; set => _levelDown.Value = value; }
public decimal TakeProfitPercent { get => _takeProfitPercent.Value; set => _takeProfitPercent.Value = value; }
public decimal StopLossPercent { get => _stopLossPercent.Value; set => _stopLossPercent.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public RsiExpertStrategy()
{
_rsiPeriod = Param(nameof(RsiPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("RSI Period", "Length of the RSI indicator", "Indicators");
_levelUp = Param(nameof(LevelUp), 70m)
.SetDisplay("RSI Overbought", "Upper RSI level triggering a short", "Indicators");
_levelDown = Param(nameof(LevelDown), 30m)
.SetDisplay("RSI Oversold", "Lower RSI level triggering a long", "Indicators");
_takeProfitPercent = Param(nameof(TakeProfitPercent), 3m)
.SetDisplay("Take Profit %", "Take profit percentage", "Risk");
_stopLossPercent = Param(nameof(StopLossPercent), 2m)
.SetDisplay("Stop Loss %", "Stop loss percentage", "Risk");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevRsi = 0m;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(rsi, ProcessCandle)
.Start();
StartProtection(
takeProfit: new Unit(TakeProfitPercent, UnitTypes.Percent),
stopLoss: new Unit(StopLossPercent, UnitTypes.Percent),
useMarketOrders: true);
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, rsi);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal rsiValue)
{
if (candle.State != CandleStates.Finished)
return;
if (_prevRsi == 0m)
{
_prevRsi = rsiValue;
return;
}
var crossUp = _prevRsi < LevelDown && rsiValue > LevelDown;
var crossDown = _prevRsi > LevelUp && rsiValue < LevelUp;
if (crossUp && Position <= 0)
{
if (Position < 0) BuyMarket();
BuyMarket();
}
else if (crossDown && Position >= 0)
{
if (Position > 0) SellMarket();
SellMarket();
}
_prevRsi = rsiValue;
}
}
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, Unit, UnitTypes
from StockSharp.Algo.Indicators import RelativeStrengthIndex
from StockSharp.Algo.Strategies import Strategy
class rsi_expert_strategy(Strategy):
def __init__(self):
super(rsi_expert_strategy, self).__init__()
self._rsi_period = self.Param("RsiPeriod", 14) \
.SetDisplay("RSI Period", "Length of the RSI indicator", "Indicators")
self._level_up = self.Param("LevelUp", 70.0) \
.SetDisplay("RSI Overbought", "Upper RSI level triggering a short", "Indicators")
self._level_down = self.Param("LevelDown", 30.0) \
.SetDisplay("RSI Oversold", "Lower RSI level triggering a long", "Indicators")
self._take_profit_percent = self.Param("TakeProfitPercent", 3.0) \
.SetDisplay("Take Profit %", "Take profit percentage", "Risk")
self._stop_loss_percent = self.Param("StopLossPercent", 2.0) \
.SetDisplay("Stop Loss %", "Stop loss percentage", "Risk")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Type of candles to use", "General")
self._prev_rsi = 0.0
@property
def RsiPeriod(self):
return self._rsi_period.Value
@RsiPeriod.setter
def RsiPeriod(self, value):
self._rsi_period.Value = value
@property
def LevelUp(self):
return self._level_up.Value
@LevelUp.setter
def LevelUp(self, value):
self._level_up.Value = value
@property
def LevelDown(self):
return self._level_down.Value
@LevelDown.setter
def LevelDown(self, value):
self._level_down.Value = value
@property
def TakeProfitPercent(self):
return self._take_profit_percent.Value
@TakeProfitPercent.setter
def TakeProfitPercent(self, value):
self._take_profit_percent.Value = value
@property
def StopLossPercent(self):
return self._stop_loss_percent.Value
@StopLossPercent.setter
def StopLossPercent(self, value):
self._stop_loss_percent.Value = value
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
def OnStarted2(self, time):
super(rsi_expert_strategy, self).OnStarted2(time)
self._prev_rsi = 0.0
rsi = RelativeStrengthIndex()
rsi.Length = self.RsiPeriod
self.SubscribeCandles(self.CandleType) \
.Bind(rsi, self.ProcessCandle) \
.Start()
self.StartProtection(
takeProfit=Unit(float(self.TakeProfitPercent), UnitTypes.Percent),
stopLoss=Unit(float(self.StopLossPercent), UnitTypes.Percent),
useMarketOrders=True
)
def ProcessCandle(self, candle, rsi_val):
if candle.State != CandleStates.Finished:
return
rsi_f = float(rsi_val)
if self._prev_rsi == 0.0:
self._prev_rsi = rsi_f
return
level_up = float(self.LevelUp)
level_down = float(self.LevelDown)
cross_up = self._prev_rsi < level_down and rsi_f > level_down
cross_down = self._prev_rsi > level_up and rsi_f < level_up
if cross_up and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif cross_down and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_rsi = rsi_f
def OnReseted(self):
super(rsi_expert_strategy, self).OnReseted()
self._prev_rsi = 0.0
def CreateClone(self):
return rsi_expert_strategy()