Commit Graph

39 Commits

Author SHA1 Message Date
jaxperro e07ef9e68f rtds: silent-stale guard — force reconnect after 120s without messages
2026-07-11 04:00Z: the socket sat 'up' delivering nothing for 35 min with
no close event, so the on-close reconnect never fired (backstops covered
detection). The ping thread now force-closes a 120s-silent stream to
trigger the clean reconnect path.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 02:04:21 -04:00
jaxperro 3784b288cd hardening trio: exit-retry (1.6), RTDS shadow ledger, boot clone-guard
- failed mirror-exits queue for up to 10 heartbeat retries (recovered
  exits ping Discord; exhaustion pages ⚠ EXIT STUCK and the position
  rides knowingly; in-play holds hand to the pending registry). 3 stub
  paths pass incl. the 1.6 spec's fail-fail-fill.
- every RTDS Set E detection appends a durable shadow-ledger row
  (lat_s + which trigger won) that rides the publish commit — the 24h
  go/no-go data for flipping RTDS on the live app.
- start.sh verifies the boot clone's HEAD against the GitHub API and
  re-clones stale replicas (bit twice today).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 18:43:22 -04:00
jaxperro fb945be2e4 T0 detection: RTDS trade stream listener (~1s, wallet-attributed)
Polymarket's real-time data socket (wss://ws-live-data.polymarket.com,
topic activity/type trades — undocumented but official: powers the site's
live feed, spec'd in Polymarket/real-time-data-client) streams every
platform trade with proxyWallet attribution. Probe 2026-07-10: median
0.8s delivery over 22k msgs, ~45/s at peak, zero drops in 45 min.

