PART 4

Market Types & Structure

“The market” is not one place. The same share of Apple can trade on a lit exchange, inside a dark pool at the midpoint, against a wholesaler’s own book, or in a once-a-day auction — and the price you get, the information you leak and the counterparty you end up with are different in each. This page is the map. Read it before you write a router.

Everything here is live in shared/orderbook.py US equities settle T+1 since 28 May 2024 Quoted price ≠ net price
Part 4.1

1What is it? Six venue types, two axes

Market structure is the set of rules that decide who may trade with whom, at what price, and who finds out. Change one rule and the whole ecology moves: cap the access fee and volume migrates; publish the depth and large orders hide. Before the taxonomy, two questions worth more than the labels.

Question 1 — where does the price come from?

Either the price is discovered at the venue (many buyers and sellers meet in one book and their orders set it) or it is derived from somewhere else (a dealer marks off a reference, a dark pool matches at the lit midpoint). A venue that derives its prices is a free rider on the venue that discovers them — which is why lit exchanges care so much about how much volume goes dark.

In the arena. exchange/price_engine.py makes the split explicit: the venue mark is a blend, weighted MID_BLEND_WEIGHT = 0.85 toward the venue’s own depth-weighted microprice and 0.15 toward the shared fundamental. Discovery dominates; the common term is what keeps two fragmented venues from drifting apart.

Question 2 — who is on the other side if it goes wrong?

On an exchange you never learn the name of your counterparty, because you do not need to: the trade is novated to a central counterparty (a CCP) that steps in as buyer to every seller and seller to every buyer. Bilateral OTC has no such thing — you have the credit of the dealer you faced, an ISDA master agreement, and a pile of collateral.

That single difference explains why an exchange can be anonymous and an OTC market cannot, why OTC has credit officers and exchanges have margin clerks, and why post-2008 regulation pushed standardised swaps onto clearing houses.

Interactive · the venue map

Pick a venue type. The map places it by pre-trade transparency (left = dark, right = fully lit depth) and by counterparty risk (bottom = CCP-cleared and anonymous, top = bilateral credit). The panel gives you the five facts you actually need about it.

selected venue other venues Bubble area ≈ rough share of US equity notional (where equities trade there at all)

—

Transparency, as a number

Pre-trade: what the world can see before you trade.

Post-trade: how fast and how completely the print is published.

Part 4.2

2How does it work? Books, dealers, auctions, and a clock

Three trading mechanisms cover almost everything: a continuous order-driven book, a quote-driven dealer, and a single-price call auction. Most real markets use all three, at different times of day, for the same instrument. Here they are, one at a time, with the same order flow poured through them.

Interactive · order-driven vs quote-driven, same flow

Five client orders arrive. On the left they hit a CLOB and walk the ladder; on the right a dealer names one price for the whole clip and wears the inventory. Step through and watch which mechanism is cheaper — the answer flips with size.

Next: BUY 200

Order-driven · CLOB price-time priority

Many participants post limits. Your market order consumes levels until it is done, so your average price is worse than the touch when you are large. The exchange is a matcher; it takes no risk and holds no inventory.

Filled
0
Avg px
—
Slippage
0.0 bps
Cost
$0

Quote-driven · dealer principal risk

One dealer quotes a firm two-way price for your whole size. No slippage — one price, one fill — but the spread is wider, widens further with size, and skews as the dealer’s inventory builds. You are paying for immediacy and for the dealer’s risk.

DEALER BID
—
DEALER ASK
—

inventory 0 · spread 4.0¢

Filled
0
Avg px
—
Slippage
0.0 bps
Cost
$0

Interactive · the call auction

An auction does not match orders one against one. It collects them, then finds the single price that maximises crossed volume — and, among ties, the one with the smallest imbalance. That is not a simplification: it is literally auction_preview() in shared/orderbook.py, and it is how NYSE and Nasdaq open and close every day. Add orders and watch the indicative price move.

Indicative px
—
Crossed vol
0
Imbalance
0
Orders in
0
Candidate pxDemand ≥ pSupply ≤ pVolumeImbalancePick

Submit into the auction book

Auction book

Interactive · the trading day

A US equity session is not one regime. Move the clock: the matching rules, the spread, the depth and the share of the day’s volume all change, and a strategy tuned at 11:00 will be badly wrong at 09:31 and at 15:59.

Phase
—
Quoted spread
—
Depth at touch
—
Share of day
—
Part 4.3

3Why it matters: fragmentation, best execution, and the plumbing behind the print

One stock, a dozen places to trade it. That is not a bug — competition narrowed spreads and cut fees — but it moved a hard problem onto you: choosing where to send the order, and proving afterwards that you chose well. Then, once you have traded, something has to actually move the shares and the cash. Both halves are graded in this course.

Interactive · smart order routing across a fragmented market

Five venues quote the same name. The best quoted ask is not the best net ask once access fees and rebates land, and the midpoint venue is cheapest of all when it fills — which it does not always do. Choose a routing policy and a size, then read the net price.

Route an order

NBBO ask
—
Gross avg px
—
Fees
—
Net avg px
—
vs NBBO
—
Venues used
—

Interactive · clearing, netting and T+1

Six firms traded 14 times among themselves this morning. Nobody is going to wire fourteen separate payments. Step through what a clearing house does to that graph: novate every trade to itself, then net. The obligation that actually settles the next morning is a small fraction of the notional that traded.

Stage 1 of 4

—

Obligations
—
Gross to move
—
Compression
—

The settlement clock

