So far you’ve been a taker — crossing the spread to get filled. A market maker is the other side: a maker who provides liquidity by resting orders on both sides of the book, and gets paid the spread for the service. It sounds like free money (“just earn the spread forever!”) and it absolutely is not, for one reason that this article is really about: inventory risk.
A note up front: educational material, not financial advice. Nothing here is a recommendation to trade.
The edge: capture the spread
A market maker continuously quotes a bid (willing to buy) below the mid and an ask (willing to sell) above it, and waits to get hit on either side.
- A seller comes along and hits your bid → you buy at 99.95.
- A buyer comes along and lifts your ask → you sell at 100.05.
- Round trip: you bought at 99.95 and sold at 100.05, keeping the 0.10 spread — and you took almost no directional view. Do this thousands of times a day and the spreads add up.
That’s the edge, and it’s real: market makers are paid to provide the liquidity everyone else consumes. In exchange they often get maker rebates too. On a liquid instrument with steady two-way flow, capturing the spread is a genuine, repeatable business.
The catch: inventory risk
Here’s the problem. Orders don’t arrive evenly. Sometimes sellers keep hitting your bid and no buyers show up — so you keep buying, accumulating a long inventory you never chose. Now you’re not market-neutral at all; you’re sitting on a big long position. And if the price then falls, the mark-to-market loss on that inventory can dwarf every spread you ever captured. The spread is the edge; the inventory you pile up while waiting for the other side is the risk that can wipe it out. That asymmetry — small steady gains from the spread, occasional large losses from inventory — is the central tension of market making.
A toy market maker in Python
Let’s simulate it. A mid-price random walk, orders arriving on each side, and a market maker quoting around a reservation price that leans against its inventory.
import numpy as np
def run_mm(gamma, seed=1, n=40_000):
rng = np.random.default_rng(seed)
mid, half, tick = 100.0, 0.05, 0.01
inv, cash, invs = 0, 0.0, []
alpha = 6.0 # how much aggressive quotes get filled
for _ in range(n):
mid += rng.normal(0, 0.02) # mid random-walks
r = mid - gamma * inv * tick # reservation price leans against inventory
bid, ask = r - half, r + half
if rng.random() < 0.5: # a seller may hit our BID -> we buy
p = min(max(0.5 + alpha * (bid - mid), 0.02), 0.98)
if rng.random() < p: cash -= bid; inv += 1
else: # a buyer may lift our ASK -> we sell
p = min(max(0.5 - alpha * (ask - mid), 0.02), 0.98)
if rng.random() < p: cash += ask; inv -= 1
invs.append(inv)
invs = np.array(invs)
return cash + inv * mid, invs.std(), int(np.abs(invs).max())
for gamma, label in [(0.0, "no inventory control"), (3.0, "skew against inventory")]:
pnl, istd, imax = run_mm(gamma)
print(f"{label:24}: P&L {pnl:7.1f} inv std {istd:5.1f} |max inv| {imax}")The key variable is gamma, the inventory skew. With gamma = 0, we quote symmetrically around the mid and ignore our inventory. With gamma > 0, when we get long (inv > 0) the reservation price r drops, which lowers both our bid (so we buy less) and our ask (so we sell more, offloading the position). The quotes lean to pull inventory back toward zero.
The measured result: skew tames inventory
| configuration | P&L | inventory std | |max inventory| |
|---|---|---|---|
| no inventory control | 477.8 | 25.5 | 90 |
| skew against inventory | 278.8 | 0.8 | 3 |
Without control, inventory random-walked out to ±90 — a huge, unwanted directional position that one adverse price move could turn into a catastrophic loss. With skewing, inventory stayed within ±3 (standard deviation collapsed from 25.5 to 0.8). The cost was some gross P&L (477 → 279), because leaning your quotes means you capture slightly less spread. That trade — give up some gross profit to crush inventory risk — is the entire craft of market making. A market maker who maximises spread capture and ignores inventory will have a great month and then one terrible day that ends the business.
What real market making adds
The toy captures the core tension; real market making layers on:
- Adverse selection — the trader hitting your quote often knows something (there’s news, a big order coming). You systematically buy just before prices fall. Makers manage this by widening quotes in fast markets and pulling quotes around news.
- Optimal quoting models — the Avellaneda–Stoikov framework formalises exactly how to set the spread and skew given your inventory, risk aversion, and time horizon. Our
gammais a crude version of its inventory term. - Speed — on lit exchanges, market making is a latency game: you must update quotes faster than others can pick you off. This is why serious market making is co-located and written in C++ — a world the trading course covers in depth.
Takeaways
- A market maker quotes both sides and earns the spread — buy at the bid, sell at the ask, pocket the difference, thousands of times.
- The real risk is inventory: uneven order flow leaves you holding a position you didn’t choose, and an adverse move on it can wipe out all your captured spread.
- The core control is to skew quotes against inventory. Measured: skewing cut |max inventory| from 90 to 3 (std 25.5 → 0.8), trading some gross P&L for far lower risk.
- Market making is a risk-management game — the spread is easy; controlling inventory (and adverse selection, and speed) is the job.
Next: the discipline that keeps any of these strategies from blowing up — position sizing and the Kelly criterion: how much to bet.







