The tax workflow for a US retail crypto investor with accounts on more than one exchange has the same shape every time. You log into each platform in turn, find the "tax" or "history" export, click download, and end up with three CSV files on your desktop that look superficially similar and are in fact incompatible. Field names differ. Date formats differ. Quantity precision differs. The classification of a transfer to your own wallet differs. None of the files can be concatenated as-is and fed into a tax tool.
This article is a side-by-side audit of the three biggest exchanges as of early 2026, focused specifically on the things that break automated reconciliation. The point is not to complain - the exports are documented and the data is there - but to make clear what work the customer is actually being asked to do.
Coinbase: the "Gain/Loss Report" and the "Transactions" CSV
Coinbase produces two distinct downloads with overlapping but non-identical content, both reachable from the Tax Reports and Forms section:
- Gain/Loss Report (CSV). Pre-calculated capital gains by lot, in USD. Useful at a glance, but Coinbase computes the basis using its own assumptions for any coin that originated outside Coinbase. The cost basis FAQ explicitly notes that transferred-in coins may show a missing or zero cost basis.
- Transactions CSV. The raw event log: buys, sells, sends, receives, conversions, rewards. Has a "Transaction Type" column, an "Asset" column, a "Quantity Transacted" column, a "Spot Price at Transaction" column, and a "Subtotal / Fees / Total" trio. This is the file you actually want to feed into a tax tool.
Two quirks in the Transactions CSV catch out automated parsers:
- "Convert" is its own transaction type, not a pair of sell/buy events. A USDC-to-ETH conversion shows up as one row with both assets implied. Tools that expect every disposal to have a paired acquisition can mis-classify these.
- "Send" and "Receive" are both used for transfers. Coinbase does not flag whether the destination is one of the customer’s own wallets. The customer has to mark these manually if they do not want them treated as taxable disposals.
Binance.US: the "Transaction History" CSV
Binance.US documents its tax exports on the tax statements page. The primary export is a single Transaction History CSV with the following column structure (paraphrased; exact names have changed across years):
| Field | What it contains |
|---|---|
| UTC Time | ISO 8601 timestamp; second precision |
| Operation | Buy / Sell / Deposit / Withdrawal / Distribution / Staking Rewards / Commission Rebate |
| Account | "Spot", "Earn", "Margin" — routing flag for which sub-account |
| Coin | Asset symbol |
| Change | Signed quantity (negative for outgoing, positive for incoming) |
| Remark | Free text. Sometimes has the trade pair, sometimes blank |
The first quirk: a single trade is recorded as two or three rows. A spot buy of ETH with USDT shows up as one row debiting USDT, one row crediting ETH and one row debiting the fee in BNB. The pairing is implicit from the timestamp; tools have to group rows that share the second-precision UTC time and the same account into a single trade event. This is one of the most common parsing failures in automated importers.
The second quirk: Binance does not record a USD spot price for non-USD pairs. A trade of ETH for SOL is recorded with the on-platform book price, which may differ from the IRS-relevant USD spot at the second of execution. For US filing, that USD value has to be looked up from an independent price source (CoinGecko and Kaiko both publish second-level historical spot for major pairs).
Kraken: the "Trades" and "Ledgers" CSVs
Kraken’s exports are documented in the account history support article. The platform produces two complementary CSVs:
- Trades CSV. One row per trade, with the pair, type (buy/sell), price, cost, fee, and volume. Easiest to read.
- Ledgers CSV. One row per balance change, including trades, deposits, withdrawals, fees and staking accruals. The most complete record of any of the three exchanges in this article.
The Ledgers CSV is what most calculators want to ingest, because it captures everything that affects the customer’s position, including staking rewards as their own line items with timestamps and asset balances. The trade-off is that to reconstruct a single trade you have to join two rows from the Ledgers file by the "refid" column, which is the only field that links the asset-out row to the asset-in row.
One Kraken-specific quirk: the asset symbols are prefixed. BTC is "XXBT", ETH is "XETH", USD is "ZUSD". The "X" and "Z" prefixes are Kraken’s internal shorthand for cryptocurrency vs fiat. Tools have to strip the prefix and remap to the standard symbol, otherwise the asset will not match anything in the price database.
The fields nobody agrees on
| Field | Coinbase | Binance | Kraken |
|---|---|---|---|
| Timestamp format | ISO 8601 with timezone | UTC second precision, no timezone marker | Unix epoch with sub-second decimals |
| Trade representation | One row per trade, paired implicitly | Two or three rows per trade, grouped by timestamp | Two rows per trade, joined by refid |
| Internal transfer flag | None; "Send" / "Receive" | None; "Withdrawal" / "Deposit" | None; "withdrawal" / "deposit" |
| Asset symbol | Standard ticker | Standard ticker | Prefixed (XXBT, XETH, ZUSD) |
| Fee currency | Same as proceeds | Often a different asset (BNB, BUSD) | Always quoted currency of the pair |
| USD value for non-USD pairs | Computed and provided | Not provided; must be looked up | Not provided; must be looked up |
Why this matters for the customer
Three implications follow from the audit above:
You cannot just concatenate the CSVs. A tax tool that asks you to "upload your exchange data" has to know which exchange each file came from, and apply the right parser per file. Generic "drop your CSV in" tools either fail silently on edge cases or pre-process to a common format and lose information.
Internal transfers must be reconciled across exchanges. If you withdrew 0.5 BTC from Coinbase on 1 March and deposited 0.499 BTC into Kraken on 1 March (the difference being the network fee), neither exchange knows the destination of the other side. Both will treat their leg as a one-sided event. The reconciliation has to happen at the calculator level, by matching withdrawals out of Exchange A to deposits into Exchange B within a few hours, and flagging them as a same-owner transfer.
USD price lookups are not optional. For any year with non-USD pair trades, somebody has to fill in the USD value at the second of execution. Tools that skip this step silently produce a tax bill that does not match what the IRS expects to see. Tools that do it well use a high-frequency historical price source and document the lookup in the audit trail.
How our calculator handles it
The SafeFinance Crypto Tax Calculator ships with explicit per-exchange parsers for Coinbase, Binance and Kraken, plus a generic CSV mode for everything else. The user picks the exchange in the upload dialog, the right parser fires, and the tool emits a normalised internal representation that is identical regardless of which exchange the data came from. Internal transfers are auto-detected by amount + timestamp matching across files. USD spot prices for non-USD pairs are filled in from a cached public price source, with the lookup time-stamped in the audit log.
The choice of three explicit parsers (rather than one generic one) is deliberate, and it is the result of the kind of audit above. A generic parser will get you 80 percent of the way through a clean year. The remaining 20 percent is where a $5,000 mis-classification hides, and it is the one the IRS notices.