Scriptone Scriptone

[Stock Analysis with Python] Weekly and Monthly Charts with Bollinger Bands to Understand Price Volatility

blog-image

Overview

In the previous article, we explained how to detect moving averages and golden cross/dead cross patterns. This time, we’ll explore fetching weekly and monthly data for longer-term trend analysis and using Bollinger Bands to statistically understand stock price movement ranges.

Motivation

In stock investing, it’s important to confirm long-term trends not only on daily charts but also on weekly and monthly charts. By taking a larger perspective, we can avoid being swayed by short-term price movements and better understand a company’s overall direction. Bollinger Bands, which combine moving averages with standard deviation, allow us to statistically understand price movement ranges. When prices approach the upper or lower bands, we can use them as reference points for trading decisions.

Like the previous article, we’ll continue our analysis using modern Python libraries: Polars, Plotly, marimo, kand, and yfinance-pl.

Libraries Used

The libraries are as follows:

LibraryRelated LibraryDescription
polarspandasA library for high-speed data frame operations
plotlymatplotlibA visualization library that allows users to interact with graphs
marimojupyterA notebook that runs in .py format and allows interactive code execution
kandta-lib-pythonA Rust-based technical analysis library that can be used in Python and Web through PYO3 and Wasm
yfinance-plyfinanceA Python library wrapping yfinance-rs that allows handling Yahoo Finance data with Polars

Notebook and Code

The HTML version of the marimo notebook is available here. Here’s also a link to the Python code on GitHub.

Explanation

Fetching Weekly and Monthly Data

With yfinance-pl, you can fetch timeframes other than daily data by specifying the interval parameter in the history() method. Use 1d for daily, 1wk for weekly, and 1mo for monthly data.

import yfinance_pl as yf

ticker = yf.Ticker("8381.T")

# Fetch daily data (default)
hist_daily = ticker.history(period="1y", interval="1d")

# Fetch weekly data
hist_weekly = ticker.history(period="2y", interval="1wk")

# Fetch monthly data
hist_monthly = ticker.history(period="5y", interval="1mo")

By using weekly or monthly data, you can eliminate short-term noise and identify longer-term trends. For example, viewing moving averages on weekly charts allows you to understand trends spanning several months to half a year.

Calculating Bollinger Bands

Bollinger Bands display a center line (moving average) with bands above and below it calculated using standard deviation. Typically, ±2σ (two standard deviations) is used. Statistically, about 95% of prices are expected to fall within these bands.

Using the kand library, you can calculate Bollinger Bands easily.

import kand as ka
import polars as pl
import yfinance_pl as yf

ticker = yf.Ticker("8381.T")
hist = ticker.history(period="1y")

# Convert closing price data to NumPy array
close = hist["close.amount"].to_numpy().astype("float64")

# Calculate Bollinger Bands (period 20, standard deviation 2)
bbands_result = ka.bbands(close, period=20, std_dev=2.0)

# Add results to DataFrame
hist_with_bbands = hist.with_columns(
    bb_upper=pl.Series(bbands_result.upper),  # Upper band (+2σ)
    bb_middle=pl.Series(bbands_result.middle),  # Center line (moving average)
    bb_lower=pl.Series(bbands_result.lower),  # Lower band (-2σ)
)

The bbands() function accepts period (moving average period) and std_dev (standard deviation multiplier) parameters. Typically, a 20-day period with 2x standard deviation is used, but you can adjust these based on the stock and timeframe.

Understanding Bollinger Bands

Bollinger Bands can be interpreted in the following ways:

1. Band Width (Volatility)

The width of the bands indicates price volatility.

  • Wide bands: Large price movements, strong trend, or unstable market
  • Narrow bands (Squeeze): Small price movements, with a potential for a large move afterward

2. Band Walk

When price moves along the upper or lower band, it’s called a “band walk.”

  • Walking along the upper band: Strong uptrend
  • Walking along the lower band: Strong downtrend

3. Band Deviation

  • Price exceeds the upper band: Potential overbought condition. Watch for reversal signals
  • Price falls below the lower band: Potential oversold condition. Watch for rebound signals

However, during strong trends, prices can remain outside the bands for extended periods, so it’s important to use other indicators in combination with Bollinger Bands.

Visualizing the Chart

Using Plotly, you can display candlesticks and Bollinger Bands simultaneously.

import plotly.graph_objects as go

# Data preparation
df_plot = hist_with_bbands.with_columns(
    [
        pl.col("open.amount").cast(pl.Float64),
        pl.col("high.amount").cast(pl.Float64),
        pl.col("low.amount").cast(pl.Float64),
        pl.col("close.amount").cast(pl.Float64),
    ]
)
dates = df_plot["date"].to_list()

# Create chart
fig = go.Figure()

# Candlestick chart
fig.add_trace(go.Candlestick(
    x=dates,
    open=df_plot["open.amount"],
    high=df_plot["high.amount"],
    low=df_plot["low.amount"],
    close=df_plot["close.amount"],
    increasing_line_color="red",
    decreasing_line_color="green",
    name="Stock Price",
))

# Upper Bollinger Band
fig.add_trace(go.Scatter(
    x=dates,
    y=df_plot["bb_upper"],
    mode="lines",
    name="BB Upper (+2σ)",
    line=dict(color="rgba(250, 128, 114, 0.5)", width=1),
))

# Middle Bollinger Band
fig.add_trace(go.Scatter(
    x=dates,
    y=df_plot["bb_middle"],
    mode="lines",
    name="BB Middle (SMA20)",
    line=dict(color="blue", width=1.5),
))

# Lower Bollinger Band
fig.add_trace(go.Scatter(
    x=dates,
    y=df_plot["bb_lower"],
    mode="lines",
    name="BB Lower (-2σ)",
    line=dict(color="rgba(250, 128, 114, 0.5)", width=1),
    fill="tonexty",  # Fill between middle and lower band
    fillcolor="rgba(250, 128, 114, 0.1)",
))

fig.update_layout(
    title="Stock Price with Bollinger Bands",
    xaxis_title="Date",
    yaxis_title="Price",
    xaxis_rangeslider_visible=False,
)

fig.show()

This code displays candlesticks and three Bollinger Band lines (upper, middle, lower). By using fill="tonexty", we lightly shade the area between the middle and lower lines, making the band range visually clearer.

Summary

We’ve explained how to fetch weekly and monthly data and understand price movement ranges using Bollinger Bands. Weekly and monthly charts let you confirm long-term trends, while Bollinger Bands help you understand price movement ranges statistically.

By combining Bollinger Bands with the moving averages and golden cross/dead cross patterns from the previous article, you can perform more comprehensive analysis. We’ll continue to analyze stocks using modern Python libraries and explore other technical indicators.

Reference Book: 『Pythonで実践する株式投資分析』(Kanemitsu Katafuchi (Author), Yoshihiro Yamada (Editor))

comment

Loading comments...