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:
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.
Upper Band: This band is plotted K standard
deviations above the Middle Band. The standard deviation is also
calculated over N periods.
Lower Band: Correspondingly, this band is
plotted K standard deviations below the Middle Band.
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)
close_prices: An array or series of closing
prices.timeperiod: The lookback period for the SMA and
standard deviation (default is 20).nbdevup: The number of standard deviations for the
Upper Band (default is 2).nbdevdn: The number of standard deviations for the
Lower Band (default is 2).matype: The type of Moving Average to use for the
middle band. matype=0 (or talib.MA_Type.SMA)
specifies a Simple Moving Average, which is standard.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)}.")Explanation of the Code:
yfinance,
talib, numpy, matplotlib.pyplot,
and pandas.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.time_period_bb (e.g., 20) and nbdev_std_bb
(e.g., 2) are set.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.plt.figure() creates the plot.plt.fill_between() is used to shade the area between
the upper and lower bands, visually highlighting the volatility
channel.plt.show() displays the chart.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.