Personal, locally-run crypto tax calculator for New Zealand. Imports trades from EasyCrypto, Kraken, Stacked, XAPO, and Wirex (plus manual entry), maintains a weighted-average-cost (WAC) ledger in NZD, and produces a per-tax-year income report (NZ tax year ending 31 March, revenue-account treatment).
npm install
npm run dev # http://localhost:3000Data lives in data/cryptotax.db (SQLite, gitignored). Delete the file to start over.
Upload exports on the Import page (source auto-detected from headers; re-importing the same file is safe — duplicates are skipped):
| Exchange | Export to use |
|---|---|
| EasyCrypto | Order history CSV |
| Kraken | Documents → Export → Trades (trades.csv) |
| Stacked | Transactions CSV |
| XAPO | BTC account statement CSV |
| Wirex | Annual statement CSV (UTF-16/semicolon handled automatically) |
What gets imported: buys, sells, crypto-to-crypto trades (two linked legs), card/ATM spending (disposals at market value), and BTC interest/cashback (income at market value). Transfers between your own wallets are skipped — the cost pool is global, so moving coins doesn't change it.
Transactions without an NZD value (USD-priced or crypto-to-crypto) get historical prices automatically:
- Keyless (default): Binance daily price × ECB USD→NZD rate (frankfurter.dev). Covers BTC, ETH, and other majors with no signup.
- CoinGecko (optional): set
COINGECKO_API_KEY=...in.env.local(free demo key from coingecko.com/en/api/pricing) to cover every coin.
Prices are cached in SQLite (one fetch per coin/day, ever). Manual per-day prices and per-transaction NZD overrides are available on the Prices page and transaction edit forms.
- Weighted average cost per coin, strict chronological order, full recompute on every read (no stale state).
- Acquisition fees are capitalized into cost basis; disposal fees reduce proceeds.
- Crypto-to-crypto trades: disposal of the sold coin at market value + acquisition of the bought coin at the same value.
- Interest/cashback: income at market value on receipt; that value becomes cost basis.
- Tax-year boundaries at midnight 1 April, Pacific/Auckland.
- Oversells (selling more than the ledger holds) are computed anyway and flagged — a warning usually means an acquisition is missing from the data.
npm testCovers the WAC engine (hand-computed fixtures), tax-year boundaries (NZDT/NZST), and all five CSV parsers against format fixtures.
This is a calculation aid, not tax advice.