Chapter 22 — Market Microstructure

"The order book is the market. Everything else is derived from it."


Learning objectives: After completing this chapter you will be able to:

  • Describe price-time priority and the mechanics of order matching in an electronic limit order book
  • Explain the difference between Kyle's linear impact model and the empirical square-root law
  • Derive the bid-ask spread decomposition into adverse selection, inventory, and processing components using the Glosten-Milgrom model
  • Understand the intraday U-shape pattern in volume and volatility and its practical implications
  • Implement VWAP, TWAP, and implementation-shortfall benchmarks in OCaml

Modern financial markets are electronic matching engines processing millions of events per second. The surface of a market — a single quoted bid and ask price — conceals a layered order book: hundreds or thousands of resting limit orders waiting for execution at various price levels above and below the current mid-price. When a market order arrives, it is matched against the best available limit order on the opposite side, consuming liquidity at that price. If the order is large enough to exhaust the best level, it continues into the next level, and so on — a process called walking the book that generates immediate price impact for large trades.

Understanding this mechanism is essential for any quantitative practitioner. Execution cost is not just the bid-ask spread — it is the full implementation shortfall between the decision price (the mid-price when the decision to trade is made) and the final average execution price, which includes spread, market impact, timing risk, and opportunity cost. For a large asset manager trading in size, these costs can easily exceed $100 million per year; for a high-frequency firm, they determine whether a strategy is profitable at all.

This chapter builds an order book simulator, implements market impact models (the linear Kyle lambda and the empirical square-root model), studies the economics of market making under adverse selection, and implements standard execution benchmarks (VWAP, TWAP, implementation shortfall). These concepts feed directly into Chapter 23's execution algorithms.


22.1 Order Book Fundamentals

A limit order book (LOB) is a record of all outstanding limit orders sorted by price-time priority. On the bid side, orders are arranged from the highest price down; on the ask side, from the lowest price up. The best bid and best ask (together forming the inside quote or touch) are the most aggressive resting prices on each side. The spread between them is the instantaneous cost of immediacy.

Why does anyone provide liquidity by posting limit orders? Market makers quote both sides of the spread to earn the spread on a round-trip: they buy at the bid and sell at the ask, ideally ending the day flat. Their revenue source is the order processing spread; their cost is the risk of being picked off by informed traders who know more about the asset's true value than the market maker does. This adverse selection cost is one of the central themes of microstructure theory, developed fully in Section 22.3.

Two key quantities characterize any order book at a given moment:

  • Level 1 (top of book): best bid, best ask, inside spread, and quantities at the touch
  • Level 2 (depth of book): aggregated quantities at each price level, revealing the liquidity available at various distances from mid-price

Order book snapshot (5-level depth, large-cap equity):

           BID SIDE                        ASK SIDE
  Price    │  Qty (shares)       Price    │  Qty (shares)
 ──────────┼──────────────      ──────────┼──────────────
  100.02   │    500  ◄─── Best bid        │
  100.01   │  1,200              100.03   │    800  ◄─── Best ask
  100.00   │  2,500              100.04   │  1,500
   99.99   │  3,000              100.05   │  2,200
   99.98   │  4,500              100.06   │  3,000
   99.97   │  6,000              100.07   │  4,000
           │                              │
                ↑                              ↑
          deep bids                     deep asks
       (supporting price)           (capping upside)

  Mid-price:  (100.02 + 100.03) / 2 = 100.025
  Inside spread:  100.03 - 100.02 = 1 cent = 1 bp

  Market buy for 900 shares:
    fills 800 @ 100.03  (exhausts best ask level)
    fills 100 @ 100.04  ("walks the book")
    VWAP = (800×100.03 + 100×100.04) / 900 = 100.031
    Impact = 100.031 - 100.025 = 0.6 bp

Deep, liquid books with tight spreads are characteristic of large-cap blue chip stocks and major FX pairs. Thin, wide-spread books characterize small-cap equities, emerging-market bonds, and exotic derivatives. The topology of the book determines execution costs for all participants.

