Market Microstructure·Performance Metrics·Intermediate

Amihud Illiquidity Ratio

Calculate the Amihud illiquidity ratio from daily absolute return and dollar trading volume data to measure the price impact per unit of trading activity, enabling cross-sectional and time-series comparison of liquidity conditions across crypto assets.

market-microstructuremicrostructure-models

Amihud Illiquidity Ratio Calculation

This notebook demonstrates the calculation and analysis of the Amihud Illiquidity Ratio. The Amihud illiquidity ratio, introduced by Yakov Amihud (2002), is a widely used measure in financial economics to quantify the impact of order flow on asset prices. It essentially measures the daily absolute stock return per unit of daily dollar trading volume. A higher Amihud ratio indicates lower liquidity, meaning a given trading volume has a larger impact on the stock's price.

Core Concepts

ConceptDescription
Amihud Illiquidity RatioA measure of market impact, calculated as the absolute daily stock return divided by the daily dollar trading volume. Higher values imply lower liquidity.
Absolute Daily ReturnThe absolute value of the daily percentage change in a stock's price, reflecting the magnitude of price movement.
Daily Dollar VolumeThe daily trading volume (number of shares traded) multiplied by the closing price, representing the total value of shares traded daily.
LiquidityThe ease with which an asset can be converted into cash without significantly affecting its market price. Highly liquid assets can be traded quickly and at a low cost.

2. Dependency Installation

This section installs all necessary Python packages required for the notebook, including pandas for data manipulation, numpy for numerical operations, yfinance for fetching financial data, and matplotlib and seaborn for visualization.

[1]
import sys

