# πŸ† Winning Wallet Finder Find Polymarket wallets with a **real, statistically-verifiable edge**, test whether copying them actually makes money β€” **with real fees, lag, and slippage** β€” and copy-trade them with a 24/7 bot (paper today, live-capable). This started as "copy the smart money." Along the way we tested β€” and ruled out β€” six systematic public-data strategies, and found that the *only* signal that holds up is **statistical improbability**: wallets that win far more than the prices they paid imply. This repo is the tooling for finding, validating, and copying those wallets, plus an honest record of everything that didn't work. > **Read [`FINDINGS.md`](FINDINGS.md) for the research story.** TL;DR: detection > works; profitable copying is *plausible but unproven* β€” every backtest here is > in-sample by construction, and **the July 2026 forward test (live now) is the > arbiter.** Treat headline returns as ceilings, not forecasts. --- ## The system today (July 2026) Three deployed pieces + one static dashboard: | piece | where it runs | what it does | |-------|--------------|--------------| | **daily pipeline** (`live/daily.sh`) | this Mac, launchd 10:00 | refresh the bet cache β†’ 5-gate skill scan β†’ fee-aware sharp selection β†’ conviction floors β†’ backtest book β†’ publish JSON feeds to GitHub | | **copybot worker** (`copybot.py` via `host/start.sh`) | Railway, 24/7 | polls the 4 followed wallets every 60s, paper-copies their conviction bets with real fees/lag/slippage accounting, settles at CLOB resolution, commits its book back to the repo | | **Discord watcher** (`webhook_receiver.py`) | Railway `web` service | Alchemy address-activity webhook β†’ instant trade pings | | **dashboard** | [jaxperro.com/trading](https://jaxperro.com/trading) (static, in the `jaxperro` repo) | renders the three JSON feeds: live bot book, backtest book, sharp table | **The July 2026 live test:** a fresh $1,000 paper book (started 2026-07-02, on Railway) following **Kruto2027, shisan888, fortuneking, LSB1** β€” the top fee-adjusted copy-positive sharps + one curated pick. Every fill records detection lag, price slippage, and the taker fee; missed bets are recorded and settled hypothetically. If this month's *measured* numbers hold up, real money follows (see [`LIVE_TEST.md`](LIVE_TEST.md)). ``` data layer selection execution display ────────── ───────── ───────── ─────── live/cache.duckdb ─▢ skill.py (5-gate funnel) copybot.py (Railway) ─▢ jaxperro.com/trading (schema v2: conviction_scan.py (p80 bets) Β· 4%-of-equity stakes Β· copybot_live.json 33k wallets, validate_timing.py (fee-aware Β· taker fees modeled Β· portfolio.json 19M resolved bets, copy replay β†’ watch_sharps) Β· lag/slip per fill Β· watch_sharps.json token-keyed, portfolio.py (backtest book) Β· missed-bet ledger archival) sync_floors.py (bot parity) Β· CLOB settle + redeem ``` --- ## File map | path | role | |------|------| | `live/` | **the current system**: cache, scanners, sharp selection, backtest, daily pipeline ([live/README](live/README.md)) | | `copybot.py` | the copy-trading bot: push/poll trigger β†’ follow filter β†’ execution engine (paper + live) | | `archive/copytrade.py` | the execution engine the bot reuses: sizing, risk gates, price guard, paper/live executors | | `host/start.sh` | 24/7 worker bootstrap for Railway/Fly/VPS (clones repo, resumes committed state) | | `LIVE_TEST.md` Β· `preflight_live.py` Β· `redeem.py` | real-money runbook, read-only credential preflight, on-chain redemption | | `insider.py` | the original detector: z-score, pre-resolution timing, fresh-wallet flags, funding-cluster rings | | `smart_money.py` | shared HTTP helper + survivorship-corrected win-rate dashboard (`:8899`) | | `webhook_receiver.py` | Alchemy webhook β†’ Discord trade pings (Railway `web` service) | | `wide/` | frozen-subgraph bulk scanner (1.76M wallets, historical only β€” subgraph froze Jan 2026) | | `archive/` | the six strategies that didn't work, kept honest ([archive/README](archive/README.md)) | | `hunt.py` Β· `huntwide.py` Β· `oos.py` Β· `copyback.py` | earlier research sweeps/backtests (superseded by `live/`) | --- ## The core idea: z-score, not win rate Every Polymarket bet has an entry price that *is* the market's estimate of its odds (a YES at 30Β’ β‡’ market thinks 30%). If you have no edge, over many bets you win about the **sum of your entry prices** β€” call it *expected wins*. ``` z = (actual wins βˆ’ expected wins) / standard deviation ``` - **z = 0** β†’ you won exactly what your prices implied β†’ no edge. - **z = 3** β†’ ~1-in-740 by luck. **z = 5** β†’ ~1-in-3.5M. Why this beats win rate: a wallet that bets longshots and wins 14% when the odds implied 8% has a huge edge (high z) despite a low win rate; a wallet buying 90Β’ favorites and winning 90% has zβ‰ˆ0. Win rate is also **survivorship-biased** on Polymarket (losing shares sit unredeemed and invisible β€” see FINDINGS). And even true win rate **over-counts scalpers** β€” so the final selection metric is **fee-adjusted Copy P&L**: what a flat-$50 copy of the wallet's conviction bets *actually* returns after taker fees (replay entries, mirror exits, settle at CLOB resolution). Judge by Copy P&L, never win rate. --- ## Quickstart for a new developer ```bash git clone https://github.com/jaxperro/winning-wallet-finder cd winning-wallet-finder pip3 install duckdb # the only dep for research/selection cp config.example.json config.json # secrets live here (gitignored) # selection layer (live/) β€” everything reads the local bet cache cd live python3 enumerate.py 30 # build a candidate pool (last 30d markets) python3 collect.py # pull their bets into cache.duckdb (resumable) python3 skill.py # 5-gate skill funnel -> watch_skilled.json python3 conviction_scan.py # conviction-bet profile scan python3 validate_timing.py # fee-aware copy replay -> watch_sharps.json python3 portfolio.py # the backtest book -> portfolio.json ./daily.sh # or: the whole thing, end to end # copy bot (repo root) β€” paper by default, no orders ever without --live python3 copybot.py --config live/copybot.paper.json --state /tmp/s.json --poll 60 python3 copybot.py --test-wallet 0x… # dry-run one wallet's latest trade # live trading (real money): read LIVE_TEST.md, then pip3 install py-clob-client web3 python3 preflight_live.py # read-only credential/balance check ``` The cache is the point: **every score re-runs in seconds from `live/cache.duckdb`** (~33k wallets / 19M+ resolved bets) instead of hours of API pulls. Schema v2 is token-keyed, provenance-tagged, and archival (refreshes upsert instead of wiping; failed pulls are never cached as "no bets") β€” details in [`live/README.md`](live/README.md). ### Config & secrets (all gitignored) | file | holds | |------|-------| | `config.json` | Discord webhooks, Alchemy key, the followed-wallet list + per-wallet conviction floors (auto-refreshed daily by `sync_floors.py`) | | `config.live.json` | live-trading credentials (`private_key`, `funder_address`) + tiny test caps β€” see `LIVE_TEST.md` | | Railway `copybot` service | `GITHUB_TOKEN` (fine-grained PAT, contents-RW on this repo β€” the bot commits its state/feed back), optional `DISCORD_WEBHOOK` | --- ## How the copy bot models reality The whole point of the July test is that paper β‰ˆ live. Every mechanism the backtest and bot share: - **Taker fees** (Polymarket V2, since 2026-03-30): `fee = shares Γ— rate Γ— p(1βˆ’p)`, sports rate 0.03 β€” charged on every marketable entry and exit; redeeming at resolution is free. Fee-adjusted Copy P&L also drives *selection*. - **Lag + slippage**: the bot fills at the live CLOB ask at detection (~60s poll), logging per-fill `detect_lag_s` and `slippage_pct`; the backtest applies a +0.5%/~90s haircut. Measured so far: 64s / +1.9% on the first live-sports fill. - **Dynamic sizing**: each bet stakes **4% of current equity** (compounds both ways), halved while equity is below 80% of its high-water mark. No per-trade cap. A per-event correlation cap exists (`risk.max_per_event`) but is **off** β€” every conviction trade is followed. - **Conviction filter**: only copy a wallet's top-20%-by-stake bets (per-wallet p80 floor, kept in sync with the dashboard by `sync_floors.py`). - **Missed-bet ledger**: every bet the bot *couldn't* take (cash deployed, price guard) is recorded and settled hypothetically β€” capacity costs are measured, not invisible. - **Settlement**: winners settle at authoritative CLOB winner flags; live mode auto-redeems on-chain (`redeem.py`; neg-risk markets need manual redeem). Safety: paper is the default; live requires `mode:"live"` **and** `--live` **and** a typed confirmation phrase, under hard caps. The GH-Actions cron runner is retired (GitHub throttled `*/5` to ~2h in practice β€” it copied 1 of ~104 qualifying trades in June; the always-on Railway poller replaced it). --- ## Data sources | Source | Used for | |--------|----------| | `data-api.polymarket.com` | positions, trades, activity (+`eventSlug`), leaderboard | | `gamma-api.polymarket.com` | market metadata (NB: `condition_ids` filter returns nothing for resolved markets) | | `clob.polymarket.com` | order books, prices, **authoritative resolution** (`winner` flags), market slugs | | Alchemy (Polygon) | funding-cluster traces + the live trade webhook | --- ## The research (how we got here) **The 5-gate funnel** (`live/skill.py`): a wallet is "skilled" only if it clears `n β‰₯ 15 resolved bets` β†’ `z > 0` β†’ `Benjamini–Hochberg FDR @5%` β†’ `split-half out-of-sample persistence` β†’ `not a market-maker` (all resolved-only: early-sold positions in unended markets are marks, not outcomes, and never score). **The clean test (June 2026):** high-win-rate "favorite-rider" wallets looked +23.6% in-sample and lost βˆ’7.4% once selected without look-ahead β€” exactly the LBS/Yale "~60% of lucky winners become losers" result. **Don't copy win rates.** **The repeatable find:** score wallets on their **conviction bets** (top 20% by stake, per-wallet p80) β€” the edge is wallets that win 70–80% on genuinely uncertain (~0.4–0.6) markets. Trained pre-June, validated June: 62/83 stayed profitable forward (pβ‰ˆ0). A **fee-aware flat-$50 copy replay** then keeps only wallets that are actually profitable to *copy* (scalpers with ~100% shown win rates lose money when copied) β†’ currently **12 copy-positive holders** in `watch_sharps.json`, refreshed daily. **The backtest** (`live/portfolio.py`): the followed four, June 1 β†’ now, with fees/lag/dynamic sizing: **+531%** β€” but June is the month these wallets were *selected on*, so that's an in-sample ceiling. July, live, is the test. **What didn't work** (see `FINDINGS.md` + `archive/`): copy-trading raw, win-rate ranking, LP reward farming, binary & multi-outcome arb, cross-venue PM↔Kalshi arb β€” all efficient or illusory. --- ## The honest verdict - **Detection works.** z + timing + funding clusters reliably surface anomalous wallets. - **Copying is promising but unproven.** Selection is fee-aware and execution-realistic now, but every historical return in this repo is in-sample. The running July book β€” real lag, real fees, measured slippage, missed bets counted β€” is the first number that deserves trust. - **Scale carefully.** Above ~$250/clip in thin sports books, best-ask fills turn optimistic; a depth-aware fill model is the known next step before sizing up.