Binance Transaction History Cost Basis: From CSV Export to a FIFO Number
The Binance transaction history cost basis problem has a specific shape. The export is complete, but nothing in it says "you bought 1 ETH at 2,000." You get three rows per trade, same timestamp, shuffled, with the fee in a coin you did not trade. This article walks through the job end to end: export, read the rows, clean them, separate transfers from sales, then run FIFO on a small sample with the arithmetic shown.
Full disclosure: I build Holdbound, so read the product parts with that in mind. The worked example is done by hand; check it with a calculator.
Step 1: Export the right file
Binance has overlapping export paths, and only one contains deposits and withdrawals. I checked these steps against Binance's help pages in August 2026.
Transaction records (the file you want first)
- On the website, go to Assets > Asset History.
- Hover over the export icon and choose Export Transaction Records.
- Pick a preset range (last 6 months) or Customize for older periods. Each generated statement covers up to one year, so generate one per year.
- Click generate. Binance sends an SMS or email when it is ready; the link expires after 7 days.
- Binance caps statements per month (the quota is shown in the interface; its help pages quote 15 to 40 for transaction records), so do not burn them on test exports.
Spot trade history is a separate export under Profile > Orders > Spot Order > Trade History > Export Trade History: quick export up to 6 months and 10,000 rows, generated statements up to one year each, 5 per month. It has the explicit price per fill but not deposits and withdrawals. If you import both, its rows replace the trade rows of the transaction records, never add to them.
Timestamps are UTC. A trade at 7 pm Pacific on December 31 is a January 1 trade in the CSV. Binance.US is a separate company with its own export.
Step 2: What the rows look like
The transaction-records CSV has no preamble and no totals row. Line one is the header:
"User_ID","UTC_Time","Account","Operation","Coin","Change","Remark"
Seven columns, usually quoted, one balance change per row:
UTC_Time:YYYY-MM-DD HH:MM:SS, second resolution, no zone suffix.Account: the wallet. ProcessSpot(plusFundingandEarnfor transfers and interest); skip margin and futures wallets.Operation: a free-text label. The current trade vocabulary isTransaction Buy,Transaction Spend,Transaction Sold,Transaction Revenue, andTransaction Fee. Trades executed before late 2022 still appear in a 2025 export asBuy,Sell,Fee, andTransaction Related, so one file can contain both.Change: signed decimal, 8 places in current exports, minus for outflows; older rows may use scientific notation like-3.605E-05.Remark: usually empty. Worth knowing:Binance Earnon interest rows andWithdraw fee is includedon withdrawals.
One buy, one sell, and a withdrawal look like this. Prices are implied, not stated: you divide 2,000 USDT by 1 ETH.
"12345678","2025-02-03 10:15:30","Spot","Transaction Buy","ETH","1.00000000",""
"12345678","2025-02-03 10:15:30","Spot","Transaction Spend","USDT","-2000.00000000",""
"12345678","2025-02-03 10:15:30","Spot","Transaction Fee","USDT","-2.00000000",""
"12345678","2025-05-20 14:02:11","Spot","Transaction Sold","ETH","-1.20000000",""
"12345678","2025-05-20 14:02:11","Spot","Transaction Revenue","USDT","3600.00000000",""
"12345678","2025-05-20 14:02:11","Spot","Transaction Fee","USDT","-3.60000000",""
"12345678","2025-06-09 08:40:57","Spot","Withdraw","ETH","-0.30000000","Withdraw fee is included"
Other families you will meet: Deposit, Fiat Deposit, Withdraw, Fiat Withdraw; Binance Convert (two rows, plus and minus, same second, no fee row because the spread is inside the price); Small Assets Exchange BNB for dust; Earn labels such as Simple Earn Flexible Interest and Staking Rewards; and Transfer Between Main and Funding Wallet, twice with opposite signs and different Account values. Binance adds labels a few times a year; keep anything unrecognised rather than dropping it.
Step 3: Cleaning
Group by timestamp before you pair anything. If a market order filled nine times within one second, the file has nine Transaction Buy rows, nine Transaction Spend rows, and nine fee rows, shuffled, with no order id and no price. Sum Change by (UTC_Time, Operation, Coin) and emit one trade per timestamp and pair; price is quote total divided by base total. Pairing rows one by one loses data.
Do not de-duplicate identical rows. Two identical rows in a multi-fill block are both real, and the file has no row id, so "remove duplicates" in a spreadsheet silently deletes fills. The duplicates to worry about are whole files imported twice or with overlapping date ranges. Name exports by year and never overlap them.
Fee rows. A Transaction Fee row may be in the quote asset, the base asset, or BNB if you use the fee discount, and one second can hold several fee coins. Sum fees per coin per timestamp and attach them to the trade; a BNB fee needs a dollar value at that moment first. In the US, exchange fees on a buy are added to your cost basis and fees on a sale reduce your proceeds. The example below uses that rule.
Dust and Convert. Small Assets Exchange BNB shows N negative rows for the dust coins and one or more positive BNB rows in the same second, without saying which dust became which BNB; treat it as one multi-input trade or split the BNB pro rata. Either way it is a crypto-to-crypto swap, and in the US swapping one crypto for another is a taxable sale of the coin you gave up, measured at the fair market value of what you received. The same applies to Binance Convert pairs.
Deposits versus withdrawals. A Deposit of USDT is money arriving, not a purchase; a Deposit of ETH is coins with a history elsewhere. Withdraw amounts include the network fee (the remark says so), which matters when you match them to the arrival on the other side.
Internal moves and Earn principal. Transfer Between Main and Funding Wallet nets to zero. Simple Earn Flexible Subscription and Redemption move your own coins between Spot and Earn, neither income nor sales. Only Interest and Rewards rows are new coins.
Timezone. Keep every exchange in UTC, or transfers can appear to run backwards.
Step 4: Separating transfers from sales
The Withdraw row above sends 0.3 ETH to another exchange. Treated naively, 0.3 ETH vanished here and 0.3 ETH appeared over there with no cost, which is the most common reason realized gains come out far too high.
You are looking for a deposit of the same asset, on a different account, shortly after the withdrawal, for an amount equal to or slightly below what was sent; the shrink is the network fee. If 0.3 ETH leaves Binance and 0.2995 ETH lands on Kraken 20 minutes later, that is one transfer.
This is the rule Holdbound applies automatically: same asset, different account, deposit within 48 hours of the withdrawal, received no more than sent, difference no bigger than a fee allowance; a matching txid is conclusive. When two candidates fit equally well, it matches nothing and lists the pair as ambiguous for you to decide. You can link, unlink, or exclude any pair by hand; a manual override always wins, and a forced link that breaks the rules is kept but labelled manual with the violations listed. Moving crypto between wallets you own is not a taxable event in the US, and the coins keep their original purchase date and cost. A network fee paid in crypto on a self-transfer is a small disposal of the coins used for the fee; whether that fee can be added to your cost basis is not addressed in official guidance, so I leave it flagged for your accountant.
Step 5: Binance transaction history cost basis under FIFO, fees included
Here is the cleaned ledger for one ETH position, from the raw rows above plus one more buy. USDT is treated as one dollar.
| # | UTC date | Event | ETH | USDT | Fee | Net cash effect |
|---|---|---|---|---|---|---|
| 1 | 2025-02-03 | Deposit | — | +5,000.00 | — | funding, not a trade |
| 2 | 2025-02-03 | Buy | +1.0 | −2,000.00 | 2.00 USDT | cost 2,002.00 |
| 3 | 2025-03-11 | Buy | +0.5 | −1,200.00 | 1.20 USDT | cost 1,201.20 |
| 4 | 2025-05-20 | Sell | −1.2 | +3,600.00 | 3.60 USDT | net proceeds 3,596.40 |
| 5 | 2025-06-09 | Withdraw to Kraken | −0.3 | — | network fee included | transfer, not a sale |
| 6 | 2025-06-09 | Deposit on Kraken | +0.2995 | — | — | matched to row 5 |
Row 2 is 2,000 plus the 2.00 fee: lot 1 is 1.0 ETH at 2,002.00. Row 3 is 0.5 ETH at 1,201.20, or 2,402.40 per ETH. Before the sale you hold 1.5 ETH with a basis of 3,203.20. Row 4 sells 1.2 ETH for 3,600.00 less the 3.60 fee: net proceeds 3,596.40.
FIFO takes the oldest coins first:
from lot 1: 1.0 ETH × 2,002.00 = 2,002.00 (lot 1 fully used)
from lot 2: 0.2 ETH × 2,402.40 = 480.48 (0.3 ETH of lot 2 remains)
basis of the 1.2 ETH sold = 2,482.48
realized gain = 3,596.40 − 2,482.48 = 1,113.92
After the sale you hold 0.3 ETH from lot 2 with a basis of 720.72 (1,201.20 − 480.48), which rows 5 and 6 move to Kraken. The 0.2995 ETH that arrives carries the March 11 date and its share of the 720.72 basis; the transfer itself is not a sale, though in the US the 0.0005 ETH that paid the network fee is a small disposal of those coins, and whether that fee can be added to basis is not addressed in official guidance. Without fees the gain would be 3,600.00 − 2,480.00 = 1,120.00; the fees moved it by 6.08, small here and not small over a few hundred trades.
The same rows under average cost
Average cost ignores lot order and uses one blended price for every unit:
total basis before sale = 2,002.00 + 1,201.20 = 3,203.20
average per ETH = 3,203.20 ÷ 1.5 = 2,135.4667
basis of the 1.2 ETH sold = 1.2 × 2,135.4667 = 2,562.56
realized gain = 3,596.40 − 2,562.56 = 1,033.84
The remaining 0.3 ETH carries 640.64 of basis, and 2,562.56 + 640.64 = 3,203.20, so nothing was lost in rounding. The gain is 80.08 lower than FIFO this year because part of the cheaper February cost was deferred; sell the rest and the two methods reach the same total.
For US readers, one sentence belongs next to any average-cost figure: average cost is a mutual-fund rule and is not a recognized method for crypto in the US. For US taxpayers the IRS recognizes specific identification (with contemporaneous records) or, by default, FIFO, applied wallet-by-wallet since 2025. Holdbound offers an average-cost mode for readers in jurisdictions that pool, such as Canada's adjusted cost base, and for comparison; which method you use is a decision for you and your accountant, not for the app.
If the import fails: the generic template
If a file will not parse, or you only have a hand-kept record, the fallback is a plain template:
timestamp,type,asset,amount,quote_asset,quote_amount,price,fee_asset,fee_amount,account,txid,note
timestamp, type, asset, and amount are required; type is one of buy, sell, deposit, withdrawal, fee, reward, or other. Write timestamps with an explicit Z so there is no zone question. The cleaned ledger above becomes:
timestamp,type,asset,amount,quote_asset,quote_amount,fee_asset,fee_amount,account
2025-02-03T10:15:30Z,buy,ETH,1.0,USDT,2000,USDT,2.00,Binance
2025-03-11T09:30:00Z,buy,ETH,0.5,USDT,1200,USDT,1.20,Binance
2025-05-20T14:02:11Z,sell,ETH,1.2,USDT,3600,USDT,3.60,Binance
2025-06-09T08:40:57Z,withdrawal,ETH,0.3,,,,,Binance
2025-06-09T09:01:40Z,deposit,ETH,0.2995,,,,,Kraken
quote_amount is the total paid or received with the fee in its own column; a fee is part of cost on a buy and reduces proceeds on a sell, the convention the arithmetic above relies on.
Where Holdbound fits, and who should not use it
Your trades stay on your computer. Pay once.
Holdbound is the tool I wrote to do Steps 2 through 5 without a spreadsheet. It is one HTML file from https://holdbound.com/download that you open in a browser; no account, no server on my side. Drop in the Binance transaction records (or OKX, Coinbase, Kraken exports, or the generic template) and it recognises the format, keeps fees attached to their trade, and carries basis across transfers with the Step 4 rule plus a manual override for the cases it refuses to guess. Cost basis runs under FIFO or average cost with fees included; the dashboard shows realized and unrealized P&L next to a trade log with notes. A holding-period card compares trades closed in under 7 days against those held longer than 90 days; performance windows, not tax categories. Data lives in the browser's IndexedDB with one-click JSON backup and restore; the app runs offline apart from the price refresh you press, which fetches prices from CoinGecko and, in the same action, a small version file from my site so it can tell you a new release exists. It exports the ledger as CSV plus an annual realized-gains summary.
The first 30 days are a free, full-featured trial. After that it is $29, once — and that buys the software, not a year of it: every version released in the following 12 months is yours to keep and keeps working forever. Updates after that are $15 a year and optional; skipping them takes nothing away. Read-only applies to one case only — a trial that ended without a purchase — and even then everything stays viewable and exportable.
You should not use Holdbound if:
- You need tax forms. The output is CSV and a yearly summary: no Form 8949, no Schedule D, no equivalent elsewhere, no tax advice.
- You are active in DeFi or NFTs. The app reads CSVs; it does not index chains.
- You trade margin, futures, or perpetuals. Rows from those wallets are skipped on import.
- You want many accounts synced automatically. No API connection; you export files and import them.
- More than one person works in the same records. Single user, single machine.
- You want someone else responsible for backups. The JSON backup is one click; pressing it is your job.
FAQ
Which Binance export do I need for cost basis? The transaction-records statement from Assets > Asset History; it is the only export with deposits, withdrawals, Convert, dust, and Earn rows.
Does a Binance withdrawal count as a sale?
Not if it went to a wallet or exchange you own: in the US that is not a taxable event and the coins keep their purchase date and cost. Match it to the deposit on the other side. The Withdraw amount includes the network fee, so the arriving amount is slightly smaller, and the fee coins themselves are a small disposal.
Can I use average cost for my Binance trades? The arithmetic works for any ledger, but average cost is a mutual-fund rule and is not a recognized method for crypto in the US. Ask your accountant before relying on either figure.
This article is for general information only — not financial or tax advice.