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
namespace StockSharp.Samples.Strategies;
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
/// <summary>
/// Trades divergences between consecutive confirmed price pivots and their RSI values.
/// A three-bar pivot is confirmed only after the bar to its right has closed.
/// </summary>
public class RsiDivergenceStrategy : Strategy
{
private readonly StrategyParam<int> _rsiPeriod;
private readonly StrategyParam<decimal> _stopLossPercent;
private readonly StrategyParam<DataType> _candleType;
private readonly List<(decimal High, decimal Low, decimal Rsi)> _bars = new();
private decimal _previousLowPrice;
private decimal _previousLowRsi;
private decimal _previousHighPrice;
private decimal _previousHighRsi;
private bool _hasLow;
private bool _hasHigh;
public int RsiPeriod { get => _rsiPeriod.Value; set => _rsiPeriod.Value = value; }
public decimal StopLossPercent { get => _stopLossPercent.Value; set => _stopLossPercent.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public RsiDivergenceStrategy()
{
_rsiPeriod = Param(nameof(RsiPeriod), 14).SetGreaterThanZero();
_stopLossPercent = Param(nameof(StopLossPercent), 2m).SetRange(0m, 100m);
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame());
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
protected override void OnReseted()
{
base.OnReseted();
ResetPivots();
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
ResetPivots();
StartProtection(new Unit(), new Unit(StopLossPercent, UnitTypes.Percent), useMarketOrders: true, isLocalStop: true);
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 ResetPivots()
{
_bars.Clear();
_previousLowPrice = _previousLowRsi = _previousHighPrice = _previousHighRsi = 0m;
_hasLow = _hasHigh = false;
}
private void ProcessCandle(ICandleMessage candle, decimal rsiValue)
{
if (candle.State != CandleStates.Finished || !IsFormedAndOnlineAndAllowTrading())
return;
_bars.Add((candle.HighPrice, candle.LowPrice, rsiValue));
if (_bars.Count < 3)
return;
var left = _bars[0];
var pivot = _bars[1];
var right = _bars[2];
var bullish = false;
var bearish = false;
if (pivot.Low < left.Low && pivot.Low < right.Low)
{
bullish = _hasLow && pivot.Low < _previousLowPrice && pivot.Rsi > _previousLowRsi;
_previousLowPrice = pivot.Low;
_previousLowRsi = pivot.Rsi;
_hasLow = true;
}
if (pivot.High > left.High && pivot.High > right.High)
{
bearish = _hasHigh && pivot.High > _previousHighPrice && pivot.Rsi < _previousHighRsi;
_previousHighPrice = pivot.High;
_previousHighRsi = pivot.Rsi;
_hasHigh = true;
}
_bars.RemoveAt(0);
if (bullish && Position <= 0m)
BuyMarket(Volume + Math.Abs(Position));
else if (bearish && Position >= 0m)
SellMarket(Volume + Math.Abs(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, Math
from StockSharp.Messages import DataType, CandleStates, Unit, UnitTypes
from StockSharp.Algo.Indicators import RelativeStrengthIndex
from StockSharp.Algo.Strategies import Strategy
class rsi_divergence_strategy(Strategy):
"""Trades confirmed three-bar price pivots unconfirmed by RSI, without future bars."""
def __init__(self):
super(rsi_divergence_strategy, self).__init__()
self._rsi_period = self.Param("RsiPeriod", 14).SetGreaterThanZero()
self._stop_loss_percent = self.Param("StopLossPercent", 2.0).SetRange(0.0, 100.0)
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5)))
self._reset_pivots()
def GetWorkingSecurities(self):
return [(self.Security, self._candle_type.Value)]
def OnReseted(self):
super(rsi_divergence_strategy, self).OnReseted()
self._reset_pivots()
def _reset_pivots(self):
self._bars = []
self._previous_low = None
self._previous_high = None
def OnStarted2(self, time):
super(rsi_divergence_strategy, self).OnStarted2(time)
self._reset_pivots()
self.StartProtection(Unit(), Unit(float(self._stop_loss_percent.Value), UnitTypes.Percent),
useMarketOrders=True, isLocalStop=True)
rsi = RelativeStrengthIndex()
rsi.Length = self._rsi_period.Value
subscription = self.SubscribeCandles(self._candle_type.Value)
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_value):
if candle.State != CandleStates.Finished or not self.IsFormedAndOnlineAndAllowTrading():
return
self._bars.append((candle.HighPrice, candle.LowPrice, rsi_value))
if len(self._bars) < 3:
return
left, pivot, right = self._bars
bullish = False
bearish = False
if pivot[1] < left[1] and pivot[1] < right[1]:
bullish = (self._previous_low is not None and
pivot[1] < self._previous_low[0] and pivot[2] > self._previous_low[1])
self._previous_low = (pivot[1], pivot[2])
if pivot[0] > left[0] and pivot[0] > right[0]:
bearish = (self._previous_high is not None and
pivot[0] > self._previous_high[0] and pivot[2] < self._previous_high[1])
self._previous_high = (pivot[0], pivot[2])
self._bars.pop(0)
if bullish and self.Position <= 0:
self.BuyMarket(self.Volume + Math.Abs(self.Position))
elif bearish and self.Position >= 0:
self.SellMarket(self.Volume + Math.Abs(self.Position))
def CreateClone(self):
return rsi_divergence_strategy()