2026-10-31 09:03:25 -04:00
2026-10-31 09:03:25 -04:00
2026-10-31 09:03:25 -04:00
2026-10-31 09:03:25 -04:00
2026-10-31 09:03:25 -04:00
2026-10-31 09:03:25 -04:00

Trade Ledger: Debugging Exercise

Time: 60 minutes Language: Python 3.10+ (standard library only) AI: Allowed (Codex in VS Code)

Files

File Purpose
logger.py A small logger that buffers records and writes them to a stream
ledger.py Trades, positions, and the ledger that applies trades, rebuilds from history, and reconciles
main.py Replays a sample trade list (a "blotter") through a live ledger, then does an end-of-day (EOD) rebuild and reconcile
test_ledger.py The existing test suite
python3 main.py
python3 -m unittest -v

The ticket

From: Trading Ops Priority: High

The end-of-day reconcile is reporting breaks between the live ledger and the EOD rebuild, and some desks say their average prices look wrong after big sells. We checked the logs and found no errors, and the log lines don't seem to match the trades they're about. CI is green.

Your tasks

  1. Clarify first. Before you change any code, tell the interviewer which assumptions you are making, and ask about any that are unclear.
  2. Reproduce the reported behaviour.
  3. Find and fix the 4 bugs in the codebase. For each one, explain the root cause, not only the symptom.
  4. Review the test suite. CI is green even though the code is broken. Explain why.
  5. Write your own tests. Each bug needs at least one test that fails before your fix and passes after it.
  6. Talk through your trade-offs as you go.

Given assumptions

  1. A Trade has trade_id, symbol, side ("BUY" or "SELL"), qty, and price.
  2. qty on a trade is always entered as a positive whole number. The side gives the direction.
  3. A trade with a qty or price of zero or less, or an unknown side, is invalid. It must be rejected and logged at ERROR.
  4. Positions use weighted-average cost.
  5. Realized P&L is booked only when a position is reduced.
  6. Ledger.history is the record of truth for every accepted trade. The EOD job rebuilds a fresh ledger from it.
  7. The two ledgers reconcile when every symbol has the same qty and avg_price.
  8. Every log line must name the trade it is about.
  9. A logger only writes messages at or above its configured level.
  10. Single-threaded. You don't need to handle persistence, partial fills, or fees.

Assumptions you should clarify with the interviewer

These are left open on purpose. Asking about them is part of the exercise.

  • Is short selling allowed? Can one trade move a position from long, through zero, to short?
  • When a position flips from long to short, or short to long, what should avg_price be on the new side?
  • Is a Trade object safe to modify once it has been submitted, or should it be treated as immutable?
  • Should a rejected trade appear in history?
  • Should the EOD rebuild stop on the first bad trade, or skip it and carry on? Either way, how should it report the problem?
  • Can records be lost if the process exits before flush() is called? Does that matter here?
  • Can level names be given in lowercase? Should custom levels be supported?
  • Is a tolerance of 1e-9 right for comparing prices?
S
Description
No description provided
Readme
34 KiB
0 Stars 1 Watchers 0 Forks
Languages
Python 100%