Position reconciliation
Reconciliation is comparing what your code believes it holds against what the exchange says it holds. It is the only detector for the failure class that produces no errors, and it is the check most automation skips.
Why nothing else catches it
Divergence has no error path. A missed stream update, an unprocessed partial fill, a manual trade — none of them raise anything.
Worse, divergence is permanent once it happens. Subsequent updates are deltas applied to an already-wrong base, so nothing self-corrects. Your view stays wrong and every decision made from it is wrong with it.
Compare an exception: it tells you something failed. Divergence tells you nothing and lets you act with full confidence on incorrect numbers.
What to compare
Position quantity per symbol — the core check.
Average entry price. A quantity match with a price mismatch usually means a partial fill you processed incompletely.
Open orders. Does every protective order you believe exists actually exist? An open position with no stop is the most expensive version of this failure.
Balance and available margin. Catches fees and funding you did not account for.
Order count per symbol. A duplicate order from a retry shows up here before it shows up in your position.
When to run it
After every stream reconnect. Non-negotiable — see WebSocket reconnection patterns.
After any ambiguous order outcome. A timeout means the result is unknown; reconciliation is what converts it into a fact rather than a guess. See retrying a failed order is not safe.
On a periodic timer. Every few minutes while positions are open. Cheap relative to what it catches.
At startup. Before acting on anything, establish what you actually hold.
After recovering from degradation. The gap between “the API is back” and “I know my state” is where duplicate positions are created — see exchange outages and degraded mode.
What to do on a mismatch
Stop first. Do not trade on an unresolved discrepancy. A halted strategy is recoverable; one acting on a wrong position is not.
Trust the exchange. It is authoritative. Your view is a cache.
Find the cause before resuming. A mismatch you paper over recurs, and the second occurrence is usually larger. Common causes:
| Symptom | Likely cause |
|---|---|
| Quantity smaller than expected | Partial fill treated as full |
| Quantity larger than expected | Duplicate from a retry |
| Position exists, you expected none | Order filled after an ambiguous failure |
| No position, you expected one | Stopped out, or liquidated |
| Entry price differs | Fills at multiple levels |
Check protective orders before resuming. If reconciliation revealed an unexpected position, it certainly has no stop.
Alert. This is rare and consequential — exactly the combination that gets lost in a log nobody reads. See monitoring a trading integration.
Reconcile against the position, not the order log
A subtlety worth getting right: reconciling your order records against the venue’s order records is a weaker check than reconciling positions.
Order histories can agree while positions do not — a fill recorded against the wrong symbol, a manual trade on the same account, or a partial fill processed as complete all produce matching order lists and diverging positions.
The position is the number that determines your exposure, so it is the number to compare. Use the order log to explain a mismatch once you have found one, not to detect it.
The cost, and reserving for it
Reconciliation is REST calls, and REST calls are metered. On Binance that is weight-based; on Hyperliquid there is an address-based allowance earned by volume.
The trap: reconnects cluster with volatility, which is also when everything else is consuming rate limit. Reserve headroom that routine polling cannot touch, so the capacity to ask what actually happened is available when you most need it.
Being unable to reconcile because a data-refresh loop used the budget is a specific, avoidable failure.
For AI-assisted setups
Two things this changes.
Re-fetch state before reasoning, do not carry it in context. A model reasoning about a position from six messages ago is reasoning about a position you may not have — see context windows and stale market data.
Reconciliation is the check the model cannot do for you. It requires comparing two authoritative sources and halting on disagreement, which is deterministic logic. The model can present the result; the comparison and the halt belong in code, for the same reason limits do.
FAQ
What is position reconciliation?
Comparing your system’s view of positions, orders and balances against the exchange’s, and halting when they disagree. It is the only reliable detector for state divergence, which produces no errors and does not self-correct — once your view is wrong, subsequent updates apply cleanly to a wrong base.
How often should I reconcile positions?
After every stream reconnect, after any ambiguous order outcome, at startup, after recovering from a degraded period, and periodically while positions are open. The periodic check is cheap relative to the class of failure it catches.
What should I do if my position does not match the exchange?
Stop trading, treat the exchange as authoritative, and find the cause before resuming. A smaller-than-expected quantity usually means a partial fill treated as full; a larger one usually means a duplicate from a retry. Check that protective orders exist for whatever you actually hold.
Why does my bot think it has a different position than the exchange?
Most often a missed stream update during a reconnect, a partial fill processed as complete, or an order that executed after an ambiguous failure and was never recorded. Manual trades on the same account do it too. None of these raise an error, which is why periodic comparison is the only way to find them.