RtdsListener: unfiltered subscribe (server-side filters broken, RTDC#34),
client-side Set E match → the same on_wallet_activity funnel as the
Alchemy push (locks internally). Capped-backoff reconnect forever; if the
lib or stream is missing, detection degrades to the existing backstops
(Alchemy ~3s, 300s poll, reconcile janitor) — never to zero. Heartbeat
shows 'rtds up Ns' / '⚠ rtds down'. Paper role: ON by default (24h shadow
run starts now). Live role: OFF until the shadow validates —
RTDS_DETECT=1 enables. 5 stub paths pass.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 18:23:41 -04:00
jaxperro f9a4b51a4d docs: sweep everything stale after the 2026-07-10 go-live day
README system-today gains the REAL-MONEY worker row (armed, push mode,
pending registry, Discord pings); /live marked live; cheat-sheet covers
both apps + disarm/re-arm + the stale-clone verify rule; guard bullet and
safety paragraph reflect the absolute +0.05 guard and retired caps; file
map adds fly.live.toml + the bridge/probe/flatten utilities. copybot/
copytrade module docstrings drop the archived py-clob-client story.
LIVE_ROLLOUT gets a status banner (executed through Phase 4; rule 0.6
superseded; Phase 5 matrix still worth running).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 17:31:51 -04:00
jaxperro 77a944cba8 pending adoptions ping Discord like any other placement
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 17:24:59 -04:00
jaxperro 705f8b2c39 live retune (user 2026-07-10): caps off, 4% paper-parity, abs guard, pending registry
1. Caps retired: risk block mirrors the paper sentinels; sizing is the
   paper bot's 4%-of-equity (class_pct 0.04/0.12), floored at the venue's
   $1 min order (4% of a $22 book is $0.89 — sub-min stakes died at the
   gate). bankroll rebased to the real $22.28 equity; spend tracker reset
   (the confusing $35 is gone with the daily cap).
2. Price guard is now ABSOLUTE +0.05 (both books): 0.14→0.15 follows,
   0.14→0.20 skips. The relative 5% blocked one-tick moves on cheap
   in-play books.
3. Pending-order registry: in-play 'delayed' holds are no longer cancelled
   at 20s — the executor hands them to state.pending_orders with full copy
   context; the heartbeat resolver adopts the fill whenever it lands
   (bets/my_pos/cash/ledger, TTL 600s → cancel + honest miss). Recovers
   Rune-Eaters-class holds (+$7.50 forfeited by the old cancel).
   5 stub-client paths pass incl. adopt + expire.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 17:17:26 -04:00
jaxperro 56fe0dee92 INCIDENT FIX: in-play 'delayed' acceptances were logged as misses and filled untracked
2026-07-10 09:10-13:14Z: six $5 in-play esports copies returned AcceptedOrder
status 'delayed' with zero matched; the executor read matched==0 as a
rejection, recorded honest misses, and forgot the orders — which then filled
at the exchange minutes later. Book went blind (6 untracked fills, ~$30 real
spend vs $5 booked), caps stopped binding, exits never mirrored. Net damage
contained by the CLOB's own balance checks: −$2.7 incl fees, two legs won.

Executor invariant now: NO order outlives _order() untracked. Zero-matched
acceptances poll get_order → cancel remainder → measure truth via the
exchange's CONDITIONAL balance diff; exception paths sweep open orders on
the token the same way. 5 stub-client unit paths pass.

State surgery (machine disarmed first): cash reset to chain ($10.03), six
fills adopted as bets (4 settled −$4.38 w/ fees, Aurora G2 open+won), spend
tracker set to the real $35/day, false miss rows purged, one documented
-0.59 adjustment (bank-vs-deposit + probe).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 11:25:10 -04:00
jaxperro c5b87afcab live executor ported to the unified SDK (polymarket-client)
py-clob-client is archived; the CLOB rejects its orders globally. New
LedgerLiveExecutor: SecureClient.create(private_key) — deposit wallet
auto-resolves, no api_key at runtime; place_market_order FAK/FOK with
protected prices (quoted ±live.max_slippage_pct, default 5%, clamped to
[0.01,0.99]); fills parsed from AcceptedOrder (BUY: making=USD given,
taking=shares got; SELL reversed — semantics PROVEN by today's $5 round
trip: buy matched 7.35294 @ 0.68, sell matched 7.35 @ 0.67). Still never
raises into the trade loop. chain_cash_gap repointed at the deposit
wallet's pUSD (was the emptied legacy proxy → CASH≠CHAIN +24.73 alarm).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 01:08:18 -04:00
jaxperro bf11de9759 live executor crash-proofed + baseline stops eating fresh trades + poll guard
Root cause of zero live placements: the FIRST two qualifying signals
(Kruto 21:21, badaf Epic 21:53) each CRASHED the bot inside the
unguarded live order path (machine events: exit_code=1 seconds after
each signal; tick-size rejection the likely thrower — price was rounded
to 3dp on 1c-tick books). Fly restarted it and boot baseline marked the
fresh trades seen-without-copying: crash -> restart -> trade eaten,
twice. Fixes: _order never raises (failures return ok:False and feed
the new missed-row instrumentation); tick-size-aware pricing (cached
get_tick_size, buys ceil / sells floor, 0.01 fallback valid on every
book); size floored to 2dp; per-wallet poll guard (parity with the push
handler); baseline exempts trades younger than the stale window so a
restart can never eat a copyable trade again. host/order_probe.py =
controlled end-to-end placement proof (~$2 round trip).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-09 20:14:38 -04:00
jaxperro 8d0b087dd1 missed rows settled at resolution get one exit-print re-check
Fast in-play markets can resolve before the 5-min pass sees the sharp's
sell (and pre-2026-07-09 rows predate exit-aware settling) — won/lost
stamps hid real pre-resolution sells. A redeem prints exactly the
payout; an exit print >2c away revalues the counterfactual at the
sharp's exit. Idempotent via exit_checked.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-09 14:10:25 -04:00
jaxperro 8b91893fc9 missed bets settle at the sharp's EXIT when they sold pre-resolution
The missed ledger valued everything hold-to-resolution — the wrong
counterfactual for a mirror strategy (Kruto's 3c Hive entry: he banked
16x selling at 48c; the paper book mirrored for +$722; the live book's
missed row would have shown the map result instead). Three affirmative
facts before settling (same as reconcile_exits), their reconstructed
exit price, entry+exit taker fees. Also: the reconcile miss reason is
now honest — 'not copied in the detection window (reconciled)'.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-09 14:04:32 -04:00
jaxperro 6995b4e8d8 copybot: never clobber a settled bet record on re-entry (+ restore the two vanished)
bets{} is keyed by token; re-entering a settled market OVERWROTE the old
record and its pnl left 'realized' — the drift alarm caught it same-day
(WTI −9.97, Dota Game-1 +19.30 recovered from state history and restored
as archive keys). All three record-writers now archive settled records
to token#settled_ts keys first; aggregators iterate values() so archived
rows keep counting. NOTE: restoring truth WIDENS displayed drift — a
second, opposite-sign residual (~−11) remains under investigation
(morning forensics queued in HANDOFF); the alarm stays red on the paper
book intentionally. Live book unaffected (0 trades, drift 0).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-09 13:53:19 -04:00
jaxperro 0b4f9158da copybot: merge fill-split conviction bets before the floor gate
A sweep or rapid clip entry splits ONE bet into several sub-floor fills:
gkmg's $612 MOUZ entry today read as 3×$204 same-second rows, every
clip below his $304 floor — the bot skipped a bet the backtest's
position-level view takes (he sold +60% five minutes later). Same-token
BUY rows within 120s now merge into the bet the sharp actually made
(weighted price, summed size, all component txs marked processed);
SELLs stay per-fill for the proportional mirror. reconcile_entries
applies the same clustering to its not-a-miss verdict so downtime
fill-splits count as real misses. Applies to BOTH books identically.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-09 13:45:08 -04:00
jaxperro 97a1138f49 live bot: per-fill Discord pings via DISCORD_WEBHOOK env secret (paper stays digest-only)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-09 00:52:17 -04:00
jaxperro d4eacbd72b publish_feed: publish untracked (first-ever) feed files — real-money feed was stuck at 404
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-09 00:50:08 -04:00
jaxperro 95998aaca4 live env credentials: strip pasted whitespace; bankroll = actual $24.73 deposit
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-09 00:30:07 -04:00
jaxperro 8ce616349e reconcile: accumulated sub-floor positions are not 'missed · bot offline'
The live path gates PER TRADE; reconcile_entries gated on POSITION size,
so 0xbadaf319's paired YES+NO arb clips ($6-37 each, all correctly
skipped below his $45 floor) accumulated into $40+ positions that read
as downtime misses while the bot was demonstrably UP. Now a miss needs
some SINGLE buy on the market to pass the same follow filter (market-
filtered /trades, full history); sub-floor accumulations log-and-skip
with a persisted verdict (state.no_miss_toks). Four phantom records
removed from the book; their hypothetical P&L never belonged in the
missed counterfactual.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-08 18:12:28 -04:00
jaxperro f19cc8d168 copybot: capture order-book snapshot (spread + 5c depth) on every copy
New 'book' field in the fills ledger: {bb, ba, spread, bid5c, ask5c}
from CLOB /book at fill time. The calibration experiment's weakest
assumption is the flat SLIP haircut; weeks of these snapshots give an
empirical fill model for the backtest and a depth gate before real
money sizes up (today's probe: a  stake vs $77 of bids within 5c).
Best-effort, never blocks a copy.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-08 17:56:20 -04:00
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 7965868181 copybot: publish recovers from a conflicted rebase instead of wedging
Abort -> hard-reset to origin -> re-commit the running book. The
process is the book's single writer; remote state surgery must stop
the bot first (2026-07-08 BOOK RESET race: stale boot clone rebased
old state onto the reset and every publish died in UU until reboot).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-08 16:25:49 -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 0c58ed8152 copybot: exec-lag/slippage report a 24h rolling window, not lifetime avg
The heartbeat/dashboard 'avg lag' was a lifetime accumulator that mixed the
retired 60s poll era into push mode, so a genuinely ~3s bot read as 48s.
lag_recent now keeps the last 24h of (ts, lag, slip); summary + feed report
the 24h average (n = lifetime copies, n24 = fills in window). Backfilled from
copybot_fills.jsonl on boot so it's populated immediately. Verified: 24h view
12s vs 48s lifetime — reflects real push execution.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 22:35:30 -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 0e95ab1bf3 live-rollout Phase 1 (partial) + discord ping post-wake retry
copybot.py:
- 1.1 feed_path/fill_log are config-driven (live run won't clobber the
  paper book's feed or fills ledger)
- 1.2 LIVE_PRIVATE_KEY / LIVE_FUNDER_ADDRESS / LIVE_SIGNATURE_TYPE env
  overrides (Fly worker has no gitignored config.live.json)
- 1.4 chain_cash_gap(): live-only book-cash vs CLOB USDC balance, logged
  as ⚠ CASH≠CHAIN (the real-money ledger_drift)
- 1.5 geo-gate is FATAL in live mode — unauth order probe; refuses to arm
  from a 403-geo-blocked box before the confirm phrase (verified: refuses
  from this US Mac)
- 1.6 mirror-exit retry: FAK sells that fill 0 on thin books retry each
  backstop poll, ⚠ EXIT STUCK alert after 10 unfilled attempts

discord_daily.py: --ping retries 4x (5/10/15s) — launchd wakes the Mac to
run daily.sh and the heads-up ping was racing DNS/WiFi coming up after
sleep (getaddrinfo 'nodename nor servname'); the end-of-run digest always
landed, only the start ping lost the race.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 10:59:07 -04:00
jaxperro 327513d185 copybot: reconcile_entries — downtime entries become missed bets, not silence
The backtest reads positions (state); the bot reads trades (events). A trade
during downtime was silently baselined away at the next boot — not copied,
not missed, invisible — while the backtest still showed it (2026-07-07:
9 ArbTrader positions opened into the Fly trial-expiry crash-loop appeared
only in portfolio.json's current list). Now every boot + backstop poll
records any unseeded, unheld, unrecorded position that clears the follow
filter as a missed bet (reason 'bot offline'), settled hypothetically like
every other miss. Never copied — the entry is stale by definition. Dust
below risk.min_order_usd is ignored; API failure skips (silence is never
data). Bets that open AND close entirely within downtime stay the
backtest's domain.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 02:10:21 -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 0c7ee62ed7 copybot: push mode — Alchemy webhook + heartbeat + backstop poll
Setting ALCHEMY_SIGNING_KEY on the worker switches start.sh to webhook
mode: instant copies on POST /alchemy (signature-verified), a 60s
housekeeping heartbeat (settle, feed, summary), and a full backstop poll
every 5 min so a dropped push costs minutes, not a silent miss. Webhook
mode now baselines at boot and publishes an initial feed like poll mode.
No signing key -> classic 60s poll, unchanged.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 00:07:23 -04:00
jaxperro 4190455436 copybot: compact follow config + auto floors + one-command deploy
config format matches backtest.json — one entry per wallet:
  wallets: [{wallet, name, class: volume|whale, floor?}]
normalize_follow_config expands it into the legacy watchlist/watch/
floors/classes structures (old-format configs like config.live.json
pass through untouched). Volume wallets without an explicit floor get
an auto p80 derived from the data-api at boot (the worker has no cache),
logged and published in the feed. live/deploy_bot.sh = validate ->
preview -> commit -> push -> railway redeploy -> confirm boot.

Promotion workflow: prove a wallet in backtest.json, copy the same
entry into copybot.paper.json, run deploy_bot.sh.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-05 23:10:51 -04:00
jaxperro cb4a33279a sharps feed: all-time trusted stats (every bet); bot feed: wallet classes
* validate_timing.display_stats adds all_win/all_won/all_lost/all_pnl —
  the wallet's record and own P&L over EVERY resolved bet ever cached,
  trusted rows only, deduped one-per-market (feeds the dashboard's new
  All-Time columns); consensus temp table now built before the pool
* copybot write_feed adds classes {name: volume|whale} so the dashboard
  can badge whale-class wallets

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-05 22:43:56 -04:00
jaxperro e07ff3d305 copybot: sold legs now realize on the bet record, not just cash
Mirror-exits were correct at book level (cash/fees) but invisible per bet:
a fully mirror-sold bet went to 'closed' with pnl null, and a TRIMmed bet
that later resolved subtracted its ORIGINAL cost+fee while ignoring the
sold leg's proceeds — understating whole-bet pnl on the feed.

* _drain_fills links every SELL fill to its bet record
  (sold_shares / sold_proceeds, net of taker fee)
* write_feed: full mirror-sell -> pnl = sold_proceeds − cost − entry fee,
  plus exit_price; dashboard's existing 'mirror-sold with recorded P&L'
  branch picks it up
* settle_resolved: pnl = resolution proceeds + sold leg − original cost −
  entry fee (pos.cost is trim-reduced; bet.cost is the original)

Sandbox-tested: TRIM cash+record, TRIM->WIN whole-bet truth, full EXIT
feed reconcile all agree to the cent.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-05 21:58:06 -04:00
jaxperro 034e128281 copybot: whale class follows ALL trades — no conviction floor
Whale-class wallets bypass min_their_usd and per-wallet floors entirely:
both current whales win ~92% across their ENTIRE book (Stavenson 469-39,
0x4bFb 862-72 all-time trusted; 99.2% last 30d for the whale), so
size-filtering them only costs flow. The 0.95 entry cap stays (execution
guard, validated). Floors removed from the paper config for both.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-05 21:45:45 -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 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 6e09e7bb71 CRITICAL settle fix: CLOB winner=False means unresolved, not lost
The CLOB reports winner=False on EVERY token of an unresolved market; only a
True winner anywhere means resolved. resolution_price treated False as "lost",
so the 60s poller settled live in-play positions as instant losses 1-3 min
after entry (June's ~2h Actions cadence masked it - markets had genuinely
resolved by the next check). Same semantics fixed in _market's resolved-cache
gate and validate_timing._clob_winner (unresolved held bets were counted as
losses, biasing copy_pnl selection downward).

Also: _record_lag now AGGREGATES fills per token (ADD used to overwrite the
display record, showing one fill's cost against the whole position's P&L -
the Cost $20.84 vs P&L -$57.30 confusion).

State repaired: the four July bets all actually WON on-chain (verified by
token winner flags) - settled correctly, +$225.40 proceeds restored, book
$1,045.19 (+45.19 realized, 4W/0L).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-02 23:15:27 -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 08f87c589e paper-run realism: taker fees, resolved-only scoring, bounded collect, local runner
- copybot: model Polymarket taker fees (V2, since 2026-03-30: shares*rate*p*(1-p),
  sports 0.03) on every paper/live fill; track fees_paid in state + feed; settle
  P&L nets the entry fee. publish_feed now commits state + fills ledger with the
  feed (autostash rebase) so the local poller is the sole state writer.
- validate_timing: copy_pnl/held_pnl are fee-aware -> sharp selection now requires
  clearing real copy costs; conv stats + lead profile use resolved bets only.
- conviction_scan/skill: exclude res_t>now rows (early-sold positions in
  unresolved markets scored at curPrice - a mark, not an outcome; was ~5% of the
  June test window at a 72% pseudo-win rate).
- portfolio: skip unresolved rows (stake used to vanish from equity); missed bets
  of kind=open no longer KeyError - mark-to-market hypothetical P&L.
- collect: cap stale refreshes at STALE_CAP=2500/run (bulk-aged pool turned the
  daily refresh into a ~40h pull holding the DuckDB lock).
- Actions cron disabled: GitHub ran */5 every ~1.5-2.5h and the 10-min stale
  window skipped the rest -> 1 of ~104 qualifying buys copied. launchd --poll 60
  is now the runner; workflow stays as manual backstop.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-01 23:15:14 -06: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