This strategy averages the last RSI values to generate trading signals. It calculates a standard Relative Strength Index (RSI) over a configurable period and then applies a simple moving average to the RSI itself. Trades are opened when the averaged RSI crosses predefined thresholds and closed when the opposite threshold is reached.
Trading Logic
RSI Calculation
The indicator uses RsiPeriod to compute RSI based on candle close prices.
RSI Averaging
The last AveragePeriod RSI values are smoothed by a simple moving average.
Entry Rules
If BuyEnabled is true and no position is open, a buy order is sent when the averaged RSI exceeds BuyThreshold (default 55).
If SellEnabled is true and no position is open, a sell order is sent when the averaged RSI drops below SellThreshold (default 45).
Exit Rules
When CloseBySignal is true, open positions are closed on opposite signals:
Long positions close when averaged RSI falls below CloseBuyThreshold (default 47).
Short positions close when averaged RSI rises above CloseSellThreshold (default 52).
Parameters
BuyEnabled – enable or disable long entries.
SellEnabled – enable or disable short entries.
CloseBySignal – allow exits on opposite RSI signals.
RsiPeriod – RSI calculation length.
AveragePeriod – number of RSI values used for averaging.
BuyThreshold – averaged RSI value above which a long position is opened.
SellThreshold – averaged RSI value below which a short position is opened.
CloseBuyThreshold – averaged RSI value below which a long position is closed.
CloseSellThreshold – averaged RSI value above which a short position is closed.
CandleType – candle type for subscriptions.
Notes
This strategy demonstrates how indicator values can be combined through binding in the StockSharp high level API. Trailing stops and money management features from the original MQL version are omitted for simplicity.
using System;
using System.Linq;
using System.Collections.Generic;
using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Strategy that trades based on averaged RSI values.
/// Uses RSI smoothed by SMA to generate signals.
/// </summary>
public class AutoTradeWithRsiStrategy : Strategy
{
private readonly StrategyParam<int> _rsiPeriod;
private readonly StrategyParam<int> _averagePeriod;
private readonly StrategyParam<decimal> _buyThreshold;
private readonly StrategyParam<decimal> _sellThreshold;
private readonly StrategyParam<DataType> _candleType;
private ExponentialMovingAverage _rsiAvg;
public int RsiPeriod { get => _rsiPeriod.Value; set => _rsiPeriod.Value = value; }
public int AveragePeriod { get => _averagePeriod.Value; set => _averagePeriod.Value = value; }
public decimal BuyThreshold { get => _buyThreshold.Value; set => _buyThreshold.Value = value; }
public decimal SellThreshold { get => _sellThreshold.Value; set => _sellThreshold.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public AutoTradeWithRsiStrategy()
{
_rsiPeriod = Param(nameof(RsiPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("RSI Period", "RSI calculation period", "Indicator");
_averagePeriod = Param(nameof(AveragePeriod), 21)
.SetGreaterThanZero()
.SetDisplay("Average Period", "SMA period to smooth RSI", "Indicator");
_buyThreshold = Param(nameof(BuyThreshold), 55m)
.SetDisplay("Buy Threshold", "Averaged RSI above which to buy", "Rules");
_sellThreshold = Param(nameof(SellThreshold), 45m)
.SetDisplay("Sell Threshold", "Averaged RSI below which to sell", "Rules");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Candle data type", "General");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
protected override void OnReseted()
{
base.OnReseted();
_rsiAvg = null;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
_rsiAvg = new ExponentialMovingAverage { Length = AveragePeriod };
Indicators.Add(_rsiAvg);
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(rsi, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
var area2 = CreateChartArea();
if (area2 != null)
DrawIndicator(area2, rsi);
}
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue rsiValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!rsiValue.IsFormed)
return;
var avgResult = _rsiAvg.Process(rsiValue);
if (!avgResult.IsFormed)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var avgRsi = avgResult.GetValue<decimal>();
if (avgRsi > BuyThreshold && Position <= 0)
BuyMarket();
else if (avgRsi < SellThreshold && Position >= 0)
SellMarket();
}
}
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, ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class auto_trade_with_rsi_strategy(Strategy):
def __init__(self):
super(auto_trade_with_rsi_strategy, self).__init__()
self._rsi_period = self.Param("RsiPeriod", 14) \
.SetDisplay("RSI Period", "RSI calculation period", "Indicator")
self._average_period = self.Param("AveragePeriod", 21) \
.SetDisplay("Average Period", "SMA period to smooth RSI", "Indicator")
self._buy_threshold = self.Param("BuyThreshold", 55.0) \
.SetDisplay("Buy Threshold", "Averaged RSI above which to buy", "Rules")
self._sell_threshold = self.Param("SellThreshold", 45.0) \
.SetDisplay("Sell Threshold", "Averaged RSI below which to sell", "Rules")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Candle data type", "General")
self._rsi_avg = None
@property
def rsi_period(self):
return self._rsi_period.Value
@property
def average_period(self):
return self._average_period.Value
@property
def buy_threshold(self):
return self._buy_threshold.Value
@property
def sell_threshold(self):
return self._sell_threshold.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(auto_trade_with_rsi_strategy, self).OnReseted()
self._rsi_avg = None
def OnStarted2(self, time):
super(auto_trade_with_rsi_strategy, self).OnStarted2(time)
rsi = RelativeStrengthIndex()
rsi.Length = self.rsi_period
self._rsi_avg = ExponentialMovingAverage()
self._rsi_avg.Length = self.average_period
self.Indicators.Add(self._rsi_avg)
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(rsi, self.process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def process_candle(self, candle, rsi_value):
if candle.State != CandleStates.Finished:
return
if not rsi_value.IsFormed:
return
avg_result = self._rsi_avg.Process(rsi_value)
if not avg_result.IsFormed:
return
avg_rsi = float(avg_result)
if avg_rsi > float(self.buy_threshold) and self.Position <= 0:
self.BuyMarket()
elif avg_rsi < float(self.sell_threshold) and self.Position >= 0:
self.SellMarket()
def CreateClone(self):
return auto_trade_with_rsi_strategy()