Market Microstructure Basics

Learn bid-ask spreads, slippage, order types, and how real-world execution costs impact strategy profitability

25 min read
Intermediate

Introduction

Market microstructure is the study of how orders become trades and how trades become prices. Understanding microstructure is essential for building realistic trading systems - the difference between a backtest showing 20% returns and live trading losing money often comes down to microstructure effects.

In this lesson, you'll learn:

  • The mechanics of bid-ask spreads and how they cost you money
  • Different order types and their execution characteristics
  • What slippage is and how to model it
  • How market makers provide liquidity
  • Why execution quality matters for strategy profitability

The Bid-Ask Spread: The Market's Tax

Every time you trade, you pay the bid-ask spread: the difference between what you can buy for (ask) and what you can sell for (bid). This is the fundamental cost of trading.

Anatomy of the Spread

Real Example: SPY ETF Order Book
Side
Price
Quantity
Implication
Ask$450.021,200You pay $450.02 to buy
Ask$450.033,500Next available ask
Bid$450.001,500You receive $450.00 if selling
Bid$449.992,000Next bid down

Spread = Ask - Bid = 450.02βˆ’450.02 - 450.00 = $0.02 (2 cents)

The Round-Trip Cost

If you buy at 450.02andimmediatelyβˆ—βˆ—sellβˆ—βˆ—at450.02 and immediately **sell** at 450.00, you lose $0.02 per share, or:

Round-tripΒ cost=SpreadMid-price=0.02450.01=0.0044%\text{Round-trip cost} = \frac{\text{Spread}}{\text{Mid-price}} = \frac{0.02}{450.01} = 0.0044\%

While 0.0044% seems tiny, if you trade 50 times per year, you pay 0.22% per year just from spreads. For high-frequency strategies trading 1,000 times per year, this becomes 4.4% annual drag.

Critical: The bid-ask spread is a guaranteed cost you pay on every trade. Many backtests ignore this cost and show profitable strategies that are actually unprofitable after accounting for spreads.

Spread Varies by Liquidity

Highly liquid assets (SPY, AAPL) have tight spreads (1-2 cents). Illiquid stocks or crypto altcoins have wide spreads (0.1-1.0% or more).

Typical Spreads by Asset Class
Asset
Example
Typical Spread
Round-Trip Cost
Mega-cap stockAAPL, MSFT1-2 cents0.001-0.002%
Large ETFSPY, QQQ1-2 cents0.001-0.002%
Mid-cap stockRegional banks3-10 cents0.01-0.05%
Small-cap stockMicrocaps5-50 cents0.1-2.0%
BTC/USDCoinbase$1-100.002-0.02%
AltcoinLow-volume crypto0.1-1.0%0.2-2.0%

Order Types: Market, Limit, and Stop Orders

Different order types have different execution characteristics. Choosing the right order type is crucial for controlling costs.

1. Market Orders

Definition: Buy or sell immediately at the best available price.

Pros:

  • Guaranteed execution (almost always fills)
  • Immediate execution

Cons:

  • You pay the ask (buying) or receive the bid (selling) - you always cross the spread
  • Subject to slippage on large orders
  • Can get terrible fills during high volatility

Use when: You need immediate execution and don't mind paying the spread (e.g., entering a breakout trade before it runs away).

2. Limit Orders

Definition: Buy or sell at a specified price or better. The order rests in the order book until filled.

Example: Place a limit buy order at 450.00whenthecurrentaskis450.00 when the current ask is 450.02. Your order sits on the bid side waiting for sellers to come down to $450.00.

Pros:

  • Control over execution price
  • Can "make the spread" if filled - buy at bid, sell at ask
  • No slippage

Cons:

  • No guarantee of execution - price may never reach your limit
  • Opportunity cost - stock may run up while you wait for a fill
  • Partial fills possible

Use when: You're not in a hurry and want to minimize costs (e.g., entering a position over several days).

3. Stop-Loss Orders

Definition: Becomes a market order when price reaches a specified "stop" level.

