Strategie Bollinger Squeeze
Strategie basierend auf Bollinger Bands Squeeze
Tests zeigen eine durchschnittliche jährliche Rendite von etwa 100%. Am besten funktioniert sie auf dem Forex-Markt.
Bollinger Squeeze wartet auf eine enge Bandbreite, die geringe Volatilität anzeigt. Ein Ausbruch außerhalb der Bänder eröffnet einen Trade in diese Richtung, der aussteigt, wenn das Momentum nachlässt oder ein entgegengesetzter Ausbruch erscheint.
Die Squeeze-Bedingung deutet auf eine bevorstehende Volatilitätsexpansion hin. Einmal ausgelöst, reitet der Trade den Ausbruch und verlässt sich auf einen ATR-Stop oder Band-Crossover zum Ausstieg.
Details
- Einstiegskriterien: Signale basierend auf Bollinger.
- Long/Short: Beide Richtungen.
- Ausstiegskriterien: Entgegengesetztes Signal.
- Stops: Nein.
- Standardwerte:
BollingerPeriod= 20BollingerDeviation= 2mSqueezeThreshold= 0.1mCandleType= TimeSpan.FromMinutes(5)
- Filter:
- Kategorie: Trend
- Richtung: Beide
- Indikatoren: Bollinger
- Stops: Nein
- Komplexität: Grundlegend
- Zeitrahmen: Intraday (5m)
- Saisonalität: Nein
- Neural Networks: 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 squeeze.
/// Detects when bands narrow (squeeze) and trades the breakout direction.
/// </summary>
public class BollingerSqueezeStrategy : Strategy
{
private readonly StrategyParam<int> _bollingerPeriod;
private readonly StrategyParam<decimal> _bollingerDeviation;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevBandWidth;
private bool _hasPrevValues;
private int _cooldown;
/// <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>
/// Initializes a new instance of the <see cref="BollingerSqueezeStrategy"/>.
/// </summary>
public BollingerSqueezeStrategy()
{
_bollingerPeriod = Param(nameof(BollingerPeriod), 20)
.SetDisplay("Bollinger Period", "Period for Bollinger Bands", "Indicators")
.SetOptimize(15, 30, 5);
_bollingerDeviation = Param(nameof(BollingerDeviation), 1.8m)
.SetDisplay("Bollinger Deviation", "Standard deviation multiplier", "Indicators");
_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();
_prevBandWidth = default;
_hasPrevValues = default;
_cooldown = default;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var bb = new BollingerBands
{
Length = BollingerPeriod,
Width = BollingerDeviation
};
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(bb, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, bb);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue bbValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var bb = (IBollingerBandsValue)bbValue;
if (bb.UpBand is not decimal upper ||
bb.LowBand is not decimal lower ||
bb.MovingAverage is not decimal middle)
return;
if (middle == 0)
return;
var bandWidth = (upper - lower) / middle;
if (!_hasPrevValues)
{
_hasPrevValues = true;
_prevBandWidth = bandWidth;
return;
}
if (_cooldown > 0)
{
_cooldown--;
_prevBandWidth = bandWidth;
return;
}
var price = candle.ClosePrice;
// Price crosses above upper band = buy (breakout)
if (price > upper && Position <= 0)
{
var volume = Volume + Math.Abs(Position);
BuyMarket(volume);
_cooldown = 10;
}
// Price crosses below lower band = sell (breakout)
else if (price < lower && Position >= 0)
{
var volume = Volume + Math.Abs(Position);
SellMarket(volume);
_cooldown = 10;
}
_prevBandWidth = bandWidth;
}
}
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
from StockSharp.Algo.Indicators import BollingerBands
from StockSharp.Algo.Strategies import Strategy
class bollinger_squeeze_strategy(Strategy):
def __init__(self):
super(bollinger_squeeze_strategy, self).__init__()
self._bollinger_period = self.Param("BollingerPeriod", 20) \
.SetDisplay("Bollinger Period", "Period for Bollinger Bands", "Indicators")
self._bollinger_deviation = self.Param("BollingerDeviation", 1.8) \
.SetDisplay("Bollinger Deviation", "Standard deviation multiplier", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))) \
.SetDisplay("Candle Type", "Type of candles to use", "General")
self._prev_band_width = 0.0
self._has_prev_values = False
self._cooldown = 0
@property
def bollinger_period(self):
return self._bollinger_period.Value
@property
def bollinger_deviation(self):
return self._bollinger_deviation.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(bollinger_squeeze_strategy, self).OnReseted()
self._prev_band_width = 0.0
self._has_prev_values = False
self._cooldown = 0
def OnStarted2(self, time):
super(bollinger_squeeze_strategy, self).OnStarted2(time)
bb = BollingerBands()
bb.Length = self.bollinger_period
bb.Width = self.bollinger_deviation
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(bb, self.OnProcess).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, bb)
self.DrawOwnTrades(area)
def OnProcess(self, candle, bb_value):
if candle.State != CandleStates.Finished:
return
if bb_value.UpBand is None or bb_value.LowBand is None or bb_value.MovingAverage is None:
return
upper = float(bb_value.UpBand)
lower = float(bb_value.LowBand)
middle = float(bb_value.MovingAverage)
if middle == 0:
return
band_width = (upper - lower) / middle
if not self._has_prev_values:
self._has_prev_values = True
self._prev_band_width = band_width
return
if self._cooldown > 0:
self._cooldown -= 1
self._prev_band_width = band_width
return
price = float(candle.ClosePrice)
if price > upper and self.Position <= 0:
self.BuyMarket(self.Volume + abs(self.Position))
self._cooldown = 10
elif price < lower and self.Position >= 0:
self.SellMarket(self.Volume + abs(self.Position))
self._cooldown = 10
self._prev_band_width = band_width
def CreateClone(self):
return bollinger_squeeze_strategy()