AuditsControls › Position reconciliation with the exchange

Accounting and reconciliation · control 10 of 21

Position reconciliation with the exchange: does your trading bot have it?

At startup and periodically, does it compare its own positions with the exchange's and resolve the differences?

Why it matters

A position opened by hand at the exchange, or left over from a crash, is invisible to a bot that only trusts its own memory. The usual outcome is a freeze or a double position.

How to check it in the code

  1. Search for reconcile, sync, fetch_positions, fetch_open_orders, fetch_balance.
  2. Check whether the result is compared with the internal state and what happens on a mismatch.
  3. Check the interval: only at startup, or also while running.

This is what the audit does for every bot in the list, on public code, without installing or running anything. Verdict values: present, partial, absent, not applicable, not verified. See the method.

Results across audited bots

Across 10 audited bots: 3 present, 5 partial, 0 absent, 0 not applicable, 2 not verified.

BotVerdictEvidenceNote
HKUDS/Vibe-TradingNot verifiedagent/backtest/binance_account_reconciliation.py exists but lives under agent/backtest/ (shadow-account/backtest verification), not under agent/src/live/Did not find a live position-vs-broker reconciliation routine run at startup within budget.
hummingbot/hummingbotPartialhummingbot/connector/client_order_tracker.py, restore_tracking_states() and process_order_not_found() (lost_order_count_limit=3)On restart it restores in-flight orders from a locally saved state and re-polls the exchange for those known orders; an order not found after 3 tries is marked lost/failed. No evidence found of a full startup reconciliation that fetches ALL open exchange positions/orders and detects ones the bot never knew about (e.g. opened manually or left over from a crash).
Drakkar-Software/OctoBotPresentindex_trading.py IndexTradingModeProducer.ensure_index() calls _wait_for_positions_init() and _wait_for_orders_init() at startup before rebalancing, loading real exchange positions/orders; telegram_bot.py exposes /refresh_portfolio ('Forces OctoBot's real trader portfolio refresh using exchange data').Both an automatic startup sync and a manual on-demand resync from the exchange exist.
freqtrade/freqtradePartialfreqtrade/freqtradebot.py, FreqtradeBot.startup() calling self.startup_update_open_orders() with code comment 'Only update open orders on startup' -- https://raw.githubusercontent.com/freqtrade/freqtrade/3774521e7028fa666770e7c7a8da323af5c4cefa/freqtrade/freqtradebot.pyOpen orders/positions are synced against the exchange once, at startup or on /reload_config. The main process() loop that runs every iteration does not repeat this reconciliation against exchange state.
jesse-ai/jesseNot verifiedjesse/store/state_positions.py is a plain in-memory dict (get_position/count_open_positions) with no method that compares stored positions against an exchange query. Population of that store from a live account happens via jesse_live (not in this repo).No startup/periodic reconciliation code found in the public repo; cannot confirm presence or absence inside jesse_live.
chrisleekr/binance-trading-botPresentapps/worker/src/queues/pipeline-handlers/reconcile-fees.ts; docs/user-guide/account/orphan-orders.md (orphan-orders-detect cron)A background cron diffs Binance's live open-order list against the local orders table every 10 minutes and surfaces/adopts mismatches (orphan orders); a separate worker pipeline handler reconciles fees.
alsk1992/CloddsBotPartialGET https://api.github.com/search/code?q=reconcile+repo:alsk1992/CloddsBot returns only 1 hit, inside src/feeds/betfair/index.ts. No general position-vs-exchange reconciliation module was found covering Binance/Bybit/MEXC/Hyperliquid/Solana/Polymarket/Kalshi.Reconciliation, if it exists at all, appears limited to one feed integration, not the whole trading surface.
Lumiwealth/lumibotPartialdocs/FAST_ORDER_LIFECYCLE_GUIDE.md: the order state machine includes 'a bounded exact-order reconciliation read after a missed callback, restart, reconnect, or ambiguous mutation result', confirmed implemented for Schwab ('performs an active-order reconciliation after login or reconnect').
YizhiSong/FriesTraderPresentPHASE_B_TASK.md Step 4 ('Pull get_equity_positions -- this snapshot... is also what Step 5's stop-loss/take-profit checks use') and Step 6 ('Re-pull fresh account state... the earlier pull is now stale for any sell that actually executed above').No independent local position ledger is kept -- every cycle re-derives truth from the broker, both at cycle start and again after this cycle's own sells.
c9s/bbgoPartialpkg/bbgo/environment.go (BindSync -> tradeWriterCreator/orderWriterCreator persist trades/orders to DB; futuresPositionWriterCreator calls SyncService.FuturesService.QueryPositionsAndInsert after each futures trade)The bot syncs historical trades/orders and periodically pulls exchange-side futures position risk into the DB, but no explicit startup routine comparing the strategy's in-memory position against the exchange and auto-resolving drift was found.

If your bot does not have it

The watchdog enforces daily loss, drawdown, position size and heartbeat limits from outside the bot, with a read-only key, whatever the bot's own code does.