← Optiver Interview Insights

Optiver·Software Engineer·Technical Phone Screen·Senior

SeniorPrefer not to say
May 2026Remote

Summary

Phone screen for a software engineering role at Optiver, centered on a freight-scheduling system written in Python. Three-part deep dive: code review for correctness, complexity analysis and data structure improvements, then concurrency and scalability. The codebase was handed to you and you had to both implement and then critique your own work, which is a weird but effective format.

Questions Asked (6)

Q1

You've just implemented process_order in a freight-scheduling codebase. Step back and critically review the entire codebase for bugs and unhandled corner cases. What categories of issues would you look for and how would you verify them under time pressure?

Root Cause AnalysisAlgorithms & Data StructuresTechnical Trade-offs
Author's notes

This one tripped me up because I'd just written the function and felt weirdly defensive about reviewing it.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by outlining a systematic taxonomy of potential issues (correctness, edge cases, concurrency, performance, integration) and then describe a prioritized verification strategy that focuses on high-risk areas first. Emphasize how you would use tools (tests, static analysis, logging) and reasoning to quickly identify and validate fixes under time pressure.

Pro tip: In a trading systems context, always consider the impact of latency and concurrency on correctness—many bugs only manifest under specific timing conditions, so stress-test with realistic load and race condition detectors.

1. Categorize potential issues

List broad categories such as logic errors, boundary conditions, concurrency issues, performance bottlenecks, and integration failures. This ensures comprehensive coverage without getting lost in details.

2. Prioritize by risk and impact

Rank categories based on likelihood and severity in a freight-scheduling system (e.g., race conditions in order assignment, incorrect fee calculations). Focus on areas most critical to business and safety.

3. Design targeted verification

For each high-risk category, define specific tests or checks: unit tests for edge cases, stress tests for concurrency, profiling for performance, and code review for logic. Use automated tools where possible.

4. Execute and iterate under time pressure

Run the most critical tests first, using parallelization and automation. If issues are found, fix and re-verify quickly, documenting assumptions and remaining risks.

5. Communicate findings and trade-offs

Summarize what was checked, what was found, and what remains uncertain. Highlight any trade-offs made due to time constraints and suggest follow-up actions.

Key Points to Mention

  • Boundary conditions: empty inputs, maximum loads, invalid dates, negative quantities.
  • Concurrency: race conditions in order assignment, deadlocks, thread safety of shared data.
  • Performance: latency spikes under high load, inefficient algorithms (e.g., O(n^2) scheduling).
  • Integration: mismatches with external systems (e.g., carrier APIs, database schemas).
  • Error handling: unhandled exceptions, silent failures, logging and monitoring gaps.
  • Verification techniques: unit/integration tests, fuzzing, static analysis, code review, profiling.

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.

Q2

What is the time complexity of the baseline process_order implementation, and which data structures would you change to improve it across m orders and n planes?

Algorithms & Data StructuresTechnical Trade-offsSystem Design
Author's notes

Linear scan plus sort per order is the obvious answer.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by clarifying the baseline implementation's operations and data structures, then derive its time complexity in terms of m and n. Identify bottlenecks and propose alternative data structures (e.g., heaps, balanced trees, hash maps) that reduce complexity, explaining the trade-offs.

Pro tip: At Optiver, interviewers value clear reasoning about trade-offs and practical optimizations. Always quantify improvements (e.g., from O(m*n) to O(m log n)) and discuss real-world constraints like memory and latency.

1. Understand the baseline

Ask clarifying questions about the process_order function: what operations does it perform? How does it interact with orders and planes? Assume a typical implementation if not specified.

2. Analyze time complexity

Break down the baseline into steps, determine the cost of each operation, and express the overall complexity in terms of m (orders) and n (planes). Identify nested loops or linear scans.

3. Identify bottlenecks

Pinpoint which data structure operations (e.g., list search, insertion) dominate the runtime. Consider worst-case and average-case scenarios.

4. Propose improved data structures

Suggest replacements (e.g., heaps for priority, balanced BSTs for ordered access, hash maps for O(1) lookups) and explain how they reduce complexity. Recalculate the new time complexity.

5. Discuss trade-offs

Mention any trade-offs: increased memory, implementation complexity, or changes in access patterns. Ensure the solution is practical for Optiver's high-performance environment.

