What Trading Systems Taught Me About Software Correctness
Lessons from building automated trading systems where a bug costs real money — idempotency, reconciliation, and trusting nothing.
In most software, a bug is annoying. In a trading system, a bug spends your money before you finish reading the stack trace. That pressure reshapes how you think about correctness.
Trust nothing, reconcile everything
The exchange is the source of truth, not your local state. After every action I reconcile:
local = position_store.get(symbol)
remote = exchange.fetch_position(symbol)
if local != remote:
alert(f"drift detected on {symbol}: {local} vs {remote}")
position_store.set(symbol, remote) # exchange wins
Drift is not an edge case. It's a when, not an if.
Idempotency or death
Networks fail mid-request. Did the order go through? You don't know. So every order carries a client-generated id, and re-sending it is a no-op:
- generate
clientOrderIdbefore sending - the exchange dedupes on it
- retries become safe
Make the dangerous path loud
The order placement code is the most boring, most reviewed, most logged code in the whole system.
Boring code in the dangerous places. Clever code only where mistakes are cheap.
Crossing over to AI agents
This mindset transfers directly to autonomous agents. An agent taking actions in the world is just a trading system with a fuzzier decision engine — and it needs the same idempotency, reconciliation, and loud failure paths.
Takeaways
- The external system is the source of truth; reconcile relentlessly.
- Make every action idempotent.
- Keep the dangerous code boring and observable.
Building AI agents
Related reading
Comments
Comments are enabled once giscus is configured.