Example: You buy AAPL at $180. Set a stop-loss at $175. If price hits $175, your stop triggers and sends a market order to sell at best available price (might fill at $174.95 due to slippage).

Pros:

  • Automated risk management
  • Limits losses on losing trades

Cons:

  • Executes as market order - subject to slippage
  • Can be triggered by temporary "stop hunts" or volatility spikes
  • Gaps can cause execution far below stop level

Use when: Managing risk on directional positions.

Pro tip: Use stop-limit orders (stop triggers a limit order instead of market order) to cap the worst-case execution price. But beware - if price gaps through your limit, you don't get filled and remain exposed.

Slippage: The Hidden Cost

Slippage is the difference between the expected execution price and the actual execution price. It occurs when:

  1. Your order is large relative to available liquidity at the best price level
  2. Price moves between when you decide to trade and when your order fills
  3. Volatility is high and the spread widens dynamically

How Slippage Happens

python
# Example: Trying to buy 5,000 shares of a stock
# Current order book:
# Ask: $100.00 (1,000 shares)
# Ask: $100.05 (2,000 shares)
# Ask: $100.10 (3,000 shares)

# Your market order for 5,000 shares consumes:
# - 1,000 shares @ $100.00
# - 2,000 shares @ $100.05
# - 2,000 shares @ $100.10

# Average execution price
total_cost = (1000 * 100.00) + (2000 * 100.05) + (2000 * 100.10)
total_shares = 5000
avg_price = total_cost / total_shares

print(f"Average execution: ${avg_price:.2f}")
print(f"Expected: $100.00")
print(f"Slippage: ${avg_price - 100.00:.2f} per share")
print(f"Total slippage cost: ${(avg_price - 100.00) * total_shares:.2f}")

In this example, you expected to buy at 100.00butactuallypaid100.00 but actually paid 100.07 - an extra $350 in slippage costs.

Modeling Slippage in Backtests

A simple slippage model for backtesting:

python
import pandas as pd
import numpy as np

def apply_slippage(prices, order_type, slippage_bps=5):
    """
    Apply slippage to trades.

    Args:
        prices: pd.Series of prices
        order_type: 'buy' or 'sell'
        slippage_bps: slippage in basis points (default 5 bps = 0.05%)

    Returns:
        Actual execution prices after slippage
    """
    slippage_factor = slippage_bps / 10000  # Convert bps to decimal

    if order_type == 'buy':
        # Buys execute at higher price (pay slippage)
        execution_prices = prices * (1 + slippage_factor)
    else:  # sell
        # Sells execute at lower price (pay slippage)
        execution_prices = prices * (1 - slippage_factor)

    return execution_prices

# Example usage
buy_signal_prices = pd.Series([100.00, 150.00, 200.00])
actual_buy_prices = apply_slippage(buy_signal_prices, 'buy', slippage_bps=5)

print("Signal prices:", buy_signal_prices.values)
print("Actual execution:", actual_buy_prices.values)
print("Slippage cost per share:", (actual_buy_prices - buy_signal_prices).values)

Typical slippage assumptions:

  • Liquid stocks/ETFs: 2-5 basis points (0.02-0.05%)
  • Mid-cap stocks: 5-10 basis points
  • Small-cap/illiquid: 10-50 basis points
  • High volatility periods: 2-5x normal slippage

Golden Rule: Always include slippage in backtests. A conservative estimate is 5 basis points (0.05%) per trade for liquid stocks. For less liquid assets, use 10-20 bps.

Market Makers and Liquidity Provision

Market makers are firms that continuously quote both bid and ask prices, providing liquidity to the market. They make money from the bid-ask spread and lose money when price moves against their inventory.