module Order_book = struct

  type side = Bid | Ask

  type order = {
    id        : int;
    side      : side;
    price     : float;
    qty       : float;
    timestamp : int64;   (* nanoseconds since epoch *)
  }

  (** Price-time priority order book *)
  module PriceMap = Map.Make(struct
    type t = float * int64
    let compare (p1, t1) (p2, t2) =
      (* Bids: highest price first, then earliest time *)
      let c = compare p2 p1 in
      if c <> 0 then c else Int64.compare t1 t2
  end)

  type t = {
    bids : order PriceMap.t;
    asks : order PriceMap.t;
    last_trade : float option;
  }

  let empty = { bids = PriceMap.empty; asks = PriceMap.empty; last_trade = None }

  let best_bid book =
    if PriceMap.is_empty book.bids then None
    else Some (fst (PriceMap.min_binding book.bids))

  let best_ask book =
    if PriceMap.is_empty book.asks then None
    else Some (fst (PriceMap.min_binding book.asks))

  let spread book =
    match best_bid book, best_ask book with
    | Some (b, _), Some (a, _) -> Some (a -. b)
    | _ -> None

  let mid_price book =
    match best_bid book, best_ask book with
    | Some (b, _), Some (a, _) -> Some ((a +. b) /. 2.0)
    | _ -> None

  (** Level-2 market data: aggregated quantities at each price level *)
  let depth ~book ~side ~levels =
    let m = match side with Bid -> book.bids | Ask -> book.asks in
    let bindings = PriceMap.bindings m in
    List.filteri (fun i _ -> i < levels) bindings
    |> List.map (fun ((price, _), order) -> price, order.qty)

end

22.2 Market Impact

When a large order executes, it moves the price against the trader. This is the single most important cost in institutional trading, and understanding it requires both a theoretical model and empirical calibration.

Kyle's Linear Model

Kyle (1985) considers a single-period auction with three types of participant: an informed trader who knows the asset's terminal value $V \sim \mathcal{N}(\bar{v}, \sigma_v^2)$; noise traders who submit random aggregate order flow $u \sim \mathcal{N}(0, \sigma_u^2)$ for liquidity reasons; and a market maker who observes only the total order flow $y = x + u$ (informed plus noise) and sets a price equal to $\mathbb{E}[V \mid y]$.

In equilibrium the informed trader submits $x = \beta(V - \bar{v})$ for some coefficient $\beta$, and the market maker's pricing rule is linear: $p = \bar{v} + \lambda y$. Substituting and matching coefficients yields the famous Kyle lambda:

$$\lambda = \frac{\sigma_v}{2 \sigma_u}$$

This single number tells you how many dollars the price moves per unit of order flow. A stock with high fundamental uncertainty ($\sigma_v$ large) or thin noise-trader activity ($\sigma_u$ small) will have a large $\lambda$ — meaning informed traders face stiff price impact, which limits how aggressively they can exploit their information. The bid-ask spread in this model equals $2\lambda \sigma_u$, so spread and impact are intimately linked.

Kyle lambda is estimated empirically by regressing signed price changes on net order flow using the Hasbrouck (1991) VAR or a simple OLS on tick data:

$$\Delta p_t = \lambda \cdot Q_t + \epsilon_t$$

where $Q_t = +1$ for a buyer-initiated trade and $-1$ for a seller-initiated trade. Thinly traded mid-cap stocks typically have $\lambda \approx 0.01$ to $0.05$ (one to five cents per share per 100 shares), while large-cap liquid names can be below $0.001$.

The Square-Root Law

In practice the most robust empirical regularity is not the linear Kyle model but the square-root impact law:

$$\Delta p \approx \sigma \cdot \gamma \cdot \sqrt{\frac{Q}{V_{\text{daily}}}}$$

where $\sigma$ is daily volatility, $Q$ is the trade size, $V_{\text{daily}}$ is the average daily volume, and $\gamma \approx 0.3$ to $0.5$ is a market-specific constant. The square-root shape arises because the order book is not uniformly populated: volume near the touch is dense but thins out rapidly away from mid-price, so each additional share consumed costs progressively more. This concavity of book depth produces the square-root relationship between order size and total price movement.

The implication for trading desks is direct: if you need to buy $Q = 0.1 \times V_{\text{daily}}$ (10% of daily volume), your expected impact is roughly $\sigma \cdot 0.4 \cdot \sqrt{0.1} \approx 13%$ of daily volatility. For a stock with 1% daily vol, that is a 13 bps cost on top of spread and fees. Doubling the order size to 20% of ADV does not double the cost — it increases it by only $\sqrt{2} \approx 41%$. This is the core intuition behind breaking large orders into smaller child orders: the total impact of 10 child orders each of size $Q/10$ is $10 \cdot \gamma\sqrt{Q/10} = \sqrt{10} \cdot \gamma\sqrt{Q}$, roughly three times cheaper than one large trade.

