← Back to Home
Technical Indicators Bollinger Bands (BBANDS)

Technical Indicators Bollinger Bands (BBANDS)

Developed by veteran technician John Bollinger, Bollinger Bands are a highly popular and versatile tool used to analyze price and volatility. They consist of a set of three lines drawn in relation to an asset’s price, forming a dynamic channel that expands and contracts with market volatility.

Theory: The construction of Bollinger Bands is straightforward yet powerful:

  1. Middle Band: This is typically an N-period Simple Moving Average (SMA) of the price. While SMA is standard, an Exponential Moving Average (EMA) can also be used. The common period (N) for the Middle Band is 20 days. \text{Middle Band} = \text{N-period SMA of Price}

  2. Upper Band: This band is plotted K standard deviations above the Middle Band. The standard deviation is also calculated over N periods. \text{Upper Band} = \text{Middle Band} + (K \times \text{N-period Standard Deviation of Price})

  3. Lower Band: Correspondingly, this band is plotted K standard deviations below the Middle Band. \text{Lower Band} = \text{Middle Band} - (K \times \text{N-period Standard Deviation of Price})

The parameter ‘K’ (the number of standard deviations) is typically set to 2. A crucial feature of Bollinger Bands is their dynamic nature: * When market volatility increases, the N-period standard deviation rises, causing the bands to widen. * When market volatility decreases, the standard deviation falls, leading the bands to narrow or “squeeze.”

This adaptability makes Bollinger Bands a direct visual measure of current market volatility.

Usage: Bollinger Bands offer a multifaceted approach to market analysis:

TA-Lib Function: The Technical Analysis Library (TA-Lib) provides a convenient function for calculating Bollinger Bands:

talib.BBANDS(close_prices, timeperiod=20, nbdevup=2, nbdevdn=2, matype=0)

Code Example (Calculation & Plot with yfinance Data):

The following Python code demonstrates how to fetch stock data using yfinance, calculate Bollinger Bands, and plot them overlapping the price chart.

import yfinance as yf
import talib
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd

# --- 1. Data Fetching using yfinance ---
ticker_symbol = "AAPL"  # Example: Apple Inc.
data_start_date = "2023-01-01"
data_end_date = "2024-05-01"

try:
    # Complying with user preference for yfinance download
    data = yf.download(ticker_symbol, start=data_start_date, end=data_end_date, auto_adjust=False, progress=False)
    if data.empty:
        raise ValueError("No data downloaded")
    # Complying with user preference for droplevel
    if isinstance(data.columns, pd.MultiIndex) and data.columns.nlevels > 1:
        data.columns = data.columns.droplevel(level=1)
except Exception as e:
    print(f"Error downloading data for {ticker_symbol}: {e}")
    data = pd.DataFrame() # Ensure data is an empty DataFrame on error

if data.empty or 'Close' not in data.columns or data['Close'].isnull().all():
    print(f"Insufficient Close price data found for {ticker_symbol}. Exiting.")
else:
    close_prices = data['Close'].dropna()
    date_index = close_prices.index

    # --- 2. Bollinger Bands (BBANDS) Calculation ---
    time_period_bb = 20    # Standard period for Bollinger Bands
    nbdev_std_bb = 2       # Standard deviations for upper/lower bands

    # BBANDS need a minimum number of data points equal to the timeperiod for calculation.
    # TA-Lib will output NaNs for the initial period.
    if len(close_prices) >= time_period_bb:
        upper_band, middle_band, lower_band = talib.BBANDS(
            close_prices,
            timeperiod=time_period_bb,
            nbdevup=nbdev_std_bb,
            nbdevdn=nbdev_std_bb,
            matype=0  # 0 = SMA for the middle band
        )
        
        print(f"\n--- Bollinger Bands (BBANDS) for {ticker_symbol} ({time_period_bb}-day SMA, {nbdev_std_bb} StdDev) ---")
        # Print last 5 valid values for each band
        last_valid_idx = np.where(~np.isnan(middle_band))[0]
        if len(last_valid_idx) > 0:
            last_idx_to_print = min(5, len(last_valid_idx))
            print(f"Output Upper Band (last {last_idx_to_print} valid): {upper_band[~np.isnan(upper_band)][-last_idx_to_print:].round(2)}")
            print(f"Output Middle Band (last {last_idx_to_print} valid): {middle_band[~np.isnan(middle_band)][-last_idx_to_print:].round(2)}")
            print(f"Output Lower Band (last {last_idx_to_print} valid): {lower_band[~np.isnan(lower_band)][-last_idx_to_print:].round(2)}")
        else:
            print("No valid Bollinger Band values to display.")

        # --- 3. Plotting ---
        plt.figure(figsize=(14, 7))
        plt.plot(date_index, close_prices, label=f'{ticker_symbol} Close Price', color='blue', alpha=0.9, linewidth=1.5)
        plt.plot(date_index, upper_band, label=f'Upper Band ({nbdev_std_bb}σ)', color='red', linestyle='--', alpha=0.7, linewidth=1)
        plt.plot(date_index, middle_band, label=f'Middle Band (SMA {time_period_bb})', color='orange', linestyle='-', alpha=0.7, linewidth=1.2)
        plt.plot(date_index, lower_band, label=f'Lower Band ({nbdev_std_bb}σ)', color='green', linestyle='--', alpha=0.7, linewidth=1)
        
        # Fill between the bands for visual appeal
        plt.fill_between(date_index, upper_band, lower_band, color='grey', alpha=0.15, label='Bollinger Channel')

        plt.title(f'{ticker_symbol} Price with Bollinger Bands')
        plt.xlabel('Date')
        plt.ylabel('Price')
        plt.legend()
        plt.grid(True, linestyle=':', alpha=0.5)
        plt.show()

    else:
        print(f"\nSkipping Bollinger Bands plot for {ticker_symbol}: Insufficient data (need >= {time_period_bb} points).")
        if not close_prices.empty:
             print(f"Available data points after cleaning: {len(close_prices)}.")
Pasted image 20250603230936.png

Explanation of the Code:

  1. Import Libraries: Includes yfinance, talib, numpy, matplotlib.pyplot, and pandas.
  2. Data Fetching:
    • yf.download() fetches historical data. Your preferences for auto_adjust=False and droplevel are applied. Basic error handling for the download is included.
    • close_prices are extracted and any NaN values are dropped.
  3. Bollinger Bands Calculation:
    • time_period_bb (e.g., 20) and nbdev_std_bb (e.g., 2) are set.
    • A check if len(close_prices) >= time_period_bb: ensures enough data for TA-Lib.
    • talib.BBANDS() calculates the upper, middle, and lower bands. matype=0 ensures the middle band is an SMA.
    • The last few valid band values are printed.
  4. Plotting:
    • plt.figure() creates the plot.
    • The closing price is plotted first.
    • The Upper, Middle, and Lower Bollinger Bands are then plotted on the same axes, as they are an overlay study.
    • plt.fill_between() is used to shade the area between the upper and lower bands, visually highlighting the volatility channel.
    • Standard plot elements (title, labels, legend, grid) enhance readability.
    • plt.show() displays the chart.
  5. Insufficient Data Handling: A message is printed if there isn’t enough data for calculation or plotting.

Bollinger Bands provide a dynamic and insightful way to frame price action, helping traders identify periods of high and low volatility, potential overextensions, and breakout opportunities.