Commit Graph

24 Commits

Author SHA1 Message Date
jaxperro a186d5a839 portfolio: --bank flag (and backtest.json 'bank') — replay any starting bankroll
$500 Set E 30d: $14,140 (+2728%) vs $1,000's +2103% — smaller books
compound purer because 4% stakes hit the their-bet ceilings later.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-08 16:55:16 -04:00
jaxperro 542fe700b6 portfolio: align the backtest's booking with the live bot and Polymarket truth
Three fixes from the 2026-07-08 alignment audit (bot feed vs replay,
row-by-row):
1. sold-detection no longer trusts res_t alone — for in-play markets
   res_t is endDate metadata (game-DAY midnight, pre-dates the entry) so
   the timestamp test never fired and every in-play sell booked as
   held-to-resolution. Price is the fallback truth: a redeem prints
   exactly the payout, a real sell prints a mid price (>2c off payout).
2. round trips on resolved-on-chain markets are booked, not dropped —
   when the trusted cache row never qualifies (bogus forward res_t:
   Chidekh 'unresolved until Jul 14' on a Jul-5 match) the bet used to
   vanish; now redeem-closes book at chain truth, sell-closes mirror.
3. Set-D wallets gate on the bot's PINNED floors (copybot.paper.json),
   not a recomputed p80 that drifts a few % and takes different bets.
Also: resolved display slice 60 -> 250 rows.
Cross-check: 9 settled Set-D bot bets -> 7 agree, 0 absent, 2 diffs that
are real execution gaps (bot missed the sharp's exit, rode to
resolution) — each book records what actually happened to IT.
Equity 30d: $29.1k -> $17.4k (+1636%) — the flattering artifacts are gone.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-08 11:35:31 -04:00
jaxperro 09e511cc2e backtest: fold in-window abandoned losers into the replay (consistency with sharps)
The replay selected trusted conviction bets + sold round-trips + chain
settlement, but abandoned losers (bets held to a decided outcome, never
redeemed — /positions at curPrice 0, not in /closed-positions, not trusted
rows on operator-resolved markets) fell out entirely, reading optimistic.
resolved_unredeemed() now pulls them; window_bets folds in the in-window,
conviction-size ones at their decided outcome (loser pays 0). Same anti-
survivorship correction as the sharps table's _open_split.

