Reconciling an Exchange Statement to Your Own Records: Where the Numbers Diverge
An exchange statement is a record of what the venue did. Your ledger is a record of what you own. They describe the same account from two directions, and the gap between them is almost never an error — it is a definition. This guide sets out the identity that makes a tie-out possible, the five categories where the two records legitimately disagree, and the fields in the venue's own API that determine whether you can reconcile a month at all.

Cover artwork: CoinSoso · AI-generated, not a photograph of a real venue, product or market capture.
Key takeaways
- A statement reports events; a ledger reports positions. The tie-out is an identity that adds the events to the opening position and compares the result with the closing one.
- Binance's trade endpoint returns the commission and the commission asset separately, and the commission asset need not be the asset traded — which is why a fee paid in BNB is a second disposal, not a discount.
- Binance's account trade list can only be queried over a window of 24 hours or less per request and returns at most 1,000 trades, so a month requires deliberate pagination rather than one call.
- OKX's bills endpoint is split by retention window — last 7 days, last 3 months, and since 2021 — and paginates by bill ID, so the completeness of an export depends on which endpoint produced it.
- Internal transfers between your own accounts are the most common source of a phantom difference: one side records a deposit, the other records nothing, and the total is unchanged.
The short answer
Reconciliation is one identity. Everything else in this article is a reason the identity fails on the first attempt.
opening balance
+ deposits
− withdrawals
+ buys (in base units)
− sells (in base units)
− fees
+ interest and rewards
± internal transfers
= closing balance
A statement gives you every term on the right except the first, and it gives them in the venue’s units and on the venue’s clock. Your ledger gives you the first and the last and whatever you remembered to record in between. The gap between them is a list of definitional differences, not a mystery.
Reason one: an event record is not a position record
The most common reconciliation failure is a category error. The statement is a journal; the spreadsheet is a balance sheet. Trying to match a trade line to a row that represents a holding produces a search for a number that was never going to appear.
The fix is to reconcile in two passes. First reconcile the cash and asset movements — every event, in units of the asset that moved. Then reconcile the closing position as a consequence. A statement that ties at the event level will tie at the position level by construction; one that is only checked at the position level can be wrong by two offsetting errors and still balance.
Reason two: the fee may be in a third asset
This is where most retail ledgers break, and the API is explicit about it.
Binance’s account trade list returns a trade with, among other fields:
| Field | What it is |
|---|---|
price |
The execution price |
qty |
The quantity of the base asset traded |
quoteQty |
The quantity of the quote asset that changed hands |
commission |
The fee charged |
commissionAsset |
The asset the fee was charged in |
isBuyer, isMaker |
Which side, and whether liquidity was provided |
time |
Execution timestamp in milliseconds |
The two commission fields are separate because the fee is not always charged in the asset you traded. Buy 1 ETH at 2,000 USDT with a 0.1% fee paid in BNB and the statement shows quoteQty of 2,000 and a commission of 0.002 denominated in BNB. Your USDT ledger records a spend of 2,000. If you record the fee as “0.1%, so 2 USDT”, you are 2 USDT out on the cash leg and you have also failed to record the BNB that left your account.
There is a second consequence that belongs to tax rather than to bookkeeping: paying a fee in a third asset is a disposal of that asset. It has a date, a quantity and a cost basis, and it belongs in the same records as any other sale. The cost basis guide covers how lots are identified; the point here is that the fee line is a transaction, not a rounding adjustment.
The execution report guide covers the per-fill version of this problem — partial fills, rebates and the difference between an order price and an average fill price — and is the right companion when the trade in question is a large one.
Reason three: internal transfers look like deposits
A transfer from your spot wallet to your funding account, or between two sub-accounts, appears twice in a statement: once as an outgoing entry and once as an incoming one. A ledger that records only the incoming leg books a deposit that never happened.
The tell is arithmetic. If total contributions in your ledger exceed the sum of external deposits on the statement by a suspiciously round amount, look for a pair of entries with the same timestamp and the same quantity. The fix is to keep a separate category for internal movement and to make sure it nets to zero across the period.
Sub-accounts make this worse because the venue may present them as separate statements. The sub-account and API key isolation guide explains why a sub-account is an account rather than a label, which is also why its statement stands alone.
Reason four: the clock, and the as-of date
Two clocks run through every statement: the venue’s timestamp and your bank’s or chain’s. They do not agree at the boundaries.
A trade executed at 23:58 UTC on the last day of the month may be booked in the next month by a ledger that works in local time. The amount is right; the period is wrong; and if the ledger is used for a period return, the error is a whole day of performance appearing in the wrong month.
The same problem exists inside the venue’s own data. A balance snapshot taken at a stated time and a trade list filtered by a stated time can be a few seconds apart, and if a trade lands in that gap the reconciliation shows a one-trade difference that no amount of re-checking will resolve. The practical fix is to reconcile to a timestamp, not to a date, and to leave the boundary events in a suspense row until the next period confirms them.
Reason five: derived fields are not stored fields
Average entry price, unrealised P&L, and “portfolio value” are computed at the moment you look at them. They are not transactions and they cannot be reconciled line by line.
When a statement shows an average cost that does not match your ledger’s, the usual cause is that the two averages were computed over different populations — one includes fees, one does not; one uses FIFO lots, one uses a running average. Neither is wrong as a definition, and neither is a fact about the account. Reconcile the events, then compute the average yourself under a stated method, and the discrepancy stops being mysterious.
What the APIs will and will not give you
Whether a statement can be reconciled at all depends on the fields the venue exposes and the windows it allows. Two large venues illustrate the range.
Binance exposes trades per symbol through GET /api/v3/myTrades. The parameters that matter for reconciliation are symbol, which is mandatory; startTime and endTime, which cannot span more than 24 hours; and limit, which defaults to 500 and caps at 1,000. Weight is 20 without an orderId and 5 with one. The data source is described as memory to database, which is the venue’s way of saying that recent trades may be served from a cache and older ones from storage.
The practical consequence is that a full month is not one request. For each symbol you trade you need at least 31 windows, more if a window hits the 1,000-trade limit, and the responses must be de-duplicated on id because a window boundary can return a trade twice. An export that stops at the first response is a partial history that looks whole — the single most common source of a “missing trade” that was never missing.
OKX exposes account bills rather than a trade list alone, through endpoints split by retention: bills from the last 7 days, bills from the last 3 months, and an application-based route for bills since 2021. Each bill carries billId, ccy, bal, balChg, type, subType, ts and notes, and pagination runs on the bill ID with after and before parameters rather than on a date.
That design has a reconciliation consequence: the endpoint reports balChg, the change in balance at the account level, alongside bal, the balance at the account level, so the bill list carries both the movement and the running position in the same row. It also means the bill types themselves encode events you must classify — a liquidation, a forced repayment of interest, a funding payment and a fee are different rows with different type and subType values, and a ledger that treats them all as “fees” will tie in total and be wrong in every category.
A reconciliation procedure that survives audit
- Fix the period and the timestamp. Choose a start and end instant in the venue’s own timezone, not your local one.
- Pull the opening balance from the venue, as of the start instant, and write it down before looking at any trades.
- Pull events in full. Page until the last page returns fewer rows than the limit, de-duplicate on the venue’s trade or bill ID, and record how many rows you expected to see.
- Classify before you sum. External deposit, external withdrawal, internal transfer, trade, fee, interest, funding, liquidation. Each category has its own check.
- Reconcile in the asset’s own units first. USDT for USDT pairs, BTC for BTC pairs. Converting everything to a fiat value at a daily rate introduces a second source of difference before the first is resolved.
- Reconcile the closing balance last, and treat a tie there as confirmation rather than as proof.
Step 3 is the one that separates a reconciliation from a review. A record that is complete by construction — every page pulled, every ID unique — can be checked. A record assembled from a CSV export of unknown scope cannot, and the withdrawal fee guide shows the same problem on the withdrawal side, where the venue’s fee and the network’s fee are two different lines that a single export may merge.
Why this matters beyond bookkeeping
The reconciled record is the input to three other jobs: the cost basis of every disposal, the fee total that offsets gains, and the year-end report that a broker now files about you. The new US broker form, Form 1099-DA, reports proceeds and, for covered assets, basis — but only for the accounts and assets within its scope, and it does not report transfers between your own wallets. A ledger that reconciles is the only way to fill the gaps the form leaves.
Risk note. The API behaviour described here was read from Binance’s spot API documentation and OKX’s v5 API documentation on 2026-10-29, including field names, parameter limits and retention windows as those documents state them. Venues change endpoints, limits and retention without notice, and the documentation is the operative source. This article describes a bookkeeping method, not tax advice; treatment of fees, transfers and disposals depends on jurisdiction and on your own facts.
Sources
How this was researched. Written from primary documentation and the exchange or protocol's own published material, with sources listed at the end of the article.
Primary sources for the factual claims on this page. A date appears only where a human has actually read the source; where it is missing, the check is still outstanding.
Frequently asked questions
Why does my exchange statement not match my spreadsheet?
Almost always because the two records answer different questions. A statement lists events — trades, fees, transfers, interest credits — and a spreadsheet usually tracks positions and cash. The difference is normally in one of five places: a fee charged in a third asset, an internal transfer counted as a deposit, a time-zone boundary, a derived field such as average entry price that is not stored per trade, or a balance that includes an unsettled item.
How do I get a full month of trades from the Binance API?
Page deliberately. The account trade list endpoint allows a start and end time no more than 24 hours apart and returns up to 1,000 trades per request at the maximum limit, so a month is at least 31 windows per symbol, and more where a symbol is busy. Querying without a window returns the most recent trades only, which is the mistake that produces a short export that looks complete.
What does the commission asset tell me that the commission amount does not?
Who paid and in what. Binance returns commission and commissionAsset as separate fields. When the fee is charged in the asset you traded, the net effect is a smaller quantity received. When it is charged in a third asset — BNB being the common case — you disposed of that asset to pay it, which is a separate transaction with its own cost basis, not a discount on the trade.
Is an internal transfer a deposit?
Not for the purpose of a total. Moving funds between your own spot wallet, funding account or sub-account changes where the balance sits, not how much there is. A ledger that books the incoming leg as a deposit without booking the outgoing leg as a withdrawal will overstate contributions by the amount transferred, and that error is usually invisible because the closing balance still ties.
Do I need the on-chain record as well as the statement?
For deposits and withdrawals, yes, if you want to prove the movement rather than accept the venue's description of it. The venue's record tells you what it credited and when; the chain tells you what arrived and with which transaction. The [deposit memo guide](/guides/deposit-memos-and-destination-tags/) covers the case where the two disagree because a tag was missing.
Where to go next
Independent research. Each card shows the platform’s invite code, and its Create Account button is a referral link that may earn us a commission at no extra cost to you. Whether an account can be opened is decided by the platform at sign-up.
Binance

One of the largest global exchanges by traded volume, with a very broad product range.
20% Trading Fee Rebate
Use invite code con888 when signing up to enjoy trading fee benefits.
Download from the exchange's official download service. Verify the source and follow the on-screen installation instructions.
Do not install an APK from an unknown source, or one that has been modified or cannot be checked.
OKX

A large global exchange offering spot, derivatives and a self-custody wallet.
20% Trading Fee Rebate
Enter invite code con888 when signing up to check available trading fee benefits.
Download from the exchange's official download service. Verify the source and follow the on-screen installation instructions.
Do not install an APK from an unknown source, or one that has been modified or cannot be checked.