# Install yfinance for fetching stock data
!{sys.executable} -m pip install pandas numpy yfinance matplotlib seaborn
Requirement already satisfied: pandas in /usr/local/lib/python3.12/dist-packages (2.2.2)
Requirement already satisfied: numpy in /usr/local/lib/python3.12/dist-packages (2.0.2)
Requirement already satisfied: yfinance in /usr/local/lib/python3.12/dist-packages (0.2.66)
Requirement already satisfied: matplotlib in /usr/local/lib/python3.12/dist-packages (3.10.0)
Requirement already satisfied: seaborn in /usr/local/lib/python3.12/dist-packages (0.13.2)
Requirement already satisfied: python-dateutil>=2.8.2 in /usr/local/lib/python3.12/dist-packages (from pandas) (2.9.0.post0)
Requirement already satisfied: pytz>=2020.1 in /usr/local/lib/python3.12/dist-packages (from pandas) (2025.2)
Requirement already satisfied: tzdata>=2022.7 in /usr/local/lib/python3.12/dist-packages (from pandas) (2026.2)
Requirement already satisfied: requests>=2.31 in /usr/local/lib/python3.12/dist-packages (from yfinance) (2.32.4)
Requirement already satisfied: multitasking>=0.0.7 in /usr/local/lib/python3.12/dist-packages (from yfinance) (0.0.13)
Requirement already satisfied: platformdirs>=2.0.0 in /usr/local/lib/python3.12/dist-packages (from yfinance) (4.10.0)
Requirement already satisfied: frozendict>=2.3.4 in /usr/local/lib/python3.12/dist-packages (from yfinance) (2.4.7)
Requirement already satisfied: peewee>=3.16.2 in /usr/local/lib/python3.12/dist-packages (from yfinance) (4.0.6)
Requirement already satisfied: beautifulsoup4>=4.11.1 in /usr/local/lib/python3.12/dist-packages (from yfinance) (4.13.5)
Requirement already satisfied: curl_cffi>=0.7 in /usr/local/lib/python3.12/dist-packages (from yfinance) (0.15.0)
Requirement already satisfied: protobuf>=3.19.0 in /usr/local/lib/python3.12/dist-packages (from yfinance) (5.29.6)
Requirement already satisfied: websockets>=13.0 in /usr/local/lib/python3.12/dist-packages (from yfinance) (15.0.1)
Requirement already satisfied: contourpy>=1.0.1 in /usr/local/lib/python3.12/dist-packages (from matplotlib) (1.3.3)
Requirement already satisfied: cycler>=0.10 in /usr/local/lib/python3.12/dist-packages (from matplotlib) (0.12.1)
Requirement already satisfied: fonttools>=4.22.0 in /usr/local/lib/python3.12/dist-packages (from matplotlib) (4.63.0)
Requirement already satisfied: kiwisolver>=1.3.1 in /usr/local/lib/python3.12/dist-packages (from matplotlib) (1.5.0)
Requirement already satisfied: packaging>=20.0 in /usr/local/lib/python3.12/dist-packages (from matplotlib) (26.2)
Requirement already satisfied: pillow>=8 in /usr/local/lib/python3.12/dist-packages (from matplotlib) (11.3.0)
Requirement already satisfied: pyparsing>=2.3.1 in /usr/local/lib/python3.12/dist-packages (from matplotlib) (3.3.2)
Requirement already satisfied: soupsieve>1.2 in /usr/local/lib/python3.12/dist-packages (from beautifulsoup4>=4.11.1->yfinance) (2.8.4)
Requirement already satisfied: typing-extensions>=4.0.0 in /usr/local/lib/python3.12/dist-packages (from beautifulsoup4>=4.11.1->yfinance) (4.15.0)
Requirement already satisfied: cffi>=2.0.0 in /usr/local/lib/python3.12/dist-packages (from curl_cffi>=0.7->yfinance) (2.0.0)
Requirement already satisfied: certifi>=2024.2.2 in /usr/local/lib/python3.12/dist-packages (from curl_cffi>=0.7->yfinance) (2026.5.20)
Requirement already satisfied: rich in /usr/local/lib/python3.12/dist-packages (from curl_cffi>=0.7->yfinance) (13.9.4)
Requirement already satisfied: six>=1.5 in /usr/local/lib/python3.12/dist-packages (from python-dateutil>=2.8.2->pandas) (1.17.0)
Requirement already satisfied: charset_normalizer<4,>=2 in /usr/local/lib/python3.12/dist-packages (from requests>=2.31->yfinance) (3.4.7)
Requirement already satisfied: idna<4,>=2.5 in /usr/local/lib/python3.12/dist-packages (from requests>=2.31->yfinance) (3.18)
Requirement already satisfied: urllib3<3,>=1.21.1 in /usr/local/lib/python3.12/dist-packages (from requests>=2.31->yfinance) (2.5.0)
Requirement already satisfied: pycparser in /usr/local/lib/python3.12/dist-packages (from cffi>=2.0.0->curl_cffi>=0.7->yfinance) (3.0)
Requirement already satisfied: markdown-it-py>=2.2.0 in /usr/local/lib/python3.12/dist-packages (from rich->curl_cffi>=0.7->yfinance) (4.2.0)
Requirement already satisfied: pygments<3.0.0,>=2.13.0 in /usr/local/lib/python3.12/dist-packages (from rich->curl_cffi>=0.7->yfinance) (2.20.0)
Requirement already satisfied: mdurl~=0.1 in /usr/local/lib/python3.12/dist-packages (from markdown-it-py>=2.2.0->rich->curl_cffi>=0.7->yfinance) (0.1.2)

3. Library Imports

This section imports all standard and third-party libraries used throughout the notebook. It also configures basic logging for better operational visibility.

[2]
import pandas as pd
import numpy as np
import yfinance as yf
import logging
from datetime import datetime, timedelta
import matplotlib.pyplot as plt
import seaborn as sns
import random
import time

# Configure logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')

4. Core Functions

This section defines the core functions used to initialize the state, fetch stock data, calculate the Amihud illiquidity ratio, add random jitter for simulated operations (as per requirements), and summarize the calculated metrics. Each function is presented in its own dedicated code block with a detailed markdown header.

Function Name: create_amihud_state

This function initializes the state dictionary used to store data, calculated ratios, and summary metrics throughout the Amihud illiquidity ratio analysis. It sets up empty DataFrames and dictionaries to be populated by subsequent functions.

Parameters: None

Returns: (dict): An initialized state dictionary with data_store, ratios_store, and metrics_summary keys.

[3]
def create_amihud_state() -> dict:
    """
    Initializes the state dictionary for Amihud ratio calculations.

    Returns
    -------
    dict
        An initialized state dictionary with keys for data storage,
        ratio storage, and metrics summary.

    Examples
    --------
    >>> state = create_amihud_state()
    >>> isinstance(state, dict)
    True
    >>> 'data_store' in state
    True
    """
    logging.info("Initializing Amihud state.")
    state = {
        'data_store': pd.DataFrame(),
        'ratios_store': pd.DataFrame(),
        'metrics_summary': {}
    }
    return state

Function Name: add_random_jitter