Key Points to Mention

  • Baseline time complexity (e.g., O(m*n) due to nested loops or linear searches)
  • Use of appropriate data structures: heaps for priority queues, balanced BSTs for ordered data, hash maps for constant-time lookups
  • Improved time complexity (e.g., O(m log n) or O(m + n)) with justification
  • Trade-offs: memory overhead, implementation complexity, and suitability for real-time trading systems
  • Edge cases: empty inputs, duplicate orders, or planes with varying capacities
  • Scalability considerations for large m and n

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.

Q3

Is this scheduler thread-safe as written? Walk through exactly what goes wrong under concurrent order processing, then design an approach to make it safe. What would you change if order volume outgrows a single machine?

System DesignTechnical Trade-offsAlgorithms & Data Structures
Author's notes

The check-then-act race is pretty classic.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by explicitly stating that thread-safety depends on the scheduler's shared state and synchronization mechanisms, then walk through a concrete race condition (e.g., two threads updating the same order queue) to show what breaks. After explaining the failure, propose a fix using appropriate synchronization or lock-free data structures, and finally discuss scaling out with partitioning or distributed scheduling when a single machine is insufficient.

Pro tip: Show you understand the trade-offs between correctness and performance: mention that coarse-grained locking is simple but can bottleneck, while fine-grained or lock-free approaches improve throughput at the cost of complexity. Also, tie your scaling answer to Optiver's low-latency, high-throughput trading environment by emphasizing partitioning by order ID or symbol to maintain locality.

1. Identify shared mutable state

List the scheduler's shared data structures (e.g., order queue, priority heap, worker pool) and explain why concurrent access without synchronization causes data races.

2. Walk through a concrete race condition

Describe a specific interleaving (e.g., two threads dequeuing the same order or corrupting the heap) that leads to lost orders, duplicate processing, or crashes.

3. Propose a thread-safe design

Suggest using locks (mutex, read-write lock), lock-free structures (concurrent queue, atomic operations), or actor-model serialization, and justify your choice based on contention and latency requirements.

4. Address scalability beyond one machine

Explain how to partition orders across multiple schedulers (e.g., by symbol or order ID), use a distributed queue (Kafka, Redis), and handle coordination (e.g., consistent hashing, leader election) to maintain ordering and fault tolerance.

Key Points to Mention

  • Data races and atomicity violations in shared queues or heaps
  • Lock granularity trade-offs: coarse vs. fine-grained locking
  • Lock-free and wait-free data structures (e.g., Michael-Scott queue, CAS operations)
  • Partitioning strategies (by symbol, order ID) for horizontal scaling
  • Distributed coordination: consistent hashing, leader election, distributed queues
  • Performance implications: latency, throughput, contention, and backpressure

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.

Q4

How would you support order cancellation or plane removal without breaking the amortized complexity you described?

System DesignTechnical Trade-offs
Author's notes

Caught me a bit flat-footed.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

First, clarify the data structure and the amortized complexity you previously described (e.g., dynamic array with O(1) amortized append). Then, propose a lazy deletion strategy using a tombstone marker or a separate set to track removed elements, ensuring lookups and iterations skip them. Finally, analyze the impact on amortized complexity, showing that the additional operations remain O(1) amortized and that periodic compaction can maintain efficiency.

Pro tip: Mention that lazy deletion trades memory for speed and that you would monitor the tombstone ratio to trigger compaction, demonstrating awareness of real-world performance trade-offs.

1. Clarify the data structure and complexity

Restate the data structure and the amortized complexity you previously described, ensuring the interviewer agrees on the baseline.

2. Propose lazy deletion

Introduce a tombstone marker or a separate set to mark elements as removed without physically deleting them immediately.

3. Maintain amortized complexity

Explain how operations like insertion, lookup, and iteration still achieve the same amortized complexity despite tombstones, and how periodic compaction (e.g., when tombstones exceed a threshold) preserves it.

4. Discuss trade-offs and alternatives

Compare lazy deletion with eager deletion (e.g., swapping with last element and popping) and mention scenarios where each is preferable.

5. Conclude with a recommendation

Summarize why lazy deletion is suitable for the given context and how you would implement it to meet performance requirements.

