You bought 0.5 BTC at $30,000. Months later you bought another 0.5 at $70,000. Then you sold 0.3. What did the BTC you are still holding cost you, and did you make money on the sale?
There is more than one defensible answer, and the one most crypto trackers use is weighted average cost. This post works through what that actually means, with numbers, and then covers the four edge cases where the arithmetic is easy but the implementation usually goes wrong.
The formula
Weighted average cost treats every unit of an asset as interchangeable. You hold a pool of coins with one blended cost per coin, and every purchase re-blends it:
new_avg = (old_avg × old_qty + price × qty) ÷ (old_qty + qty)Run the example through it. You start with nothing. The first buy sets the average at $30,000 on 0.5 BTC. The second buy blends in:
(30,000 × 0.5 + 70,000 × 0.5) ÷ 1.0 = $50,000So you hold 1.0 BTC at an average cost of $50,000. Not $30,000, not $70,000 — one number covering the whole pool.
What a sale does — and does not do
Sell 0.3 BTC at $80,000. The realised profit is measured against the average, not against any particular purchase:
(80,000 − 50,000) × 0.3 = $9,000 realisedHere is the part people get wrong: the sale does not change your average cost. You now hold 0.7 BTC, still at $50,000 each. Selling removes coins from the pool at the pool’s price; it does not re-price what is left. If your tracker’s average cost moves when you sell, it is doing something else and you should find out what.
| Event | Quantity held | Average cost | Realised P&L |
|---|---|---|---|
| Buy 0.5 @ $30,000 | 0.5 | $30,000 | — |
| Buy 0.5 @ $70,000 | 1.0 | $50,000 | — |
| Sell 0.3 @ $80,000 | 0.7 | $50,000 | +$9,000 |
| Transfer 0.7 to a Ledger | 0.7 | $50,000 | +$9,000 |
Edge case 1: transfers are not trades
That last row is the one that catches trackers out. Moving coins from an exchange to a hardware wallet changes where they are and nothing else. Your quantity is the same, your cost is the same, and no profit or loss occurred.
Naive tools see a withdrawal from the exchange and an arrival at the wallet, and book a disposal followed by an acquisition. That single mistake manufactures a fake realised gain and then resets your cost basis to the transfer-day price — corrupting every number downstream. Cost basis has to be tracked per asset across your whole portfolio, not per venue, precisely so that moving coins around is a non-event.
Edge case 2: acquisitions with no price
An airdrop lands. A staking reward accrues. What did those coins cost you?
The tempting answer is zero, and it is wrong in an actively harmful way. Folding a free coin into the pool at a cost of zero drags your average down and manufactures profit that never existed — the more you were airdropped, the more imaginary gain appears. The right treatment is to leave the average untouched and mark that quantity as not covered by any cost. If you want it counted, supply the price yourself — its market value when you received it is the usual convention.
Edge case 3: the ledger covers less than you hold
This is the most common real-world situation and almost nobody handles it honestly. Your wallet says 0.8 BTC. Your imported history only explains 0.5 of it — the rest arrived before you started tracking, or from a source you never exported.
The wrong answer is to extrapolate: take your known $50,000 average and apply it to all 0.8. That produces a cost basis, and a profit figure, for 0.3 BTC you know nothing about. It looks like data. It is fabrication.
The honest treatment splits the two:
- Value is shown on all 0.8 — you do hold it, and it is worth what it is worth.
- Profit and loss is shown on the 0.5 your ledger explains, and only that.
- The remaining 0.3 reads cost basis unknown, with a prompt to add the missing transaction.
- Portfolio-level profit percentages are suppressed while a material share is uncovered — “P&L on 62% of holdings” is a true statement; a single blended percentage would not be.
Edge case 4: fees
Fees paid to acquire coins are part of what the coins cost you, so they belong in the basis: a $10,000 buy with a $10 fee has a cost of $10,010. Fees on the way out reduce your proceeds instead. And coins paid away as a fee — a network fee denominated in ETH, say — leave the pool at the pool’s average and book a small realised loss. None of these move the needle on one trade; across a few hundred they are the difference between a strategy that looks profitable and one that is.
Weighted average versus FIFO — and the tax warning
Weighted average is not the only method. FIFO assumes the coins you sell are the oldest ones you bought; LIFO the newest; specific identification lets you nominate exact lots. On the same trades these produce different realised gains, sometimes very different ones.
Weighted average wins for understanding your own trading because it is explainable and needs no lot tracking — one number per asset, and partial sells are trivial. It is genuinely worse for tax, and here is the warning: many jurisdictions do not accept weighted average for crypto. The United States generally expects FIFO or specific identification; the UK has its own share-pooling rules with same-day and 30-day matching that resemble averaging but are not it.
So a portfolio tracker using weighted average is a tool for knowing where you stand, not a tax report. It does not track tax lots or disposal dates, and a CSV export from one is “here is my data”, not a filing-ready gain/loss statement. Take it to an accountant or dedicated tax software; do not file from it.
Why any of this matters
Cost basis is the difference between knowing what you own and knowing how you are doing. Without it, a portfolio is a list of quantities and a total that moves with the market — informative for about four seconds.
The reason to insist on the honest treatment of every edge case above is that the dishonest ones all fail in the same direction. A zero-cost airdrop, an extrapolated average, a transfer booked as a sale — each one makes your performance look better than it is. A tracker that flatters you is not a neutral tool with a small bug; it is doing the same thing your memory does, which is the exact problem a written record was supposed to solve.