Bollinger RSI Strategie
Bollinger RSI kombiniert die Überdehnung der Bollinger Bänder mit RSI-Momentum-Signalen. Wenn der Kurs außerhalb der Bänder schließt, aber der RSI eine Divergenz zeigt, ist oft eine Umkehr nahe.
Tests zeigen eine durchschnittliche jährliche Rendite von etwa 148%. Die Strategie funktioniert am besten auf dem Forex-Markt.
Das System geht bei dieser Divergenz gegen den Trend vor und steigt aus, sobald der Kurs wieder in die Bänder eintritt oder der RSI zurückkreuzt.
Ein enger prozentualer Stop begrenzt das Risiko, falls die Volatilität weiter zunimmt.
Details
- Einstiegskriterien: Indikatorsignal
- Long/Short: Beide
- Ausstiegskriterien: Stop-Loss oder entgegengesetztes Signal
- Stops: Ja, prozentbasiert
- Standardwerte:
CandleType= 15 minuteStopLoss= 2%
- Filter:
- Kategorie: Mean Reversion
- Richtung: Beide
- Indikatoren: Bollinger Bands, 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>
/// Combined strategy that uses Bollinger Bands and RSI indicators
/// for mean reversion trading.
/// </summary>
public class BollingerRsiStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _bollingerPeriod;
private readonly StrategyParam<decimal> _bollingerDeviation;
private readonly StrategyParam<int> _rsiPeriod;
private readonly StrategyParam<decimal> _rsiOversold;
private readonly StrategyParam<decimal> _rsiOverbought;
private readonly StrategyParam<int> _cooldownBars;
private decimal _rsiValue;
private int _cooldown;
/// <summary>
/// Candle type for strategy calculation.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Bollinger Bands period.
/// </summary>
public int BollingerPeriod
{
get => _bollingerPeriod.Value;
set => _bollingerPeriod.Value = value;
}
/// <summary>
/// Bollinger Bands standard deviation multiplier.
/// </summary>
public decimal BollingerDeviation
{
get => _bollingerDeviation.Value;
set => _bollingerDeviation.Value = value;
}
/// <summary>
/// RSI period.
/// </summary>
public int RsiPeriod
{
get => _rsiPeriod.Value;
set => _rsiPeriod.Value = value;
}
/// <summary>
/// RSI oversold level.
/// </summary>
public decimal RsiOversold
{
get => _rsiOversold.Value;
set => _rsiOversold.Value = value;
}
/// <summary>
/// RSI overbought level.
/// </summary>
public decimal RsiOverbought
{
get => _rsiOverbought.Value;
set => _rsiOverbought.Value = value;
}
/// <summary>
/// Cooldown bars between trades.
/// </summary>
public int CooldownBars
{
get => _cooldownBars.Value;
set => _cooldownBars.Value = value;
}
/// <summary>
/// Strategy constructor.
/// </summary>
public BollingerRsiStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
_bollingerPeriod = Param(nameof(BollingerPeriod), 20)
.SetRange(10, 50)
.SetDisplay("Bollinger Period", "Period of the Bollinger Bands indicator", "Indicators");
_bollingerDeviation = Param(nameof(BollingerDeviation), 2.0m)
.SetDisplay("Bollinger Deviation", "Standard deviation multiplier", "Indicators");
_rsiPeriod = Param(nameof(RsiPeriod), 14)
.SetRange(7, 21)
.SetDisplay("RSI Period", "Period of the RSI indicator", "Indicators");
_rsiOversold = Param(nameof(RsiOversold), 30m)
.SetDisplay("RSI Oversold", "RSI oversold level", "Indicators");
_rsiOverbought = Param(nameof(RsiOverbought), 70m)
.SetDisplay("RSI Overbought", "RSI overbought level", "Indicators");
_cooldownBars = Param(nameof(CooldownBars), 100)
.SetDisplay("Cooldown Bars", "Bars between trades", "General")
.SetRange(5, 500);
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_rsiValue = 50;
_cooldown = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var bollinger = new BollingerBands
{
Length = BollingerPeriod,
Width = BollingerDeviation
};
var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
var subscription = SubscribeCandles(CandleType);
// Bind RSI to capture value
subscription.Bind(rsi, OnRsi);
// Bind Bollinger for main logic
subscription
.BindEx(bollinger, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, bollinger);
DrawOwnTrades(area);
var rsiArea = CreateChartArea();
if (rsiArea != null)
DrawIndicator(rsiArea, rsi);
}
}
private void OnRsi(ICandleMessage candle, decimal rsi)
{
_rsiValue = rsi;
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue bollingerValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var bollingerTyped = (BollingerBandsValue)bollingerValue;
if (bollingerTyped.UpBand is not decimal upperBand ||
bollingerTyped.LowBand is not decimal lowerBand ||
bollingerTyped.MovingAverage is not decimal middleBand)
return;
var close = candle.ClosePrice;
if (_cooldown > 0)
{
_cooldown--;
return;
}
// Long entry: price below lower band + RSI oversold
if (close < lowerBand && _rsiValue < RsiOversold && Position == 0)
{
BuyMarket();
_cooldown = CooldownBars;
}
// Short entry: price above upper band + RSI overbought
else if (close > upperBand && _rsiValue > RsiOverbought && Position == 0)
{
SellMarket();
_cooldown = CooldownBars;
}
// Exit long: price returns to middle band
if (Position > 0 && close > middleBand)
{
SellMarket();
_cooldown = CooldownBars;
}
// Exit short: price returns below middle band
else if (Position < 0 && close < middleBand)
{
BuyMarket();
_cooldown = CooldownBars;
}
}
}
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 BollingerBands, RelativeStrengthIndex
from StockSharp.Algo.Strategies import Strategy
class bollinger_rsi_strategy(Strategy):
def __init__(self):
super(bollinger_rsi_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))) \
.SetDisplay("Candle Type", "Type of candles to use", "General")
self._bollinger_period = self.Param("BollingerPeriod", 20) \
.SetDisplay("Bollinger Period", "Period of the Bollinger Bands indicator", "Indicators")
self._bollinger_deviation = self.Param("BollingerDeviation", 2.0) \
.SetDisplay("Bollinger Deviation", "Standard deviation multiplier", "Indicators")
self._rsi_period = self.Param("RsiPeriod", 14) \
.SetDisplay("RSI Period", "Period of the RSI indicator", "Indicators")
self._rsi_oversold = self.Param("RsiOversold", 30.0) \
.SetDisplay("RSI Oversold", "RSI oversold level", "Indicators")
self._rsi_overbought = self.Param("RsiOverbought", 70.0) \
.SetDisplay("RSI Overbought", "RSI overbought level", "Indicators")
self._cooldown_bars = self.Param("CooldownBars", 100) \
.SetDisplay("Cooldown Bars", "Bars between trades", "General")
self._rsi_value = 50.0
self._cooldown = 0
@property
def candle_type(self):
return self._candle_type.Value
@property
def bollinger_period(self):
return self._bollinger_period.Value
@property
def bollinger_deviation(self):
return self._bollinger_deviation.Value
@property
def rsi_period(self):
return self._rsi_period.Value
@property
def rsi_oversold(self):
return self._rsi_oversold.Value
@property
def rsi_overbought(self):
return self._rsi_overbought.Value
@property
def cooldown_bars(self):
return self._cooldown_bars.Value
def OnReseted(self):
super(bollinger_rsi_strategy, self).OnReseted()
self._rsi_value = 50.0
self._cooldown = 0
def OnStarted2(self, time):
super(bollinger_rsi_strategy, self).OnStarted2(time)
bollinger = BollingerBands()
bollinger.Length = self.bollinger_period
bollinger.Width = self.bollinger_deviation
rsi = RelativeStrengthIndex()
rsi.Length = self.rsi_period
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(rsi, self._on_rsi)
subscription.BindEx(bollinger, self.OnProcess).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, bollinger)
self.DrawOwnTrades(area)
rsi_area = self.CreateChartArea()
if rsi_area is not None:
self.DrawIndicator(rsi_area, rsi)
def _on_rsi(self, candle, rsi_val):
self._rsi_value = float(rsi_val)
def OnProcess(self, candle, bollinger_value):
if candle.State != CandleStates.Finished:
return
bb = bollinger_value
if bb.UpBand is None or bb.LowBand is None or bb.MovingAverage is None:
return
upper_band = float(bb.UpBand)
lower_band = float(bb.LowBand)
middle_band = float(bb.MovingAverage)
close = float(candle.ClosePrice)
if self._cooldown > 0:
self._cooldown -= 1
return
if close < lower_band and self._rsi_value < self.rsi_oversold and self.Position == 0:
self.BuyMarket()
self._cooldown = self.cooldown_bars
elif close > upper_band and self._rsi_value > self.rsi_overbought and self.Position == 0:
self.SellMarket()
self._cooldown = self.cooldown_bars
if self.Position > 0 and close > middle_band:
self.SellMarket()
self._cooldown = self.cooldown_bars
elif self.Position < 0 and close < middle_band:
self.BuyMarket()
self._cooldown = self.cooldown_bars
def CreateClone(self):
return bollinger_rsi_strategy()