Interview Experience | SWE Intern OA | π₯π₯π₯ | Optiver
2026 (Sep) Software Engineer Intern 2027 @ Optiver US β OA | π΅ Hard | Pending
The OA was 90 minutes of coding plus Zap-N. Coding had one question, but the prompt was long.
OA β market data processor
What it asked for
A simplified market data processor. The exchange keeps sending messages: ADD, UPDATE, DELETE, SNAPSHOT. Each message has a symbol, price, size, and a sequence number, and I had to keep the current best bid / ask state for every symbol.
The base part was not hard. On ADD or UPDATE, update the level. On DELETE, remove that level.
Sequence numbers
The part that made it hard was the sequence number.
If I had already processed up to seq=105 and the next message was 107, I could not just apply it. 107 goes into a buffer, and it waits there until 106 arrives so the messages can be applied in order.
If the missing message never comes, the feed sends a SNAPSHOT instead. A snapshot is the complete state at some sequence point, so I had to rebuild the book from it, then go back through the buffer and see which messages can still be applied.
The structure I ended up with
MarketDataProcessor
symbol -> OrderBook
lastSequence
pendingMessages
OrderBook
bid / ask
process(message)
apply(message)
applySnapshot(snapshot)
Rules that were added later
- Duplicate message. The same sequence can arrive twice. It cannot be applied twice.
- Stale message. If a snapshot already moved the book to seq=200 and 198 shows up after that, ignore it.
- Symbol independence. If AAPL is stuck at seq=50, that should not block MSFT's messages.
Whether the sequence is global or per-symbol has to be read carefully from the prompt. I got it wrong the first time and had to change part of the structure.
Best bid / best ask
One follow-up was returning the current best bid and best ask.
Keeping price levels in an unordered_map makes finding the best price awkward, so I changed to an ordered structure for prices. The bid takes the highest, the ask takes the lowest. If a DELETE removes a level and that level was the best, the best has to update on its own.
Corner cases
- UPDATE on a level that does not exist
- DELETE on a level that was already deleted
- a snapshot overlapping with buffered updates
- several sequence numbers missing in a row
- a duplicate snapshot
The hidden cases were mostly on snapshot plus buffer. The normal messages passed. A few test cases were still failing when the time ran out.
Time
90 minutes was very tight. Not because the algorithm was hard, but because you first have to read a long requirement, then decide how to hold the state, and halfway through you find that the abstraction from the start is not enough. If all the logic goes into process(), adding snapshot afterwards mostly blows up.
Zap-N
Zap-N came after the coding. A few reaction and attention games. In some you press a key when a certain pattern shows up. In others you memorize positions or an order for a short time. The rules are not complicated, but it keeps getting faster. There is nothing to prepare, you just play it.
Coding was much harder than Zap-N.
This OA did not feel like LeetCode practice. It felt closer to event processing, state management, and OOD with a pile of edge cases, and the points come off on sequence handling, recovery, and keeping the state consistent.