Skip to content
Multi-Currency Systems: Engineering Money Across Borders 2 min

Multi-Currency Systems: Engineering Money Across Borders

SD
ScaleDojo
May 11, 2026
2 min read528 words
Multi-Currency Systems: Engineering Money Across Borders

The $0.01 Bug That Cost Millions

A trading platform stored prices as floating-point numbers. On one trade, 0.1 + 0.2 evaluated to 0.30000000000000004 instead of 0.3. Across millions of transactions per day, these rounding errors accumulated into real money: some accounts gained fractions of cents, others lost them. The total discrepancy reached $2.3 million before anyone noticed. The fix required reprocessing 18 months of transactions.

Rule 1: Never Use Floating Point for Money

Floating Point Disasters:

  Language       Expression             Result
  -----------    --------------------   ----------------------
  Python         0.1 + 0.2              0.30000000000000004
  JavaScript     0.1 + 0.2              0.30000000000000004
  Java (double)  0.1 + 0.2              0.30000000000000004

  The fix: store money as integers in smallest denomination

  Currency   Amount    Stored As    Subunit
  --------   -------   ----------   --------
  USD        $10.99    1099         cents (10^-2)
  EUR        9.50      950          cents (10^-2)
  JPY        1500      1500         no subunit (10^0)
  BHD        5.123     5123         fils (10^-3)
  BTC        0.0001    10000        satoshi (10^-8)

  Data type: BIGINT (not INT - overflows at $21M in cents)
  Column: amount BIGINT + currency CHAR(3)

Exchange Rate Architecture

Exchange Rate Handling:

  [Rate Provider]  (Open Exchange Rates, ECB, Bloomberg)
       |
  Poll every 60s (e-commerce) or every 100ms (trading)
       |
  [Rate Cache]  rates stored with timestamp
       |
  rate_snapshots table:
  +----------+----------+----------+--------------------+
  | from_ccy | to_ccy   | rate     | fetched_at         |
  +----------+----------+----------+--------------------+
  | USD      | EUR      | 0.9234   | 2024-01-15 14:30:01|
  | USD      | JPY      | 148.52   | 2024-01-15 14:30:01|
  +----------+----------+----------+--------------------+

  Critical rules:
  1. SNAPSHOT the rate at transaction time
     Store rate_used IN the transaction record
     Auditors need: 'what rate was applied?'

  2. NEVER re-convert stored amounts
     Once $10.99 is stored, it stays $10.99
     Conversions are explicit, one-time operations

  3. ADD a margin (1-3%) to mid-market rate
     Your actual exchange cost is never the mid-market rate

  4. Transaction record:
     amount: 1099, currency: USD
     converted_amount: 1015, converted_currency: EUR
     exchange_rate: 0.9234, rate_timestamp: 2024-01-15T14:30:01Z

Currency-Aware Rounding

Rounding Rules by Currency (ISO 4217):

  Currency   Code   Exponent   Rounding
  --------   ----   --------   -------------------------
  US Dollar  USD    2          Round to nearest cent
  Euro       EUR    2          Round to nearest cent
  Yen        JPY    0          Round to whole units
  Dinar      BHD    3          Round to 3 decimal places
  Bitcoin    BTC    8          Round to satoshi

  Common mistake: hardcoding 2 decimal places for all currencies
  JPY 1500.49 should round to 1500, not 1500.49
  BHD 5.1234 should round to 5.123, not 5.12

  Use libraries that know ISO 4217:
  - Python: py-moneyed, babel
  - JavaScript: Dinero.js, currency.js
  - Java: Joda-Money, JSR 354
  - Ruby: money-rails

Interview Tip

When asked about handling money in a system, say: 'I would store all monetary values as BIGINT integers in the smallest denomination (cents for USD, satoshi for BTC) with a CHAR(3) currency code per ISO 4217. Never use float or double. For multi-currency, I would snapshot the exchange rate at transaction time and store it in the transaction record for auditability. Rounding rules vary by currency (JPY has 0 decimals, BHD has 3), so I would use a currency-aware library like Dinero.js rather than hardcoding 2 decimal places.'

<
Multi-Currency Systems: Engineering Money Across Borders - Architecture Diagram
Architecture overview
/blockquote>

Key Takeaway

Store money as integers in the smallest denomination. Never use floating point. Always save the exchange rate at transaction time for auditability. Use ISO 4217 for currency codes and respect per-currency rounding rules. Libraries like Dinero.js or Money-Rails handle these edge cases for you.

Enjoyed this article?

Share it with your network to help others level up their system design skills.

Discussion0

Join the Discussion

Sign in to leave comments, reply to others, or like insights.

Sign In to ScaleDojo

No comments yet. Be the first to start the thread!

Related Articles

Enjoyed this content?

Your support keeps us creating free resources

We put a lot of hours into researching and writing these guides. If it helped you, consider buying us a coffee. Every bit goes toward keeping ScaleDojo's content free and growing.

$

One-time payment via Stripe. ScaleDojo account required.

ScaleDojo Logo
Initializing ScaleDojo