← Back to work
Work

Fixing money calculations with no automated tests

Leverage, margin, liquidation and transactions were fixed in the inherited code over 29 days, each change tried by hand in a staging environment before release.

↓

What arrived

  • A purchased exchange script with a couple of weeks of one developer's changes on top.
  • No automated tests and no migrations. The schema came from sequelize.sync the first time the app started against an empty database.
  • Nothing stated what any money path was supposed to do. The running code was the only definition of correct.

How changes were checked

Each change was tried by hand in a staging environment before release. The regressions below were found there.

The order of fixes

  • Day 3: leverage, which the admin panel saved twice and nothing read.
  • Day 14: leverage applied to the margin charged when a trade opened.
  • Day 20: one margin and profit formula across the endpoints; liquidation reimplemented as a 30-second job.
  • Day 25: the single frontend store split into five, across 96 files.
  • Day 29: order execution, position close and every timed job wrapped in a database transaction. None had been.

Features in the same period

Crypto deposits in the first week, fiat deposits after, then TradingView charts with a REST price feed behind a three-second cache.

Regressions

  • The day-20 rewrite read an order's metadata as an object where it was stored as a JSON string, and limit orders got zero margin reserved. It was found and fixed the next day.
  • A bonus-balance feature on day 26 left cancelled orders holding their margin. Release on cancellation came three days later, in the change that wrapped it in a transaction.

Left open

Two of the three timed jobs, margin calls and stop-loss, were registered under the same name at handoff.

Up next
A 24-hour hold on the seller's share→