19 Commits

Author SHA1 Message Date
jaxperro 82f62124e7 copytrade.py moves out of archive/ + Fly health check (watchdog layer 1)
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>
2026-07-08 17:34:36 -04:00
jaxperro 35201963e3 copybot: BOOK RESET — fresh $1,000 paper book from 2026-07-08 (Set E era)
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>
2026-07-08 16:19:07 -04:00
jaxperro 167a0b9c92 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>
2026-07-07 22:49:47 -04:00
jaxperro 7b1e86685a copybot: feed reconciles my_pos -> bets so open_count matches the visible table
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>
2026-07-07 21:05:47 -04:00
jaxperro 972b32e8f0 CRITICAL: fix their_prev crash that silently killed all new opens since 07-05
_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>
2026-07-07 11:33:36 -04:00
jaxperro dbb48b3ac3 copybot P0 fixes: on-chain settle fallback, exit reconciliation, ledger self-check
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>
2026-07-06 18:06:42 -04:00
jaxperro 8958279ee8 cleanup: archive everything the live system no longer touches
- retired-infra/: Railway config, Mac launchd runner, GH-Actions cron
  (worker is Fly.io arn now; Actions cron last fired 2026-07-02)
- live-research/: the June selection experiments (strategy/followability/
  pnl_basket/pnl_focused/backtest_june/clean_test + outputs)
- us-venue/: the scrapped Polymarket-US listability probe (+ its
  env-gated ONLY_CONDS replay filter stays in portfolio.py — generally
  useful for subset replays)
- root sweeps hunt/huntwide/oos/copyback/watch.json -> archive/
- untracked logs/CSVs of dead experiments -> archive/local/ (gitignored)
- READMEs updated: Fly migration, geoblock gotcha, new file map

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 17:18:46 -04:00
jaxperro 6d2fb0f34b copybot: their-bet stake ceiling replaces stake cap + banked reserve (parity with backtest)
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>
2026-07-05 23:45:56 -04:00
jaxperro 5c0e50efb2 copybot: wallet classes replace raw multipliers — 'volume' 4% / 'whale' 12%
follow.wallet_class marks each wallet (default: volume); follow.class_pct
maps class -> equity fraction. Stavenson + 0x4bFb-whale are whales at 12%,
everyone else rides volume at 4%. Drawdown brake, stake cap, and the
base-fraction sweep threshold unchanged. Verified: $120 whale / $40 volume.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-04 19:14:46 -04:00
jaxperro b1b6246883 copybot: per-wallet stake multiplier — Stavenson + 0x4bFb-whale bet 3x (12% of equity)
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>
2026-07-04 19:09:31 -04:00
jaxperro 8c07343735 discord: retire per-trade pings, add daily sharp digest; trust: v2 self-certify + invalidated-wallet fallback
* 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>
2026-07-04 18:31:30 -04:00
jaxperro 6fa1ba94bf sizing discipline binds per market: adds capped at the current stake size
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>
2026-07-03 21:06:25 -04:00
jaxperro 7e9ccdf5c8 profit ratchet: stakes pin at $250, surplus swept to a banked reserve
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>
2026-07-03 00:49:22 -04:00
jaxperro b6db6f3833 asymmetric price guard (better prices never blocked) + 0.95 entry cap
- 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>
2026-07-02 23:35:51 -04:00
jaxperro e1d264ddfe event cap off: follow every conviction trade (max_per_event 0 everywhere)
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>
2026-07-02 11:21:08 -04:00
jaxperro b398e5d682 live bot: record + settle missed bets, publish in feed
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>
2026-07-02 11:03:32 -04:00
jaxperro 716daeccc1 dynamic sizing: 4% of equity per bet, drawdown brake, per-event correlation cap
- 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>
2026-07-02 10:54:07 -04:00
jaxperro 2946ac9170 copybot: 24/7 paper copy-trade test + live dashboard feed
Push-or-poll copy bot (FollowFilter conviction gate + copytrade engine),
cash-gated $1k book, resolution settling, lag/slippage logging, FOK live
orders, on-chain redeem. Runs free 24/7 via GitHub Actions (--poll-once
cron) and publishes live/copybot_live.json for the trading dashboard.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-25 12:41:56 -06:00
jaxperro 34d02956d8 Archive dead-end strategies; add FINDINGS.md write-up
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>
2026-06-13 13:09:56 -04:00