The execution engine was load-bearing from archive/ — the one thing in
there that wasn't retired. Now at repo root next to copybot.py; the two
archived scripts that imported it as a sibling get a parent-path shim.
fly.toml gains an http /health check so Fly restarts a dark machine
(self-heal); the notify half is the GH Actions watchdog (next commit).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Old book (started Jun 25, Sets B–D, ended $1,000 bank / +$229.79
realized / 8 open discarded) lives in git history and
archive/copybot_fills.pre-reset-2026-07-08.jsonl. Clean slate so the
book measures Set E from day one.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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>
A position can land in my_pos without a bet record when its buy fill is
drained in a context where _record_lag doesn't fire (e.g. a second market on
the same event in one batch): cash-correct (open_count/deployed read my_pos)
but INVISIBLE in the feed table — the header showed '2 open / $75 deployed'
while only 1 bet rendered. write_feed now synthesizes a bet record from any
open my_pos position lacking one, so the count always equals what's shown.
Ledger was unaffected (drift -0.0) — display-only. my_pos entries now carry
'wallet' for proper name attribution on the synthesized record.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
_handle_their_buy referenced their_prev in the fresh-OPEN branch but only
assigned it in the is_add branch — every new position crashed with
UnboundLocalError the moment the their-bet ceiling landed 2026-07-06. The
webhook/heartbeat try/except swallowed it as 'handler error', so the bot
logged FOLLOW then silently placed NOTHING (last real fill 07-05 23:17;
live Fly logs show FOLLOW ArbTrader ... -> heartbeat error: their_prev).
This is the primary cause of 'live bot missing bets'. Fix: hoist their_prev
above the if/else so both branches see the signal's prior position.
Also (the user's two asks):
- copybot on_wallet_activity: a QUALIFYING bet we were too slow to catch
(webhook missed / bot down / fast market resolved before we polled) is now
recorded as a missed bet 'too slow to follow (Nm late)' instead of silently
dropped; below-floor dust stays console-only. Filter runs before the stale
gate so we know if it would have qualified.
- sync_floors.py rewritten: PIN each paper-bot wallet's floor to the trusted
cache p80 (identical to the backtest's conv_thr), written to
copybot.paper.json, wired into daily.sh + committed. Kills the boot-time
data-api floor drift (fortuneking $1,498 boot vs $892 backtest) that made
the live bot filter out bets the backtest kept.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Audit 2026-07-06 found the live paper book stuck: 4 of 5 open positions were
50/50 refunds the bot could never settle, and the 5th was a position the
signal had exited a day earlier.
- resolution_price tier 2: CTF payoutNumerators/Denominator via RPC
(ALCHEMY_RPC_URL env or config alchemy_key). CLOB winner flags never
populate for operator-resolved in-play markets and never express 50/50
refunds; the chain records both. Token-id match now precedes outcome-label
match in tier 1. New bet status: 'refund' (settles at $0.50/share,
redeems in live mode).
- reconcile_exits(): at boot + every backstop poll, verify the signal still
holds each copied token (market-filtered data-api queries — no pagination
cap). Exit requires three AFFIRMATIVE facts (open-positions fetched+empty,
closed-positions fetched+contains token, market fetched+still trading) —
an API failure must never read as an exit.
- ledger_drift(): cash-vs-ledger invariant checked every heartbeat, warned
in the log, published in the feed (ledger_drift / adjustments fields).
Accumulators no longer round per fill (that drifted cents per trim);
the feed rounds at render. SELL fills now logged to copybot_fills.jsonl.
- their_positions seed cap 500 -> 2000 (whale books exceed 500).
Dry-run vs a copy of the real stuck state: 4 refunds settled at 0.50,
McCormick mirror-exited at 0.69, drift stable at the known +15.45 residue.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
stake = class % of equity (drawdown-braked), capped at the signal's own
position size so far (OPEN caps at their fill, ADDs grow with their
position). No sweep, no $250 pin — fills stay within size the market
demonstrably absorbed from the signal itself.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
follow.stake_mult ({address: mult}) scales the equity fraction for that
wallet's signals; drawdown brake and stake cap still apply, and the
profit-ratchet sweep threshold stays on the BASE fraction so which wallet
happens to trade doesn't change when profits get banked. Verified: $40
base stake -> $120 for the two, $40 for everyone else, case-insensitive.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* per-trade Discord pings removed everywhere: copybot placement/settle/startup
alerts silenced (engine.webhook forced off), webhook_receiver.py archived,
Procfile removed. The ONLY Discord output is now live/discord_daily.py at the
end of the daily pipeline: one embed listing every watch_sharps wallet with a
Polymarket profile link + 30D conviction win% / record / P&L.
* trust.py fixes found on the first scheduled run (sharp list collapsed 25->7):
- Polymarket rewrites endDate after resolution, so freshly re-pulled wallets'
corrected res_t stopped matching the stale cross-wallet consensus
(374/454 of iohihoo's rows wrongly distrusted). v2 rows with resolved=TRUE
are now self-certifying (resolved=TRUE implies endDate-based res_t observed
post-end) — consensus only gates legacy rows.
- daily.sh invalidates watchlist wallets by DELETING their pulled row; a
transiently failed re-pull then dropped the wallet's entire history from
the trusted set (the 0x73afc816 whale vanished). Legacy rows of wallets
missing from pulled now fall back to trusting markets resolved >=14d ago.
Re-run: 85 conviction wallets, 34 copy-positive sharps — whale/iohihoo/
Stavenson/LSB1/Kruto all recovered.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Proportional add-mirroring was unbounded after max_position_usd was lifted -
fortuneking doubling into his own bet took one game to $90 on a $42-stake
book (2.15 stakes). Adds now only top a position up to stake_usd(); the
backtest was already one-market-one-stake, so bot and model agree again.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Once working equity exceeds stake_cap/pct ($6,250 at 4%), surplus cash sweeps
to state["reserve"]/portfolio reserve - banked, never bet, immune to drawdown
- keeping stakes at the $250 level where marketable fills sit inside typical
book depth. Feed/summary gain reserve; realized = cash+exposure+reserve-bank.
June backfill: equity $15,684 (+1468%), $9,185 banked, next stake pinned $250.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- guard: by rule, a price BELOW the sharp's fill always passes (strictly
better odds; the symmetric guard once skipped a 0.70->0.51 improvement that
won +$36). Only adverse drift is gated by price_guard_pct.
- entry cap: June sweep (0.75-1.0) peaked at max_entry 0.95 - >95c favorites
added ~23 wins yet lowered final equity (slip+fee eat 1-3% payouts, capital
compounds better elsewhere); deep caps cut real winners. Set in all configs
+ portfolio MAX_ENTRY (env-overridable for sweeps; PORTFOLIO_OUT added).
Canonical June backfill: +716%, 219W/52L, $374 fees.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Engine default + both bot configs + backtest set to 0 (cap logic stays, opt-in
via risk.max_per_event). June backfill without the cap: +465%, 237 resolved
(202W/35L), 22 missed, $170 fees.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Engine records every blocked OPEN (no free cash, event cap, price guard) with
its would-be stake; settle_resolved marks them won/lost at CLOB resolution with
hypothetical P&L (fee-inclusive) - the live counterpart of the backtest's
Missed table. Feed gains missed[] + missed_pnl.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- engine (copytrade): stake_usd() = bankroll_pct x current equity (cash + open
cost basis) - Kelly-style compounding both directions - halved while equity
sits below 80% of its high-water mark; new risk.max_per_event (default 2)
blocks stacking correlated markets on one real-world event (dated-slug prefix
grouping; LSB1 once put 6 conviction bets on a single match).
- copybot: feed/summary report the dynamic stake, stake_pct, event_cap, hwm.
- portfolio backtest mirrors the exact same rule (PCT 4%, clamp $5-$150,
EVENT_CAP 2, brake 80%/half), with per-bet stakes in every table row and a
persistent CLOB slug cache for event grouping. June backfill: +426% vs +168%
flat - compounding amplifies the in-sample month; July live is the test.
Misses fell 62 -> 19 cash-missed (+26 deliberate event-cap skips): smaller
early stakes capture more signals.
- configs: bankroll_pct 0.04, max_trade/max_position 150 (runaway guards),
max_per_event 2.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Moved the 8 tested-and-failed strategy tools into archive/ (copytrade, backtest,
edge_research, lookback, table_77, lp_screener, lp_paper, xarb) with an
archive/README explaining each. Root now holds the keepers: insider.py (made
self-sufficient — dropped the copytrade load_json dependency) and smart_money.py
(data foundation). New FINDINGS.md is the honest scorecard: six systematic
public-data edges all efficient/illusory, the win-rate survivorship-bias
finding, and the one real signal (z-score improbability + funding clustering).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>