Software engineers at Jane Street build the systems a quantitative trading firm runs on: high-frequency trading systems, low-latency execution engines, risk management tools, real-time market data pipelines, and internal tools such as monitoring dashboards and visual editors used by traders and engineers. The work involves close collaboration with quantitative traders, researchers and systems operations teams, often in short feedback loops rather than against fixed requirement documents.
OCaml is the firm's primary language. Reports say candidates may interview in a mainstream language such as Python, C++ or Java, and list prior functional programming experience as a nice-to-have that is taught on the job. The systems have to be correct and fast: a bug or a latency spike in a production trading loop can have direct financial consequences. That is why the reported interview advice keeps returning to readable code, precise data modelling and checking your own work before calling it done.
The reported questions are practical and often multi-part. A bracket validator later has to return exact positions. A run-length encoder later has to decode partial streams. A trade-volume aggregator later has to handle short sales and credit adjustments. Class-design questions model stateful tools: a game board where pieces enter from the bottom, a text editor buffer, a code-folding editor. Probability and combinatorics questions (a three-player dice game, palindromic permutations, conditional probability) sit alongside system design, SQL and debugging questions from the bank. Prepare to extend your own code under new requirements, not only to solve fresh problems.
Online Assessment
reportedCandidates report that the process opens with an online assessment or take-home task. It may be a coding assessment or a data analysis task. Some tracks report a data challenge in Excel that tests how quickly you can work with a raw dataset. Ask your recruiter which format you will get, because the preparation differs. A coding assessment rewards a solution tested against inputs the examples do not show. A spreadsheet task rewards formulas that are correct, easy to trace and quick to build.
What to demonstrate
- In a coding assessment, whether the solution handles cases beyond the worked examples, such as empty input, a single element and repeated values
- In a data analysis task, whether you can clean, look up and aggregate a raw dataset with formulas you can explain and audit
- Whether you finish something correct rather than leaving an ambitious approach half-built
How to prepare
- Before each practice solution, write a small test harness that runs the stated examples plus empty and single-element inputs and prints expected against actual
- Practise the bank question on computing haircuts with Excel formulas, plus lookups, conditional sums, absolute versus relative references and pivot tables, until you can build them without searching
- Confirm the format with your recruiter and put your practice into that format
Virtual Technical Rounds
reportedReports describe one or two virtual technical rounds of live coding and quantitative problem-solving, held in a shared editor such as CoderPad or over Zoom with a current engineer. The guide's reported coding questions, whichever round they come from, are practical and multi-part: bracket parsing that later returns positions, a run-length encoder that later handles partial streams, and trade aggregation that later handles short sales. The reported quantitative questions cover probability, combinatorics and expected value. Treat the session as pair programming. Say your plan, write readable code, and trace it by hand before calling it finished.
What to demonstrate
- Whether you restate the problem and name an approach and its cost before typing
- Whether part one leaves behind state that makes the next requirement cheap to add, rather than forcing a rewrite
- Whether a probability problem is set up precisely, with the sample space and any tie or reset rule stated, before any calculation
- Whether you test a hint against a concrete input and act on the result, rather than arguing past it
How to prepare
- Solve the reported bracket, run-length encoding and trade-processing questions in your most fluent language, in a plain editor, narrating as you go
- Work three probability questions out loud, including the three-player dice game and the bank's conditional probability with balls, and check each answer with a symmetry, sums-to-one or enumeration test where the rules make that test valid
- Ask a partner to add a requirement halfway through a problem, and practise extending your code without breaking part one's tests
Onsite Interview Day
reportedCandidates who pass the virtual rounds report a full-day onsite, called a Superday, or a virtual equivalent, of three to five technical rounds back to back. The rounds cover practical coding, class design, systems concepts and real-time troubleshooting. The risk is fatigue, and carrying one room's mode into the next: over-designing a coding problem, or coding a class-design question before the interface is agreed. Reset your opening in every room: restate the problem, ask for constraints, and say the plan before writing anything.
What to demonstrate
- Whether your opening habits (restating, clarifying, planning aloud) still hold in the later rounds of the day
- Whether a class-design answer starts from an agreed interface and representation before any implementation
- Whether code is checked by tracing a small example before you declare it done
How to prepare
- Book three to five mocks back to back on one day, mixing coding, class design, probability and debugging, and note where your habits slipped
- For each reported class-design question, write the public method signatures and one small example state before any implementation
- Keep a short card with your opening steps for each question type and read it before every mock
Technical Rounds
reportedReports say the onsite technical rounds cover coding, system design and deep-dive debugging. For the debugging side, practise tasks such as searching logs on a virtual machine, or working in a terminal with failing service logs to isolate a memory leak or a network timeout. For the design side, practise bank questions such as distributed system design, order book APIs, processing one million quote updates per second, and database design for a market. In both kinds of problem, state your assumptions and your evidence before you act.
What to demonstrate
- Whether a debugging session moves from observation to one testable hypothesis to a confirming check before anything is changed
- Whether a design answer settles requirements, throughput and failure cases before choosing components
- Whether trade-offs such as latency against consistency are explained in terms of the specific problem rather than in general
How to prepare
- Work the guide's cache-stampede debugging drill and write the ordered checks that separate a genuine demand increase from a retry storm
- Do the worked design exercise on recovering an order session that dropped mid-fill, and the worked SQL exercise on join fan-out
- Practise reading a real service log from the command line with grep, tail, sort and uniq, and say what each command rules in or out
22 candidate reports. Individual accounts describe a particular role and hiring cycle.
Jane Street Intern Software Engineer Interview Experience — Exchange Arbitrage and Quote Throughput
It was a low-level-design problem. Core problem: An Exchange Arbitrage System for stocks. Assume there are multiple exchanges, each with a market feed continuously publishing bid and ask prices for different instruments or stocks. Design and implement an arbitrage strategy. The example gave AAPL on exchange A a bid of \$1.00 and an ask of \$1.10, while exchange B had a bid of \$0.90 and an ask of…
Read full experienceJane Street Quantitative Analyst interview experience: probability progression
I went through math-focused interviews that started with easier questions and became harder. The rounds centered on probability. Early questions established the fundamentals, then the difficulty increased. Each round also began with a behavioral check-in, which set expectations before the technical work. In a similar run, I had three phone interviews along the same probability track. The first co…
Read full experienceJane Street Quantitative Analyst interview: probability games before superday
I had several Zoom interviews, with three technical rounds before a superday. The questions were built around games presented by the interviewers and relied heavily on probability and game thinking. The early games were more straightforward and closer to deterministic setups. Later rounds brought more randomness and more game theory. In the more open-ended game rounds, I needed to optimize outcom…
Read full experienceJane Street Quantitative Analyst interview: probability rounds and nerves
After applying online, I had a resume screen and a first technical round. It was my first quant interview, and I was nervous enough that I did not answer as smoothly as I wanted. I did not move past that round. I later entered through a program that sent me directly to interviews. There were two 45-minute Zoom technical rounds. The first was clearly easier than the second, and the interviewers we…
Read full experienceJane Street Software Engineer interview: final onsite mattered most
I started with a virtual round and then moved to an onsite. The questions blended coding with system-design-style work, but they emphasized real-world systems more than academic exercises. By the onsite, it was clear that this was the most important stage and that the bar was highest there. I did not perform well enough in that final stage to move forward. The process was intense, and my main tak…
Read full experiencePracHub editorial advice for the preparation topics above.
Treating a reported multi-part coding question as done once part one passes, then having to rewrite it when the extension arrives.
Several reported coding questions grow in stages. Validate brackets, then return exact positions for inline edits. Encode run-length data, then decode partial streams. Aggregate trade volume, then handle short sales and credit adjustments. If part one returns only a boolean, assumes the whole string is in memory, or stores unsigned quantities, part two becomes a rewrite. Before coding, ask what the likely extension is. Keep indices, carry decoder state across chunks, and use signed quantities, and keep part one's tests passing while you extend.
Calculating the three-player dice probability before pinning down the tie rules.
The reports differ on tie handling: one version resets the game if all three players tie, another says ties trigger a complete re-roll. Ask how a two-way tie for the highest roll is handled before computing. If the rule always ends with exactly one winner, for example a re-roll on any tie at the top, condition on the game not resetting instead of summing an infinite series by hand, check that the three win probabilities sum to one, and use symmetry as a check: with no advantaged player, each wins with probability 1/3. If a two-way tie means both win or nobody wins, the three probabilities neither equal 1/3 each nor sum to one, so say which rule you are using. For the variant where one player always rolls at least a 4, enumerate that player's three possible rolls explicitly.
Starting to code the bottom-insertion game board or the editor buffer before agreeing on the interface and representation.
In the reported board question, pieces enter from the bottom and push existing pieces up, so in a plain row-major grid every insert shifts a whole column. Write the public methods and one example state first. Pick a representation that makes the frequent operation cheap, such as a list per column, and state its cost. When checking for matches, point out that a bottom insert moves every piece in that column. Re-check that column and each row it intersects rather than only the new cell or the whole board.
Changing code or config in a debugging problem before a failing case has been reproduced and explained.
Reports list deep-dive debugging among the onsite technical rounds. Practise on tasks such as isolating a memory leak or a network timeout from failing service logs in a terminal. Say what the logs show, state one hypothesis, and name the command or log line that would confirm or rule it out. Only then change something. Use this guide's cache-stampede drill as practice: separate a rise in demand from a retry storm before proposing any fix.
Switching to OCaml, or another language you know only passively, to signal interest in the firm.
Reports say candidates may use any mainstream language and are not expected to know OCaml. An unfamiliar language costs you time on syntax and standard-library lookups in live coding, which is time taken away from correctness and testing. Interview in your most fluent language. Drill its calls for maps, sorting with a custom comparator, heaps and string splitting until you no longer need to look them up.
Choose a category, try a prompt, then open its approach, worked solution or follow-up when you need it.
Parentheses tracking & string manipulation: Write a robust parser to v…
Parentheses tracking & string manipulation: Write a robust parser to validate nested brackets, then refactor it to return exact positions for inline string edits.
Approach
- Name the brute-force solution and its complexity before improving on it.
- Restate the input: its shape, its size, and what is guaranteed about it.
- Walk one small example through your approach before writing the whole thing.
Follow-up
- Which test case would catch an off-by-one here?
- How does this change if the input no longer fits in memory?
Run-Length Encoding (RLE) utility: Implement a stream encoder and deco…
Run-Length Encoding (RLE) utility: Implement a stream encoder and decoder using run-length encoding principles, building additional features to handle partial streams and data transformations.
Approach
- State the target complexity and say which constraint rules the naive version out.
- Restate the input: its shape, its size, and what is guaranteed about it.
- Name the brute-force solution and its complexity before improving on it.
Follow-up
- What is the worst case, and how likely is it on real data?
- Which test case would catch an off-by-one here?
Trade transaction processing: Given a log of execution trades, write a…
Trade transaction processing: Given a log of execution trades, write a function to aggregate trade volume and retrieve the top trades, extending the solution to correctly process short sales and credit adjustments.
Approach
- Name the brute-force solution and its complexity before improving on it.
- Restate the input: its shape, its size, and what is guaranteed about it.
- Choose the data structure from the access pattern, not from familiarity.
Follow-up
- How does this change if the input no longer fits in memory?
- Which test case would catch an off-by-one here?
Resolve position identity across a corporate action graph
Corporate actions are edges (from_instrument_id, to_instrument_id, action_type in symbol_change, merger, spinoff, expiry_roll, ratio_num, ratio_den, effective_ts) — up to 2 x 10^6 edges over 10^6 instruments. Given a position in instrument I held at t0, return the set of (instrument_id, exact rational multiplier) that it becomes at t1 > t0, following only edges whose effective_ts lies in (t0, t1]. Mergers give a node in-degree above one; spinoffs give out-degree above one. Detect cycles and report them as data errors rather than breaking them. Give both the per-query and the batch complexity.
Approach
- Start from what the shape of the answer has to be. A spinoff makes out-degree greater than one, so a position maps to a set, not to a single successor; a merger makes in-degree greater than one, so the reverse map is not a function. Anything that collapses each instrument to one representative — union-find being the usual reflex — cannot express either, and also destroys the as-of property that makes the query meaningful.
- Filter the edge set to effective_ts in (t0, t1] and traverse forward from I with DFS, carrying an exact rational multiplier along each path as a reduced (num, den) pair. Multiply at each hop, run gcd immediately to keep the components small, and use checked 128-bit multiplication so a long chain fails loudly rather than wrapping.
- Accumulate at the terminals by summing multipliers across distinct paths that reach the same instrument, because a spinoff that later re-merges into its parent genuinely contributes twice. Summing rationals means a common denominator, then a gcd reduction again.
- Run the cycle check before the path-carrying traversal, not after it. The DFS above carries a multiplier down every distinct path and so does not terminate on a cyclic subgraph at all; the traversal's termination is a precondition that Kahn establishes, not a property the traversal has on its own.
- Complexity: a single query is O(V + E) in the worst case. For a batch — end-of-day, every position in the book — sort nodes by effective_ts to get a topological order of the filtered subgraph and memoise the resolution per (node, t1), which makes the whole batch O(V + E) once instead of O(positions x (V + E)).
- Detect cycles with Kahn's algorithm on the filtered subgraph: after the queue drains, the residual set is exactly the nodes on or downstream of a cycle. Run Tarjan on the residual to name the strongly connected components of size above one, report them with the offending edges and exit non-zero. Time is monotone along real corporate actions, so a cycle is always a vendor or load error; deleting an edge to make the traversal terminate hides the error and leaves positions mapped to the wrong instrument.
- Keep ratios rational end to end. A 1/3 hop followed by a 3/1 hop — a consolidation and then a re-split, through distinct instruments — must compose to exactly 1/1, which it does with reduced rationals and does not with binary64, where the round trip lands near 0.9999999999999998 and a position quantity is then off by a share after rounding.
Worked solution 40 min
- Build the fixture inside the query window (t0, t1]: A -> B symbol_change 1/1 at ta; A -> D spinoff 1/4 at ta; B -> C merger 2/5 at tb, with t0 < ta < tb <= t1.
- Resolve a position of 1000 units of A by hand along both paths, multiplying reduced rationals rather than decimals.
- Run the traversal and compare its (instrument, multiplier) set against the hand computation.
- Extend the fixture with a chain through distinct nodes rather than a round trip: A -> E symbol_change 1/3 at ta and E -> F symbol_change 3/1 at tb, both inside the window, and confirm the multiplier carried to F composes to exactly 1/1. Pointing the second leg back at A instead would close a cycle, which is the next step's fixture and not a test of rational arithmetic.
- Add an edge C -> A at a timestamp inside the window, rerun, and confirm Kahn leaves a residual and Tarjan names the cycle before any path-carrying traversal starts.
- Remove the C -> A edge, delete the spinoff edge, and rerun to confirm the result set shrinks without disturbing C's or F's multiplier.
Follow-up
- A vendor correction arrives at 18:00 changing yesterday's merger ratio. What do you recompute, and what does that do to already-published positions?
- A cash-in-lieu component means the mapping is not purely quantity-to-quantity. Where does that land in the model?
- How do you make this resolution replayable, so a backtest run in six months resolves the same identity the live session did?
Check-then-act on a position limit under concurrent submits
A pre-trade check reads the current net position for (account_id, instrument_id) from position_snapshot where snapshot_kind = 'intraday_derived', compares it against risk_limit.limit_value for limit_type = 'max_position_qty', and if the order fits, inserts an order_event row and updates that same snapshot row. Two orders for the same account and instrument are submitted concurrently under READ COMMITTED. Name the anomaly precisely and say what separates it from write skew, say whether PostgreSQL's REPEATABLE READ prevents it and under exactly what precondition, and give three implementations that hold the cap, with the cost of each and what happens when the snapshot row does not yet exist.
Approach
- Pin the interleaving before naming anything. Both transactions read the same position_snapshot row for (account_id, instrument_id): net_qty = 900 against a cap of 1000, both find 900 + 80 inside the cap, both proceed, and both then write that same row. That makes it a read-modify-write conflict on a single row, not write skew. Write skew requires the two transactions to write rows that the other's check did not read, which is precisely not the case here, as Implementation B's conditional UPDATE targeting the very row the check read makes obvious.
- Say which failure the SET clause buys. SET net_qty = 980, the value the application computed from its stale read, is a lost update: the second write overwrites the first, the row settles at 980, and the ledger now disagrees with the 1060 the venue actually filled. SET net_qty = net_qty + 80 loses nothing arithmetically and settles at 1060, over the cap and faithfully recorded. Both admitted two orders against one reading of the headroom.
- READ COMMITTED allows it. The second UPDATE blocks on the row lock, and once the first commits it re-evaluates its WHERE clause against the newly committed row version and proceeds. The write lands against fresh data; nothing re-checks the decision that authorised it.
- REPEATABLE READ does prevent this interleaving, and the precondition is the whole answer. PostgreSQL's REPEATABLE READ is snapshot isolation: a transaction that updates a row which a concurrent transaction committed after its snapshot is aborted with SQLSTATE 40001 rather than let through, so the second submit fails and a replay of the whole transaction re-reads 980 and rejects the order. That holds only because both transactions write the same row. Derive the position from a SUM over inserted order rows instead, so each transaction only appends and neither writes what the other read, and the identical check becomes genuine write skew, which REPEATABLE READ permits and only SERIALIZABLE catches.
- Implementation A, serialize on one row: SELECT ... FOR UPDATE the (account_id, instrument_id, business_date, 'intraday_derived') row inside the transaction. Correct only if every writer takes the same lock, and it has a hole worth naming: FOR UPDATE matching zero rows locks nothing, so the first order of the day in an instrument needs INSERT ... ON CONFLICT to materialize the row, or a lock on a surrogate such as pg_advisory_xact_lock over a hash of the pair, remembering that a hash collision merely over-serializes two unrelated pairs rather than letting either through. Cost: every order in a hot instrument serializes behind one row.
- Implementation B, collapse the check and the act into one statement: UPDATE position_snapshot SET pending_qty = pending_qty + :qty WHERE ... AND pending_qty + :qty <= :limit_value, and treat zero affected rows as the rejection. At READ COMMITTED an UPDATE that blocks on the row lock re-tests its WHERE against the version the other transaction committed, so the predicate is evaluated against fresh data with no window between reading and acting, and the second order is rejected with zero rows rather than admitted. Note the level interaction before deploying it: the same statement at REPEATABLE READ or SERIALIZABLE raises 40001 instead of quietly rejecting, so a retry loop is mandatory there rather than optional.
- Implementation C, SERIALIZABLE: serializable snapshot isolation tracks read-write dependencies rather than row versions, so it covers both shapes, the single-row conflict here that REPEATABLE READ already catches and the append-only variant it does not. It aborts with SQLSTATE 40001 and does not block. The retry has to replay the transaction from BEGIN including the read the decision rested on, because an aborted transaction rejects every further command with 25P02, so retrying just the failed statement is not a thing that exists. Throughput falls as contention on the pair rises, and an unbounded retry loop turns a hot instrument into a livelock.
- Then say what a trading system actually does, because the interviewer is waiting for it: the check is not a database round trip at all. It runs in process on a single-writer order path against a preloaded, versioned limit snapshot, because one round trip costs more than the entire tick-to-trade budget. The rows are the audit record, and the check records which limit_version it evaluated against so a rejection is explainable months later.
Follow-up
- A limit is tightened at 10:00:00.000 while an order approved at 09:59:59.999 is in flight. What does the venue see, and what does your ledger record?
- Your in-process check is the authority. How do you bound its divergence from the database, and what happens when they disagree?
- Two order gateway processes serve the same account. What stops each from believing it owns the whole position?
A desk report that silently multiplies filled quantity
A report joins order_event (many rows per order_id: submit, ack, each partial_fill, fill), execution_report (one row per venue execution, keyed (venue_mic, venue_exec_id)) and risk_limit (PRIMARY KEY (limit_id, limit_version), one row per version per effective window) to show, per strategy_run_id, filled quantity, filled notional, and the max_order_notional in force. Filled quantity comes back roughly five times too large and notional shifts run to run. Identify both fan-outs, give the diagnostic that proves each one, and rewrite the query so the totals are correct.
Approach
- Name the mechanism rather than the symptom: an inner join multiplies rows, and SUM over a multiplied row set multiplies the measure. Each execution matches every lifecycle row of its order, and each limit scope matches every stored version, so the two factors compound.
- Prove each fan-out with a cardinality probe on the key alone, before touching the aggregate: GROUP BY order_id HAVING count() > 1 on order_event, and GROUP BY limit_id HAVING count() > 1 on risk_limit. Then compare COUNT() of the joined set against COUNT() of execution_report restricted the same way; the ratio is the multiplier.
- Fix the execution side by aggregating before joining: a subquery summing last_qty and the notional per order_id, joined one-to-one against a genuine one-row-per-order source such as the submit event, instead of joining the event log directly.
- Fix the limit side with a LATERAL that picks the one version in force: effective_from <= the order's sent_ts AND (effective_to IS NULL OR effective_to > sent_ts) ORDER BY effective_from DESC LIMIT 1. Picking by MAX(limit_version) is a different answer and usually the wrong one, because the newest version may not have been in force when the order was sent.
- Scale notional correctly while you are in there: last_px is an integer at the instrument's price_scale and derivatives carry a contract_multiplier, so notional is last_qty * last_px * contract_multiplier / 10^price_scale, with both attributes resolved from the instrument version as of the execution.
- Reject the reflex fixes explicitly: SELECT DISTINCT and SUM(DISTINCT last_qty) both change the answer by collapsing two legitimately equal fills into one.
Worked solution 30 min
- Reproduce on a fixture: one order with five lifecycle rows and two fills of 100 each, and one limit scope carrying three versions.
- Run the naive join and confirm filled quantity comes back as 200 * 5 * 3 = 3000.
- Rewrite with a pre-aggregated execution subquery and a LATERAL limit lookup, and confirm 200.
- Add a second order to the same run and confirm the run total is the sum of the two orders, not a multiple of it.
- Add a sixth lifecycle row to the first order and confirm no total moves.
Follow-up
- A LEFT JOIN to risk_limit would keep orders that matched no limit. What does that do to your totals against an inner join, and which do you actually want?
- How would you catch this class of bug automatically before the report ships to a desk?
- Which of these joins would you push into a materialized view, and what event invalidates it?
Implement a game board simulator: Build a class representing a 2D grid…
Implement a game board simulator: Build a class representing a 2D grid game where pieces dropped from the bottom shift existing pieces upward, with validation logic to detect matching sequences along rows and columns.
Approach
- Work from the requirement backwards to the design.
- Clarify what is being asked and what a complete answer contains.
- State your assumptions explicitly before working the problem.
Follow-up
- How would you know your answer was wrong?
- What assumption would you test first?
Visual editor state tracking: Design a simple parenthesis-matching str…
Visual editor state tracking: Design a simple parenthesis-matching structure, then extend it to store structural metadata to render editor visual cues.
Approach
- State your assumptions explicitly before working the problem.
- Clarify what is being asked and what a complete answer contains.
- Say what you would check first and why it is the highest-information step.
Follow-up
- How would you know your answer was wrong?
- What assumption would you test first?
Design a interactive text editor buffer: Implement a backend class for…
Design a interactive text editor buffer: Implement a backend class for a simple code editor supporting text insertion, line-by-line navigation, and block selection expansion/shrink.
Approach
- Say what you would check first and why it is the highest-information step.
- Work from the requirement backwards to the design.
- State your assumptions explicitly before working the problem.
Follow-up
- What assumption would you test first?
- How would you know your answer was wrong?
Recover an order session that dropped mid-fill
A venue session drops at 10:14:03 with three orders live: one submitted 8 ms earlier with no ack, one partially filled at 300 of 1,000, and one with a cancel request outstanding. The session returns 400 ms later and the venue replays execution reports it may already have delivered. An independent drop-copy stream is available. Design the recovery: what the gateway is entitled to believe about each order, what it may send while state is unknown, how replayed reports are applied, and when strategies may quote again. Name the trade-off you are making and what it costs.
Approach
- Classify by what is known rather than by the local status field. The unacked submit is ambiguous in both directions: the venue may hold it, may have filled it, may never have seen it. The partial fill has a known lower bound of 300 on cum_qty and an unknown upper bound. The outstanding cancel may have been applied or may have been beaten by a fill already matched.
- Resolve by asking, never by resending. On reconnect issue an order status request per live order, or a mass status request, and read the drop copy as an independent witness of the same facts. The client order id was persisted before the send precisely so the venue can be asked about it; resending the submit is the single action that converts the ambiguity into a real duplicate position.
- Apply the replayed reports through the same idempotent path as live ones: deduplicate on (venue_mic, venue_exec_id) and take the venue's cum_qty as authoritative over anything accumulated locally. Expect is_possible_duplicate to be set on some replayed reports and not others; the flag is a hint from the session layer, not the mechanism that makes reapplication safe.
- Make the consistency-versus-availability call and say what it costs. While any order's state is unknown the position is unknown, so every position-dependent risk check is evaluating a number that may be wrong. Permit risk-reducing actions, refuse new risk, and put a deadline on it: if status has not resolved within a stated number of seconds, escalate to a human and use the venue's cancel-on-disconnect if it offers one. The price is going dark for the 400 ms plus resolution time, and the thing bought is never hedging a position that does not exist.
- Close the loop afterwards. Reconcile the recovered state against the drop copy immediately and against clearing at end of day; a fill that appears only on the replayed stream and never in the status response is exactly the discrepancy position_snapshot's break column exists to surface rather than absorb.
Worked solution 35 min
- Build a fake venue that acks, fills, disconnects on command, and on reconnect replays the last N reports with is_possible_duplicate set on some and not others.
- Drive all three scenarios and record the gateway's state before the drop, after reconnect, and after status resolution.
- Run the same scenario twice with the replayed reports delivered in different orders.
- Have the fake answer the status request for the ambiguous order two ways, unknown and filled, and follow both branches to the end.
Follow-up
- The status response says filled 500, the last live report said 300, and 300 has already been hedged. What is the sequence of actions now?
- Cancel-on-disconnect is available on this venue. What does turning it on cost you on a day with a two-second network blip?
- How do you test this without a venue, and what is the minimum fidelity the fake needs to be worth trusting?
Instrument cache flush degrades every book at once
At 13:05 a vendor correction reaches the reference service. Within two seconds its request rate rises forty-fold, p99 goes from 3 ms to 2 s, callers time out and retry, and the market data gateway marks books degraded because it cannot resolve symbology. Every service caches instrument_version with a five-minute TTL and flushes the entire cache on a correction notice. Give an ordered checklist that distinguishes a capacity problem from a stampede, and a fix that preserves as-of resolution for replay.
Approach
- Decide whether demand rose or supply fell. Compare distinct keys requested against total requests through the spike window. Forty times the requests over roughly the same key set is a stampede compounded by retries; forty times the distinct keys is genuine new demand and wants a different fix entirely.
- Check whether misses are correlated across processes. A global flush makes every instance miss the same key in the same instant, so the service receives one request per instance per key rather than one request per key. A uniform TTL does the same thing more slowly by aligning expiry across instances that started together.
- Quantify what the callers add before touching the server. A client that retries a timeout without backoff and without jitter multiplies an overload it is already inside; count retries separately from first attempts and state the amplification factor.
- Narrow the invalidation. A correction affects specific instrument_ids, and flushing discards 10^4 to 10^6 unrelated entries to fix a handful. Invalidate by key, which requires the notice to carry the affected instrument_id list rather than being a bare signal.
- Coalesce and stagger. One in-flight fetch per key per process with concurrent callers awaiting that single fetch bounds fan-out to the process count; TTL jitter stops survivors re-aligning; a bounded retry budget with backoff stops the client side recreating the burst.
- Handle the degraded case honestly. Serving a stale definition is only acceptable where the caller records which version it served, because a replay must resolve symbology exactly as the live session did; where it cannot, the correct behaviour is the one the gateway already took - mark the book degraded rather than price off a guess.
Follow-up
- Stale-while-revalidate would have kept the gateway quoting through this. When is that the right call, and when does it become a correctness bug?
- The correction notice is a topic every service subscribes to. What would you change about the notice itself?
- What signal would have made this visible as a design flaw before it was an incident?
For a candidate senior enough that the loop turns on design and judgement rather than on whether the coding round gets finished. Five days build one system properly and then stress it; coding gets a single maintenance day, on the assumption that the risk at this level is an unexamined tradeoff rather than a missed algorithm.
Prepare, practise & reflect
One practical outcome each day. Spend longer where you need it.
0 / 7 done01Online assessment: test harness and spreadsheet
- Solve the reported bracket-validation and run-length encoding questions in a plain editor under a timer. Write a small test main first that feeds the stated examples plus an empty input and a single element.
- Some tracks report an Excel data analysis task. Practise the bank question on computing haircuts with Excel formulas, then rehearse lookups, conditional sums, absolute versus relative references and a pivot table on a raw dataset.
- After each problem, list the inputs your harness did not cover, add them, and rerun.
Deliverable: Two solved problems with their test harnesses, and one spreadsheet that cleans and aggregates a raw dataset with formulas you can explain line by line.
Practice prompt ↗Practice prompt ↗Worked solution ↗02Coding questions that grow in stages
- Parentheses: write the validator with a stack, then extend it to return the matching index for each bracket and the position of the first unmatched one, keeping the part-one tests passing.
- Run-length encoding: write the encoder and decoder, then a stateful stream decoder that accepts chunks split mid-run and mid-count. Test a chunk boundary that falls inside a multi-digit count.
- Do the bank's Collapsible Code Editor: Brace Matching and Toggle, and say aloud which data structure part one should leave behind for part two.
Deliverable: Three solutions, each with part-one and part-two tests in one file, and a one-line note per problem on what you would have built differently had you known the extension.
Practice prompt ↗Practice prompt ↗03Trade data, ordering and exact results
- Reported trade processing: aggregate volume per symbol and return the top trades with a size-k heap (O(n log k)), then extend it to short sales and credit adjustments using signed quantities.
- Work the bank's Top Trades From Event Sequence and Sort Trade Executions Into a Canonical Order, writing the comparator and its tie-break rule explicitly.
- Do the worked coding exercise on resolving positions across a corporate action graph (drill-coding-3). Compute the {C: 400, D: 250} fixture by hand before reading the solution.
Deliverable: Trade aggregation with short-sale handling and tests, a canonical-order comparator with its tie-break written out, and your hand computation of the corporate-action fixture.
Practice prompt ↗Practice prompt ↗04Class design for stateful tools
- Reported game board with bottom insertion: write insert(column, piece) and winner() signatures first, choose a per-column representation, and state which rows a bottom insert changes. Then do the bank's Bottom-Insertion Connect Game: Detect the First k-in-a-Row Winner.
- Reported text editor buffer: support insertion, line-by-line navigation and selection expand/shrink. Compare a list of lines with a gap buffer for these operations and state the cost of each in your choice.
- Reported visual editor state tracking: build parenthesis matching, then store per-pair metadata such as depth and matching index so a renderer can highlight or fold blocks (see the bank's Visual Code Editor Folding).
- Reported class interface wrap: given a provided interface, write a wrapper that meets a target API, with explicit data mapping and error checks.
Deliverable: Four class designs, each with its public interface, its chosen representation, the cost of every operation, and one test per method.
Practice prompt ↗Practice prompt ↗Worked solution ↗05Probability and combinatorics out loud
- Reported three-player dice game: ask how two-way ties at the top are handled. Under a rule that always ends with one winner (such as re-rolling any top tie), condition on the game not resetting and check that the results sum to one; then redo it with one player rolling at least a 4.
- Reported palindromic permutations: a palindrome exists only if at most one character count is odd, and then the count is floor(n/2)! divided by the product of floor(c_i/2)! over the characters. Verify on a small string by listing the permutations.
- Work the bank's Conditional Probability With Balls, Optimal Stopping With Square-Number Ruin and Optimize a Two-Box Place-or-Take Game, stating the sample space before any arithmetic.
Deliverable: Five worked probability or counting answers, each with a stated sample space and one sanity check (symmetry, sums to one, or brute-force enumeration) whose conditions you have confirmed hold.
Practice prompt ↗Practice prompt ↗06System design, SQL and debugging
- Do the worked design exercise on recovering an order session that dropped mid-fill (drill-design-4) and check that your answer never resends the ambiguous submit.
- Do the worked SQL exercise on join fan-out (drill-sql-2): reproduce the inflated 3000 on the fixture, then 200 after the rewrite. Then attempt the position-limit race drill (drill-sql-1).
- Work the cache-stampede debugging drill (drill-debugging-5) and write the ordered checks before writing any fix.
- Sketch one bank design question, such as Process One Million Quote Updates per Second or Design Jane Street Orderbook APIs, starting from requirements, throughput and failure cases before any component.
Deliverable: Checked answers to the design and SQL worked exercises, an ordered debugging checklist, and one design sketch with its requirements and trade-offs written down.
Practice prompt ↗Practice prompt ↗07Onsite rehearsal
- Run three to five mocks back to back to match the reported onsite day: one coding, one class design, one probability, and one design or debugging. Ask each partner to add a requirement midway.
- Prepare two short answers from the bank: why Jane Street, tied to the engineering work this role describes, and a walkthrough of one project with your part, one trade-off and what you would change.
- Go back over the misses from days 1-6 and redo the two problems you got most wrong, without notes.
Deliverable: Mock notes recording where your opening habits slipped in the later sessions, two rehearsed spoken answers, and the two redone problems passing their tests.
Practice prompt ↗Practice prompt ↗Worked solution ↗Expand any day for tasks and deliverables. Your progress is saved on this device.
Candidates describe this process as mostly technical, with no standard behavioural screen. Two bank questions still ask about you directly: why Jane Street, and explaining a project you worked on. Answer both with specifics you can defend under follow-up: what you built, the decision you made, what it cost, and how you knew it worked.
Estimate a kernel-bypass migration you have never attempted
Leadership asks how long it would take to move the order path off the conventional kernel networking stack, where it sits in the tens of microseconds, onto a kernel-bypass stack targeting single-digit microseconds. You have never done this migration. Give an estimate you are prepared to defend: the decomposition, the range and what drives its width, the spike that would narrow it most, and the conditions under which you would recommend not doing it at all. State what you would refuse to put a number on until the spike is finished.
Approach
- Refuse the single number first and say what you are giving instead: a range with the driver of its width named. The width is the information the requester actually needs, and handing over a point estimate destroys it.
- Decompose by uncertainty, not by component. The transport swap is well-bounded. What is not is everything currently leaning on kernel facilities: packet capture feeding the recording, session recovery on reconnect, failover between redundant lines, the timestamping source, and core pinning and isolation. Mark each item done-before or never-done and estimate only the first group directly.
- Attack the premise before estimating the work. Profile where the tens of microseconds actually sit; if a meaningful share is allocation, a lock, a synchronous log write or a page fault, the migration buys much less than the headline and the cheaper work comes first. State that as a decision gate with a threshold, not as a caveat at the end.
- Specify the spike as the narrowest experiment that collapses the widest uncertainty: one instrument, one venue session, send and receive only, tick-to-trade p99.9 measured against the current path on the same open-loop harness, with a fixed time box and a written question it must answer.
- State the costs that persist after delivery, because that is the part usually missing. Taking the network out of the kernel also takes it out of the kernel's tooling, so capture, counters and the existing packet recording need replacements, and a core is now permanently dedicated. Those are recurring costs against a one-time latency gain.
- Name the conditions for not doing it and what you will not estimate yet: if the strategies are not latency-sensitive at the margin, or the venue queue rather than your stack is the binding constraint, the answer is no — and the recovery and capture rework stays unestimated until the spike says what the new stack actually provides.
Follow-up
- Give me one number anyway, with the probability you attach to it.
- The spike shows 4 microseconds where you projected 9. What do you do with the estimate?
- What would you cut to get half the benefit in a quarter of the time?
Retract a latency result you had already published
You reported that a change cut p99 tick-to-trade by 40 percent, and the figure is now in a deck. A colleague shows that your harness sent the next request only after the previous reply arrived, so it stopped issuing load whenever the system stalled. Describe a time you retracted a result. State how you confirmed the error, who you told and in what order, what the corrected number was and how it was measured, and what you changed about how results get published so the next one is checkable by someone else.
Approach
- Confirm before announcing, but time-box the confirmation. Re-run under an open-loop generator that holds the intended send schedule and records latency from intended send time rather than actual send time, then compare it against the closed-loop run on the same build.
- Explain the mechanism precisely enough that the retraction is credible: a closed-loop harness never issues the requests that would have arrived during a stall, so the stall is sampled once instead of at the rate it would really have faced. That is coordinated omission, and it can understate the tail by an order of magnitude — so the correction is usually not a small adjustment to the same conclusion.
- Tell the people acting on the number before the people judging you, and say which decisions were made on it. If work was scheduled or descoped because of the figure, that belongs in the first sentence of the retraction, not the last.
- Give the corrected figure with its method attached: percentiles from a high-dynamic-range histogram, the load pattern, and the utilisation it was taken at. A tail number without a utilisation is not a number, because waiting time rises sharply as utilisation approaches one and real market data bursts harder than the queueing models that describe it.
- Separate what still holds from what does not. The change may remain a genuine improvement of smaller size, and saying so is part of being accurate — over-retracting is a failure of accuracy in the other direction.
- Change the process rather than only the number: require the harness type and the utilisation on every reported latency result, and publish percentiles rather than means by default. Say whether that was adopted or quietly ignored.
Follow-up
- At what utilisation were both numbers taken, and why does that matter more than the change you made?
- Your open-loop generator cannot keep up at the target rate. How do you tell that apart from the system being slow?
- What would you need to see before trusting a latency claim from someone else?
Ship an order gateway with named, scheduled reconciliation debt
A venue connection must be live for a session start in three weeks. The order state machine, idempotent application on (venue_mic, venue_exec_id) and the pre-trade check are done. Drop-copy reconciliation and trade_correct / trade_cancel handling are not. Describe a time you shipped with known debt. State exactly what you cut, the detector you put in its place, the date the debt was scheduled for, who agreed to it, and what the debt actually cost before it was paid. Include the item you cut that you should not have.
Approach
- Split the cut list into two piles out loud: things that make the system slower to operate, and things that make it silently wrong. Only the first pile is negotiable, and saying so is the whole judgement being tested.
- Place trade corrections in the right pile. A fold that only adds quantities cannot represent a negating entry referencing an earlier execution at all, so cutting trade_correct is not an unhandled edge case — it is a position that is wrong with nothing raised. If you cut it, the compensating control is a break report that blocks the next session, not a log line.
- Attach a detector, a threshold and an owner to every item in the silently-wrong pile. Without drop-copy reconciliation the control is an end-of-day diff of derived against clearing positions, paging a named person on break_qty != 0, with a stated maximum position size until the real thing lands.
- Make the schedule concrete. The debt lands in a named release with a ticket, and the interim risk limit is what gets relaxed when it lands — which gives the desk a reason to care about the date instead of treating it as engineering's problem.
- Report what it actually cost: how many breaks per day, how much manual work, whether any of it reached a position, and which cut you would take back. The signal is your calibration, not your willingness to ship.
Follow-up
- A trade correction arrives for a fill booked three sessions ago. What does your compensating control actually do with it?
- The debt slipped twice. What changes on the second slip?
- How would you scope this if the date were immovable and the desk wanted twice the size?
- 01
Why Jane Street? Tie your answer to the engineering work the role involves, such as trading systems, data pipelines or internal tools, rather than to the firm's reputation.
- 02
Explain a project you worked on: the problem, your specific part, one trade-off you chose and why, and what you would change now.
- 03
Take code you wrote to solve an interview-style problem and describe how you would turn it into a reusable library or API: the interface, the error handling and the tests.
- 04
Describe a time you retracted a result you had already shared: how you confirmed the error, who you told first, and what you changed so the next result could be checked.
- 05
Describe a time you shipped with known debt: what you cut, the check you put in its place, and which cut you would take back.
- 06
Tell me about a time a reviewer's or colleague's question changed your approach midway, and how you tested their point before acting on it.
Is this an official Jane Street interview guide?
No. It is PracHub's own research and practice material for the Software Engineer role at Jane Street. Rounds and questions reflect what candidates have reported, not a process Jane Street has published, and they change over time. Confirm the current format and scope with your recruiter.
PracHub interview research ↗Do I need prior experience in finance or quantitative trading to apply?
Reports say no finance background is required and that domain concepts are taught on the job. Some reported questions do use trading vocabulary, such as trade logs with short sales, order matching and order books. Learn what an order book, a fill and a short sale are well enough that the wording of a prompt does not slow you down.
PracHub interview research ↗Do I need to code in OCaml during the interview?
No. Reports say candidates can use a mainstream language they are comfortable with, such as Python, C++ or Java, even though OCaml is the firm's primary language. Use the language you know best. One you know only passively costs you time on syntax and library lookups during live coding.
PracHub interview research ↗How difficult are the interviews compared to standard FAANG coding screens?
The reported questions lean less on memorised algorithm tricks and more on practical, multi-part problems where each requirement builds on the last. Examples include a bracket parser that later returns positions and a run-length encoder that later handles partial streams. Prepare by extending your own solutions under new requirements, not only by solving new problems.
PracHub interview research ↗What is on the online assessment?
Candidates report an online assessment or take-home task that may be a coding assessment or a data analysis task, with some tracks reporting a data challenge in Excel. Ask your recruiter which format applies. For coding, test against inputs the examples do not show. For Excel, practise lookups, conditional aggregation and pivot tables until you can build them without searching.
PracHub Software Engineer practice ↗Is there a behavioral round?
Candidates describe the process as mostly technical, without a standard behavioural screen. Still prepare two answers that appear in the bank: why Jane Street, and a walkthrough of a project you worked on, covering your part, a trade-off you made and what you would change.
PracHub Software Engineer practice ↗What should I do if I get stuck during live coding?
Say out loud what you are trying to achieve and where the approach breaks, then try a small concrete input. If the interviewer offers a hint, test it against that input rather than defending your first approach. Reports describe these sessions as collaborative, so a hint you apply well is better than a stall.
PracHub Software Engineer practice ↗How much probability and math should I prepare?
Reported questions include a three-player dice game, counting palindromic permutations, and speed, rate and expected-value puzzles. The bank adds conditional probability and optimal stopping. Be fluent with conditioning, expected value and basic counting. Practise stating the sample space and any tie or reset rule out loud before calculating, and check answers with symmetry, a sums-to-one test or brute-force enumeration once you have confirmed the rule makes that check valid.
PracHub Software Engineer practice ↗Sources & methodology 3 sources ↗
Official role evidence, timestamped platform data and clearly labeled preparation advice.
- 01PracHub interview research ↗
PracHub editorial research into this company and role, maintained with this guide. Candidate-reported, not an employer publication.
platform · Accessed 2026-09-24 - 02PracHub Software Engineer practice ↗
Cross-company practice questions for this role.
platform · Accessed 2026-09-24 - 03PracHub interview preparation framework ↗
The framework the preparation plan follows.
platform · Accessed 2026-09-24