$$\Delta p = \lambda Q, \quad \lambda = \frac{\sigma_v}{2\sigma_u}$$

The Almgren-Chriss (2000) framework combines temporary and permanent impact to find the optimal trajectory that minimises expected cost plus variance of execution. Temporary impact affects only the current trade's price; permanent impact shifts the mid-price for all subsequent trades in the trajectory.

module Market_impact = struct

  (** Kyle lambda: price impact per unit net order flow.
      sigma_v: std dev of fundamental value; sigma_u: noise order flow std dev *)
  let kyle_lambda ~sigma_v ~sigma_u = sigma_v /. (2.0 *. sigma_u)

  (** Square root impact model.
      eta usually ~0.3–0.5; returns cost as fraction of price *)
  let price_impact ~vol_daily ~adv ~order_qty ?(eta = 0.4) () =
    vol_daily *. eta *. sqrt (order_qty /. adv)

  (** Permanent vs temporary impact (Almgren-Chriss) *)
  type impact_params = {
    gamma : float;   (* permanent impact coefficient *)
    eta   : float;   (* temporary impact coefficient *)
    sigma : float;   (* asset volatility *)
    adv   : float;   (* average daily volume *)
  }

  let temporary_impact p rate =
    p.eta *. p.sigma *. (rate /. p.adv) ** 0.6   (* empirical power *)

  let permanent_impact p rate =
    p.gamma *. p.sigma *. (rate /. p.adv) ** 0.5

  (** Implementation shortfall cost for an execution trajectory.
      trajectory.(i): shares to trade in interval i; dt: length of each interval. *)
  let implementation_shortfall ~params ~trajectory ~dt =
    let n = Array.length trajectory in
    let total_cost = ref 0.0 in
    for i = 0 to n - 1 do
      let qty   = trajectory.(i) in
      let rate  = qty /. dt in
      let temp  = temporary_impact params rate in
      let perm  = permanent_impact  params rate in
      total_cost := !total_cost +. qty *. (temp +. 0.5 *. perm)
    done;
    !total_cost

end

22.3 Bid-Ask Spread Components

The bid-ask spread is not a random number or a market convention — it is the solution to a zero-profit condition for a competitive market maker. Glosten and Milgrom (1985) provide the canonical decomposition.

A market maker cannot distinguish informed from uninformed order flow. When an order arrives, there is some probability $\alpha$ that the trader is informed (knows $V$, the true asset value) and probability $1 - \alpha$ that they are noise (trading for liquidity reasons). An informed buyer arrives only when $V > a$ (the ask), so by trading against a buyer the market maker updates upward her estimate of $V$. The ask must therefore satisfy:

$$a = \mathbb{E}[V \mid \text{buyer}] = \bar{v} + \frac{\alpha \cdot \mathbb{E}[V - \bar{v} \mid V > a]}{1}$$

Solving this for a symmetric distribution yields the Glosten-Milgrom spread:

$$\text{Spread} = 2\alpha \cdot |V - \bar{v}|$$

or more precisely, the half-spread equals the market maker's expected loss per trade to informed traders. If $\alpha = 5%$ of the order flow is informed and the average informed trader has an edge of 50 cents, the half-spread must be at least $0.05 \times 0.50 = 2.5$ cents.

This decomposition identifies three components:

ComponentCauseMagnitude
Adverse selectionInformed traders have foreknowledge; market maker loses to them40–60% of spread for liquid stocks
Inventory riskMarket maker accumulates a directional position and faces mark-to-market losses20–40% of spread
Order processingOperational and infrastructure costs5–20% of spread

For highly liquid large-cap stocks, adverse selection dominates. For illiquid small-caps where few institutions trade, inventory risk becomes more significant because the market maker cannot quickly offset an unwanted position.

The practical implication is that spread is endogenous to information. Around earnings announcements, FDA decisions, or M&A rumours, the informed fraction $\alpha$ rises sharply and spreads widen. This is why it is typically more expensive to execute on the day before an event than on a quiet Tuesday in January.

