Strategie Bollinger Reversion
Strategie basierend auf Bollinger Bands Mean Reversion
Tests zeigen eine durchschnittliche jährliche Rendite von etwa 118%. Sie funktioniert am besten am Aktienmarkt.
Bollinger Reversion handelt gegen Bewegungen außerhalb der Bollinger Bands. Trades öffnen gegen Schlusskurse jenseits der Bänder und schließen, sobald der Preis wieder ins Innere zurückkehrt oder einen Stop trifft.
Standardabweichungsbänder bieten eine statistische Sicht auf Überextensionen. Der Einstieg nach extremen Schlusskursen zielt darauf ab, vom Rückprall in Richtung des mittleren Bands zu profitieren.
Details
- Einstiegskriterien: Signale basierend auf RSI, ATR, Bollinger.
- Long/Short: Beide Richtungen.
- Ausstiegskriterien: Gegensätzliches Signal oder Stop.
- Stops: Ja.
- Standardwerte:
BollingerPeriod= 20BollingerDeviation= 2mAtrMultiplier= 2mCandleType= TimeSpan.FromMinutes(5)
- Filter:
- Kategorie: Mean Reversion
- Richtung: Beide
- Indikatoren: RSI, ATR, Bollinger
- 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 Bollinger Bands mean reversion.
/// Enters when price touches bands, exits when price returns to middle.
/// </summary>
public class BollingerReversionStrategy : Strategy
{
private readonly StrategyParam<int> _bollingerPeriod;
private readonly StrategyParam<decimal> _bollingerDeviation;
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _cooldownBars;
private readonly StrategyParam<int> _maxHoldBars;
private int _cooldown;
private int _holdBars;
/// <summary>
/// Bollinger Bands period.
/// </summary>
public int BollingerPeriod
{
get => _bollingerPeriod.Value;
set => _bollingerPeriod.Value = value;
}
/// <summary>
/// Bollinger Bands deviation multiplier.
/// </summary>
public decimal BollingerDeviation
{
get => _bollingerDeviation.Value;
set => _bollingerDeviation.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Cooldown bars between trades.
/// </summary>
public int CooldownBars
{
get => _cooldownBars.Value;
set => _cooldownBars.Value = value;
}
/// <summary>
/// Maximum bars to hold position before forced exit.
/// </summary>
public int MaxHoldBars
{
get => _maxHoldBars.Value;
set => _maxHoldBars.Value = value;
}
/// <summary>
/// Initializes a new instance of the <see cref="BollingerReversionStrategy"/>.
/// </summary>
public BollingerReversionStrategy()
{
_bollingerPeriod = Param(nameof(BollingerPeriod), 20)
.SetRange(5, 50)
.SetDisplay("Bollinger Period", "Period for Bollinger Bands calculation", "Indicators")
;
_bollingerDeviation = Param(nameof(BollingerDeviation), 2.0m)
.SetRange(0.5m, 4m)
.SetDisplay("Bollinger Deviation", "Standard deviation multiplier for Bollinger Bands", "Indicators")
;
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(1).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
_cooldownBars = Param(nameof(CooldownBars), 500)
.SetRange(1, 1000)
.SetDisplay("Cooldown Bars", "Number of bars to wait between trades", "General");
_maxHoldBars = Param(nameof(MaxHoldBars), 300)
.SetRange(1, 1000)
.SetDisplay("Max Hold Bars", "Maximum bars to hold a position", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_cooldown = default;
_holdBars = default;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_cooldown = 0;
_holdBars = 0;
var bollingerBands = new BollingerBands
{
Length = BollingerPeriod,
Width = BollingerDeviation
};
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(bollingerBands, ProcessCandle)
.Start();
// Setup chart visualization
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, bollingerBands);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue bollingerValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!bollingerValue.IsFormed)
return;
// Track hold duration
if (Position != 0)
_holdBars++;
else
_holdBars = 0;
if (_cooldown > 0)
{
_cooldown--;
return;
}
var bb = (BollingerBandsValue)bollingerValue;
if (bb.UpBand is not decimal upper ||
bb.LowBand is not decimal lower ||
bb.MovingAverage is not decimal middle)
return;
var close = candle.ClosePrice;
// Exit logic: revert to middle or time-based forced exit
if (Position > 0 && (close >= middle || _holdBars >= MaxHoldBars))
{
SellMarket();
_cooldown = CooldownBars;
_holdBars = 0;
return;
}
if (Position < 0 && (close <= middle || _holdBars >= MaxHoldBars))
{
BuyMarket();
_cooldown = CooldownBars;
_holdBars = 0;
return;
}
// Entry logic - buy below lower band, sell above upper band
if (Position == 0 && close < lower)
{
BuyMarket();
_cooldown = CooldownBars;
}
else if (Position == 0 && close > upper)
{
SellMarket();
_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
from StockSharp.Algo.Strategies import Strategy
class bollinger_reversion_strategy(Strategy):
"""
Bollinger Bands mean reversion strategy.
Enters when price touches bands, exits when price returns to middle.
"""
def __init__(self):
super(bollinger_reversion_strategy, self).__init__()
self._bollinger_period = self.Param("BollingerPeriod", 20).SetDisplay("Bollinger Period", "Period for Bollinger Bands calculation", "Indicators")
self._bollinger_deviation = self.Param("BollingerDeviation", 2.0).SetDisplay("Bollinger Deviation", "Standard deviation multiplier for Bollinger Bands", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(1))).SetDisplay("Candle Type", "Type of candles to use", "General")
self._cooldown_bars = self.Param("CooldownBars", 500).SetDisplay("Cooldown Bars", "Number of bars to wait between trades", "General")
self._max_hold_bars = self.Param("MaxHoldBars", 300).SetDisplay("Max Hold Bars", "Maximum bars to hold a position", "General")
self._cooldown = 0
self._hold_bars = 0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(bollinger_reversion_strategy, self).OnReseted()
self._cooldown = 0
self._hold_bars = 0
def OnStarted2(self, time):
super(bollinger_reversion_strategy, self).OnStarted2(time)
self._cooldown = 0
self._hold_bars = 0
bb = BollingerBands()
bb.Length = self._bollinger_period.Value
bb.Width = self._bollinger_deviation.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(bb, self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, bb)
self.DrawOwnTrades(area)
def _process_candle(self, candle, bb_val):
if candle.State != CandleStates.Finished:
return
if not bb_val.IsFormed:
return
# Track hold duration
if self.Position != 0:
self._hold_bars += 1
else:
self._hold_bars = 0
if self._cooldown > 0:
self._cooldown -= 1
return
if bb_val.UpBand is None or bb_val.LowBand is None or bb_val.MovingAverage is None:
return
upper = float(bb_val.UpBand)
lower = float(bb_val.LowBand)
middle = float(bb_val.MovingAverage)
close = float(candle.ClosePrice)
max_hold = self._max_hold_bars.Value
cd = self._cooldown_bars.Value
# Exit logic: revert to middle or time-based forced exit
if self.Position > 0 and (close >= middle or self._hold_bars >= max_hold):
self.SellMarket()
self._cooldown = cd
self._hold_bars = 0
return
if self.Position < 0 and (close <= middle or self._hold_bars >= max_hold):
self.BuyMarket()
self._cooldown = cd
self._hold_bars = 0
return
# Entry logic
if self.Position == 0 and close < lower:
self.BuyMarket()
self._cooldown = cd
elif self.Position == 0 and close > upper:
self.SellMarket()
self._cooldown = cd
def CreateClone(self):
return bollinger_reversion_strategy()