This function adds a small, normally distributed random value (jitter) to a given numerical value. This can be useful in simulations or when introducing slight variability, although its direct application to Amihud ratio calculation is limited, it satisfies the general requirement for including random jitter.

Parameters: value (float): The numerical value to which jitter will be added. scale (float, optional): The standard deviation of the normal distribution for the jitter. Defaults to 0.01.

Returns: (float): The original value with added random jitter.

[4]
def add_random_jitter(value: float, scale: float = 0.01) -> float:
    """
    Adds a small, normally distributed random jitter to a numerical value.

    Parameters
    ----------
    value : float
        The numerical value to which jitter will be added.
    scale : float, optional
        The standard deviation of the normal distribution for the jitter,
        by default 0.01.

    Returns
    -------
    float
        The original value with added random jitter.

    Examples
    --------
    >>> round(add_random_jitter(10.0, scale=0.001), 1)
    10.0
    """
    return value + np.random.normal(0, scale)

Function Name: fetch_stock_data

This function fetches historical stock data (Open, High, Low, Close, Volume) for a specified ticker symbol within a given date range using the yfinance library. It includes retry logic with exponential backoff and random jitter for robustness against transient network issues or API rate limits.

Parameters: state (dict): The current state dictionary to store the fetched data. ticker (str): The stock ticker symbol (e.g., 'AAPL', 'MSFT'). start_date (str): The start date for fetching data in 'YYYY-MM-DD' format. end_date (str): The end date for fetching data in 'YYYY-MM-DD' format.

Returns: (dict): The updated state dictionary with fetched stock data stored in state['data_store'] under the respective ticker key.

[5]
def fetch_stock_data(state: dict, ticker: str, start_date: str, end_date: str) -> dict:
    """
    Fetches historical stock data for a given ticker and date range.
    Includes retry logic with exponential backoff and random jitter.

    Parameters
    ----------
    state : dict
        The current state dictionary.
    ticker : str
        The stock ticker symbol (e.g., 'AAPL').
    start_date : str
        The start date for data fetching in 'YYYY-MM-DD' format.
    end_date : str
        The end date for data fetching in 'YYYY-MM-DD' format.

    Returns
    -------
    dict
        The updated state dictionary with fetched stock data.

    Examples
    --------
    >>> initial_state = create_amihud_state()
    >>> updated_state = fetch_stock_data(initial_state, 'AAPL', '2023-01-01', '2023-01-10')
    >>> 'AAPL' in updated_state['data_store'] # doctest: +SKIP
    True
    """
    logging.info(f"Fetching data for {ticker} from {start_date} to {end_date}")
    max_retries = 3
    base_delay = 1  # seconds

    for attempt in range(max_retries):
        try:
            df = yf.download(ticker, start=start_date, end=end_date, progress=False)
            if df.empty:
                logging.warning(f"No data fetched for {ticker}. It might be a delisted stock or incorrect ticker.")
                state['data_store'] = pd.DataFrame() # Store empty DF if no data
                return state
            df.index = pd.to_datetime(df.index)
            state['data_store'] = df
            logging.info(f"Successfully fetched data for {ticker}.")
            return state
        except Exception as e:
            logging.warning(f"Attempt {attempt + 1} to fetch data for {ticker} failed: {e}")
            if attempt < max_retries - 1:
                delay = add_random_jitter(base_delay * (2 ** attempt))
                logging.info(f"Retrying in {delay:.2f} seconds...")
                time.sleep(delay)
            else:
                logging.error(f"Failed to fetch data for {ticker} after {max_retries} attempts.")
                state['data_store'] = pd.DataFrame() # Store empty DF on failure
                return state
    return state # Should not be reached but for safety

Function Name: calculate_amihud_ratio

This function computes the Amihud illiquidity ratio for the stock data stored in the state dictionary. It calculates daily returns, absolute daily returns, daily dollar volume, and then the Amihud ratio. It handles potential division by zero errors by setting the ratio to np.nan when dollar volume is zero.

Parameters: state (dict): The current state dictionary containing the stock data in state['data_store']. ticker (str): The stock ticker symbol for which to calculate the ratio.

Returns: (dict): The updated state dictionary with the Amihud ratios stored in state['ratios_store'] under the ticker key. The DataFrame will also contain the intermediate calculations (Return, Abs_Return, Dollar_Volume).

