Leveraging Z-Scores for Stock Analysis: A Data-Driven Guide Using Python

Identifying Overbought and Oversold Signals in ASML.AS with Rolling Z-Scores

In partnership with

`

Savvy Investors Know Where to Get Their News—Do You?

Here’s the truth: Most financial media focuses on clicks, not clarity. The Daily Upside, created by Wall Street insiders, delivers valuable insights—free. Join 1M+ readers and subscribe today!

Exciting News: Paid Subscriptions Have Launched! 🚀

On September 1, we officially rolled out our new paid subscription plans at GuruFinance Insights, offering you the chance to take your investing journey to the next level! Whether you're just starting or are a seasoned trader, these plans are packed with exclusive trading strategies, in-depth research paper analysis, ad-free content, monthly AMAsessions, coding tutorials for automating trading strategies, and much more.

Our three tailored plans—Starter Investor, Pro Trader, and Elite Investor—provide a range of valuable tools and personalized support to suit different needs and goals. Don’t miss this opportunity to get real-time trade alerts, access to masterclasses, one-on-one strategy consultations, and be part of our private community group. Click here to explore the plans and see how becoming a premium member can elevate your investment strategy!

Check Out Latest Premium Articles

This study juxtaposes the stock price trajectory of ASML.AS with rolling Z-Scores calculated over 30, 60, and 90-day periods. Using clear visual markers, green dots indicate potential buy signals, while red dots signal potential sell opportunities, guided by pre-set Z-Score thresholds.

1. Introduction

In the ever-evolving world of trading, data-driven approaches have revolutionized how traders analyze and make decisions. Whether the goal is to forecast future price movements, analyze trends, or measure a stock’s volatility, modern tools like Python offer immense possibilities.

One such analytical tool is the Z-Score, a statistical metric that gives insight into a stock’s relative positioning compared to its historical norms.

What is a Z-Score?

  • A measure of how far a stock price deviates from its historical average, expressed in terms of standard deviations.

  • Z-Scores help identify moments when a stock may be overbought (Z-Score > threshold) or oversold (Z-Score < -threshold), pointing to potential trading opportunities.

This article explores how Python can be harnessed to compute and interpret Z-Scores, providing traders with actionable insights into stock behavior. With ASML.AS as the focus, you’ll see the step-by-step process of integrating Z-Scores into your stock trading analysis.

Highlighting Normal Distribution Extremes

By spotlighting areas of a standard normal distribution where Z-Scores exceed ±1.5\pm 1.5, we can underscore statistically significant deviations in stock prices. These deviations often point to abnormal price movements that signal potential reversals or opportunities:

  1. Beyond +1.5+1.5: Indicates overvaluation relative to the historical mean, serving as a potential sell signal.

  2. Below −1.5–1.5: Suggests undervaluation, potentially signaling a buy opportunity.

2. Delving into Z-Scores

Z-Scores are a statistical measure that indicates how far a data point deviates from the mean, expressed in terms of standard deviations. For trading, this metric allows the assessment of whether a stock’s current price is within its typical range or an anomaly.

  • Normal Distribution Insight: Picture a bell curve. The majority of stock prices cluster near the mean (the peak of the bell), with fewer values located in the “tails” (beyond ±1.5\pm 1.5).

  • Formula:

Through Z-Scores, traders quantify whether a stock is trading in statistically unusual territory.

3. Equipping Ourselves with Tools

To analyze and visualize Z-Scores, we rely on robust Python libraries:

  • yfinance: Fetch historical stock data.

  • pandas: Perform data manipulation and computations.

  • matplotlib: Generate visual insights.

Code snippet for imports:

import yfinance as yf
import pandas as pd
import matplotlib.pyplot as plt

4. Gathering Stock Data

For our analysis, we focus on ASML.AS. By leveraging the yfinance library, we fetch its historical price data:

# Define ticker symbol
ticker_symbol = "ASML.AS"

# Fetch stock data
ticker_data = yf.Ticker(ticker_symbol)

# Retrieve historical prices
stock_data = ticker_data.history(period='1d', start='2020-1-1', end='2023-12-25')

This data forms the foundation for computing rolling averages, standard deviations, and ultimately Z-Scores, enabling us to identify stock price anomalies.5. Computing the Z-Score

At the heart of this method is the Z-Score calculation, which quantifies how far a stock’s price deviates from its typical behavior over a given historical range. By applying this to multiple rolling windows, we uncover anomalies that span both short-term and long-term trends.

# Calculate the rolling mean for a given period
rolling_mean = close_prices.rolling(window=period).mean()

# Calculate the rolling standard deviation for the same period
rolling_std = close_prices.rolling(window=period).std()

# Compute Z-Scores, measuring deviations from the average
z_scores = (close_prices - rolling_mean) / rolling_std

5. Visualizing Deviations with Buy and Sell Signals

By overlaying rolling Z-Scores on the stock price chart, traders can easily spot patterns of “normal” behavior and outliers. Z-Scores that breach thresholds such as ±1.5 or ±2.0 serve as alerts for potential action. Adjusting the Z-Score threshold can help align the signals with your trading strategy.

  • Above the Threshold: Indicates a potential sell point due to overvaluation.

  • Below the Threshold: Suggests a possible buy signal if the stock is undervalued.

This visualization, combined with threshold signals, provides an intuitive understanding of deviations.

import yfinance as yf
import pandas as pd
import matplotlib.pyplot as plt

# Constants
Z_SCORE_THRESHOLD = 2
WINDOWS = [30, 60, 90]
STOCK_SYMBOL = "ASML.AS"
STARTING_DATE = '2020-01-01'
ENDING_DATE = '2023-12-25'

def retrieve_stock_data(stock_symbol, start_date, end_date):
    """Retrieves historical stock prices for the specified stock symbol and date range."""
    stock_info = yf.Ticker(stock_symbol)
    return stock_info.history(period='1d', start=start_date, end=end_date)

def compute_rolling_z_scores(prices, windows):
    """Computes rolling Z-scores for multiple window lengths."""
    z_scores_map = {}
    for window in windows:
        # Calculate the rolling average for the given window
        rolling_avg = prices.rolling(window=window).mean()
        # Calculate the rolling standard deviation for the given window
        rolling_deviation = prices.rolling(window=window).std()
        # Calculate Z-scores for the given prices
        z_scores_map[window] = (prices - rolling_avg) / rolling_deviation
    return z_scores_map

def visualize_stock_data(prices, z_scores_dict):
    """Visualizes stock prices along with Z-scores."""
    
    # Create a figure with subplots for prices and Z-scores
    fig, (top_plot, bottom_plot) = plt.subplots(2, sharex=True, figsize=(20, 8))
    
    # Plot the stock prices on the first subplot
    top_plot.plot(prices.index, prices, label='Stock Prices')
    
    for window, z_scores in z_scores_dict.items():
        # Plot Z-scores for each window on the second subplot
        bottom_plot.plot(z_scores.index, z_scores, label=f'Z-Scores {window}-Day Window', alpha=0.7)
        
        # Add buy and sell markers on the price plot using the first window
        if window == WINDOWS[0]:
            buy_points = z_scores < -Z_SCORE_THRESHOLD
            sell_points = z_scores > Z_SCORE_THRESHOLD
            top_plot.plot(prices[buy_points].index, prices[buy_points], 'o', color='green', label='Buy Signal')
            top_plot.plot(prices[sell_points].index, prices[sell_points], 'o', color='red', label='Sell Signal')
    
    # Label the first plot and add its legend
    top_plot.set_ylabel('Stock Prices')
    top_plot.legend(loc="upper left")
    top_plot.grid(True)
    
    # Add threshold lines to the Z-scores plot
    bottom_plot.axhline(-Z_SCORE_THRESHOLD, color='red', linestyle='--')
    bottom_plot.axhline(Z_SCORE_THRESHOLD, color='red', linestyle='--')
    bottom_plot.set_ylabel('Z-Scores')
    bottom_plot.legend(loc="upper left")
    bottom_plot.grid(True)
    
    # Add a title for the overall figure
    plt.suptitle(f'{STOCK_SYMBOL} Price Trends and Z-Scores ({Z_SCORE_THRESHOLD} Threshold)')
    plt.show()

# Retrieve stock price data for the given symbol and dates
stock_data = retrieve_stock_data(STOCK_SYMBOL, STARTING_DATE, ENDING_DATE)
# Calculate Z-scores using the given windows
rolling_z_scores = compute_rolling_z_scores(stock_data['Close'], WINDOWS)
# Visualize the stock prices and Z-scores
visualize_stock_data(stock_data['Close'], rolling_z_scores)

Tracking the trajectory of ASML.AS stock prices alongside rolling Z-Scores over 30, 60, and 90-day intervals. Green markers signal potential buying opportunities, while red markers indicate possible selling points, determined by specific Z-Score thresholds.

6. Conclusion & Final Reflections

Although Z-Scores provide a quantitative framework for analyzing stocks, it is crucial to remember that trading is influenced by numerous variables. Z-Scores should be used as a supplementary tool within your strategy, always paired with thorough market analysis.