This is the kind of question where you think you know what they want and then realize halfway through you've been thinking about it wrong.
Start by clarifying requirements (e.g., expected tick rate, latency, symbol count) and then propose a design using a hash map from symbol to an order book structure that maintains the best bid and ask. Discuss the trade-offs of different data structures (e.g., heaps vs. balanced trees vs. sorted arrays) and justify your choice based on performance and update patterns.
Pro tip: Emphasize that the best bid/ask can be maintained in O(1) time per update if you use a data structure that tracks the top of book directly, such as a double-ended priority queue or a custom structure with cached best prices, rather than recomputing from scratch.
Ask about expected tick volume, number of symbols, latency requirements, and whether out-of-order or duplicate ticks are possible. This informs data structure choice and concurrency needs.
Propose a hash map (e.g., unordered_map) from symbol to an order book. For each symbol, maintain separate structures for bids and asks, such as a max-heap for bids and a min-heap for asks, or a balanced BST (e.g., std::map) for each side.
Explain how updates (new tick, cancel, trade) affect the best bid/ask. For heaps, lazy deletion or a hash map of price levels can handle updates; for balanced trees, begin() and rbegin() give O(1) access to best prices.
Discuss threading model: single-threaded event loop per symbol or lock-free data structures. Mention memory management and cache efficiency, especially if using custom allocators.
Compare chosen structures: heaps offer O(log n) updates but O(1) best price; balanced trees offer O(log n) updates and O(1) best price with ordered iteration; sorted arrays give O(1) best price but O(n) updates. Justify based on expected update/query ratio.
AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.
I spent too long on implementation details and not enough time nailing the interface first.
Start by clarifying the system's purpose and constraints, then define each class's responsibilities and public API with clear contracts. Use interfaces and immutability where appropriate, and discuss how the classes interact to ensure thread safety and performance.
Pro tip: Emphasize immutability and thread safety for market data classes, as they are often shared across threads in high-frequency trading systems. Also, mention the importance of defining clear contracts to facilitate testing and future extensions.
Ask questions to understand the system's scale, latency requirements, and expected usage patterns. This ensures the design meets the actual needs.
Design Symbol as an immutable value object representing a unique identifier for a financial instrument, with methods for equality, hashing, and string representation.
Design OrderBookSnapshot as an immutable snapshot of the order book at a point in time, exposing bid/ask levels and methods to query best prices and depth.
Design MarketDataFeed as an interface for subscribing to market data updates, with methods to start/stop the feed and register listeners for snapshots and incremental updates.
Clearly state the contracts for each class, including thread safety, immutability, and error handling. Explain how they interact, e.g., MarketDataFeed produces OrderBookSnapshot instances for Symbols.
AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.
Start by clarifying the data structures and operations involved, then analyze the time complexity of on_tick and get_snapshot separately. Explain how you achieve O(1) for get_snapshot, likely by maintaining a precomputed snapshot or using an incremental update strategy.
Pro tip: Emphasize that O(1) get_snapshot often requires a trade-off: either on_tick becomes more expensive or you use extra memory. Discussing this trade-off shows you understand real-world constraints.
Ask or state the assumptions about the data structures, the frequency of calls, and what on_tick and get_snapshot are supposed to do.
Determine the time complexity of on_tick based on the operations it performs, such as updating aggregates or maintaining a data structure.
Explain how get_snapshot can be O(1) by returning a precomputed value or a reference to an immutable snapshot.
Mention the trade-offs involved, such as increased memory usage or higher on_tick complexity, to achieve O(1) get_snapshot.
If possible, give a concrete example (e.g., maintaining a running sum or using a versioned data structure) to illustrate your approach.
AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.
Start by clarifying the data source and business impact of stale/out-of-order ticks, then propose a layered solution combining buffering, watermarking, and deduplication. Emphasize trade-offs between latency, accuracy, and complexity, and mention how you would validate the approach with metrics and tests.
Pro tip: Show that you understand the difference between event time and processing time, and that you would use watermarks to handle out-of-order data while bounding state size. Also, mention that you would monitor the rate of late events and adjust the allowed lateness dynamically.
Ask about the data source, expected lateness, business impact of stale data, and latency requirements. This ensures the solution aligns with the use case.
Decide whether to use event time or processing time, and explain why event time is usually preferred for financial tick data to ensure correctness.
Use a buffer to hold out-of-order events and watermarks to track progress. Define allowed lateness and a strategy to emit results when the watermark passes.
Deduplicate based on unique tick identifiers, and decide whether to drop, side-output, or update results for late events beyond the watermark.
Instrument metrics for late events, buffer size, and latency. Use these to tune allowed lateness and buffer capacity, and to detect anomalies.
AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.
The optional callback subscribe was framed as a stretch but they did ask about it.
Start by clarifying the requirements: what is the expected update frequency, latency tolerance, and number of subscribers? Then propose a publish-subscribe design with a central market data service that maintains the top of book and notifies registered listeners via callbacks or message queues. Emphasize thread safety, efficient data structures, and decoupling of producers and consumers.
Pro tip: Mention that you would use a lock-free or read-copy-update (RCU) approach for the order book to avoid blocking the hot path, and consider batching updates to reduce overhead. Also, discuss how you would handle slow subscribers to prevent them from affecting the publisher.
Ask about latency, throughput, number of symbols, and subscribers. Determine if updates need to be reliable or can be dropped, and whether ordering matters.
Define the top of book structure (best bid/ask price and size). Explain how changes are detected, e.g., by comparing new values or using sequence numbers.
Propose a publish-subscribe pattern: subscribers register callbacks or subscribe to a topic. Consider in-process (observer pattern) vs. inter-process (message queue like Kafka, Redis Pub/Sub) based on scale.
Discuss thread safety: use concurrent data structures, locks, or lock-free techniques. Ensure the publisher is not blocked by slow subscribers; consider async dispatch or bounded queues.
Cover subscriber lifecycle (subscribe/unsubscribe), error handling, backpressure, and ensuring updates are delivered in order. Mention monitoring and testing strategies.
AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.