Regulation, as vocabulary you will be expected to have

You do not need to be a lawyer. You do need to know which rule is about to reject your order, halt your symbol, or force your router’s hand. Filter by jurisdiction.

RuleWhoWhat it doesThe number
Read this as engineering, not law. Every row above is a branch in somebody’s order-entry path. In exchange/circuit_breaker.py three of them are yours to enforce: a velocity halt at VELOCITY_HALT_PCT = 5% in 60 seconds, a session band at SESSION_HALT_PCT = 25%, and market-wide breakers at -7% and -13%. An LULD_BAND_PCT = 10% collar rejects the fat-finger print before it ever happens.
Part 4.4

4Five ways this goes wrong

All five have shown up in student submissions on a live arena session. Open them.

Routing on the quoted price and paying more than the wide venue

Two venues show the same $100.03 ask. One charges 30 mils per share to take, one pays you 4 mils. Your router picks by price, so it picks whichever came back first in the snapshot, and half the time it leaves 34 mils per share on the table — about 3.4 bps on a $100 stock, which is larger than most intraday alpha.

The arena makes this bigger on purpose. exchange/config.py ships TAKER_FEE_RATE = 0.0015 and MAKER_REBATE_RATE = 0.0010 — 15 and 10 bps of notional, roughly fifty times a real US access fee — so that in a 45-minute session fees are visible in the standings rather than a rounding error.

Fix: rank on net price — quote + taker_fee when taking, quote − maker_rebate when posting — and log both so your TCA report can show the gap you avoided. Never compare a lit quote to a midpoint fill without adjusting both for fees.

Treating a dark midpoint as free liquidity

The midpoint is half a spread better than the touch, so a naive router sends everything dark first. Then two things happen. The fill rate is not 100% — you sit unfilled while the price walks away, and that opportunity cost does not appear in your average-fill statistics because unfilled orders have no fill price. And the flow you do get filled against is selected: the counterparty who wanted the other side of your order at the midpoint often knew something.

Fix: measure fill rate and post-fill mark-out together, not average price alone. A venue with a great average price and a 20% fill rate is a venue you are being adversely selected on. Report fills / attempts and the 1-second and 10-second mark-out next to every venue’s average price.

Assuming continuous trading all day and getting destroyed at the auctions

The closing auction is roughly a tenth of a US name’s consolidated volume on an ordinary day and much more on an index rebalance. A bot that keeps working a limit order through 15:59 is competing against every index fund in the world at 16:00:00 and does not know it. The mirror image happens at 09:30, when the first minutes carry a large slice of the day at several times the midday spread.

In the arena this is not hypothetical: with CLOSING_AUCTION=true the first close request freezes continuous matching for CLOSING_AUCTION_TICKS and the official close is one volume-maximising cross. A market order sitting in your queue when that happens does not do what you think it does.

Fix: make the session phase an input to your strategy. Read the phase off the event stream, size differently in the first and last five minutes, and if you need the closing price, submit into the closing auction rather than trying to trade near it.

Confusing the exchange with the clearing house

“The exchange guarantees my trade” is false, and the distinction bites when a counterparty fails. The exchange matched you; a CCP took the credit risk by novation, and it did that in exchange for initial and variation margin that it will call from your clearing member — possibly intraday, possibly at a very inconvenient moment.

The practical consequence for a systematic shop is that your funding and your position are two different constraints. You can be right about the price and still be closed out because a margin call landed before the P&L did.

Fix: model financing explicitly. The arena does — MARGIN_HAIRCUT = 0.5 on long inventory, MARGIN_RATE_PER_TICK on borrowed cash and BORROW_FEE_PER_TICK on shorts — so a strategy that ignores funding loses to one that does not, on the same signal.

Building one router for one venue, then discovering the season is multi-venue

Week one you hardcode EXCHANGE_URL. Then a scenario turns on multi_venue, a second exchange team opens with a different fee schedule, and your bot is quoting into the venue with the worse rebate because that is the only URL it knows. Every price it computes is now conditioned on a partial view of the market.

Fix: from the start, keep a list of venues, a per-venue book, and a consolidated top-of-book that your signal reads. One extra layer of indirection on day one; a rewrite mid-season if you skip it. This is exactly the boundary a smart order router lives at.

Part 4.5

5Check yourself

Three questions, instant feedback, nothing recorded.

Q1A call auction has collected its book. Which price does the engine choose?

Q2You must buy 40,000 shares of a name whose lit book shows 400 shares at the touch, right now, in one go. Which mechanism gives the better average price?

Q3Your exchange fill is anonymous — you never learn who sold to you. What makes that safe?

Part 4.6

6Do the work

Before you move on

  • Place your own course’s trading venue on the venue map above, on both axes, and say what would have to change to move it.
  • Reproduce the auction clearing price by hand for a five-order book, then check it against auction_preview().
  • Write the net-price formula for taking and for posting, with the arena’s 0.0015 / 0.0010 fee schedule, and sanity-check the sign.

Then, in code

  • Keep venues in a list from day one — a per-venue book plus one consolidated top-of-book.
  • Log the session phase on every decision, so your post-mortem can separate the open from midday.
  • Record fill rate alongside average price for every venue you touch. Average price alone lies.
Code
Get the code
The starter repo is public: a real matching engine, a real venue, and the fee schedule quoted on this page. Use it as a template, clone, make install.
Previous
← Part 3 · Derivatives
The instruments that trade in the venues you just mapped.
Next
Part 5 · Market Microstructure →
Now go inside one venue and take the order book apart, level by level.