Reconciling local state vs broker order book
Your bot almost certainly keeps some local record of "what I think my positions/orders are" (for speed, for strategy logic, for tagging attribution). The broker's order book and positions API are the only ground truth. These two views will drift apart eventually — from crashes, manual intervention, partial fills your code didn't handle, or bugs. Reconciliation is the discipline of catching and correcting that drift before it causes a bad decision.
When to reconcile
- On every startup — never trust local state to reflect reality after any restart, planned or crash-induced.
- Periodically during the day — e.g. every few minutes, or after every order event, depending on strategy frequency.
- Before every new order placement — a lightweight check that your local "current position" for this instrument matches what the broker reports.
def reconcile_positions(kite, local_positions: dict[str, int]) -> dict[str, dict]:
"""local_positions: tradingsymbol -> quantity your bot believes it holds.
Returns a diff report of mismatches."""
broker_positions = {p["tradingsymbol"]: p["quantity"] for p in kite.positions()["net"] if p["quantity"] != 0}
all_symbols = set(local_positions) | set(broker_positions)
diffs = {}
for sym in all_symbols:
local_qty = local_positions.get(sym, 0)
broker_qty = broker_positions.get(sym, 0)
if local_qty != broker_qty:
diffs[sym] = {"local": local_qty, "broker": broker_qty}
return diffs
The broker's state always wins
def resync_local_state(local_positions: dict, kite) -> dict:
broker_positions = {p["tradingsymbol"]: p["quantity"] for p in kite.positions()["net"] if p["quantity"] != 0}
diffs = reconcile_positions(kite, local_positions)
if diffs:
logging.warning(f"Position drift detected, resyncing to broker truth: {diffs}")
send_alert(f"Position mismatch corrected: {diffs}")
return broker_positions # always trust this over local state
A mismatch is not something to silently "fix and continue" — it's a signal something in your bot's own bookkeeping is wrong, and it should be logged and alerted on (chapter 91), not just quietly patched over every time. Repeated mismatches indicate a real bug worth finding.
Same discipline applies to orders
def reconcile_open_orders(kite, local_order_ids: set[str]) -> set[str]:
broker_open = {o["order_id"] for o in kite.orders() if o["status"] in ("OPEN", "TRIGGER PENDING")}
return local_order_ids ^ broker_open # symmetric difference = discrepancies