copybot: close the orphan/cash-debit seam (HANDOFF proper fix, Option A)

Every drained buy fill is now recorded: the tok-match keeps _record_lag
(real lag/slippage), leftovers get a bet record synthesized from the fill
(_record_untracked_buy). check_book() asserts the book invariant after
every trade and at boot: my_pos token => bet record + conds entry + cash
debited. Records/conds self-correct; the cash leg heals only at boot and
only when ledger_drift matches one un-vouched position's cost+fee exactly
— anything else stays a visible ⚠ drift. my_pos entries now carry cond
(engine) and fills-ledger BUY lines carry token, so the book can always
self-attribute. reconcile_exits' drain no longer discards leftover buys.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
jaxperro
2026-07-07 22:49:47 -04:00
parent fcfaaea431
commit 167a0b9c92
2 changed files with 180 additions and 16 deletions
+6 -1
View File
@@ -483,11 +483,16 @@ class CopyTrader:
if is_add:
mine["shares"] += res["filled_shares"]
mine["cost"] += spent
if cond:
mine.setdefault("cond", cond)
else:
# wallet/cond ride on the position so the book can always self-repair:
# wallet for the feed's my_pos->bets safety net, cond so check_book can
# rebuild the conds map (an orphan without it can never settle)
self.state["my_pos"][token] = {
"shares": res["filled_shares"], "cost": spent,
"title": title, "outcome": outcome, "event": event,
"wallet": wallet} # attribution for the feed's my_pos->bets safety net
"wallet": wallet, "cond": cond}
tag = "[PAPER]" if not self.ex.live else "[LIVE]"
self.alert(
f"{kind} {label}{tag} buy {res['filled_shares']:.1f} "