Multi-currency looks like an “add a currency column” feature — until you try to compute PnL. Because PnL requires a common unit of account, and to have that you need a price table, a rates history and clear rules on when to convert. A ledger built for multi-asset solves all three at once.
The problem
In crypto and FX, every transaction has, in practice, two currencies: what left and what came in. “I sold 0.5 BTC for R$ 175,000” isn’t a single movement — it’s two: an outflow of 0.5 BTC and an inflow of R$ 175,000. The match between them is the trade. And the gain or loss depends on the average entry price of the BTC, which is only traceable via a ledger.
Accounts with an asset dimension
The structural difference: every account has a declared asset. user:u_42:crypto:BTC and user:u_42:crypto:ETH are separate accounts. They never mix. A multi-asset transaction is simply one with entries in different currencies — and the invariant changes: Σ debits = Σ credits holds per asset, not globally.
| Account | Asset | Meaning |
|---|---|---|
user:<id>:cash:BRL | BRL | Real balance |
user:<id>:cash:USD | USD | Dollar balance |
user:<id>:crypto:BTC | BTC | Bitcoin holdings |
user:<id>:crypto:ETH | ETH | Ether holdings |
ops:pool:BTC | BTC | BTC treasury |
ops:pool:BRL | BRL | BRL treasury |
ops:revenue:spread:BTC-BRL | BRL | Spread revenue on the pair |
ops:pnl:realized:BTC | BRL | BTC realized PnL (in BRL) |
A sell order
The user sells 0.5 BTC for R$ 175,000.00. Platform spread 0.5% (R$ 875.00). The trade is a single transaction with entries in two assets:
| Account | Debit | Credit |
|---|---|---|
| ops:pool:BRL | — | 175000.00 |
| user:u_42:cash:BRL | 174125.00 | — |
| ops:revenue:spread:BTC-BRL | 875.00 | — |
| Totals | 175,000 | 175,000 |
| Account | Debit | Credit |
|---|---|---|
| user:u_42:crypto:BTC | — | 0.50000000 |
| ops:pool:BTC | 0.50000000 | — |
| Totals | 0.5 | 0.5 |
Check: in BTC, debit 0.5 = credit 0.5. In BRL, debit R$ 175,000 = credit R$ 174,125 + R$ 875. Each asset nets to zero, separately. That’s the rule that replaces single-asset “Σ debits = Σ credits”.
Realized PnL
To compute the gain on the sale, the ledger needs the average cost of the BTC that left. The most common convention (WAC — weighted average cost) lives in a materialized view per account-asset. At sale time, an additional transaction books the difference between sale value and average cost into ops:pnl:realized:BTC.
| Account | Debit | Credit |
|---|---|---|
| ops:pnl:realized:BTC | — | 20000.00 |
| ops:retained:earnings | 20000.00 | — |
| Totals | 20,000 | 20,000 |
For tax purposes, the entry history shows every acquisition with date, price and quantity. The supporting calculation comes straight out of the ledger — the tax authority gets everything it needs.
Mark-to-market (unrealized)
For internal reporting, holdings are marked to market daily. That doesn’t touch the asset accounts, but generates a balance_in_BRL view that queries the price table. The ledger keeps truth in native units; the reporting layer does the conversion.
Invariants
| Invariant | Why |
|---|---|
| Σ debits = Σ credits per asset per transaction | Double-entry with an extra dimension |
Account asset is immutable | Prevents posting BTC on a BRL account |
ops:pool:<asset> balance ≥ Σ user balances in the asset | Real custody ≥ internal obligation |
| Conversions run through a registered rate source | Price audit trail |
In crypto, the regulator doesn’t ask you “how much do you have”. They ask you “how do you know how much you have”.
FAQ
How do I integrate with external exchanges (Binance, Kraken)?
Each exchange is an ops:exchange:<name>:<asset>. Deposits and withdrawals move those accounts; trades inside the exchange are mirrored in your ledger via webhook. Daily reconciliation compares reported balance vs. your books.
Stablecoins — currency or crypto?
Crypto. Always. Your internal accounting must keep the asset separate (USDC ≠ USD) because the risk is different. Converting into USD is an explicit transaction, with a declared rate.
Forks, airdrops, staking rewards?
Each becomes a transaction of origin income:<type>. The ledger doesn’t care whether the source is trade, fork or reward — they’re all entries with asset, quantity and moment.
When you need this
- 1 You custody more than one currency or assetFrom the second currency on, multi-asset ledger stops being a luxury.
- 2 You compute PnL (yours or the customer's)Without an acquisition history, PnL is a guess.
- 3 You report capital-gain taxThe tax authority wants a calculation trail.
- 4 You integrate with more than one venueEvery venue brings a balance; the ledger is where they all meet.
A ledger that’s actually yours.
entrytarget.com →