Impact on the follow-set 30d backtest is ~0 ($16,255->$16,260): those 8
wallets are clean, AND abandoned-loser survivorship is an all-time
ACCUMULATION (oliman2: 1123 losers lifetime, only 2 in any 30d window), so a
30d period metric structurally can't surface much of it. The fix guarantees
no in-window loss is dropped and keeps the backtest consistent with the
all-time sharps view where survivorship actually lives. Verified the fold-in
fires (oliman2's 2 in-window conviction losers identified).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 21:44:52 -04:00
jaxperro fb462b7168 exits: fix the 50-row page cap + incremental exits cache in duckdb
/closed-positions serves 50-row pages regardless of limit; stepping by the
requested size truncated every wallet's exit history to its most recent ~50
closes (1% coverage for hyperactive wallets) — sold-mirroring was silently
falling back to the hold-to-res ceiling almost everywhere. Now: page by
returned size, cache exits incrementally in duckdb (immutable events —
deep backfill once, a page or two per refresh; title/outcome columns for
display). Deep-exit 30d replay: $18,270 (+1727%), 259W/79L/29R/284S,
misses 253 -> 1 (mirrored exits recycle capital as fast as the signal does).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 07:27:30 -04:00
jaxperro 72245e4053 sharps stats mirror exits too (SOLD) — one exit model across all three books
smart_money.closed_exits() is now the shared implementation (backtest +
sharps): close time from /closed-positions, exit price reconstructed from
realized P&L. validate_timing's conv/conv30/all-time/realized tallies count
a bet the wallet sold pre-resolution at its exit price (conv_sold /
conv30_sold / all_sold fields) instead of pretending it rode to resolution.
Beyond the ~4000-row data horizon exits fall back to hold-to-res.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 03:18:41 -04:00
jaxperro 44a08cdc0d backtest: exits mirror the signal (SOLD status) — same model as the live bot
The replay held everything to resolution while the live bot mirrors exits —
two different strategies wearing one dashboard. Now, when a followed wallet
fully closed a position pre-resolution, the replay sells there too: close
time from /closed-positions, exit price reconstructed as
avgPrice + realizedPnl/totalBought, exit taker fee + slippage haircut paid.
Complete in-window round trips on unresolved markets (entered AND exited —
previously invisible to the replay) are included; on-chain-resolved conds
are excluded from round-trip synthesis so redeems can't masquerade as
sells. Sold legs count apart from W/L/R (they're price events, not
outcomes): 30d now 226W/55L/84R/31S, $12,730 (+1173%) — mirrored exits
bank the wallets' early profit-taking that hold-to-resolution left behind.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 03:09:21 -04:00
jaxperro 3674d2f099 whales demoted to volume class everywhere + status vocabulary in the backtest feed
- all three whales -> volume (conviction-only, 4%/bet); truth-scored 30d
  replay IMPROVES $2.5k -> $10.5k (+946%, 230W/54L/88R): follow-all at 12%
  was burning bankroll on low-conviction in-play scraps. Demoted wallets get
  floors PINNED from trusted cache p80 (Stavenson $4,760 / 0x4bFb $1,090 /
  ArbTrader $168) — their dust-heavy recent books auto-derive uselessly low.
- portfolio feed rows now carry status won/lost/refund (missed too),
  mirroring the live bot; no 'sold' by design (hold-to-resolution replay
  never exits early). Dashboard renders refunds amber with W/L/R counts.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 02:59:13 -04:00
jaxperro 0de033398a feeds: first truth-scored refresh + refunds counted apart in the replay
The honest 30d backtest: $1k -> $2,538 (+154%), 78W/18L/112R — not the
refund-inflated +8,627%. Sharp list: 33 copy-positive holders under truth
gates; 0x4bFb-whale and ArbTrader no longer qualify (their conviction
records were carried by 50/50 refunds counted as wins). portfolio.py now
reports refunds as R, not L (a scratch is not a loss).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 02:50:46 -04:00
jaxperro 4941818d51 scoring: chain-truth resolutions overlay — refunds no longer count as wins
The cache's won (curPrice>=0.5 at pull) counts 50/50 refunds as wins for
BOTH sides — 521 of 2,128 chain-checked follow-set markets (24%) were
refunds, which is where the whales' 92-100% displayed win rates came from.

- live/payouts.py: resolutions table in cache.duckdb, filled from the CTF
  contract's payout vectors (batched+paced JSON-RPC, ~12 calls/s free tier;
  resolved rows immutable, unresolved recheck 6h, RPC failures never cached).
  truth(cond, asset) -> 1/0/0.5/None; refunds need no asset side.
- validate_timing: every displayed stat (conv/conv30/all-time/realized/copy
  replay) settles at truth; refunds count as neither W nor L, P&L is
  size*(wp-p)/p; new conv_ref/conv30_ref/all_ref feed fields.
- trust.conviction_record: optional truthfn — the selection gates
  (trust_wr/trust_roi) no longer select on refund inflation.
- portfolio.py: replay pays wp (refunds 0.5/share, was 1.0).
- conviction_scan: documented as the (refund-inflated) candidate layer;
  final selection re-judges against truth downstream.

Validation: 0x4bFb-whale conv 174-16 91.6% $1.61M -> 34-16 +140ref 68%
$214k, and truth-adjusted all-time P&L now sits within ~16% of lb-api's
PM P&L (was 7x apart); LSB1 (0 refunds) byte-identical, its P&L matches
PM P&L to 0.07%.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 01:55:50 -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 1b8f48eda3 backtest: drop banking/stake-cap; stakes capped at the followed wallet's own bet
cur_stake = class % of equity (drawdown-braked), then min(their stake):
a copy is never bigger than what the wallet actually bet. No reserve
sweep, no $250 pin — the their-bet ceiling is the liquidity bound now
(fills stay within size the market demonstrably absorbed).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-05 23:41:59 -04:00
jaxperro 4792235582 backtest: interchangeable wallets + rolling window (live/backtest.json)
portfolio.py now replays ANY wallet set over a rolling N-day window
(default 30) instead of the hardcoded four-from-June-1:

