Liquidity Risk and Other Non-Market Risks › Market Liquidity Risk

Michael BrenndoerferDecember 24, 202513 min read
Quantitative FinanceAll chapters
Part 10 of 15Risk Management and Financial Risk Controls
Chapter 57Liquidity Risk and Other Non-Market Risks › Market Liquidity Risk
Reading section 2 of 14 · Market Liquidity Risk · 13 minSection 2 of 14 · 13 min

Book contents

Section 2 of 14 · 13 min read

Liquidity Risk and Other Non-Market Risks › Market Liquidity RiskOne section · Sections in this chapter2 / 14 ↓
Reading tools Definitions & inline links

Choose your expertise level to adjust how many terms are explained. Beginners see more tooltips, experts see fewer to maintain reading flow. Hover over underlined terms for instant definitions.

Article links

Make inline references clickable

Market liquidity refers to the ability to execute transactions quickly and at prices close to the asset's fundamental value. When liquidity is high, you can buy or sell large positions without significantly moving the market price. When liquidity is low, even modest trades can cause substantial price impact, eroding returns and potentially triggering cascading losses.

To see why market liquidity matters, consider the difference between owning an asset and being able to realize its value. A portfolio statement might show a position worth ten million dollars based on the last traded price, but this figure assumes you can sell at or near that price. In reality, the process of selling turns the abstract concept of "value" into concrete cash, and that step is neither free nor instantaneous. Liquidity measures how smoothly and cheaply this step occurs.

Market Liquidity

The ease with which an asset can be bought or sold in the market without causing a significant movement in its price. High liquidity means tight bid-ask spreads, deep order books, and minimal price impact from trades.

The Bid-Ask Spread

The most immediately observable measure of liquidity is the bid-ask spread: the difference between the highest price buyers are willing to pay (bid) and the lowest price sellers are willing to accept (ask). This spread represents a direct transaction cost: to enter and immediately exit a position, you would lose the spread.

The intuition behind why the bid-ask spread exists is straightforward. Market makers and other liquidity providers face inventory risk when they accommodate traders. If you want to sell immediately, a market maker must buy from you and hold the inventory until another buyer arrives. During that holding period, the market maker bears the risk that prices will move against them. The spread compensates market makers for this risk, for the cost of maintaining their operations, and for the informational disadvantage they face when trading against potentially better-informed counterparties.

From a practical standpoint, the spread is an implicit trading cost. Every time you enter a position, you pay half the spread (buying at the ask when the "true" price is the midpoint). When you exit, you pay the other half (selling at the bid). For active traders executing many transactions, these costs compound materially. For long-term investors, the spread is a one-time friction that matters less as the holding period lengthens.

In[2]:
Code
# Sample order book data for a liquid stock
liquid_stock = {
    "bid_prices": [99.98, 99.97, 99.96, 99.95, 99.94],
    "bid_sizes": [1000, 2500, 1800, 3200, 2100],
    "ask_prices": [100.00, 100.01, 100.02, 100.03, 100.04],
    "ask_sizes": [800, 1500, 2200, 1900, 2800],
}

# Sample order book for an illiquid small-cap stock
illiquid_stock = {
    "bid_prices": [24.50, 24.40, 24.25, 24.00, 23.75],
    "bid_sizes": [100, 200, 150, 300, 100],
    "ask_prices": [25.00, 25.25, 25.50, 25.75, 26.00],
    "ask_sizes": [50, 100, 150, 75, 200],
}


def calculate_spread_metrics(order_book, mid_price=None):
    """Calculate various spread metrics from order book data."""
    best_bid = order_book["bid_prices"][0]
    best_ask = order_book["ask_prices"][0]

    absolute_spread = best_ask - best_bid
    mid = (best_bid + best_ask) / 2 if mid_price is None else mid_price
    relative_spread = absolute_spread / mid * 100  # in percent

    return {
        "best_bid": best_bid,
        "best_ask": best_ask,
        "mid_price": mid,
        "absolute_spread": absolute_spread,
        "relative_spread_pct": relative_spread,
    }


liquid_metrics = calculate_spread_metrics(liquid_stock)
illiquid_metrics = calculate_spread_metrics(illiquid_stock)
Out[3]:
Console
Liquid Stock (Large-Cap):
  Best Bid: $99.98
  Best Ask: $100.00
  Spread: $0.02 (0.020%)

Illiquid Stock (Small-Cap):
  Best Bid: $24.50
  Best Ask: $25.00
  Spread: $0.50 (2.02%)
