Reading time: ~8 min
If you’ve spent any time in the market microstructure literature, you’ve probably come across the Avellaneda-Stoikov (A-S) model. Published in 2008, it’s one of those rare papers that gives you a clean, closed-form answer to a genuinely hard problem: where should a market maker post its bid and ask quotes?
I recently built a full simulation of the model — with several extensions drawn from Fushimi, González Rojas & Herman (2018) — and ran it across three volatility regimes to see how well the theory holds up in practice. Here’s the short version of what I found. The full technical article is available on my research page.
The Core Idea
A market maker sits in the order book all day, posting a bid and an ask. Every time both sides fill, it earns the spread. The risk is inventory: if the market moves against your accumulated position before you can unwind it, those spread gains disappear fast.
A-S solves this by introducing the reservation price: instead of quoting symmetrically around the mid-price [math]S_t[/math], the market maker shifts its quotes based on its current inventory [math]q_t[/math]:
where [math]\gamma[/math] is the risk-aversion coefficient, [math]\sigma[/math] is volatility, and [math]T – t[/math] is time remaining. If you’re long (positive [math]q[/math]), your reservation price drops — you quote a lower ask to encourage selling. If you’re short, the opposite happens. It’s inventory management baked directly into the pricing.
The optimal spread around [math]r_t[/math] is:
Two things to notice: the spread is wider when volatility is high (you need more compensation for the risk), and it narrows over time (near market close, you get aggressive to unwind). Both are intuitive.
What I Added
The vanilla A-S model is elegant but unrealistic for a few reasons. I implemented three extensions from Fushimi et al. (2018), plus one of my own:
1. Intraday volume pattern. Real order flow isn’t constant — it’s high at open, low at noon, high again at close (the classic U-shape). Following Cartea, Jaimungal & Penalva (2015), I model fill probability as [math]\alpha(t) \cdot e^{-k\delta}[/math] where [math]\alpha(t)[/math] follows:
2. Three-state order book algorithm. Real market makers don’t just quote continuously — they track whether they have zero, one, or two live orders. Fushimi et al. (2018) formalise this as a state machine: if one side fills and the other doesn’t within a timeout, cancel and requote. I implement this with a 5-second timeout.
3. Dynamic order sizing. When your inventory is large, you should trade smaller on the side that makes it worse. The size model (from Fushimi et al. 2018):
…and symmetrically for the ask when [math]q_t < 0[/math]. This exponentially reduces size in the direction of excess inventory.
4. Volatility-adjusted size cap (my extension). Fushimi et al. fix [math]\varphi^{\max} = 100[/math] for all stocks. In a cross-volatility study, this is a problem — at [math]\sigma = 5[/math], large positions create massive mark-to-market swings. I set:
Without this, the optimal strategy actually loses money on average at high volatility (Sharpe [math]-0.66[/math]). With it, it recovers to [math]+0.91[/math]. That single change is arguably the most impactful thing in the whole paper.
The Experiment
I ran 1,000 Monte Carlo simulations per scenario, each simulating a full 6.5-hour trading day at 5-second resolution ([math]N = 4{,}680[/math] steps). Three volatility regimes:
- Low ([math]\sigma = 0.5[/math]): think stable ETF
- Medium ([math]\sigma = 2.0[/math]): typical large-cap
- High ([math]\sigma = 5.0[/math]): volatile event-driven stock
I compared the extended A-S strategy against a naive fixed-spread baseline that always quotes at the time-independent component of the spread, with no inventory adjustment.
Results
| Scenario | Strategy | Avg PnL | Std PnL | Sharpe |
|---|---|---|---|---|
| Low vol ([math]\sigma=0.5[/math]) | Optimal | 34.40 | 15.61 | 2.20 |
| Baseline | 35.15 | 16.49 | 2.13 | |
| Medium vol ([math]\sigma=2.0[/math]) | Optimal | 7.68 | 4.99 | 1.54 |
| Baseline | 8.77 | 8.53 | 1.03 | |
| High vol ([math]\sigma=5.0[/math]) | Optimal | 2.54 | 2.81 | 0.91 |
| Baseline | 4.30 | 8.45 | 0.51 |
A few things stand out:
At low volatility, it barely matters. Both strategies are nearly identical. When price moves are tiny, inventory risk is negligible, and dynamic quoting adds almost nothing.
At medium volatility, variance control kicks in. The baseline actually earns more on average ($8.77 vs $7.68) — but at nearly twice the standard deviation. The Sharpe improvement is 50%: 1.54 vs 1.03.
At high volatility, the gap is enormous. The baseline blows up its P&L variance with undiscriminating quoting — it keeps filling at the fixed spread even as inventory accumulates dangerously. The optimal strategy widens its spread (it quotes 3–4× wider at [math]\sigma = 5[/math]) and trades less often (3.8 vs 6.8 trades/day). The Sharpe improvement is 78%: 0.91 vs 0.51.
The key insight: A-S doesn’t maximise expected P&L — the baseline often earns more per trade. It maximises risk-adjusted returns, trading a small reduction in mean for a large reduction in variance. That’s the whole point of the CARA utility framework.
What This Tells Us About Market Making
The model reveals a hierarchy of what matters:
- Volatility-adjusted sizing is the most critical piece. Without it, the strategy fails at high vol.
- Dynamic spread adjustment (the reservation price) matters most precisely when markets are most dangerous — high volatility, trending conditions.
- The U-shaped intensity and Gamma fills add realism but don’t change the qualitative ordering.
This maps directly to what professional market makers do in practice: quote tighter on quiet large-caps, wider on volatile small-caps, and always smaller when you’re sitting on a large position.
Want the Full Details?
The complete technical write-up covers all the mathematics, the three-state algorithm pseudocode, the full parameter table, and eight figures including P&L paths, inventory distributions, and conditional P&L analysis. You can find it on my research page.
The Python simulation code is available in the repository linked.
References: Avellaneda & Stoikov (2008), Quantitative Finance 8(3). — Fushimi, González Rojas & Herman (2018), Stanford Technical Report. — Cartea, Jaimungal & Penalva (2015), Algorithmic and High-Frequency Trading, Cambridge UP.