Arena documentation · advanced
The realistic exchange (L3)
The main exchange explainer covers a teaching-grade matching engine driven by L2data — aggregated size per price level, snapshotted once a second. That's perfect for learning the rules, but it can't represent the three things that actually make market making hard: queue position, latency, and the cancel race. Those need L3 — the order-by-order feed.
L1 → L2 → L3
- L1 — just the best bid and ask. The top of the book.
- L2 — total size at each price level (what most “depth” charts show). Our snapshot Arena uses this.
- L3 / market-by-order — every individual order: each add, change, cancel, and execution, with its own id and microsecond timestamp. This is the real message stream a matching engine processes.
Only L3 tells you how many orders, and whose, are ahead of yours at a price — which is the whole game for a passive trader.
Queue position — the thing L2 can't show
When you post a limit order, you join the back of a FIFO queueat your price. You only get filled once everything ahead of you is gone — either cancelled or traded through. With L2 snapshots, the “5 BTC at the bid” is an anonymous blob that gets re-drawn each second; you have no idea if you're first in line or last.
With L3 you know exactly: when you join behind, say, 0.42 BTC, you can watch that queue drain order by order as the orders ahead cancel and trade — and only when it hits zero does the next incoming market order start filling you. Good queue position is often worth more than a slightly better price.
Latency and the cancel race
There are two clocks a real trader fights:
- Market-data latency — the book you see is already a little stale.
- Order-entry latency — your order (or cancel) takes time to reach the matching engine.
Put them together and you get the defining moment of market making: you're resting a bid, the tape suddenly looks toxic (informed selling), and you fire a cancel. Does your cancel reach the engine beforethe incoming market sell trades against you? If yes, you dodged it. If the cancel is even tens of milliseconds too slow, you're adversely selected— filled right as the price moves against you. The L2 snapshot model has no time and no queue, so this race simply doesn't exist in it.
L2 snapshot vs L3 order-by-order
| L2 snapshot (the teaching Arena) | L3 order-by-order (the realistic one) | |
|---|---|---|
| Data | Aggregated size per level, ~1/sec | Every order add / cancel / trade, microsecond stamped |
| Queue position | Not modelled | Exact FIFO position; drains order by order |
| Time | Discrete ticks | Continuous, event-driven |
| Latency | None | Market-data + order-entry latency |
| Cancel race / adverse selection | Absent | Modelled — the core risk of market making |
| Best for | Learning the mechanics fast | Realistic market making & microstructure research |
They're separate instances on purpose — start on the L2 Arena to learn the rules, then graduate to the L3 exchange where queue and latency decide everything.
Where this stands
The L3 engine exists as a reference implementation in Python — it defines the semantics (per-price FIFO queues, order-by-order drain, fills, and the latency/cancel race) and is the teaching artifact. It runs against real recorded order-by-order data(Bitstamp's public order feed). You can read it in the open:
- •
mbo.py— the reference L3 book + queue simulator - •
fetch_crypto_l3.py— the real L3 recorder - •
mbo_demo.py— queue-drain + cancel-race demonstration
Next: a live, playable L3 instance with its own competition, where your agent's fills depend on the queue it's sitting in and how fast it can cancel. The reference stays the source of truth; a compiled (Rust) core can later run it at research scale behind the same interface.
Look at both
Learn the mechanics on the snapshot Arena, then see why the real thing is harder.

