Rsi Supertrend Strategy
Strategy based on RSI and Supertrend indicators. Enters long when RSI is oversold (< RsiOversold) and price is above Supertrend Enters short when RSI is overbought (> RsiOverbought) and price is below Supertrend
Testing indicates an average annual return of about 112%. It performs best in the forex market.
The RSI oscillator defines momentum extremes while Supertrend points to the prevailing direction. Trades occur when RSI aligns with the Supertrend color.
Works for traders who appreciate a trailing-stop style exit. The Supertrend's own ATR settings shape that trailing line.
Details
- Entry Criteria:
- Long:
RSI < RsiOversold && Close > Supertrend
- Short:
RSI > RsiOverbought && Close < Supertrend
- Long/Short: Both
- Exit Criteria: Supertrend change
- Stops: Trailing with Supertrend
- Default Values:
RsiPeriod = 14
SupertrendPeriod = 10
SupertrendMultiplier = 3.0m
RsiOversold = 40
RsiOverbought = 60
CandleType = TimeSpan.FromMinutes(5).TimeFrame()
On five-minute candles RSI almost never reaches 30 while price is above Supertrend (or 70 below it): the March 2024 BTC archive has no such candle at all. The levels are therefore parameters defaulting to 40 and 60, which still mark a pullback against the trend and trade on both sides. A long closes when Supertrend flips down and a short when it flips up. An entry signal against an open position reverses it.
- Filters:
- Category: Mean reversion
- Direction: Both
- Indicators: RSI, Supertrend
- Stops: Yes
- Complexity: Intermediate
- Timeframe: Mid-term
- Seasonality: No
- Neural Networks: No
- Divergence: No
- 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 Supertrend strategy.
/// A close above the Supertrend line with RSI below RsiOversold goes long and a close below it with RSI above RsiOverbought goes short,
/// reversing an opposite position. The Supertrend line is the trailing stop: a long closes when Supertrend flips down and a short
/// when it flips up.
/// </summary>
public class RsiSupertrendStrategy : Strategy
{
private readonly StrategyParam<int> _rsiPeriod;
private readonly StrategyParam<int> _supertrendPeriod;
private readonly StrategyParam<decimal> _supertrendMultiplier;
private readonly StrategyParam<decimal> _rsiOversold;
private readonly StrategyParam<decimal> _rsiOverbought;
private readonly StrategyParam<DataType> _candleType;
/// <summary>
/// Period of RSI.
/// </summary>
public int RsiPeriod
{
get => _rsiPeriod.Value;
set => _rsiPeriod.Value = value;
}
/// <summary>
/// ATR period of Supertrend.
/// </summary>
public int SupertrendPeriod
{
get => _supertrendPeriod.Value;
set => _supertrendPeriod.Value = value;
}
/// <summary>
/// ATR multiplier of Supertrend.
/// </summary>
public decimal SupertrendMultiplier
{
get => _supertrendMultiplier.Value;
set => _supertrendMultiplier.Value = value;
}
/// <summary>
/// RSI level for longs.
/// </summary>
public decimal RsiOversold
{
get => _rsiOversold.Value;
set => _rsiOversold.Value = value;
}
/// <summary>
/// RSI level for shorts.
/// </summary>
public decimal RsiOverbought
{
get => _rsiOverbought.Value;
set => _rsiOverbought.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public RsiSupertrendStrategy()
{
_rsiPeriod = Param(nameof(RsiPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("RSI Period", "Period of RSI", "RSI");
_supertrendPeriod = Param(nameof(SupertrendPeriod), 10)
.SetGreaterThanZero()
.SetDisplay("Supertrend Period", "ATR period of Supertrend", "Supertrend");
_supertrendMultiplier = Param(nameof(SupertrendMultiplier), 3m)
.SetGreaterThanZero()
.SetDisplay("Supertrend Multiplier", "ATR multiplier of Supertrend", "Supertrend");
_rsiOversold = Param(nameof(RsiOversold), 40m)
.SetDisplay("RSI Oversold", "RSI level for longs", "RSI");
_rsiOverbought = Param(nameof(RsiOverbought), 60m)
.SetDisplay("RSI Overbought", "RSI level for shorts", "RSI");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).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 OnStarted2(DateTime time)
{
base.OnStarted2(time);
var supertrend = new SuperTrend { Length = SupertrendPeriod, Multiplier = SupertrendMultiplier };
var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(supertrend, rsi, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, supertrend);
DrawOwnTrades(area);
var oscillators = CreateChartArea();
if (oscillators != null)
{
DrawIndicator(oscillators, rsi);
}
}
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue supertrendValue, IIndicatorValue rsiValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!supertrendValue.IsFormed || !rsiValue.IsFormed || supertrendValue is not SuperTrendIndicatorValue trend)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var line = trend.Value;
var isUpTrend = trend.IsUpTrend;
var rsi = rsiValue.GetValue<decimal>();
var close = candle.ClosePrice;
if (close > line && rsi < RsiOversold && Position <= 0)
BuyMarket(Volume + Math.Abs(Position));
else if (close < line && rsi > RsiOverbought && Position >= 0)
SellMarket(Volume + Math.Abs(Position));
else if (Position > 0 && !isUpTrend)
SellMarket(Position);
else if (Position < 0 && isUpTrend)
BuyMarket(-Position);
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Decimal
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import SuperTrend, RelativeStrengthIndex
from StockSharp.Algo.Strategies import Strategy
class rsi_supertrend_strategy(Strategy):
"""
RSI Supertrend strategy.
A close above the Supertrend line with RSI below RsiOversold goes long and a close below it with RSI above RsiOverbought goes short,
reversing an opposite position. The Supertrend line is the trailing stop: a long closes when Supertrend flips down and a short
when it flips up.
"""
def __init__(self):
super(rsi_supertrend_strategy, self).__init__()
self._rsi_period = self.Param("RsiPeriod", 14).SetGreaterThanZero().SetDisplay("RSI Period", "Period of RSI", "RSI")
self._supertrend_period = self.Param("SupertrendPeriod", 10).SetGreaterThanZero().SetDisplay("Supertrend Period", "ATR period of Supertrend", "Supertrend")
self._supertrend_multiplier = self.Param("SupertrendMultiplier", 3.0).SetGreaterThanZero().SetDisplay("Supertrend Multiplier", "ATR multiplier of Supertrend", "Supertrend")
self._rsi_oversold = self.Param("RsiOversold", 40.0).SetDisplay("RSI Oversold", "RSI level for longs", "RSI")
self._rsi_overbought = self.Param("RsiOverbought", 60.0).SetDisplay("RSI Overbought", "RSI level for shorts", "RSI")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))).SetDisplay("Candle Type", "Type of candles to use", "General")
@property
def candle_type(self):
return self._candle_type.Value
def OnStarted2(self, time):
super(rsi_supertrend_strategy, self).OnStarted2(time)
supertrend = SuperTrend()
supertrend.Length = self._supertrend_period.Value
supertrend.Multiplier = Decimal(self._supertrend_multiplier.Value)
rsi = RelativeStrengthIndex()
rsi.Length = self._rsi_period.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(supertrend, rsi, self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, supertrend)
self.DrawOwnTrades(area)
oscillators = self.CreateChartArea()
if oscillators is not None:
self.DrawIndicator(oscillators, rsi)
def _process_candle(self, candle, supertrend_value, rsi_value):
if candle.State != CandleStates.Finished:
return
if not supertrend_value.IsFormed or not rsi_value.IsFormed:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
line = supertrend_value.Value
is_up_trend = supertrend_value.IsUpTrend
rsi = rsi_value.GetValue[Decimal](None)
close = candle.ClosePrice
if close > line and rsi < Decimal(self._rsi_oversold.Value) and self.Position <= 0:
self.BuyMarket(self.Volume + abs(self.Position))
elif close < line and rsi > Decimal(self._rsi_overbought.Value) and self.Position >= 0:
self.SellMarket(self.Volume + abs(self.Position))
elif self.Position > 0 and not is_up_trend:
self.SellMarket(self.Position)
elif self.Position < 0 and is_up_trend:
self.BuyMarket(-self.Position)
def CreateClone(self):
return rsi_supertrend_strategy()