← Back to Home
Bollinger Band Squeeze Breakout Trading Strategy with Trailing Stops

Bollinger Band Squeeze Breakout Trading Strategy with Trailing Stops

This article describes a trading strategy implemented in Backtrader that capitalizes on periods of low volatility followed by price breakouts. The strategy uses Bollinger Bands to identify a “squeeze” (low volatility) and enters trades when the price breaks out of the bands, employing trailing stops to manage risk and lock in profits.

Strategy Overview

The Bollinger Band Squeeze Breakout Trading Strategy integrates the following components:

Code Implementation

Below is the complete Backtrader code for the strategy:

import backtrader as bt

class BollingerBandSqueezeStrategy(bt.Strategy):
    """
    A strategy that enters on a breakout after a period of low volatility
    and uses a trailing stop for risk management.
    1. Identify Squeeze: Bollinger Bandwidth is at a multi-period low.
    2. Enter on Breakout: Price closes outside the bands.
    3. Exit: A trailing stop-loss order is placed upon entry.
    """
    params = (
        ('bband_period', 7),
        ('bband_devfactor', 1.0),
        ('squeeze_period', 30),
        ('trail_percent', 0.02),  # Trailing stop loss percentage (e.g., 2%)
    )

    def __init__(self):
        self.order = None
        self.dataclose = self.datas[0].close

        # Add Bollinger Bands indicator
        self.bband = bt.indicators.BollingerBands(
            self.datas[0],
            period=self.p.bband_period,
            devfactor=self.p.bband_devfactor
        )

        # Calculate Bollinger Bandwidth
        bb_bandwidth = (self.bband.lines.top - self.bband.lines.bot) / self.bband.lines.mid
        
        # Find the lowest bandwidth over the squeeze_period
        self.lowest_bb_width = bt.indicators.Lowest(
            bb_bandwidth, period=self.p.squeeze_period
        )

    def notify_order(self, order):
        if order.status in [order.Submitted, order.Accepted]:
            # An order has been submitted/accepted - nothing to do
            return

        # Check if an order has been completed
        # Attention: broker could reject order if not enough cash
        if order.status in [order.Completed]:
            if order.isbuy():
                # --- Trailing Stop for LONG position ---
                # The stop price will be calculated based on the trail_percent
                self.sell(exectype=bt.Order.StopTrail, trailpercent=self.p.trail_percent)

            elif order.issell():
                # --- Trailing Stop for SHORT position ---
                self.buy(exectype=bt.Order.StopTrail, trailpercent=self.p.trail_percent)

        self.order = None

    def next(self):
        # Check for pending orders and sufficient data
        if self.order or len(self) < self.p.squeeze_period:
            return

        # Check if a squeeze is happening by comparing the current bandwidth to its historic low
        is_squeeze = self.lowest_bb_width[-1] == ((self.bband.top[-1] - self.bband.bot[-1]) / self.bband.mid[-1])

        # Only enter if not already in a position
        if not self.position:
            if is_squeeze:
                # Breakout to the upside
                if self.dataclose[0] > self.bband.top[0]:
                    self.order = self.buy()
                # Breakout to the downside
                elif self.dataclose[0] < self.bband.bot[0]:
                    self.order = self.sell()

Strategy Explanation

1. BollingerBandSqueezeStrategy

The strategy identifies low-volatility periods and trades breakouts with risk management:

Key Features

Pasted image 20250716175856.png
Pasted image 20250716175908.png

Potential Improvements

This strategy is designed for markets with periodic low-volatility periods followed by strong breakouts, such as stocks, forex, or cryptocurrencies, and can be backtested to evaluate its effectiveness across various timeframes and assets.