How Market Making Works

  1. Quote both sides: MM quotes bid 100.00(willingtobuy)andask100.00 (willing to buy) and ask 100.02 (willing to sell)
  2. Earn the spread: If a buyer takes the ask and a seller takes the bid, MM earns $0.02 per share
  3. Manage inventory: MM must balance inventory (can't accumulate unlimited long or short positions)
  4. Provide liquidity: MM absorbs temporary supply/demand imbalances

Why This Matters for Traders

  • Tight spreads exist because of market makers - without them, spreads would be much wider
  • Spreads widen during volatility because market makers increase quotes to compensate for higher risk
  • Large orders get worse fills because they exhaust MM inventory and force MMs to adjust quotes

Payment for Order Flow is when brokerages (like Robinhood) sell retail orders to market makers instead of routing them to exchanges. Market makers pay for this order flow because retail orders are considered "uninformed" (not from sophisticated institutions), making them profitable to trade against.

Controversy: While retail traders often get "price improvement" (execution slightly better than NBBO - National Best Bid and Offer), critics argue PFOF creates conflicts of interest.

Practical Implications for Trading Strategies

Understanding microstructure changes how you design and evaluate strategies.

1. Minimum Trade Frequency for Profitability

Given transaction costs (spread + slippage + commissions), there's a minimum edge required per trade.

Example calculation:

  • Round-trip spread cost: 0.01%
  • Round-trip slippage: 0.10% (0.05% each way)
  • Commission: $0 (assuming zero-commission broker)
  • Total round-trip cost: 0.11%

To break even, your average trade must make at least 0.11% before costs. If your strategy has a 50% win rate, winners must average 0.22% profit (to cover the 50% losers).

2. Higher Frequency = Higher Costs

A strategy that trades 100 times per year pays 11% per year in transaction costs (100 round-trips Γ— 0.11%). That strategy needs to generate 11% gross return just to break even.

This is why high-frequency trading requires:

  • Tight spreads (mega-cap stocks, futures, forex)
  • Sophisticated execution algorithms
  • Co-location (servers physically next to exchanges)

3. Position Sizing and Market Impact

Large positions relative to average daily volume (ADV) cause market impact - your order moves the price against you.

Rule of thumb: Keep individual orders below 1% of ADV to minimize market impact.

python
# Example: Checking if position size is reasonable
import yfinance as yf
import pandas as pd

def check_market_impact(ticker, shares_to_buy):
    """Check if order size might cause market impact."""
    stock = yf.Ticker(ticker)

    # Get average daily volume (last 30 days)
    hist = stock.history(period='1mo')
    avg_daily_volume = hist['Volume'].mean()

    # Calculate what % of ADV your order represents
    pct_of_adv = (shares_to_buy / avg_daily_volume) * 100

    print(f"Ticker: {ticker}")
    print(f"Your order: {shares_to_buy:,} shares")
    print(f"Average daily volume: {avg_daily_volume:,.0f} shares")
    print(f"Your order as % of ADV: {pct_of_adv:.2f}%")

    if pct_of_adv < 1:
        print("βœ… Low market impact expected")
    elif pct_of_adv < 5:
        print("⚠️  Moderate market impact - consider splitting order")
    else:
        print("❌ High market impact - definitely split order over multiple days")

# Example: Trying to buy 10,000 shares of AAPL
check_market_impact('AAPL', 10000)

For AAPL (highly liquid), 10,000 shares is tiny. But for a small-cap stock with 50,000 ADV, a 10,000-share order is 20% of ADV - expect significant market impact.

Summary

Key Takeaways

  1. Bid-ask spread is the fundamental cost of trading - you always pay it on market orders
  2. Market orders guarantee execution but cross the spread; limit orders offer price control but no fill guarantee
  3. Slippage occurs when large orders consume multiple price levels - model it as 5-10 bps for realistic backtests
  4. Market makers provide liquidity and earn the spread; they widen spreads during volatility
  5. Transaction costs add up quickly - a strategy trading 100x/year with 0.11% round-trip costs loses 11% to friction alone
  6. Market impact matters for large orders - keep orders below 1% of average daily volume

Next Steps

Now that you understand how markets operate at the microstructure level, we'll move to financial time series foundations to learn the statistical properties of price data: stationarity, autocorrelation, and volatility clustering. This knowledge is essential for building indicators and strategies.