Citadel Intern Software Engineer Interview Experience — A Deep Dive on the Classic Orderbook Problem

Citadel·Software Engineer·Sep 2026
Technical ScreenInternmedium

This was my second round for the Citadel SWE intern process. The technical part was the classic orderbook problem.

The question was the classic orderbook problem.

Problem description: Design and implement an order book data structure that maintains order records containing the exchange name, price, quantity, and side (bid or ask). It needs to support three core APIs:

  • add(exchange, price, quantity, side): add a new order record.
  • get_exchange_bbo(exchange): get the BBO (Best Bid and Offer) for a given exchange — the best bid and best ask within that exchange.
  • get_nbbo(): get the NBBO (National Best Bid and Offer) across the whole market — the best bid and best ask across all exchanges.

Data structure design and complexity analysis (my Python implementation approach):

Per-exchange order book design: Each exchange maintains two hash tables and two heaps.

A hash table (price_counts) tracks the total quantity at each price level within that exchange. A max-heap for bids (max_heap_bids) stores negative prices so the highest bid can be read off the top. A min-heap for asks (min_heap_asks) stores prices directly so the lowest ask can be read off the top.

Lazy deletion: When the quantity at a price level drops to 0, I don't do an expensive O(N) linear search-and-delete on the heap — I just update the count in the hash table. When get_exchange_bbo() looks at the top of the heap, if the price there has a count of 0 in the hash table, it keeps popping until it finds the first valid price.

Global NBBO maintenance: I keep two global heaps (global_max_heap_bids and global_min_heap_asks) holding (price, exchange) tuples. Whenever an exchange's local BBO (best bid or best ask) updates, the new (price, exchange) pair gets pushed onto the corresponding global heap.

Global lazy deletion: When get_nbbo() is called, it checks whether the (price, exchange) at the top of the global heap still matches that exchange's current local best price. If it's been superseded by a newer, better price, the stale top gets popped off, so the read comes back O(1) once the cleanup is amortized.

Time complexity:

  • add(): O(1) for the hash table update, O(log K) for the heap push, where K is the number of price levels.
  • get_exchange_bbo() and get_nbbo(): O(1) on average for the heap-top read, amortized over the lazy cleanup.

Published

Curated and edited by PracHub

Practice the questions from this interview

Discussion

Sign in to join the discussion. The author is notified of every comment.

Loading comments…

Interview at a glance

Company
Citadel
Role
Software Engineer
Level
Intern
Rounds
Technical Screen
Difficulty
medium
Interview date
Sep 2026
Questions from this interview
1 question

Real Citadel interview experiences

First-hand reports from Citadel candidates — the rounds, the questions they were asked, and how it went.

All 19 Citadel interview experiences