The Glosten-Milgrom model (Glosten and Milgrom, 1985) explains why: the spread is compensation for adverse selection. A market maker who posts firm quotes trades against a population that includes agents who know more than she does. Every trade is informative, every quote must price in the possibility of trading with a better-informed counterparty, and the spread emerges endogenously from Bayesian updating rather than being imposed as a friction.
This article develops the model from first principles, derives the quoting rule and its key properties step by step, and then walks through a concrete implementation: the market_maker module of my QuantSim Terminal, a Rust/Axum simulation platform with an HTMX front end. The implementation generalizes the textbook model with an informed-trader accuracy parameter, which turns out to have a clean closed-form effect on the spread.
1. The economic problem
Consider a dealer quoting a single risky asset. The asset has an unknown fundamental value that will eventually be revealed. Orders arrive one at a time, each for one unit, and the dealer must post a bid and an ask before seeing the order. Two trader types arrive:
Informed traders know, or have a signal about, the fundamental value. They buy when the asset is underpriced at the ask and sell when it is overpriced at the bid. Trading against them is a guaranteed loss in expectation.
Uninformed (noise) traders trade for exogenous reasons: liquidity needs, hedging, portfolio rebalancing. Their order direction carries no information. Trading against them is profitable whenever the spread is positive.
If the dealer quoted a single price equal to her unconditional expectation of value, informed traders would pick her off systematically. The defense is asymmetric quoting: the ask must be the expected value conditional on the next order being a buy, and the bid the expected value conditional on the next order being a sell. Because a buy is more likely when the value is high, the conditional expectations differ, and the gap between them is the spread.
2. Model setup
The version implemented in QuantSim Terminal uses the standard binary-value structure with one extension.
The fundamental value is a random variable
It is drawn once at the start and fixed thereafter. The dealer's prior is .
At each discrete time :
With probability , the arriving trader is informed; with probability , she is a noise trader.
An informed trader observes a signal that matches the true state with probability and trades in the direction of her signal: buy if the signal says , sell if it says . Setting recovers the classic perfectly informed Glosten-Milgrom trader.
A noise trader buys or sells with probability each.
The dealer, knowing and but not the trader's type or signal, posts a bid and an ask before the order arrives, executes at the quoted price, and updates her belief.
The accuracy parameter is the main departure from the textbook treatment. It interpolates continuously between a market with perfectly informed insiders and a market where “informed” flow is only weakly correlated with fundamentals, and it lets the simulation explore how signal quality, separately from informed-arrival intensity, shapes spreads and price discovery.
3. Deriving the quotes
Let
be the dealer's belief entering round , where is the history of observed order directions.
3.1 Order-direction likelihoods
Condition on the state. If , a buy occurs when either an informed trader receives a correct signal, or a noise trader flips heads:
If , a buy requires either an informed trader with a wrong signal or a noise buy:
By symmetry,
Note that for each state the two likelihoods sum to one, and that buys are more likely under than under precisely when : information content requires both informed presence, , and signal quality, .
3.2 Posterior beliefs
Bayes' rule gives the posterior after observing a buy:
And after a sell:
A buy raises the belief, a sell lowers it, and the magnitude of the revision grows with .
3.3 Regret-free quotes
Under competition, or equivalently a zero-expected-profit condition per trade, the dealer quotes conditional expectations:
These quotes are regret free: after the trade prints, the transaction price already equals the dealer's updated expectation of value, so she would not want to revise the executed price ex post. The spread is
strictly positive whenever , , and .
3.4 A closed form at the uninformative prior
At , the algebra collapses nicely. The denominator of each posterior equals
so
and the spread becomes
With , this reduces to the classic result : the half-spread is exactly the probability of informed arrival times the informational stake. The extension shows that halving signal accuracy from perfect, , to coin-flip, , shrinks the spread linearly to zero, because informed flow with no signal quality is indistinguishable from noise. Adverse selection is priced through the product , so the dealer cannot separately identify “many weakly informed traders” from “few strongly informed traders” through the spread alone.
4. Properties worth internalizing
Beliefs are a martingale and prices are semi-strong efficient
By the law of iterated expectations,
The dealer cannot predict her own belief revision. Transaction prices equal conditional expectations of value given public information, the order history, so the price process is a martingale with respect to the public filtration. No trading strategy based only on past prices and trades earns excess returns against this dealer.
Price discovery: beliefs converge to the truth
Each trade is a noisy but informative signal about . Because is a bounded martingale, it converges almost surely, and with the only absorbing points consistent with the trade likelihoods are the truth:
As beliefs converge, and the spread collapses. Information gets impounded into prices purely through anonymous order flow; nobody announces anything.
The dealer breaks even; noise traders pay informed traders
Each quote earns zero expected profit conditional on the order direction, so the dealer's aggregate expected profit is zero. Ex post, she loses to informed traders, who buy below value and sell above it in expectation, and wins the spread against noise traders. The spread is exactly the transfer mechanism: noise traders subsidize the dealer's expected losses to insiders. This is the cleanest formalization of the adage that in trading you should know who the sucker at the table is.
Price impact is permanent
In Glosten-Milgrom, a trade moves the midquote because it moves beliefs, and the belief revision never mean-reverts due to the martingale property. Contrast this with inventory-based models—Ho-Stoll and Avellaneda-Stoikov, also implemented in QuantSim Terminal—where impact is transitory: quotes are skewed to shed inventory and revert once the position normalizes. Real markets exhibit both components, and decomposing them is a central task of empirical microstructure.
Tradeoffs of the modeling choices
The binary value space buys tractability: posteriors are scalars and quotes are convex combinations, at the cost of a degenerate spread once beliefs converge. Unit trade sizes eliminate the strategic dimension of order sizing; Kyle (1985) takes the opposite route with a strategic insider choosing quantity, trading anonymity of direction for anonymity via batching. Sequential arrival with exogenous ignores that informed traders would rationally time their arrival and that noise traders facing wide spreads might exit, a point Glosten and Milgrom themselves raise: severe enough adverse selection can shut the market entirely, with no spread wide enough to let the dealer break even. None of these simplifications is innocuous, but each is what makes the model solvable in three lines of Bayes' rule.
5. Implementation in QuantSim Terminal
QuantSim Terminal is a simulation platform I built in Rust on Axum and Tokio, with server-rendered Askama templates, HTMX for partial page updates, and Chart.js for rendering. The Glosten-Milgrom engine lives in src/market_maker.rs, with the HTTP handler in src/handlers.rs and the interface at /glosten-milgrom.
5.1 Parameters and validation
The simulation is parameterized by a plain struct validated with the validator crate:
#[derive(Debug, Clone, Copy, Serialize, Deserialize, Validate)]
pub struct Params {
#[validate(range(min = 0.0, max = 10000.0))]
pub v_h: f64,
#[validate(range(min = 0.0, max = 10000.0))]
pub v_l: f64,
#[validate(range(min = 0.0, max = 1.0))]
pub prior_h: f64,
#[validate(range(min = 0.0, max = 1.0))]
pub alpha: f64,
#[validate(range(min = 0.5, max = 1.0))]
pub accuracy_informed: f64,
#[validate(range(min = 1, max = 10000))]
pub steps: usize,
pub seed: u64,
pub true_state_is_high: bool,
}Two details matter here. First, accuracy_informed is constrained to : an accuracy below one half would make “informed” traders systematically wrong, which is economically equivalent to relabeling their signals, so the constraint removes a redundant region of the parameter space. Second, a validate_limits method enforces and caps steps at so a form submission cannot pin the server.
5.2 The Bayesian core
The posterior updates are direct transcriptions of the formulas in Section 3.2:
fn posterior_buy(p: f64, alpha: f64, rho: f64) -> f64 {
let like_h = alpha * rho + (1.0 - alpha) * 0.5;
let like_l = alpha * (1.0 - rho) + (1.0 - alpha) * 0.5;
let numerator = p * like_h;
numerator / (numerator + (1.0 - p) * like_l)
}posterior_sell mirrors it with the likelihoods swapped. Quotes are computed from the prior, before the order arrives, which is the economically correct sequencing: the dealer commits to prices for both contingencies, then learns which one occurred.
fn quotes_from_prior(
p: f64,
v_h: f64,
v_l: f64,
alpha: f64,
rho: f64
) -> (f64, f64, f64, f64) {
let p_buy = Self::posterior_buy(p, alpha, rho);
let p_sell = Self::posterior_sell(p, alpha, rho);
let ask = p_buy * v_h + (1.0 - p_buy) * v_l;
let bid = p_sell * v_h + (1.0 - p_sell) * v_l;
(bid, ask, p_sell, p_buy)
}Returning both candidate posteriors alongside the quotes avoids recomputing Bayes' rule after the order direction is realized: the simulation loop just selects the branch that occurred.
5.3 The simulation loop
Each round draws the trader type with a Bernoulli(), then the action. Informed traders trade with the signal, which is correct with probability ; noise traders flip a fair coin:
let informed = self.rng.random_bool(params.alpha);
let action = if informed {
if true_h {
if self.rng.random_bool(params.accuracy_informed)
{ Action::Buy } else { Action::Sell }
} else if self.rng.random_bool(params.accuracy_informed)
{ Action::Sell } else { Action::Buy }
} else if self.rng.random_bool(0.5)
{ Action::Buy } else { Action::Sell };
let (new_p, px) = match action {
Action::Buy => (post_buy, ask),
Action::Sell => (post_sell, bid),
};The RNG is a ChaCha8Rng seeded from a user-supplied u64. Deterministic seeding is not cosmetic: it makes every chart on the site exactly reproducible, lets you hold the order-flow realization fixed while varying or to isolate parameter effects from sampling noise, and makes the module unit-testable. The test suite asserts, among other things, that a buy raises the belief, a sell lowers it, and always holds.
Each round records a full RoundData snapshot: bid, ask, mid, spread, belief, action, trader type, transaction price, per-trade PnL against fundamental value, and price impact measured as the change in midquote. Storing the full panel rather than just the paths keeps every downstream diagnostic a pure function over the rounds.
6. Closing
Glosten-Milgrom is the minimal model in which prices learn. It takes one mechanism, Bayesian updating on order direction, and produces from it a positive spread, permanent price impact, martingale prices, and full price discovery, with adverse selection intensity summarized by the single product . The Rust implementation is short precisely because the theory is: two posterior functions, one quoting rule, one loop. Everything else is instrumentation.
References
Glosten, L. R., and P. R. Milgrom (1985). Bid, ask and transaction prices in a specialist market with heterogeneously informed traders. Journal of Financial Economics, 14(1), 71–100.
Kyle, A. S. (1985). Continuous auctions and insider trading. Econometrica, 53(6), 1315–1335.
Easley, D., N. M. Kiefer, M. O'Hara, and J. B. Paperman (1996). Liquidity, information, and infrequently traded stocks. Journal of Finance, 51(4), 1405–1436.
O'Hara, M. (1995). Market Microstructure Theory. Blackwell.