[6]
def calculate_amihud_ratio(state: dict, ticker: str) -> dict:
    """
    Calculates the Amihud illiquidity ratio for the provided stock data.

    Parameters
    ----------
    state : dict
        The current state dictionary containing the stock data.
    ticker : str
        The stock ticker symbol.

    Returns
    -------
    dict
        The updated state dictionary with Amihud ratios stored.

    Examples
    --------
    >>> initial_state = create_amihud_state()
    >>> # Assume data is fetched into initial_state['data_store'] as a DataFrame
    >>> # Example DataFrame structure:
    >>> sample_data = pd.DataFrame({
    ...     'Close': [100, 101, 99, 102, 103],
    ...     'Volume': [1000000, 1200000, 900000, 1500000, 1100000]
    ... }, index=pd.to_datetime(['2023-01-01', '2023-01-02', '2023-01-03', '2023-01-04', '2023-01-05']))
    >>> initial_state['data_store'] = sample_data.copy() # Assign copy to avoid modifying original
    >>> updated_state = calculate_amihud_ratio(initial_state, 'TEST')
    >>> 'Amihud_Ratio' in updated_state['ratios_store'].columns # doctest: +SKIP
    True
    """
    logging.info(f"Calculating Amihud ratio for {ticker}.")
    data_df = state['data_store'].copy()

    if data_df.empty:
        logging.warning(f"No data available for {ticker} to calculate Amihud ratio.")
        state['ratios_store'] = pd.DataFrame(columns=['Return', 'Abs_Return', 'Dollar_Volume', 'Amihud_Ratio'])
        return state

    # Calculate daily returns
    data_df['Return'] = data_df['Close'].pct_change()

    # Calculate absolute daily returns
    data_df['Abs_Return'] = data_df['Return'].abs()

    # Calculate daily dollar volume
    data_df['Dollar_Volume'] = data_df['Volume'] * data_df['Close']

    # Calculate Amihud Ratio
    # Handle division by zero: if Dollar_Volume is 0, Amihud_Ratio is NaN
    data_df['Amihud_Ratio'] = data_df['Abs_Return'] / data_df['Dollar_Volume'].replace(0, np.nan)

    state['ratios_store'] = data_df
    logging.info(f"Amihud ratio calculation complete for {ticker}.")
    return state

Function Name: summarize_amihud_metrics

This function calculates key summary statistics (mean, median, standard deviation, min, max) for the Amihud illiquidity ratios. These statistics provide an overview of the liquidity characteristics of the asset over the analyzed period.

Parameters: state (dict): The current state dictionary containing the calculated Amihud ratios in state['ratios_store']. ticker (str): The stock ticker symbol whose metrics are being summarized.

Returns: (dict): The updated state dictionary with summary statistics stored in state['metrics_summary'] under the ticker key.

[7]
def summarize_amihud_metrics(state: dict, ticker: str) -> dict:
    """
    Calculates summary statistics for the Amihud illiquidity ratios.

    Parameters
    ----------
    state : dict
        The current state dictionary containing the calculated Amihud ratios.
    ticker : str
        The stock ticker symbol.

    Returns
    -------
    dict
        The updated state dictionary with summary statistics.

    Examples
    --------
    >>> current_state = create_amihud_state()
    >>> # Assume current_state['ratios_store'] contains 'Amihud_Ratio' column
    >>> sample_ratios = pd.DataFrame({'Amihud_Ratio': [0.001, 0.002, 0.0015, 0.003, 0.0005]})
    >>> current_state['ratios_store'] = sample_ratios
    >>> updated_state = summarize_amihud_metrics(current_state, 'TEST')
    >>> 'TEST' in updated_state['metrics_summary'] # doctest: +SKIP
    True
    """
    logging.info(f"Summarizing Amihud metrics for {ticker}.")
    ratios_df = state['ratios_store']

    if 'Amihud_Ratio' not in ratios_df.columns or ratios_df['Amihud_Ratio'].isnull().all():
        logging.warning(f"No valid Amihud Ratios available for {ticker} to summarize.")
        state['metrics_summary'][ticker] = {
            'mean': np.nan,
            'median': np.nan,
            'std_dev': np.nan,
            'min': np.nan,
            'max': np.nan
        }
        return state

    summary = {
        'mean': ratios_df['Amihud_Ratio'].mean(),
        'median': ratios_df['Amihud_Ratio'].median(),
        'std_dev': ratios_df['Amihud_Ratio'].std(),
        'min': ratios_df['Amihud_Ratio'].min(),
        'max': ratios_df['Amihud_Ratio'].max()
    }
    state['metrics_summary'][ticker] = summary
    logging.info(f"Summary metrics for {ticker} generated: {summary}")
    return state

