The moment everyone notices
It usually happens the first time somebody builds a proper record. Three platforms, one asset, a total that should be a simple sum — and the number does not match the balances.
The first reaction is to look for the mistake. Did a row get missed, a decimal misplaced, a file imported twice? Several hours later, having found nothing, the second reaction sets in: something must be wrong with one of the platforms.
Usually nothing is wrong with any of them. The differences are structural, they have specific and identifiable causes, and once you know what those are the exercise stops being an investigation and becomes a routine.
That is what this is about: the seven reasons, why none of them is a defect, and what a record should do about them instead of chasing an exact tie-out that was never going to happen.
Why this is not a bug
The expectation of exactness comes from bank statements, and it is a reasonable expectation there. A bank account has one ledger, one operator, one currency and one set of conventions. Two statements of the same period should agree, and if they do not, something is genuinely wrong.
An exchange is a different kind of object. It maintains an internal ledger for its own operations, which is not the same thing as a record of your activity. An export is a rendering of parts of that ledger, produced for your convenience, in a format the platform chose.
Two renderings can differ from each other without either being wrong — the same way two reports from the same accounting system can differ if they were run at different times, with different filters, or with different display settings.
Add several platforms with different internal designs, assets that move between them, and a chain that records some events and not others, and exact agreement stops being a realistic target.
Which is worth internalising early, because a lot of wasted effort goes into chasing a reconciliation that cannot be achieved and would not mean much if it were.
Seven reasons, at a glance
| Cause | Looks like | Size |
|---|---|---|
| Internal ledger design | Events you did not make | Small, frequent |
| Timestamp and time zone | Rows in the wrong period | Zero, but shifts periods |
| Rounding and precision | Totals that drift | Tiny each, cumulative |
| Netting of fees | Consistently understated cost | Consistent, plausible |
| Restated history | A row that changed | Occasionally large |
| Pending and settled | Something present or absent | Whole transactions |
| Off-chain versus on-chain | Activity the chain never saw | Everything internal |
The fourth is the one that causes the most damage, because it is the only one that is both consistent and invisible. Everything else either shows up as an obvious oddity or stays too small to matter.
The exchange is keeping its own books, not yours
This is the root cause behind several of the others and it is worth understanding on its own.
When you trade one asset for another on an exchange, nothing moves anywhere. The platform adjusts two balances in its own database. From its point of view that may be one event, or two, or four — a debit, a credit, a fee posting, an internal transfer between account types.
How it chooses to model that is an internal design decision, and it shows up in your export as rows you did not knowingly create. A single trade appearing as three lines is normal, not an error.
It also means the same activity produces genuinely different row counts on different platforms. Comparing “number of transactions” between two exports is close to meaningless.
The practical consequence: build your record around what you did, not around what the export rows say happened. A trade is one economic event however many lines describe it.
Timestamps, time zones and the period boundary
A difference that is zero in total and enormous in effect.
Platforms record times in different zones. Some use the account's setting, some use a fixed zone, some export in one convention and display in another. A trade at 23:40 on the last day of a period in one zone is the first day of the next period in another.
Across a year this changes nothing at all. Across a period boundary it moves an entire event from one reporting period to the other, which can matter a great deal.
It also breaks the transfer matching described in the records guide: a withdrawal and its corresponding deposit can appear hours apart, or on different days, purely because two platforms recorded the same moment differently.
The fix is unremarkable — normalise everything to one zone as you read it, and keep the original stamp alongside so the conversion can be checked. What matters is doing it consciously rather than discovering the problem at a year end.
Precision, and why totals drift
Assets divisible to eight decimal places, interfaces that display four, exports that give six, and a calculation somewhere that used all of them.
Each individual rounding is invisible. Across a few thousand rows they accumulate into a difference large enough to notice and small enough to be baffling — the totals disagree by an amount that corresponds to no transaction at all.
This is the difference people spend the longest chasing, because it looks like a missing row. It is not; it is the sum of a thousand imperceptible truncations.
Two habits contain it. Read amounts at the full precision the document gives rather than rounding on import, and expect a residual that scales with row count rather than with value.
A useful diagnostic: if the difference is proportional to the number of rows rather than to the amounts involved, it is rounding, and there is nothing to find.
What gets netted, and why it is the dangerous one
Of all seven, this is the one that produces wrong answers rather than confusing ones.
Some platforms show what you received before the fee, with the fee as its own line. Others show what actually landed in your balance — already net. Both are honest descriptions; they are describing different things.
Combine exports from both kinds into one record without noting which is which, and every row from the netting platforms is understated by its fee. Consistently. Plausibly. In the same direction, every time.
That is the hardest error class to detect, because nothing looks anomalous. There is no outlier, no row that stands out, no total that fails to add up. The record is internally coherent and quietly wrong.
The defence is to record which convention each source used, at the moment of reading, and to keep the fee as a separate field always — which is the argument made in full on asset and fee splitting.
History that does not stay still
An assumption worth abandoning early: that an export of a past period will be the same whenever you take it.
Platforms restate. A trade is reversed after a dispute, a fee is corrected, a pending item settles at a different amount, a promotional credit is reclassified, a migration renders older activity differently. None of this is unusual and none of it is announced.
So an export taken in January and an export of the same period taken in November can genuinely differ, with both being accurate as of when they were taken.
This has a direct practical consequence: keep your old exports. If a figure you reported came from the January file, that file is the evidence for what you reported — and the November one, however current, does not show what you knew at the time.
It also means dating your exports is not fussiness. An undated file whose contents have since changed elsewhere is a document you cannot place.
The chain settles less than people expect
A common assumption is that on-chain data is the authoritative record that resolves all of this. It resolves a specific part of it and leaves the rest untouched.
What the chain shows: movements between addresses, with amounts and network fees, immutably. That is genuinely useful for transfers.
What it does not show: anything that happened inside a platform. Trades between two assets on an exchange never touch the chain. Neither do internal transfers, fee postings, or rewards credited to a balance. For a holder whose activity is mostly on exchanges, the chain sees almost none of it.
It also cannot tell you which addresses were yours, which is the question that matters most for transfer matching. An address is not labelled, and only you know that both ends were under your control.
So on-chain data is a supplement to exports rather than a replacement — and for the specific problem of getting exports to agree, it mostly is not the answer.
A worked difference, taken apart
One asset, three platforms, invented figures. The balances say one thing and the sum of the rows says another.
| Component | Amount | Cause |
|---|---|---|
| Expected from rows | 14.82000000 | — |
| Actually held | 14.79310000 | — |
| Difference | 0.02690000 | To explain |
| — network fees on transfers | 0.02400000 | Only on the receiving side |
| — netted trading fees | 0.00260000 | One platform reports net |
| — rounding across 1,400 rows | 0.00030000 | Precision, finished business |
| Unexplained | 0.00000000 | Nothing left |
The difference looked like a missing transaction and was three separate technical causes stacked on top of each other. Nothing was lost, nothing was wrong, and no amount of searching for a missing row would have found anything.
Note the proportions. The network fees are the bulk of it and are entirely legitimate; the netting is small but is the only component that would have made a downstream figure wrong; the rounding is negligible and would have consumed the most time to chase.
A reconciliation that ends with the word “unexplained” against zero is achievable. One that ends with an exact match on the first attempt usually means something was quietly rounded away.
Pending, settled, and the export taken in between
A cause that gets overlooked because it is invisible unless you take two exports at different moments.
Platforms hold transactions in intermediate states. A withdrawal is requested but not yet broadcast. A deposit has arrived but not yet confirmed. A trade has executed but the settlement posting has not run.
Whether such an item appears in an export depends entirely on when the export was taken and on how that platform treats pending items — some include them, some exclude them, some include them with a flag most people ignore.
So two exports of the same period, taken a fortnight apart, can differ by an entire transaction with nothing having gone wrong. The item settled in between.
This is a good argument for taking period-end exports a little after the period end rather than on the day. A few days of settling time removes most of this category, and it costs nothing but patience.
It is also why an export should be dated when you file it. An undated file that differs from another undated file is a puzzle; two dated files that differ are a timeline.
Living with it instead of fighting it
The shift that makes this manageable is giving up on exact agreement as the goal, and replacing it with something achievable.
Record the source, not just the number
Every row knowing which file and page it came from turns an unexplained difference into an attributable one.
Record the convention per source
Gross or net, which time zone, what precision. Four notes per platform, written once.
Expect a residual, and size it
A small unexplained difference that scales with row count is rounding, and it is finished business.
Investigate direction, not magnitude
A difference that is always the same sign has a cause. One that alternates is noise.
The last one is the most useful diagnostic in the whole exercise. Random differences are the accumulation of small technical causes; a one-directional difference is a systematic treatment issue, and it has a specific explanation worth finding.
Setting a tolerance in advance
Without a threshold, one of two things happens: everything gets investigated until the person doing it gives up, or nothing does because there is no line to cross.
So decide, before you start, what size of difference you will look into — and write it down, because the temptation to move it once you see the numbers is considerable.
What the threshold should be depends on what the record is for, and that is a conversation with whoever will use it. What matters more than the figure is that it exists and is applied consistently.
One refinement is worth having: a separate, much lower threshold for differences that are one-directional. A persistent one-sided gap of a small amount is more interesting than a large random one, because it has a cause that will keep operating.
And whatever you decide, record the differences you chose not to investigate rather than deleting them. A documented tolerance is a position; a silently dropped difference is a hole.
When a difference genuinely does matter
Most differences are technical residue. A few are not, and it is worth knowing which shapes to take seriously.
A whole holding appearing or disappearing
Not a rounding effect. Usually an unmatched transfer, occasionally a missing export.
A one-directional gap that grows
Almost always a netting convention. It will keep growing until the convention is recorded.
A difference that lands exactly on a period boundary
Time zone, and it moves an event between reporting periods rather than changing any total.
A row that exists in an old export and not a new one
Restated history. Both files are evidence; the old one is evidence of what you were told at the time.
A balance that does not match any sum of rows
Sometimes an event with no row at all — a reward credited directly, which is its own subject.
The last of these is more common than expected and is the reason a balance can be right while no combination of rows explains it. Events that appear in a balance without ever appearing as a transaction are covered on staking and airdrop records.
Wallet exports have their own set of problems
Everything so far has been about exchanges. Wallet exports disagree for overlapping but not identical reasons, and it is worth separating them because the fixes differ.
A wallet shows addresses, not ownership
It records what moved to and from an address. Whether the other address was also yours is not in the data, and that single unknown drives most transfer-matching effort.
Network fees appear on one side only
The sender pays. A record built from the receiving wallet alone shows a smaller amount arriving with no explanation for the difference.
Internal contract activity produces extra entries
A single action can generate several movements, none of which correspond to anything you consciously did.
Dust and unsolicited tokens accumulate
Tiny amounts nobody sent deliberately, sitting in the balance and appearing in every export.
Software changes what it exports
A wallet application updated between two exports may render the same history differently, with more or fewer columns.
The first is the fundamental one and it has no technical solution. An address is a string; nothing about it says whose it is. Only the holder knows, and if they have forgotten, nobody can recover it from the data.
The second is the most common source of a small unexplained shortfall when comparing an exchange withdrawal to a wallet deposit. The amounts differ by the network fee, which is correct, and looks like a discrepancy until it is named.
The practical consequence is that wallet and exchange exports should be read together rather than separately. Each contains half of several stories, and reconciling either alone produces gaps that the other file would have closed.
The fifth point deserves a habit rather than an explanation. Because wallet software changes what it exports between versions, an export taken today and one taken after an update can differ in structure as well as content — extra columns, renamed fields, a different treatment of internal movements.
That makes the old file worth keeping for the same reason a restated exchange export is: it records what the software said at the time, in the shape it said it. When two exports of the same wallet disagree structurally, having both is what lets you tell a genuine change from a rendering change.
None of this makes wallet data unreliable. It makes it partial — one side of movements whose other side lives elsewhere, described by software that evolves. Read alongside the exchange files it is genuinely useful; read in isolation it is a source of differences with no visible cause.
Explaining this to somebody who expects an exact match
At some point this has to be explained — to a client, a partner, an adviser, or somebody reviewing the record. The explanation lands better when it does not sound like an excuse.
The framing that works is comparative rather than apologetic. A bank account has one operator, one ledger and one set of conventions, so exact agreement is a reasonable test. A digital asset position spans several independent systems that were never designed to agree with each other, so exact agreement is not the test — completeness and attribution are.
What that means concretely is worth spelling out: every row can be traced to a document, every source's convention is recorded, and every difference is either explained or explicitly noted as unexplained with its size.
A record with those three properties is stronger than one that ties exactly, because a perfect tie across independent systems usually means something was quietly adjusted to make it so.
And there is a useful thing to offer alongside: the decomposition. Showing that a difference is thirty parts network fee, three parts netting convention and one part rounding turns an apparent problem into a demonstration that the record was actually examined.
People asking about a difference are usually asking whether anyone looked. The decomposition answers that better than a matching total would.
What to do about it
Take two exports — same account, different dates, or two platforms holding the same asset — and read them side by side. Do not try to reconcile them. Just look at how they differ.
Then classify the differences using the seven causes. Most will fall into rounding and convention, both of which are finished business once identified.
Whatever is left after that is your real list, and it is usually short: an unmatched transfer, an event with no row, a restated figure. Those are worth an hour each; the rest are not worth an hour between them.
And note the conventions you found, per platform, somewhere permanent. That note is what stops you rediscovering the same seven causes next year — and it is the difference between a record that gets rebuilt annually and one that accumulates.
The full ordering, including what to do before any of this, is in how to prepare crypto records for tax.