Out[4]:
Visualization
Horizontal bar chart of bid and ask levels for a liquid large-cap stock showing tight spreads and deep order book depth.
Horizontal bar chart showing the order book for a liquid, large-cap stock. The market displays tight price clustering with substantial volume at each price level, indicating high liquidity and low transaction costs for small to medium trades.
Horizontal bar chart of bid and ask levels for an illiquid small-cap stock showing wide spreads and shallow order book depth.
Horizontal bar chart showing the order book for an illiquid, small-cap stock. The market exhibits wide price gaps between bids and asks and significantly smaller order sizes at each level, which leads to higher execution costs and greater price impact.

The liquid stock has a spread of just 2 cents (0.02%), while the illiquid stock shows a spread of 50 cents (2%). For a $1 million position, entering and exiting the liquid stock costs approximately $200 in spread costs, while the same round trip in the illiquid stock costs $20,000, a hundred-fold difference that can dramatically affect trading strategy profitability.

This hundred-fold difference in transaction costs can determine whether a strategy is viable. A strategy that generates 50 basis points of alpha per trade might be highly profitable in liquid markets but utterly unprofitable in illiquid ones, where the spread alone consumes or exceeds the expected return. This is why quantitative trading strategies often focus exclusively on the most liquid instruments, and why institutional investors demand significant expected returns before venturing into less liquid asset classes.

Market Depth and Price Impact

The bid-ask spread captures only the cost of small trades. For larger orders, we must consider market depth: how much volume exists at each price level. Executing a large order "walks through the book," consuming liquidity at progressively worse prices.

The concept of market depth extends the intuition of the spread to larger transactions. Imagine a limit order book as a series of shelves, each holding a certain quantity of shares available at a particular price. The best bid shelf holds shares that buyers are willing to purchase at the highest price. The next shelf holds buyers at a slightly lower price, and so on. When you want to sell a large quantity, you may need to empty the first shelf and potentially many more, each at progressively less favorable prices.

This phenomenon creates what economists call "price impact": the tendency of trades to move prices against you. A large sell order exhausts buyers at high prices and must accept lower prices from buyers further down the book. The resulting average execution price will be worse than the initial quote, and the market price after the trade may remain depressed as the order reveals selling pressure to other market participants.

Understanding market depth requires thinking about both visible and hidden liquidity. The limit order book shows standing orders, but there may also be "iceberg" orders that reveal only a fraction of their true size, algorithmic traders who dynamically provide liquidity in response to market conditions, and potential buyers who would enter the market if prices became attractive. This hidden liquidity means that market depth is partially observable, adding uncertainty to execution cost estimates.

In[5]:
Code
def calculate_execution_cost(order_book, trade_size, side="buy"):
    """
    Calculate the execution cost and average price for a given order size.

    Parameters:
    -----------
    order_book : dict with bid/ask prices and sizes
    trade_size : number of shares to trade
    side : 'buy' or 'sell'
    """
    if side == "buy":
        prices = order_book["ask_prices"]
        sizes = order_book["ask_sizes"]
    else:
        prices = order_book["bid_prices"]
        sizes = order_book["bid_sizes"]

    remaining = trade_size
    total_cost = 0
    fills = []

    for price, size in zip(prices, sizes):
        if remaining <= 0:
            break
        fill_size = min(remaining, size)
        total_cost += fill_size * price
        fills.append((price, fill_size))
        remaining -= fill_size

    if remaining > 0:
        # Not enough liquidity - would need to wait or move price further
        return None, None, fills, remaining

    avg_price = total_cost / trade_size
    mid_price = (order_book["bid_prices"][0] + order_book["ask_prices"][0]) / 2
    impact = (
        (avg_price - mid_price) / mid_price * 100
        if side == "buy"
        else (mid_price - avg_price) / mid_price * 100
    )

    return avg_price, impact, fills, 0


# Execute various order sizes
order_sizes = [500, 2000, 5000, 10000]
results_liquid = []
results_illiquid = []

for size in order_sizes:
    avg_price, impact, _, unfilled = calculate_execution_cost(
        liquid_stock, size, "buy"
    )
    results_liquid.append(
        {
            "size": size,
            "avg_price": avg_price,
            "impact_pct": impact,
            "unfilled": unfilled,
        }
    )

    avg_price, impact, _, unfilled = calculate_execution_cost(
        illiquid_stock, size, "buy"
    )
    results_illiquid.append(
        {
            "size": size,
            "avg_price": avg_price,
            "impact_pct": impact if impact else None,
            "unfilled": unfilled,
        }
    )
Out[6]:
Console
Price Impact Analysis - Liquid Stock:
--------------------------------------------------
  500 shares: Avg price $100.0000, Impact: 0.010%
  2,000 shares: Avg price $100.0060, Impact: 0.016%
  5,000 shares: Avg price $100.0148, Impact: 0.025%
  10,000 shares: Insufficient liquidity (800 unfilled)