* live/backtest.json: {days, stake_cap_usd, class_pct, wallets:[{wallet,
  name, class}]} — edit to add/remove/swap wallets; seeded with the paper
  bot's current 7-wallet follow set
* class parity with the bot: 'whale' replays EVERY trusted bet at
  class_pct.whale of equity; 'volume' replays conviction bets at
  class_pct.volume, p80 threshold from PRE-window bets only (no peeking)
* outcomes read through trust.py (trusted rows) so any pasted-in wallet
  is scored honestly, not on cache marks
* ad-hoc CLI that leaves the dashboard feed alone:
    python3 portfolio.py --wallets 0xabc,0xdef:whale --days 14 --out /tmp/t.json
* fix: open positions with unknown entry time used to sort at t=0 and
  drain the bankroll before any historical bet ran; they now queue at the
  end (and pre-window entries are excluded)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-05 22:15:37 -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 132793a166 follow imwalkinghere (5th wallet): top fee-adjusted sharp
+$2,454 copy P&L, 72.4% conviction win (144-55), $257 avg bet, 2.1h median
lead. Added to bot configs (p80 floor $115.27) + backtest set. June backfill
with him: +2677% (in-sample selection bias + compounding, next stake $1,070 -
treat as a ceiling; depth-aware fills become necessary at these clip sizes).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 00:41:25 -04:00
jaxperro b9ed4b1d2b portfolio: per-wallet win/loss records in the feed's allocation rows
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-02 23:48:54 -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 e85809e8b1 uncap per-trade sizing: pure 4%-of-equity compounding
max_trade/max_position guards lifted in both paper configs; backtest STAKE_CAP
-> inf. June backfill uncapped: +531%, next stake $252, $195 fees.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-02 11:26:08 -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 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 f18162058d July live test: follow Kruto/shisan/fortuneking/LSB1; fee+lag backtest; 24/7 host runner
- portfolio.py: follow set -> the fee-aware copy-positive sharps (Kruto2027,
  shisan888, fortuneking) + LSB1; entries pay the 0.03 sports taker fee and a
  +0.5%/~90s lag haircut (entry_model); backfilled from June 1; feed exposes
  fee_rate/slip/lag_est_s/fees_paid and unreal uses true cost basis.
- copybot.paper.json: same four wallets, p80 conviction floors from the cache
  (Kruto $123.08, shisan $704.33, fortuneking $970, LSB1 $231). Fresh $1k state
  committed separately by the bot - clean July book.
- host/start.sh + nixpacks: turnkey 24/7 worker for Railway/Fly/VPS - clones
  with GITHUB_TOKEN, resumes the committed state, polls 60s, publishes
  state+feed+fills back through publish_feed. Replaces the Mac poller.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-02 09:51:35 -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 92fe276737 live: expose per-wallet conv_thr in portfolio.json (for live current-bets)
Adds each followed wallet's cache p80 conviction threshold so the dashboard
can filter LIVE open positions the same way the server does.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 15:16:13 -06:00
jaxperro 87a956a059 live: reset paper portfolio to a forward test starting 2026-06-23
Set portfolio.py START to today so the $1k book tracks these wallets from
now forward (clean forward test, no in-sample backfill). Equity resets to
~$1,000; the daily run fills it in as bets resolve.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 15:00:11 -06:00
jaxperro 9cbafabfdd live: precompute the $1k paper portfolio off the cache (portfolio.py)
New portfolio.py replays the followed wallets' conviction bets ($1k/$50,
hold-to-resolution) from cache.duckdb — which has res_t, so capital
RECYCLES at the true resolution time (no client-side clob storms, no
phantom-locked capital) and covers the full bet history (~40 pages, not
the browser's 4). Writes portfolio.json (equity, splits, current/
resolved/missed tables, per-wallet); wired into daily.sh + publish. The
dashboard now renders the top page from this feed (1 request) with the
client-side replay kept as a fallback.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 14:43:50 -06:00