Key Points to Mention

  • Tombstone/lazy deletion approach
  • Amortized analysis of insertion, deletion, and lookup
  • Periodic compaction to reclaim memory and maintain performance
  • Trade-off between memory overhead and speed
  • Alternative: swap-with-last for O(1) deletion if order doesn't matter
  • Impact on iteration and how to skip tombstones efficiently

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.

Q5

If the process crashes mid-allocation, what state could be corrupted and how would you add durability to recover cleanly?

System DesignTechnical Trade-offs
Author's notes

Write-ahead logging was my first answer.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by clarifying the allocation process and failure model, then systematically identify all mutable state that could be left inconsistent. Propose a durability mechanism (e.g., write-ahead logging or journaling) that ensures atomicity and enables recovery to a consistent state.

Pro tip: Emphasize the trade-off between durability guarantees and performance overhead—Optiver values low-latency systems, so discuss how to minimize sync costs while still ensuring recoverability.

1. Clarify the allocation process and failure scenario

Ask questions to understand what resources are being allocated, the steps involved, and what 'mid-allocation' means (e.g., after reserving but before committing).

2. Identify mutable state and potential corruption

List all data structures (in-memory and on-disk) that are modified during allocation, such as free lists, bitmaps, metadata, and transaction logs, and explain how a crash could leave them inconsistent.

3. Design a durability mechanism

Propose a write-ahead log (WAL) or journal that records intent before modifying state, ensuring that on recovery, incomplete allocations can be rolled back or completed.

4. Define the recovery protocol

Describe how the system detects and recovers from a crash: replay the log, undo incomplete operations, and restore a consistent state, possibly with idempotent operations.

5. Discuss trade-offs and optimizations

Address performance implications (e.g., fsync frequency, batching) and how to balance durability with latency requirements, possibly using techniques like group commit or non-volatile memory.

Key Points to Mention

  • Write-ahead logging (WAL) or journaling for atomicity and durability
  • Idempotent recovery operations to handle partial writes
  • Trade-off between fsync frequency and latency (e.g., group commit)
  • Use of checksums or versioning to detect corruption
  • In-memory state reconstruction from durable logs on restart
  • Consideration of hardware failures and replication for high availability

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.

Q6

How would you test the concurrent version of the scheduler to reliably catch oversold capacity?

System DesignTechnical Trade-offs
Author's notes

Property-based testing was the angle I took.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by clarifying the scheduler's invariants and the definition of oversold capacity, then propose a layered testing strategy that combines deterministic stress tests, property-based testing, and model checking. Emphasize how you would reproduce concurrency bugs reliably using controlled scheduling and instrumentation.

Pro tip: Use deterministic simulation testing (e.g., with a controlled scheduler and fault injection) to make concurrency bugs reproducible, and always assert the invariant 'sum of allocated resources ≤ total capacity' after every operation.

1. Define Invariants and Failure Modes

Clearly state the key invariant: at no point should the sum of allocated resources exceed total capacity. Identify potential race conditions, such as check-then-act on capacity, and list all operations that modify capacity.

2. Design Deterministic Stress Tests

Create tests that run many concurrent allocation and deallocation operations with varying thread counts and timing. Use barriers, latches, and controlled delays to force interleavings that might trigger oversell.

3. Apply Property-Based and Model Checking

Use property-based testing to generate random sequences of operations and assert the invariant after each step. For critical sections, apply model checking (e.g., TLA+, Spin) to exhaustively verify correctness under all interleavings.

4. Instrument and Monitor

Add logging and metrics to track capacity changes and detect oversell in real-time. Use thread sanitizers and race detectors to catch data races that could lead to oversell.

5. Reproduce and Fix

When a failure is found, minimize the test case and reproduce it deterministically. Analyze the root cause, fix the synchronization, and add a regression test to prevent recurrence.

Key Points to Mention

  • Invariant: sum of allocated resources ≤ total capacity at all times
  • Race conditions: check-then-act, lost updates, non-atomic operations
  • Deterministic simulation testing with controlled scheduling
  • Property-based testing with random operation sequences
  • Model checking for exhaustive verification of critical sections
  • Use of thread sanitizers and race detectors
  • Stress testing with high concurrency and varying timing
  • Regression tests for any found oversell scenario

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.