Tests zeigen eine durchschnittliche jährliche Rendite von etwa 85%. Am besten funktioniert sie auf dem Kryptomarkt.
RSI Divergence sucht nach Preisextremen, die vom RSI-Oszillator nicht bestätigt werden. Eine bullische Divergenz führt zu einem Kauf und eine bärische Divergenz veranlasst einen Verkauf. Der Trade dauert an, bis sich der RSI umkehrt oder ein Stop ausgelöst wird.
Divergenz-Setups entstehen oft gegen Ende langer Trends. Durch den Vergleich des Oszillator-Verhaltens mit der Preisaction versucht die Strategie, frühe Umkehrungen mit kontrolliertem Risiko zu erfassen.
Details
Einstiegskriterien: Signale basierend auf RSI.
Long/Short: Beide Richtungen.
Ausstiegskriterien: Entgegengesetztes Signal oder Stop.
Stops: Ja.
Standardwerte:
RsiPeriod = 14
StopLossPercent = 2m
CandleType = TimeSpan.FromMinutes(5)
Filter:
Kategorie: Trend
Richtung: Beide
Indikatoren: RSI
Stops: Ja
Komplexität: Grundlegend
Zeitrahmen: Intraday (5m)
Saisonalität: Nein
Neural Networks: Nein
Divergenz: Ja
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 divergence detection.
/// Uses RSI overbought/oversold level crossings to generate reversal signals.
/// </summary>
public class RsiDivergenceStrategy : Strategy
{
private readonly StrategyParam<int> _rsiPeriod;
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>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Initializes a new instance of the <see cref="RsiDivergenceStrategy"/>.
/// </summary>
public RsiDivergenceStrategy()
{
_rsiPeriod = Param(nameof(RsiPeriod), 14)
.SetDisplay("RSI Period", "Period for RSI calculation", "Indicators")
.SetOptimize(10, 20, 2);
_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 subscription = SubscribeCandles(CandleType);
subscription
.Bind(rsi, ProcessCandle)
.Start();
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 (!IsFormedAndOnlineAndAllowTrading())
return;
if (rsiValue == 0)
return;
if (!_hasPrevValues)
{
_hasPrevValues = true;
_prevRsi = rsiValue;
return;
}
if (_cooldown > 0)
{
_cooldown--;
_prevRsi = rsiValue;
return;
}
// RSI crosses from oversold into neutral zone - buy
if (_prevRsi < 30 && rsiValue >= 30 && Position <= 0)
{
var volume = Volume + Math.Abs(Position);
BuyMarket(volume);
_cooldown = 15;
}
// RSI crosses from overbought into neutral zone - sell
else if (_prevRsi > 70 && rsiValue <= 70 && Position >= 0)
{
var volume = Volume + Math.Abs(Position);
SellMarket(volume);
_cooldown = 15;
}
_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
from StockSharp.Algo.Strategies import Strategy
class rsi_divergence_strategy(Strategy):
"""
Strategy based on RSI divergence detection.
Uses RSI overbought/oversold level crossings to generate reversal signals.
"""
def __init__(self):
super(rsi_divergence_strategy, self).__init__()
self._rsi_period = self.Param("RsiPeriod", 14).SetDisplay("RSI Period", "Period for RSI calculation", "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_divergence_strategy, self).OnReseted()
self._prev_rsi = 0.0
self._has_prev_values = False
self._cooldown = 0
def OnStarted2(self, time):
super(rsi_divergence_strategy, self).OnStarted2(time)
rsi = RelativeStrengthIndex()
rsi.Length = self._rsi_period.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(rsi, self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, rsi)
self.DrawOwnTrades(area)
def _process_candle(self, candle, rsi_val):
if candle.State != CandleStates.Finished:
return
rv = float(rsi_val)
if rv == 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
# RSI crosses from oversold into neutral zone - buy
if self._prev_rsi < 30 and rv >= 30 and self.Position <= 0:
self.BuyMarket(self.Volume + abs(self.Position))
self._cooldown = 15
# RSI crosses from overbought into neutral zone - sell
elif self._prev_rsi > 70 and rv <= 70 and self.Position >= 0:
self.SellMarket(self.Volume + abs(self.Position))
self._cooldown = 15
self._prev_rsi = rv
def CreateClone(self):
return rsi_divergence_strategy()