Quant developer HFT course · Module 9: Trading systems
Drill: trading systems
System-design prompts at trading firms are concrete. Use the vocabulary, name the data structures, and spend your time on the edge cases: they are where the interviewer is looking.
Prompt 1: Cancel and fill cross
The interviewer says
You send a cancel for a resting order. Next you receive a fill for the full quantity, then a reject of your cancel. What state is the order in, and what must your system have done meanwhile?
Before you answer
Question · choose every correct option
Which are correct? Choose all that apply.
The exchange's sequence of events decides. The system must count fills whatever it has requested.
Answers that lose the point
Cancelled; we asked first.
The exchange decides the order of events, not the client.
A strong answer
Filled. At the exchange the order traded before the cancel arrived, so the cancel was rejected as too late. Our system must have kept the order as pending cancel, still counting its open quantity for risk, applied the fill to the position and P&L when it arrived, and then closed the order as filled on the reject.
The general rule is that the trading system's view lags the exchange's, so pending requests are treated pessimistically and every incoming event is applied whatever we have asked for.
Prompt 2: Build a book
The interviewer says
Design the order book for a market-by-order feed. Data structures?
Before you answer
Question · choose every correct option
Which choices are right? Choose all that apply.
O(1) find by id, O(1) level access and O(1) unlink cover the frequent operations without allocation.
Answers that lose the point
std::map<double, std::list<Order>>.
Floating-point keys, allocation per node, pointer chasing; correct but slow and fragile.
A strong answer
I would design for the operations: adds, deletes and executions identified by order id, most of them near the top of the book. Orders live in a preallocated pool; an open-addressing hash map goes from exchange id to pool handle. Each side keeps levels in an array indexed by ticks from a reference price, with an overflow for far prices, and each level holds its total quantity and an intrusive time-ordered queue linked through the orders.
Every operation is then a hash lookup and a few array accesses with no allocation, and I track the best level index so top of book is immediate. Prices are integer ticks, never doubles.
Prompt 3: The matching loop
The interviewer says
An aggressive buy limit order arrives. Write the core matching logic in words.
Before you answer
Question · choose every correct option
Which statements are correct? Choose all that apply.
The aggressor may get a better price than its limit; the resting order's price sets the trade price.
Answers that lose the point
Match it at the limit price.
Gives the aggressor a worse price than the book offers.
A strong answer
While the order has quantity left and the best ask is at or below its limit, take the best ask level and trade against its resting orders in arrival order, each trade at the resting order's price for the smaller of the two quantities, removing resting orders as they fill and the level when it empties. When the loop stops, a day order rests its remainder on the bid side at its limit; an IOC cancels it.
Around that core, a real engine adds sequencing for a single defined order of events, journaling, self-trade prevention, price bands and publication of every change.
Prompt 4: Risk on the hot path
The interviewer says
Which pre-trade checks would you run, and how do you keep them under a microsecond?
Before you answer
Question · choose every correct option
Which belong in the answer? Choose all that apply.
Checks must read precomputed numbers; anything that looks things up remotely is off the hot path.
Answers that lose the point
Call the risk service.
A network round trip per order.
A strong answer
Price collars against a reference, maximum quantity and notional per order, position limits counting open orders, exposure limits, order-rate limits including the exchange's, duplicate and runaway detection, and a kill switch that stops new orders and cancels open ones.
For speed, limits and positions sit in flat arrays indexed by the dense instrument id, positions are updated incrementally on every order and fill, arithmetic is integer ticks and lots, rate limits are fixed-size token buckets, and limit changes arrive by atomic swap of an immutable table. The passing path is a handful of compares.
Prompt 5: Testing it
The interviewer says
How do you test a trading strategy before letting it trade?
Before you answer
Question · choose every correct option
Which approaches are right? Choose all that apply.
Replay of recorded data is the foundation; live trading with limits is the last step, not the test.
Answers that lose the point
Paper trade it for a week.
Useful at the end, but slow, unrepeatable and blind to rare cases.
A strong answer
The foundation is deterministic replay: recorded packets with their receive timestamps fed through the same feed handler, book and strategy code as production, with time taken from the data and no dependence on thread timing, so the same recording always gives the same decisions. That lets us test every change against long periods of history and reproduce any production incident exactly.
Around it, unit tests for components, especially order-state edge cases like fills crossing cancels; simulated exchange responses for rejects and disconnects; and finally a cautious live start with tight risk limits.
After the drill
Trading-system questions are where your C++ and systems knowledge meets what the firm actually does. Module 10 finishes with numbers and time: how prices are represented and how timestamps can be trusted.