Tests zeigen eine durchschnittliche jährliche Rendite von etwa 115%. Sie funktioniert am besten am Aktienmarkt.
RSI Reversion geht davon aus, dass der Preis nach dem Erreichen extremer RSI-Werte zurückkehrt. Wenn der RSI unter den unteren Schwellenwert fällt, wird gekauft; wenn er über den oberen Schwellenwert steigt, wird verkauft. Positionen werden geschlossen, wenn der RSI sich wieder in Richtung neutraler Niveaus bewegt.
Die Extremwerte können für verschiedene Märkte kalibriert werden. Die Verwendung zusätzlicher Filter wie die Trendrichtung hilft, starke Bewegungen nicht zu früh zu kontern.
Details
Einstiegskriterien: Signale basierend auf RSI.
Long/Short: Beide Richtungen.
Ausstiegskriterien: Gegensätzliches Signal oder Stop.
Stops: Ja.
Standardwerte:
RsiPeriod = 14
OversoldThreshold = 30m
OverboughtThreshold = 70m
ExitLevel = 50m
StopLossPercent = 2m
CandleType = TimeSpan.FromMinutes(5)
Filter:
Kategorie: Mean Reversion
Richtung: Beide
Indikatoren: RSI
Stops: Ja
Komplexität: Grundlegend
Zeitrahmen: Intraday (5m)
Saisonalität: Nein
Neuronale Netze: Nein
Divergenz: Nein
Risikolevel: Mittel
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>
/// Strategy based on RSI mean reversion.
/// Buys when RSI crosses up from oversold zone, sells when RSI crosses down from overbought.
/// Uses SMA as trend filter.
/// </summary>
public class RsiReversionStrategy : Strategy
{
private readonly StrategyParam<int> _rsiPeriod;
private readonly StrategyParam<int> _smaPeriod;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevRsi;
private bool _hasPrevValues;
private int _cooldown;
/// <summary>
/// RSI period.
/// </summary>
public int RsiPeriod
{
get => _rsiPeriod.Value;
set => _rsiPeriod.Value = value;
}
/// <summary>
/// SMA period for trend filter.
/// </summary>
public int SmaPeriod
{
get => _smaPeriod.Value;
set => _smaPeriod.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Initializes a new instance of the <see cref="RsiReversionStrategy"/>.
/// </summary>
public RsiReversionStrategy()
{
_rsiPeriod = Param(nameof(RsiPeriod), 14)
.SetDisplay("RSI Period", "Period for RSI calculation", "Indicators")
.SetOptimize(10, 20, 2);
_smaPeriod = Param(nameof(SmaPeriod), 50)
.SetDisplay("SMA Period", "Period for SMA trend filter", "Indicators")
.SetOptimize(30, 70, 10);
_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 OnReseted()
{
base.OnReseted();
_prevRsi = default;
_hasPrevValues = default;
_cooldown = default;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
var sma = new SimpleMovingAverage { Length = SmaPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(rsi, sma, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, rsi);
DrawIndicator(area, sma);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal rsiValue, decimal smaValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (rsiValue == 0 || smaValue == 0)
return;
if (!_hasPrevValues)
{
_hasPrevValues = true;
_prevRsi = rsiValue;
return;
}
if (_cooldown > 0)
{
_cooldown--;
_prevRsi = rsiValue;
return;
}
var price = candle.ClosePrice;
// RSI crosses up from oversold (30) = buy (mean reversion)
if (_prevRsi < 30 && rsiValue >= 30 && Position <= 0)
{
var volume = Volume + Math.Abs(Position);
BuyMarket(volume);
_cooldown = 10;
}
// RSI crosses down from overbought (70) = sell (mean reversion)
else if (_prevRsi > 70 && rsiValue <= 70 && Position >= 0)
{
var volume = Volume + Math.Abs(Position);
SellMarket(volume);
_cooldown = 10;
}
_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
from StockSharp.Algo.Indicators import RelativeStrengthIndex, SimpleMovingAverage
from StockSharp.Algo.Strategies import Strategy
class rsi_reversion_strategy(Strategy):
"""
Strategy based on RSI mean reversion.
Buys when RSI crosses up from oversold zone, sells when RSI crosses down from overbought.
Uses SMA as trend filter.
"""
def __init__(self):
super(rsi_reversion_strategy, self).__init__()
self._rsi_period = self.Param("RsiPeriod", 14) \
.SetDisplay("RSI Period", "Period for RSI calculation", "Indicators")
self._sma_period = self.Param("SmaPeriod", 50) \
.SetDisplay("SMA Period", "Period for SMA trend filter", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))) \
.SetDisplay("Candle Type", "Type of candles to use", "General")
self._prev_rsi = 0.0
self._has_prev_values = False
self._cooldown = 0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(rsi_reversion_strategy, self).OnReseted()
self._prev_rsi = 0.0
self._has_prev_values = False
self._cooldown = 0
def OnStarted2(self, time):
super(rsi_reversion_strategy, self).OnStarted2(time)
rsi = RelativeStrengthIndex()
rsi.Length = self._rsi_period.Value
sma = SimpleMovingAverage()
sma.Length = self._sma_period.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(rsi, sma, self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, rsi)
self.DrawIndicator(area, sma)
self.DrawOwnTrades(area)
def _process_candle(self, candle, rsi_value, sma_value):
if candle.State != CandleStates.Finished:
return
rv = float(rsi_value)
sv = float(sma_value)
if rv == 0 or sv == 0:
return
if not self._has_prev_values:
self._has_prev_values = True
self._prev_rsi = rv
return
if self._cooldown > 0:
self._cooldown -= 1
self._prev_rsi = rv
return
if self._prev_rsi < 30 and rv >= 30 and self.Position <= 0:
self.BuyMarket(self.Volume + abs(self.Position))
self._cooldown = 10
elif self._prev_rsi > 70 and rv <= 70 and self.Position >= 0:
self.SellMarket(self.Volume + abs(self.Position))
self._cooldown = 10
self._prev_rsi = rv
def CreateClone(self):
return rsi_reversion_strategy()