ConvexPi

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-orderevery 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)
DataAggregated size per level, ~1/secEvery order add / cancel / trade, microsecond stamped
Queue positionNot modelledExact FIFO position; drains order by order
TimeDiscrete ticksContinuous, event-driven
LatencyNoneMarket-data + order-entry latency
Cancel race / adverse selectionAbsentModelled — the core risk of market making
Best forLearning the mechanics fastRealistic 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:

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.