Take-home: trade reconciliation

hard~300 min#correctness#data#take-home#trading

Two systems record the same trades and disagree. Write a tool that reconciles them.

Input: two CSV files, each with columns trade_id, timestamp, symbol, side, quantity, price. They should contain the same trades. They do not.

Requirements

  1. Report trades present in one file and missing from the other, in both directions.
  2. Report trades present in both where any field differs, showing which fields and both values.
  3. Handle a file that does not fit in memory. State the size at which your approach would need to change, and what you would change it to.
  4. Output must be usable both by a human reading it and by another program consuming it.

Explicitly not specified — decide and document:

  • Whether a price differing by 0.0000001 is a mismatch. (Think carefully before answering.)
  • Whether timestamps in different timezones or precisions are equal.
  • Whether a duplicate trade_id within one file is an error, and what to do with it.
  • What happens on a malformed row — abort, or skip and report.

Time budget: five hours.

Deliver: a repository and a README covering how to run it, your decisions on the above, the memory characteristics of your approach, and what you would change for a 500GB input.

Solution

What a strong submission looks like.

Float comparison is the trap, and it is the main thing being tested. A submission comparing prices with == will report spurious mismatches on data that round-tripped through a float, and a candidate who does not notice has told the reviewer something important. The strong answer is to parse prices as decimals or scaled integers and compare exactly; the acceptable answer is a tolerance with a stated justification for its size. What is not acceptable is == on a float with no comment.

Memory. The naive approach loads both files into dictionaries — fine for the sample data and stated as fine, with the crossover point identified. The better answer sorts both files by trade_id and merges them in a single streaming pass, which is O(1) memory beyond the sort and handles arbitrary size. Either is acceptable if the README says which one it is and why. Claiming to stream while holding a dictionary of every row is not.

Duplicates. Real reconciliation data contains duplicate ids, and a tool that silently keeps the last one is producing wrong answers quietly. Detecting and reporting them is a strong signal.

Output. Two formats — a human summary and machine-readable rows — or one well-chosen format that serves both. A tool whose output can only be read by a person is a tool nobody can build on.

Malformed rows. Skipping silently is the worst option, because a reconciliation report that omits the rows it could not parse is actively misleading. Abort, or skip and report the count and the line numbers.

What distinguishes the top submissions: the README leads with the decisions and their reasoning rather than with installation instructions, and the float question is addressed before the reviewer has to go looking for it.