Note
Go to the end to download the full example code or to run this example in your browser via JupyterLite.
Glosten and Milgrom: a spread from adverse selection alone#
Lawrence Glosten and Paul Milgrom (1985) explained the spread with no inventory and no costs. A competitive dealer trades one unit at a time with traders who are informed with probability \(\alpha\). Since a buy is more likely to come from someone who knows the value is high, the dealer sets the ask to \(E[V \mid \text{buy}]\) and the bid to \(E[V \mid \text{sell}]\), losing to the informed exactly what it gains from the uninformed. Each trade updates the dealer’s belief by Bayes’ rule, so prices are a martingale that converges to the truth.
import matplotlib.pyplot as plt
import numpy as np
from financialkit.market_microstructure import glosten_milgrom_quotes, simulate_glosten_milgrom
from financialkit.market_microstructure.visualizers import plot_glosten_milgrom
Learning from the order flow#
fig, axes = plt.subplots(1, 2, figsize=(10, 3.8), sharey=True)
for ax, value in zip(axes, (110.0, 90.0), strict=True):
res = simulate_glosten_milgrom(80, alpha=0.2, v_low=90.0, v_high=110.0, true_value=value, rng=9)
plot_glosten_milgrom(res, ax=ax)
ax.set_title(f"true value {value:g}, {res.informed.sum()} informed of 80 trades")
fig.tight_layout()

More informed traders, wider spread#
At the start (belief 1/2) the spread grows linearly with the share of informed traders; a dealer facing only informed traders would not trade.

Faster learning with more informed trading#
fig, ax = plt.subplots(figsize=(6, 3.5))
for al in (0.05, 0.2, 0.5):
runs = [simulate_glosten_milgrom(60, al, 90.0, 110.0, rng=seed) for seed in range(200)]
spreads = np.mean([r.ask - r.bid for r in runs], axis=0)
ax.plot(spreads, label=f"$\\alpha$ = {al}")
ax.set_xlabel("trade")
ax.set_ylabel("average spread")
ax.legend()
fig.tight_layout()
plt.show()

Total running time of the script: (0 minutes 0.259 seconds)