module Spread_model = struct

  (** Glosten-Milgrom half-spread: alpha = fraction of informed traders,
      edge = average informed trader's information advantage (price units) *)
  let glosten_milgrom_half_spread ~alpha ~edge =
    alpha *. edge

  type spread_decomposition = {
    gross_spread      : float;   (** half-spread captured by market maker *)
    adverse_selection : float;   (** post-trade price drift (loss to informed) *)
    realized_spread   : float;   (** net market-maker profit per trade *)
  }

  (** Decompose realized spread into adverse selection and inventory components.
      trade_price: execution price; mid_before: mid at time of trade;
      mid_after: mid 5 minutes after trade (post-trade benchmark). *)
  let realized_spread ~trade_price ~mid_before ~mid_after ~side =
    let gross = match side with
      | `Buy  -> trade_price -. mid_before   (* buyer pays above mid *)
      | `Sell -> mid_before -. trade_price   (* seller receives below mid *)
    in
    let price_impact = match side with
      | `Buy  -> mid_after -. mid_before    (* mid moves up after aggressive buy *)
      | `Sell -> mid_before -. mid_after    (* mid moves down after aggressive sell *)
    in
    { gross_spread      = gross;
      adverse_selection = price_impact;
      realized_spread   = gross -. price_impact }

end

22.4 Empirical Microstructure Facts

Before building or calibrating any execution model, a practitioner should internalize the following empirically stable stylized facts:

The intraday U-shape. Trading volume, bid-ask spreads, and return volatility all follow a U-shaped pattern through the day: high at the open, declining through mid-morning, reaching a minimum around noon, then rising steadily into the close. The open is expensive because overnight news is absorbed and positional uncertainty is high; the close is expensive because institutions and benchmarks settle at the closing price, generating correlated order flow. The cheapest time to trade is generally 10:30–11:30 am or 1:00–2:30 pm.

Spread scales with market cap. As a rough guide for US equities:

Market cap tierTypical spread (bps)Typical daily vol (bps)
Mega-cap ($500B+)0.5–280–150
Large-cap ($10–500B)2–8100–200
Mid-cap ($2–10B)8–30150–300
Small-cap ($300M–2B)30–100200–400
Micro-cap (<$300M)100–500300–600

Impact scales with participation rate. The closer you are to 100% of the daily volume, the more you move the market. The square-root law $\Delta p \approx \sigma\sqrt{Q/V}$ implies that trading $Q = V$ (the entire daily volume) costs roughly $\sigma$ in impact — one full day's volatility. Most institutional desks target 5–20% of ADV as a sensible range.

Order flow is autocorrelated. Large institutional orders arrive as long series of child orders (an I&II from BARRA study found typical institutional order completion takes 3–5 days). This means order book imbalance is informative: a sequence of aggressive buys predicts further buying. High-frequency market makers use short-term order flow predictors to adjust their quotes in real time.


22.5 VWAP and TWAP

module Benchmarks = struct

  (** Volume-Weighted Average Price *)
  let vwap ~prices ~volumes =
    let pv = Array.fold_left2 (fun a p v -> a +. p *. v) 0.0 prices volumes in
    let v  = Array.fold_left (+.) 0.0 volumes in
    pv /. v

  (** Time-Weighted Average Price *)
  let twap ~prices ~times =
    let n = Array.length prices in
    let total_time = times.(n - 1) -. times.(0) in
    let sum = ref 0.0 in
    for i = 0 to n - 2 do
      sum := !sum +. prices.(i) *. (times.(i + 1) -. times.(i))
    done;
    !sum /. total_time

  (** Arrival price: mid at time of order submission *)
  let arrival_price ~book = Order_book.mid_price book

  (** Implementation shortfall between arrival and executed VWAP *)
  let impl_shortfall ~side ~arrival ~executed_vwap ~shares =
    let slippage = match side with
      | `Buy  -> executed_vwap -. arrival   (* we pay more *)
      | `Sell -> arrival -. executed_vwap   (* we receive less *)
    in
    slippage *. shares

end

22.6 Chapter Summary

Market microstructure is the physics of financial markets: the study of how prices are formed, how orders are matched, and what determines the cost of trading. This chapter provides the conceptual and computational foundation for the execution algorithms in Chapter 23 and the trading strategies in Chapter 24.

The order book is a priority queue of resting limit orders, sorted by price (best first) and then by time (first-in, first-out within a price level). The bid-ask spread at any moment reflects the cost of immediacy — the premium a market taker pays for the certainty of immediate execution. Market makers stand on both sides of the spread, profiting from the difference but exposed to two risks: inventory risk (the position accumulated from imbalanced order flow may move adversely) and adverse selection risk (informed traders tend to trade when prices are about to move against the market maker).

Kyle's 1985 model of strategic trading in a single-period auction derives that price impact is linear in order flow, with the Kyle lambda $\lambda = \sigma_v / (2\sigma_u)$ measuring the price change per unit of net order flow. A large $\lambda$ indicates a market where informed trading is relatively frequent, making it expensive for all participants to execute. In practice, the empirical square-root law $\Delta p \approx \sigma\sqrt{Q/V}$ describes actual market impact more accurately than the linear model, and is the foundation for Almgren-Chriss optimal execution.

The Glosten-Milgrom model (1985) derives the bid-ask spread as a break-even condition for competitive market makers facing adverse selection. The spread decomposes into three parts: the adverse selection component (the expected loss to informed traders), the inventory component (compensation for directional risk), and the order processing component (fixed operational costs). For large-cap equities, adverse selection typically accounts for 40–60% of the spread.

The intraday U-shape in volume, volatility, and spread is one of the most robust stylized facts in finance: costs are highest at the open and close and lowest in mid-morning and early afternoon. The implementation shortfall framework by Perold (1988) provides the correct accounting of total execution cost: the difference between the paper portfolio value (valued at the arrival mid-price) and the actual portfolio value (valued at the execution prices). This decomposes into spread cost, market impact, timing risk, and fees — and serves as the objective function that execution algorithms in Chapter 23 seek to minimize.


In Practice — Market Making at a High-Frequency Firm

A high-frequency market maker quotes bid and ask prices in hundreds of stocks simultaneously, earning the spread on each round-trip. The firm's edge is speed and information: it processes market data faster than competitors, updates its quotes before being picked off by stale prices, and uses statistical models to predict short-term price direction.

Adverse selection management is the central challenge. When a large informed trader hits the market maker's quote, the market maker is on the wrong side of a price move. The market maker's response is to widen the spread (to earn more per trade) and reduce size (to limit exposure). The Kyle lambda — estimated in real time from the autocorrelation of order flow — tells the market maker how much information is in the current order flow. High lambda → widen spreads; low lambda → tighten spreads.

Inventory management. A market maker who has accumulated a large long position is exposed to adverse price moves. The standard approach is to skew quotes: lower the bid slightly (to discourage more buys) and lower the ask slightly (to attract sells that reduce inventory). The Avellaneda-Stoikov model (2008) provides the optimal quote skew as a function of inventory, risk aversion, and remaining time.

Latency arms race. Co-location (placing servers in the same data centre as the exchange) reduces round-trip latency from milliseconds to microseconds. FPGA-based market data processing can reduce it further to nanoseconds. The economic value of speed is captured by the latency arbitrage opportunity: a fast firm can update its quotes before a slow firm, effectively trading against the slow firm's stale quotes. Regulatory debate continues about whether this constitutes a market efficiency improvement or a tax on slower participants.


Exercises

22.1 [Basic] Build an in-memory limit order book with add/cancel/match operations. Process 1 000 random orders and measure the evolution of the spread and mid-price over time. Verify that your matching engine correctly enforces price-time priority.

22.2 [Basic] Generate an order flow simulation (Poisson arrivals, random bid/ask quantities) and measure realized VWAP vs mid-price. Study how spread varies with volume and how quickly the order book recovers after a large market order.

22.3 [Intermediate] Implement Kyle lambda estimation from a time series of trade signs (Lee-Ready algorithm) and price changes using OLS. Apply it to a simulated order flow series and compare the estimated $\lambda$ to the theoretical $\sigma_v / (2\sigma_u)$.

22.4 [Intermediate] Simulate implementation shortfall for a large sell order (10% of ADV) using the square-root impact model with three trajectories: (a) uniform participation over full day; (b) TWAP; (c) front-loaded (50% in first hour). Compare total costs and volatility of outcomes.

22.5 [Advanced] Implement the Glosten-Milgrom spread model as a simulation. At each step, draw a random trader type (informed with probability $\alpha$, uninformed with probability $1-\alpha$). If informed, draw $V$ and have them trade the profitable side; if uninformed, trade randomly. Run the simulation 10 000 steps and measure how the market maker's realized spread compares to the theoretical $2\alpha|V - \bar{v}|$.

22.6 [Advanced] Implement a simple market-making strategy: post quotes at $\text{mid} \pm s/2$ for some chosen spread $s$, and cancel and re-quote whenever your inventory exceeds $\pm I_{\max}$ shares. Simulate it against 1 000 random incoming orders drawn from a Poisson process with drift. At what spread does the strategy break even given adverse selection rate $\alpha = 5%$?


Next: Chapter 23 — Execution Algorithms