Position Reconciliation: When a Bot’s Records Differ from the Exchange
The quietest and most expensive automated-trading accident is not a wrong strategy. It is continuing to run while the position remembered by the bot differs from the position actually held at the exchange. The bot makes decisions from its own records and may keep operating for hours without noticing the mismatch.
Divergence is normal, not exceptional
A bot stores a state such as “currently long 0.1.” The exchange stores the same information. They should agree, but a network between them means they can diverge at any time.
① A lost response
The order was accepted, but its response never arrived.
② A bot restart
Memory state disappears while the position remains.
③ A partial fill
Only 0.04 of a 0.1 order fills.
④ Manual intervention
Someone closes part of the position in the app.
⑤ Liquidation or ADL
The exchange reduces the position without the bot knowing.
─────────────
Four of these five can happen even when the bot's code is sound.
Reconciliation is therefore a component that should run continuously, not a debugging feature enabled only when a bug appears. What happens to a position when connectivity fails? explains why the position remains on the exchange's servers. From the bot's perspective, that persistence is where the problem begins.
A timeout does not mean failure
The most common cause is simple: after sending an order and receiving no response, people assume it failed and send it again. A timeout means the result is unknown, not that the request failed.
Intended entry: Long 0.1.
First request → Response timeout.
In fact, the exchange has already filled it.
Second request → Success response.
─────────────
Bot's records: 0.1.
Actual exchange position: 0.2.
Notional doubles → Account risk doubles.
The bot places a stop for 0.1.
→ Even after the stop executes, 0.1 remains.
The most alarming consequence is not simply doubled exposure: the stop closes only half. The bot closes the 0.1 it knows about, records “closed,” and waits for the next signal. The remaining 0.1 becomes an unmanaged position. An adverse move then creates losses of an unplanned size.
Idempotency: Making retries safe
The answer is not to eliminate retries; network communication requires them. Instead, arrange for the same request to execute only once even if sent twice. This is idempotency, commonly implemented with a client order ID.
The bot assigns an ID when creating an order.
Example: btc-20260905-1412-a7.
First request: Send with this ID → Timeout.
Second request: Resend with the same ID.
─────────────
Exchange response:
• Already accepted → Reject the duplicate.
• Not previously accepted → Accept normally.
Either way, the final quantity is 0.1.
Create a new ID for each new order, but never create a new one for its retry. A new retry ID destroys idempotency and allows duplicate orders through. Field names and length limits differ by exchange, so consult the integration documentation first. See the exchange API trading integration guide for the overall structure. For outright rejection causes, start with eight reasons an order can be rejected.
What does reconciliation compare?
First decide which record is authoritative. The answer is always the exchange. However plausible the bot's records look, the exchange's numbers represent the money actually at risk.
① Direction: Long, short or none.
Different → Immediate alert.
② Quantity: Compare absolute quantities.
Difference greater than tolerance → Alert.
③ Average entry price: Reference information.
Small decimal differences from fees or partial fills are normal.
④ Unfilled orders: Count and quantity.
An active order absent from the records → Alert.
─────────────
Example tolerance:
Ignore differences within 10% of the minimum order unit,
to absorb rounding and display-precision differences.
Zero tolerance can produce dozens of daily alerts from decimal formatting alone. Excessively wide tolerance can hide real omissions. Using the minimum order unit as the reference adapts better across instruments. See partial fills for cases where execution leaves an awkward remaining quantity.
A quantity mismatch distorts every account calculation
A mismatch changes more than exposure. Nearly every number calculated by the bot becomes inaccurate.
Entry price: $80,000. Account: $2,000.
What the bot believes
Notional = 0.1 × 80,000 = $8,000.
Loss on a 1% adverse move = $80.
Percentage of account = 4.0%.
Actual values
Notional = 0.2 × 80,000 = $16,000.
Loss on a 1% adverse move = $160.
Percentage of account = 8.0%.
─────────────
• Liquidation buffer: Halved.
• Risk from one stop: Doubled.
• The bot's position-sizing calculations: Invalid.
The bot may still log “risk is being managed at 4%.” Risk-management logic cannot produce meaningful results from incorrect inputs. The calculations in portfolio heat apply when measuring actual account-wide exposure.
The sequence immediately after a restart
Following one startup sequence can prevent most of these accidents.
1) Query positions from the exchange.
2) Query unfilled orders from the exchange.
3) Reconcile with local records.
4) If a mismatch exists → Stop here.
5) Only if they match → Allow new orders.
─────────────
Common mistakes:
• Start with empty state without querying.
→ Enter again on top of an existing position.
• Treat a failed query as no position.
→ The same result.
Steps 4 and 5 are critical. Discovering a mismatch and deciding to “fix it while running” adds new trades on top of inconsistent state. Treating a failed query as no position causes the same accident: unknown and absent are different states. Representing them with the same value eventually creates a failure. A common query-failure cause is covered in API rate limits and HTTP 429 errors.
Frequency and false alarms: Watch for stale data
Frequent reconciliation is useful, but making decisions from outdated query results can create new danger.
• An entry order has just filled.
• Reconciliation reads a 10-second-old cache.
• Result: Exchange 0; local records 0.1.
• Interpretation: “A phantom position exists only in the records.”
• Automatic correction: Reset the local position to zero.
─────────────
The actual position is still open.
→ An unmanaged position is created.
Defenses
• Defer judgment if the queried data is older than N seconds.
• Confirm a mismatch only after 2–3 consecutive observations.
• Pause reconciliation for a few seconds immediately after an order.
Consecutive-observation requirements alone can greatly reduce false alarms. A single apparent difference is often a timing problem; the same directional mismatch three times in a row is evidence of a real issue. Logs must also distinguish a failed query from an actual mismatch so the cause can be traced later.
What to correct automatically and what to report
Decide in advance whether the bot should correct a discovered mismatch or hand it to a person.
Suitable for automatic correction
• Update recorded notes to match exchange values.
• Cancel phantom pending orders.
• Absorb decimal precision differences.
Escalate to a person
• The position direction is opposite.
• The actual quantity is greater than the records show.
• Queries keep failing.
─────────────
Principle:
Correcting records can be automatic.
Moving money follows confirmation.
Letting a bot automatically send market closes may look convenient, but incorrect query data can make it close a valid position. An automatic close based on bad data can be more expensive than the original mismatch. Automated-trading myths and reality provides context for deciding how much judgment to delegate to automation.
Recap
② Timeout means unknown result, not failure; an unguarded retry can double quantity.
③ Double quantity is especially dangerous because the stop closes only half.
④ Use client order IDs for idempotent retries; never generate a new ID for the same retry.
⑤ The exchange is authoritative; the bot's records are a copy.
⑥ Compare direction, quantity and unfilled orders; average price is supporting information.
⑦ Base tolerance on the minimum order unit.
⑧ Startup: Query → Reconcile → New orders only when state agrees.
⑨ Do not interpret a failed query as no position.
⑩ Confirm mismatches with consecutive observations; update records automatically, but confirm before closing positions.
The numbers a bot believes are a copy; the original is at the exchange. Without periodically comparing them, even an excellent strategy produces calculations based on the wrong quantity. Reconciliation does not increase returns; it helps prevent losses from an inconsistency that has already occurred.
NOONOO TRADING invites you to follow live trading in our free chat.
Start in the bot📈 OKX trading fee discount for new registrations
Register for the OKX Fee Discount →