Let the Server Do the Money Maths
Floating-point rounding, hard-coded currencies and duplicated pricing logic in the UI: why price conversion and money calculations belong behind an API, with base and term currencies explicit and a decimal library wherever numbers are money.
On this page
Some of the most stubborn bugs I’ve chased in a trading UI weren’t about rendering at all. They were arithmetic. A
value that should display as 0.15 showing as 0.14. A quantity rounded to the wrong step size. A conversion that only
worked when the quote currency happened to be US dollars. All of them came from doing money maths in the browser.
Floating point is not money
JavaScript numbers are binary floating point. Most decimal fractions can’t be represented exactly:
0.1 + 0.2; // 0.30000000000000004
(1.005).toFixed(2); // "1.00", not "1.01"
For display that’s sometimes tolerable. For prices, quantities, fees and anything a user acts on, it isn’t. Rounding twice (once in a calculation, once for display) compounds the error, and the user sees a number that disagrees with what the server will actually execute.
The fix on the client, where you must calculate, is a decimal library (decimal.js, big.js or similar) for every value
that represents money or quantity, with an explicit rounding mode. On the server, use the language’s decimal type
(BigDecimal in Java, Decimal in Python), or integer minor units where the precision is fixed.
Base and term, never “USD”
A trading pair has a base asset (the thing you’re buying or selling) and a term or quote asset (what the price is expressed in). A lot of code quietly assumes the term is US dollars, because it usually is. Then someone lists a pair quoted in something else and every notional value, conversion and display is wrong.
Make both explicit everywhere: in API responses, in types, in component props. A price without its term currency is an incomplete value.
Why conversion belongs behind an API
Converting a quantity in one asset to a notional value in another needs a reference price, the instrument’s rules (minimum order size, step size, decimal places per asset) and a decision about which price source to use. When that lives in the UI:
- The logic is duplicated in every component that needs it, and drifts.
- It disagrees with the server, which does its own calculation when the order is executed.
- It’s hard to change. Adding a new term currency means touching the front end everywhere.
A conversion or pricing endpoint fixes all three. The client sends the base, term, amount and side; the server returns the converted value using the same rules and price source it will execute against, with precision and step size already applied. The UI displays it and stays dumb about money.
There’s still client-side work: validation as the user types needs to feel instant. The balance I’d aim for is that the client does provisional calculation for responsiveness, using the same instrument rules delivered by the API, and the server is always the authority for anything submitted.
Precision is data, not code
Decimal places, minimum order quantity and step size vary by asset and by venue, and sometimes by user preference for
display. Those should come from reference data, not constants scattered in components. A quantity snaps to the step size
with something like floor(value / step) * step, but only if step is correct for that instrument, and only in decimal
arithmetic.
The broader lesson for a back-end mindset
Domain rules belong with the domain. The front end should own presentation and interaction; the server should own anything that must be correct and consistent across every client. That’s the same instinct behind API Modelling and typed contracts (TypeScript as a Team Contract): make the server’s promises explicit, then let the UI rely on them.
Related: Designing Snapshot and Delta APIs · REST API Design Trade-offs: Bulk Deletes, Request Bodies and Cancellation
- #money
- #decimal
- #currency
- #pricing
- #api-design
- #floating-point
↩ Linked from (1)
- Spring and Java, RefreshedGrowing
…lk Deletes, Request Bodies and Cancellation, API Modelling). Money needs BigDecimal. Never double for prices (Let the Server Do the Money Maths).
↪ Links to (4)
Related by topic
- Growing
Where Content Should Live: Markdown, a Headless CMS, or Both
Frontend craft - Growing
AG Grid Performance Patterns
Real-time UIs - Growingcase study
Building a Graph Component Library
Frontend craft - Growing
Choosing Frameworks and Standards for 80 Sites
Frontend craft