Price Impact Analysis - Illiquid Stock:
--------------------------------------------------
  500 shares: Avg price $25.5625, Impact: 3.28%
  2,000 shares: Insufficient liquidity (1,425 unfilled)
  5,000 shares: Insufficient liquidity (4,425 unfilled)
  10,000 shares: Insufficient liquidity (9,425 unfilled)

This analysis reveals a critical asymmetry. In the liquid stock, we can execute 10,000 shares with modest price impact. In the illiquid stock, we cannot even fill 1,000 shares from the available order book. We would exhaust visible liquidity and either wait for new orders to arrive or signal our demand through repeated attempts, likely pushing prices even higher.

The inability to execute at any price represents an extreme form of liquidity risk. In the illiquid stock example, if you have an urgent need to buy 1,000 shares, you face an impossible situation based solely on visible liquidity. You must either accept that your order cannot be filled immediately, thereby taking on timing risk, or you must signal your demand more aggressively, potentially attracting predatory trading behavior from others who recognize the urgency of your need.

The Square-Root Law of Market Impact

Empirical research on market microstructure has established a remarkably consistent relationship between order size and price impact. The square-root law, observed across diverse markets and time periods, states that the permanent price impact of a trade scales with the square root of its size relative to typical trading volume.

The mathematical formulation of this relationship provides a practical tool for estimating execution costs before placing trades:

Impact=σ⋅QV\text{Impact} = \sigma \cdot \sqrt{\frac{Q}{V}}

where:

  • Impact: estimated price impact of the trade
  • σ\sigma: asset's daily volatility
  • Q: trade quantity
  • V: average daily trading volume

This relationship implies that doubling your order size increases impact by only about 41%, not 100%, which reflects the market's ability to partially absorb larger orders over time.

To understand why the square-root relationship arises, consider the nature of price discovery in markets. Prices move because traders' demands reveal information about asset values. A large order suggests the trader has strong conviction, either because they possess private information or because they urgently need to transact. However, the information content does not scale linearly with order size. A trade of twice the size does not contain twice the information; rather, the incremental information in each additional share diminishes as the trade grows.

The presence of volatility in the formula reflects an important insight: price impact is fundamentally about how much your trade moves the market relative to how much the market moves on its own. In a highly volatile market where prices routinely swing several percent per day, a trade that moves prices by half a percent may be unremarkable. In a calm market, the same absolute price movement would be striking. The volatility term normalizes impact across different market regimes.

The participation rate, defined as your trade quantity divided by the average daily volume, captures how significant your trade is relative to the overall market activity. Trading 1% of daily volume is routine and unlikely to attract attention. Trading 50% of daily volume signals that something unusual is happening, drawing scrutiny from other participants and potentially triggering adverse selection effects.

In[7]:
Code
import numpy as np


def square_root_impact(trade_size, daily_volume, daily_volatility):
    """
    Calculate expected market impact using the square-root law.

    Parameters:
    -----------
    trade_size : number of shares
    daily_volume : average daily trading volume
    daily_volatility : daily volatility (standard deviation of returns)
    """
    participation_rate = trade_size / daily_volume
    impact = daily_volatility * np.sqrt(participation_rate)
    return impact


# Example: trading Apple stock
daily_vol_aapl = 0.015  # 1.5% daily volatility
daily_volume_aapl = 50_000_000  # 50 million shares average volume

# Example: trading a small-cap stock
daily_vol_smallcap = 0.035  # 3.5% daily volatility
daily_volume_smallcap = 200_000  # 200,000 shares average volume

trade_sizes = np.linspace(10_000, 5_000_000, 100)

impact_aapl = [
    square_root_impact(s, daily_volume_aapl, daily_vol_aapl) * 100
    for s in trade_sizes
]
impact_smallcap = [
    square_root_impact(s, daily_volume_smallcap, daily_vol_smallcap) * 100
    for s in trade_sizes
]
Out[8]:
Visualization
Line chart comparing market impact curves for liquid and illiquid stocks showing square-root scaling.
Estimated market impact as a function of trade size for liquid versus illiquid stocks based on the square-root law. While impact grows at a decreasing rate relative to trade size for both assets, the illiquid stock experiences significantly higher percentage costs at every volume level due to its lower daily volume and higher volatility.

For the liquid stock, trading 1 million shares (2% of daily volume) produces an expected impact of about 0.21%. The same 1 million shares in the illiquid stock represents 500% of daily volume and would generate impact exceeding 7%, if such a trade could even be executed without moving the market further.

The practical implication of the square-root law is that optimal trade execution requires patience. Because impact grows with the square root of trade size, splitting a large order into smaller pieces and executing over time typically reduces total impact cost. If you can spread your trading over four days instead of one, the impact per day falls, and the sum of four days of smaller impacts is less than the single-day impact of trading all at once. This insight underlies the extensive literature on optimal execution algorithms that balance urgency against market impact.