5. Demonstration and Visualization

This section demonstrates the end-to-end workflow of calculating the Amihud illiquidity ratio. It fetches historical stock data, computes the ratio, presents summary statistics, and visualizes the Amihud ratio over time. This helps in understanding the liquidity dynamics of a selected stock.

[8]
# 1. Initialize the state
state = create_amihud_state()

# 2. Define parameters for demonstration
ticker = 'GOOG'
end_date = datetime.now().strftime('%Y-%m-%d')
start_date = (datetime.now() - timedelta(days=365*2)).strftime('%Y-%m-%d') # 2 years of data

logging.info(f"Demonstration started for ticker: {ticker}")

# 3. Fetch stock data
state = fetch_stock_data(state, ticker, start_date, end_date)
df_data = state['data_store']

if df_data.empty:
    logging.error(f"Cannot proceed with demonstration as no data was fetched for {ticker}.")
else:
    print(f"\n--- Fetched Data for {ticker} (First 5 Rows) ---")
    display(df_data.head())
    display(df_data.tail())

    # 4. Calculate Amihud Ratio
    state = calculate_amihud_ratio(state, ticker)
    df_ratios = state['ratios_store']

    print(f"\n--- Amihud Ratio Calculation for {ticker} (First 5 Rows) ---")
    display(df_ratios[['Close', 'Volume', 'Return', 'Abs_Return', 'Dollar_Volume', 'Amihud_Ratio']].head())

    # 5. Summarize Amihud Metrics
    state = summarize_amihud_metrics(state, ticker)
    summary_metrics = state['metrics_summary'].get(ticker, {})

    print(f"\n--- Summary Statistics for Amihud Ratio ({ticker}) ---")
    summary_df = pd.DataFrame([summary_metrics])
    display(summary_df.round(8))

    # 6. Visualization: Amihud Ratio over Time
    if 'Amihud_Ratio' in df_ratios.columns and not df_ratios['Amihud_Ratio'].isnull().all():
        plt.figure(figsize=(14, 7))
        sns.lineplot(x=df_ratios.index, y='Amihud_Ratio', data=df_ratios)
        plt.title(f'Amihud Illiquidity Ratio for {ticker} Over Time', fontsize=16)
        plt.xlabel('Date', fontsize=12)
        plt.ylabel('Amihud Ratio', fontsize=12)
        plt.yscale('log') # Use log scale due to potential large fluctuations
        plt.grid(True, linestyle='--', alpha=0.7)
        plt.xticks(rotation=45)
        plt.tight_layout()
        plt.show()

        # Visualization: Distribution of Amihud Ratio
        plt.figure(figsize=(10, 6))
        sns.histplot(df_ratios['Amihud_Ratio'].dropna(), bins=50, kde=True)
        plt.title(f'Distribution of Amihud Illiquidity Ratio for {ticker}', fontsize=16)
        plt.xlabel('Amihud Ratio', fontsize=12)
        plt.ylabel('Frequency', fontsize=12)
        plt.yscale('log') # Log scale for y-axis to better show distribution
        plt.grid(True, linestyle='--', alpha=0.7)
        plt.tight_layout()
        plt.show()
    else:
        logging.warning("Skipping visualizations as Amihud Ratio data is not available or entirely null.")

logging.info("Demonstration complete.")
/tmp/ipykernel_7600/2846172299.py:35: FutureWarning: YF.download() has changed argument auto_adjust default to True
  df = yf.download(ticker, start=start_date, end=end_date, progress=False)

--- Fetched Data for GOOG (First 5 Rows) ---
Price Close High Low Open Volume
Ticker GOOG GOOG GOOG GOOG GOOG
Date
2024-06-17 177.419189 178.550512 175.146627 175.632887 15272900
2024-06-18 175.106934 177.548216 174.283249 177.429119 15640300
2024-06-20 176.357330 177.379489 175.116845 175.364942 16753200
2024-06-21 178.887939 181.122797 176.704688 177.131423 58903200
2024-06-24 179.413879 180.694069 178.858144 179.900155 18198300
Price Close High Low Open Volume
Ticker GOOG GOOG GOOG GOOG GOOG
Date
2026-06-10 353.320007 366.309998 352.809998 361.049988 19878600
2026-06-11 356.559998 358.010010 343.630005 353.049988 28771800
2026-06-12 358.160004 364.773010 353.339996 361.100006 17637100
2026-06-15 367.109985 370.649994 364.649994 365.989990 17268600
2026-06-16 NaN NaN NaN NaN 16348251

