asp53826 / lob-market-making

The best PnL
is the worst strategy.

A limit order book, market makers quoting into it, and informed traders who can see a fair value the makers cannot. Rank the strategies by profit and the naive one wins. Rank them by anything that accounts for risk and it is not close.

36 tests 12 paired seeds naive holds the inventory risk A-S was a taker on 72.7% of volume source

Watch it get picked off LIVE

The book below is running now. Faint green and red are resting bids and asks from other liquidity providers; cyan is this market maker's own two quotes. The dashed amber line is fair value — only the informed traders can see it. When a quote drifts onto the wrong side of that line they take it, the fill flashes red, and the maker's realised edge on that trade is negative. Noise fills flash cyan.

2
0.030
0.18
inventory
0
PnL, marked to fair
0
spread capture
0
inventory PnL
0
realised edge / share
volume taken by informed

A browser port of the same model as src/lob/, not the same code — it exists to make the mechanism visible, and its numbers will wander from run to run. Every measured figure elsewhere on this page comes from the Python benchmark over 12 paired seeds. Push informed flow to 1.0 and watch spread capture fall while volume rises.

Rank them two ways

12 paired seeds, 20,000 steps, identical random draws for every strategy. Click a column header to re-rank.

strategy PnL PnL sd capture inventory PnL inv sd Sharpe wins

Sort by PnL. naive(2) tops the table at 20,853. It also carries an inventory standard deviation of 88.1 against skew(2)'s 12.0, and a PnL spread of ±11,010 against ±3,129. It earns 35% more by taking roughly seven times the position risk.

Sort by Sharpe. The order inverts: skew(2) at 5.7, naive(2) at 1.3. The decomposition says why — of naive's 20,853, only 16,238 came from quoting. The rest is an unhedged directional bet that happened to pay on these seeds.

The maker that was secretly a taker

Avellaneda–Stoikov at high risk aversion showed −176k PnL on five times the volume of anything else. A market maker should not trade more as it becomes more risk-averse. Counting who was the aggressor on each trade explained it.

72.7% of its volume was taken, not made. The inventory term scales with risk aversion, so a non-zero position pushed one quote clear across the book. A limit order that crosses executes immediately — the strategy was paying the spread and booking the cost as market-making PnL.

Real makers use post-only orders, which exchanges reject or reprice. Adding them moved γ=0.5 from −175,958 to −68,155 — still bad, but now bad for an honest reason. A test asserts zero taken volume for every strategy.

Avellaneda–Stoikov is only as good as its k

The published spread is γσ²(T−t) + (2/γ)·ln(1 + γ/k). k is the decay of fill intensity with distance and has to be calibrated. The market's own spread here is about 5 ticks.

γkspread termquoted PnLedge/sharevolume

At k=1.5 the model quotes 1.3 ticks into a 5-tick market and loses at every risk aversion. At k=0.3 the same model is profitable. The bottom row is also the cleanest demonstration that edge per share is gameable on its own: 20.6 ticks looks superb until you notice it was earned on 404 shares.