RSI Failure Swing Strategie
RSI Failure Swing ist eine klassische Umkehrtechnik, bei der der RSI ein höheres Tief im überverkauften Bereich oder ein niedrigeres Hoch im überkauften Bereich bildet. Dieses Versagen, einen neuen Extremwert zu erreichen, geht oft einer Trendwende voraus.
Tests zeigen eine durchschnittliche jährliche Rendite von etwa 67%. Die Strategie funktioniert am besten am Aktienmarkt.
Die Strategie kauft, wenn der RSI über seinem vorherigen Tief bleibt und dann über 30 kreuzt, oder verkauft, wenn er ein vorheriges Hoch nicht überschreitet und unter 70 fällt.
Ein prozentualer Stop begrenzt den Nachteil, und Positionen werden geschlossen, wenn der RSI das entgegengesetzte Niveau kreuzt.
Details
- Einstiegskriterien: Indikatorsignal
- Long/Short: Beide
- Ausstiegskriterien: Stop-Loss oder entgegengesetztes Signal
- Stops: Ja, prozentbasiert
- Standardwerte:
CandleType= 15 minuteStopLoss= 2%
- Filter:
- Kategorie: Umkehr
- Richtung: Beide
- Indikatoren: RSI
- Stops: Ja
- Komplexität: Mittel
- Zeitrahmen: Intraday
- 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 that trades based on RSI Failure Swing pattern.
/// A failure swing occurs when RSI reverses direction without crossing through centerline.
/// Uses cooldown to control trade frequency.
/// </summary>
public class RsiFailureSwingStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _rsiPeriod;
private readonly StrategyParam<decimal> _oversoldLevel;
private readonly StrategyParam<decimal> _overboughtLevel;
private readonly StrategyParam<int> _cooldownBars;
private RelativeStrengthIndex _rsi;
private decimal _prevRsi;
private decimal _prevPrevRsi;
private int _cooldown;
/// <summary>
/// Candle type and timeframe.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// RSI period.
/// </summary>
public int RsiPeriod
{
get => _rsiPeriod.Value;
set => _rsiPeriod.Value = value;
}
/// <summary>
/// Oversold level.
/// </summary>
public decimal OversoldLevel
{
get => _oversoldLevel.Value;
set => _oversoldLevel.Value = value;
}
/// <summary>
/// Overbought level.
/// </summary>
public decimal OverboughtLevel
{
get => _overboughtLevel.Value;
set => _overboughtLevel.Value = value;
}
/// <summary>
/// Cooldown bars between trades.
/// </summary>
public int CooldownBars
{
get => _cooldownBars.Value;
set => _cooldownBars.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public RsiFailureSwingStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_rsiPeriod = Param(nameof(RsiPeriod), 14)
.SetDisplay("RSI Period", "Period for RSI", "RSI Settings")
.SetRange(2, 50);
_oversoldLevel = Param(nameof(OversoldLevel), 40m)
.SetDisplay("Oversold Level", "RSI oversold threshold", "RSI Settings")
.SetRange(10m, 45m);
_overboughtLevel = Param(nameof(OverboughtLevel), 60m)
.SetDisplay("Overbought Level", "RSI overbought threshold", "RSI Settings")
.SetRange(55m, 90m);
_cooldownBars = Param(nameof(CooldownBars), 400)
.SetDisplay("Cooldown Bars", "Bars between trades", "General")
.SetRange(10, 2000);
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_rsi = default;
_prevRsi = 0;
_prevPrevRsi = 0;
_cooldown = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_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;
// Need at least 2 previous RSI values
if (_prevRsi == 0 || _prevPrevRsi == 0)
{
_prevPrevRsi = _prevRsi;
_prevRsi = rsiValue;
return;
}
if (_cooldown > 0)
{
_cooldown--;
_prevPrevRsi = _prevRsi;
_prevRsi = rsiValue;
return;
}
// Bullish Failure Swing: RSI was oversold, rose, pulled back but stayed above prior low
var isBullish = _prevPrevRsi < OversoldLevel &&
_prevRsi > _prevPrevRsi &&
rsiValue < _prevRsi &&
rsiValue > _prevPrevRsi;
// Bearish Failure Swing: RSI was overbought, fell, bounced but stayed below prior high
var isBearish = _prevPrevRsi > OverboughtLevel &&
_prevRsi < _prevPrevRsi &&
rsiValue > _prevRsi &&
rsiValue < _prevPrevRsi;
if (Position == 0)
{
if (isBullish)
{
BuyMarket();
_cooldown = CooldownBars;
}
else if (isBearish)
{
SellMarket();
_cooldown = CooldownBars;
}
}
else if (Position > 0)
{
// Exit long when RSI crosses above overbought or reverses from peak
if (rsiValue > OverboughtLevel || (rsiValue < 45 && _prevRsi > 45))
{
SellMarket();
_cooldown = CooldownBars;
}
}
else if (Position < 0)
{
// Exit short when RSI crosses below oversold or reverses from trough
if (rsiValue < OversoldLevel || (rsiValue > 55 && _prevRsi < 55))
{
BuyMarket();
_cooldown = CooldownBars;
}
}
_prevPrevRsi = _prevRsi;
_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_failure_swing_strategy(Strategy):
"""
Strategy that trades based on RSI Failure Swing pattern.
A failure swing occurs when RSI reverses direction without crossing through centerline.
Uses cooldown to control trade frequency.
"""
def __init__(self):
super(rsi_failure_swing_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))).SetDisplay("Candle Type", "Candle timeframe", "General")
self._rsi_period = self.Param("RsiPeriod", 14).SetDisplay("RSI Period", "Period for RSI", "RSI Settings")
self._oversold_level = self.Param("OversoldLevel", 40.0).SetDisplay("Oversold Level", "RSI oversold threshold", "RSI Settings")
self._overbought_level = self.Param("OverboughtLevel", 60.0).SetDisplay("Overbought Level", "RSI overbought threshold", "RSI Settings")
self._cooldown_bars = self.Param("CooldownBars", 400).SetDisplay("Cooldown Bars", "Bars between trades", "General")
self._prev_rsi = 0.0
self._prev_prev_rsi = 0.0
self._cooldown = 0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(rsi_failure_swing_strategy, self).OnReseted()
self._prev_rsi = 0.0
self._prev_prev_rsi = 0.0
self._cooldown = 0
def OnStarted2(self, time):
super(rsi_failure_swing_strategy, self).OnStarted2(time)
self._prev_rsi = 0.0
self._prev_prev_rsi = 0.0
self._cooldown = 0
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)
# Need at least 2 previous RSI values
if self._prev_rsi == 0 or self._prev_prev_rsi == 0:
self._prev_prev_rsi = self._prev_rsi
self._prev_rsi = rv
return
if self._cooldown > 0:
self._cooldown -= 1
self._prev_prev_rsi = self._prev_rsi
self._prev_rsi = rv
return
cd = self._cooldown_bars.Value
oversold = self._oversold_level.Value
overbought = self._overbought_level.Value
# Bullish Failure Swing: RSI was oversold, rose, pulled back but stayed above prior low
is_bullish = (
self._prev_prev_rsi < oversold and
self._prev_rsi > self._prev_prev_rsi and
rv < self._prev_rsi and
rv > self._prev_prev_rsi
)
# Bearish Failure Swing: RSI was overbought, fell, bounced but stayed below prior high
is_bearish = (
self._prev_prev_rsi > overbought and
self._prev_rsi < self._prev_prev_rsi and
rv > self._prev_rsi and
rv < self._prev_prev_rsi
)
if self.Position == 0:
if is_bullish:
self.BuyMarket()
self._cooldown = cd
elif is_bearish:
self.SellMarket()
self._cooldown = cd
elif self.Position > 0:
# Exit long when RSI crosses above overbought or reverses from peak
if rv > overbought or (rv < 45 and self._prev_rsi > 45):
self.SellMarket()
self._cooldown = cd
elif self.Position < 0:
# Exit short when RSI crosses below oversold or reverses from trough
if rv < oversold or (rv > 55 and self._prev_rsi < 55):
self.BuyMarket()
self._cooldown = cd
self._prev_prev_rsi = self._prev_rsi
self._prev_rsi = rv
def CreateClone(self):
return rsi_failure_swing_strategy()