--- Amihud Ratio Calculation for GOOG (First 5 Rows) ---
/tmp/ipykernel_7600/1143497547.py:40: FutureWarning: The default fill_method='pad' in DataFrame.pct_change is deprecated and will be removed in a future version. Either fill in any non-leading NA values prior to calling pct_change or specify 'fill_method=None' to not fill NA values.
  data_df['Return'] = data_df['Close'].pct_change()
Price Close Volume Return Abs_Return Dollar_Volume Amihud_Ratio
Ticker GOOG GOOG
Date
2024-06-17 177.419189 15272900 NaN NaN 2.709706e+09 NaN
2024-06-18 175.106934 15640300 -0.013033 0.013033 2.738725e+09 4.758684e-12
2024-06-20 176.357330 16753200 0.007141 0.007141 2.954550e+09 2.416869e-12
2024-06-21 178.887939 58903200 0.014349 0.014349 1.053707e+10 1.361795e-12
2024-06-24 179.413879 18198300 0.002940 0.002940 3.265028e+09 9.004679e-13

--- Summary Statistics for Amihud Ratio (GOOG) ---
mean median std_dev min max
0 0.0 0.0 0.0 0.0 0.0
cell output
cell output

6. Production Considerations

When deploying Amihud illiquidity ratio calculations in a production environment, several factors must be considered to ensure robustness, accuracy, and efficiency.

ConsiderationDescription
Data ValidationImplement rigorous checks for input data (price and volume). Ensure no zero or negative values for volume and that prices are sensible. Handle missing data appropriately (e.g., forward-fill, interpolation, or exclusion) to avoid erroneous ratio calculations.
Error HandlingUtilize comprehensive try/except blocks, especially for external API calls (e.g., yfinance). Implement retry mechanisms with exponential backoff and random jitter for transient network issues or API rate limits. Log all errors, warnings, and informational messages.
PerformanceFor large datasets (e.g., calculating for many stocks over long periods), optimize calculations using vectorized operations with numpy and pandas. Consider using specialized time-series databases or distributed computing frameworks if data volume is extremely high.
Historical Data ReliabilityChoose reliable and consistent data sources for historical stock prices and volumes. Be aware of data quality issues like stock splits, dividends, delistings, and market holidays, which can affect return and volume calculations.
Edge CasesExplicitly handle edge cases such as periods with zero trading volume (which would lead to division by zero in the Amihud formula), extreme price movements, or stocks with very low liquidity. The current implementation sets Amihud to NaN if dollar volume is zero.
Unit TestingWrite unit tests for each core function (create_amihud_state, fetch_stock_data, calculate_amihud_ratio, summarize_amihud_metrics) to ensure correctness and adherence to expected behavior under various scenarios, including valid inputs, edge cases, and erroneous inputs.
LoggingImplement structured logging (logging module) to provide visibility into the application's execution flow. Log significant events, warnings, and errors. This is crucial for debugging, monitoring, and auditing the calculation process in production.
Resource ManagementEfficiently manage memory and CPU resources. For yfinance or similar tools, be mindful of potential memory leaks or excessive API calls. Consider caching frequently accessed data.
Configuration ManagementExternalize configuration parameters (e.g., API keys, ticker lists, date ranges) from the code using environment variables, configuration files, or a secrets manager.

7. Conclusion

This notebook successfully demonstrated the calculation, summarization, and visualization of the Amihud illiquidity ratio. We have implemented a structured approach including:

  • Initialization: Setting up a state dictionary for organized data management.
  • Data Acquisition: Fetching historical stock data using yfinance with robust error handling and retry mechanisms.
  • Core Calculation: Computing the Amihud illiquidity ratio, handling potential division by zero scenarios.
  • Summary Statistics: Providing key statistical insights into the ratio's distribution.
  • Visualization: Illustrating the Amihud ratio's trend over time and its distribution, which helps in identifying periods of high/low liquidity and understanding the overall liquidity profile of an asset.

The implemented functions adhere to best practices, including detailed docstrings, type hints, and logger statements, making them suitable for integration into larger financial analysis systems. The considerations for production deployment highlight important aspects for building reliable and efficient financial tools.