Files
winning-wallet-finder_github/FINDINGS.md
T
jaxperro 1d754353c2 selection: trusted-row layer + holder-gate fix — the holder blind spot
Two data bugs were hiding the best copy targets (FINDINGS 'The holder
blind spot'):

* live/trust.py (new): only score rows whose res_t matches the market's
  consensus resolution time across >=2 wallets, pulled after resolution,
  resolved != False. Kills the res_t=ts fallback poison that let scalpers
  masquerade as 99%-win holders (ArbTraderRookie's rows were 100% this).
* conviction_scan.py: trusted rows only; p80 conviction cutoff from the
  train window only (look-ahead leak); new gates z_all>2 (whole-book z,
  ~doubles pooled forward copy-ROI) and median conviction stake >=$50
  (dust filter). 55 wallets selected, forward 30/38 profitable, +21.4%
  pooled (was 284 selected, +16.0%).
* validate_timing.py: the held-edge gates now read the trailing-90d
  trusted conviction record via trust.conviction_record instead of the
  replay's held leg, which is structurally ~all-unresolved for week-lead
  holders (whale 0x73afc816 showed 'held 0-0, 21 unresolved' and was
  rejected at 100% fwd win). 25 copy-positive holders now, including
  Stavenson (51-0), the whale (112-4) and iohihoo (98-10).
* cache.py: query() helper so trust.py shares the single in-process
  connection instead of fighting the single-writer lock.
* README: gotcha 8 (fake res_t/won) + candidate next data sources
  (Goldsky pipelines, PolymarketData order books, Pinnacle CLV,
  Polysights); FINDINGS: dated section correcting the iohihoo/ArbTrader
  scalper-trap verdicts as winner=False-bug artifacts.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-04 09:08:35 -04:00

309 lines
19 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Findings — what works and what doesn't on Polymarket
A research log of an honest attempt to find a systematic, automatable edge on
Polymarket using public data. The short version: **almost nothing works** — the
market is efficient — and the one thing that does isn't a money-printer, it's a
detection signal.
## The goal
Find a repeatable way to make money on Polymarket: identify "smart money"
wallets, copy them, farm rewards, or arbitrage — anything systematic and
automatable from public data.
## Scorecard
| Approach | Verdict | Why |
|----------|---------|-----|
| **Copy high-win-rate wallets** | ❌ dead | Win rate was an illusion (see below). True rates ~50%. Flat-size copying backtested **48%** over a week. |
| **Rank by leaderboard / PnL** | ❌ dead | Raw PnL is variance; top wallets win ~50% and profit via sizing/timing you can't copy. |
| **LP reward farming** | ❌ dead | The fat "thin-book" APRs are illusory — Polymarket **refunds unearned pool to the sponsor** when liquidity is low. Real yield is modest and adverse-selection-dominated. |
| **Binary YES+NO arbitrage** | ❌ dead | Efficient — min observed sum was 1.001 (the spread). Closed instantly by the engine. |
| **Multi-outcome logical arb** | ❌ dead | True partitions priced efficiently (min sum 0.999). Apparent "arbs" were non-exclusive market groupings. |
| **Cross-venue arb (Polymarket↔Kalshi)** | ❌ dead | Venues agree to ~1¢; locking both legs costs **>$1 after fees**. Real gaps last ~seconds and are taken by bots. |
| **Insider / sharp detection** | ✅ **works** | Statistical improbability (z-score of wins vs. odds) is a real, hard-to-fake edge signal. See `insider.py`. |
## The big technical findings
**1. Win rate on Polymarket is survivorship-biased — badly.**
The platform only redeems *winning* shares; losing shares are worth $0 and sit
unredeemed in `/positions` at `curPrice 0` forever, never entering
`/closed-positions`. Measuring win rate over `/closed-positions` alone counts
almost only winners. We saw a wallet read **90.6%** that was truly **48.3%**.
A correct win rate must union both endpoints. *Lesson: a high reported win rate
is a red flag for a measurement bug, not a sharp.*
**2. Win rate ≠ profit, and PnL ≠ reliability.**
A wallet winning 54% made millions; the all-time #1 wallet (43% win) was $3.8M
over 90 days. Profit comes from sizing and entry prices, not hit rate.
**3. The market is efficient.** Six systematic public-data edges, all closed or
illusory. There is no turnkey retail edge sitting in public data in 2026 —
durable edge requires *speed/infrastructure* (arb bots), *private information*,
or *getting paid to provide liquidity* (modest, adverse-selection-dominated).
**4. The one real signal: statistical improbability (z-score).**
Each bet entered at price `p` has an odds-implied win probability `p`. A wallet
winning far more than `Σp` is beating the market's own pricing — measured as a
z-score and one-sided p-value. This is the rigorous version of the edge metric
the whole project was chasing. It distinguishes:
- **Sharps** — high z, normal entry timing (skill over many bets).
- **Insiders** — high z **+** late (pre-resolution) entry **+** fresh wallet.
Plus **funding-cluster linking** (à la Bubblemaps / the 2026 *60 Minutes*
investigation): trace each wallet's USDC funders on Polygon and link wallets
that share a *personal* funding hub — judged by the funder's own outbound degree
so shared exchanges don't false-link everyone. (See `insider.py`.)
## Practical conclusion
- **Don't** fund copy-trading, LP farming, or arb based on this work — we tested
them and they don't clear.
- **Do** use `insider.py`'s z-score as a rigorous "who actually has edge" filter,
far better than leaderboard or win rate.
- A genuine money-making edge has to come from *you* — a niche you understand
better than the market — with tooling built around it, not from a public-data
scanner.
- **Legal note:** *detecting* suspected insider trading is fine; *trading on*
material nonpublic information is illegal, and blindly following a suspected
insider is not a safe strategy.
## Insider detection — what the z-score signal actually found
Building `insider.py` and sweeping markets (`hunt.py`, `huntwide.py`) surfaced
genuinely improbable wallets. Out of ~289 scored:
- **DREAMBIG.** (z=8.9, p≈2e-19) and **qcp14** (z=5.3) on the Iran ceasefire
market — 4577% of wins entered <24h before resolution. Textbook insider
fingerprint, on exactly the theme the *60 Minutes* story covered.
- **Famecesgoal** (z=9.6) won only 14.5% of bets — but bet longshots and hit
+98 above what the odds implied. The clearest "beats the prices it pays" case.
Two refinements proved essential:
- **Trade count separates insiders from bots.** `bjprolo` scored z=37 — but on
**306,873** lifetime trades. That's a market-maker grinding a tiny systematic
edge, not information. Real edge wallets show concentrated z over 13k trades.
- **Funding-cluster linking** (Alchemy, the Bubblemaps "who-funded-whom" step)
works *only* with a personal-hub filter: a shared exchange (everyone uses
Coinbase) is not a shared operator. Judge a funder by its own outbound degree.
## The copy-trade verdict — in-sample vs out-of-sample
The decisive test: does copying z-selected wallets make money?
- **In-sample** (`copyback.py`): copy the edge wallets from May 30, z-weighted,
reinvest 100%. Result: **+545%** in 15 days. Looks incredible — and it's
circular (the wallets were *selected* for winning over that very window).
86% of it came from one wallet; the highest-z pick contributed $23.
- **Out-of-sample** (`oos.py`): select wallets using **only data through
Apr 30**, then copy forward May 30→now. Result: **+168%** — but **entirely
from one longshot lottery wallet** (1.5% pre-period win rate hitting again).
The two strongest pre-period signals made **$0** forward. Forward hit rate was
27%. That's variance, not edge that persists.
**Conclusion:** even the one real signal (z-score), when tested for whether you
can *profit by copying it*, fails out-of-sample — joining every other strategy.
The detector is valuable for *finding* anomalous wallets; copying them is not a
proven, fundable edge. The live watcher (`webhook_receiver.py`) exists to gather
real forward (out-of-sample) data on these wallets — observe before you size up.
## Practical conclusion 2
- **Don't** fund a copy strategy — both the +545% and +168% are
variance/concentration, not repeatable edge.
- **Do** use the detector to find statistically anomalous wallets and watch them
live; judge persistence forward with your own eyes.
- A durable trading edge has to come from *you* (a niche you know), with this
tooling built around your judgment.
## The skilled-3% scan, and a clean out-of-sample loss (June 2026)
External validation arrived: an LBS/Yale study (Gomez-Cram, Guo, Kung, Jensen,
Apr 2026; SSRN 5910522) over 1.72M accounts found only **~3.14%** of traders are
genuinely skilled — measured by randomizing each trader's bet *directions* 10k×
(a Monte-Carlo z-score) and requiring out-of-sample persistence. That is exactly
this project's z-score + `oos.py` method, independently confirmed.
Built `live/` to operationalize it at scale: enumerate recent liquid markets →
cache every candidate's resolved bets locally (~26k wallets / 12.5M bets, so
re-scoring at any cutoff is seconds) → a 5-gate funnel (n≥15, z>0, BH-FDR,
split-half OOS, MM/bot cap). It surfaced 107 "validated" wallets.
**The decisive test.** Copying the high-win-rate "favorite-rider" cohort, $1000,
no execution lag, June 1→now:
- selected *through* the test window (look-ahead): 99% win rate, **+23.6%**.
- selected on **pre-June-1 data only** (honest): 68% win rate, **7.4%**
(19% on the settled portion).
The +23.6% was selection bias. Done cleanly, the favorites **lose** — a textbook
reproduction of the paper's "~60% of lucky winners become losers out-of-sample,"
now on our own live data. *Lesson reinforced: high win rate is the most
misleading signal on the platform; favorite-riders are uncopyable.* The
underdog/`value` archetype (beats longshot prices) is the only one left worth
testing.
## Train/test wallet selection, and the capital wall (June 2026)
Built `live/strategy.py` (train on bets resolved before May 30, validate June 1+)
and `live/followability.py` (entry-time + lead-time + cadence filter). Selecting
on **copy-ROI + z + monthly consistency + diversification** (not win rate) gave
150 wallets; **59/100 stayed profitable forward** (p=0.044), and filtering to
*followable* markets lifted it to **49/77 (p=0.011), +23.4% pooled** out-of-
sample. So a real, persistent, copyable edge **does** exist — unlike favorites.
Then the reality check (`live/pnl_basket.py`, `live/pnl_focused.py`): a $1,000
copier with **missed-trade accounting** (capital tied in open positions).
- **Broad 10-wallet basket:** the wallets fire **1,210 markets** in June; $1,000
can follow only ~213% of them. At realistic stakes it **loses** ($384 to
$800); the gains sit in the trades you couldn't afford ($14k$153k "missed").
**Capital, not edge, is the binding constraint.**
- **Focused + conviction:** copy only 12 top wallets and only their larger-stake
(≥$200) bets → trade count drops to ~3040, $1,000 affords them all, and it
**clears: +91% to +247% across stakes, stable, no blowup.**
*Lesson: a small-bankroll copier cannot follow a skilled wallet's whole feed —
the edge is only capturable by concentrating on few wallets' high-conviction
bets. The live tracker (jaxperro.com/trading) now runs exactly that config.*
## The repeatable profile: conviction bets + a timing gate (the best result)
Refining the above: instead of all bets, score wallets on their HIGH-CONVICTION
bets only — the top 20% of each wallet's own stake sizes (per-wallet p80). This
replaced the original flat >= $200 cutoff (2026-06-22): p80 reproduces flat-$200's
win-rate lift across the sharps while adapting to each wallet's scale — a whale's
$200 bet isn't conviction, a minnow's is. The top wallets win **70-80% of their
big bets on genuinely-uncertain (~0.4-0.6 priced) markets** — real edge, not
favorite-riding — and it persists. `live/conviction_scan.py` (train pre-June,
validate June) under p80 finds **218 wallets** matching the profile; forward,
**62/83 stayed profitable (p≈0), +16.0% pooled**. A reproducible class, not a fluke.
(The original flat-$200 run found 69 wallets, 25/37 forward, +11.7%.)
Then the decisive copyability filter, `live/validate_timing.py`: a near-100% win
rate is only useful if we can mirror it. The tell is **entry->resolution lead
time on winning conviction bets** — this is a copyability heuristic, NOT proof of
inside information (a short lead can be a genuine insider or just someone good at
fast-resolving markets; we can't tell, and for copy purposes it doesn't matter).
Of the 218, the gate drops the **"last-minute" wallets** (median lead <24h — you
can't get the trade in before resolution), then a 30-day-active filter, leaving
**~31 validated copyable sharps** (`watch_sharps.json`) with multi-day leads. The standout `0x60ec1744…` held 80%
win over **1,017 forward conviction bets**; even the suspiciously-perfect `0x72e1…`
(99/100% win) enters ~7 days early — a real forecaster, clearly not last-minute.
These 50 are surfaced live on jaxperro.com/trading.
*Lesson: score conviction bets, not all bets; require avg entry ~0.4-0.6 (edge,
not favorites); and gate on lead time to drop last-minute (un-mirrorable) wallets.
That funnel produces a copyable, forward-validated set — the strongest evidence in
this project that
followable skill exists.*
## Copy P&L: position win% ≠ copyability (the scalper trap, 2026-06-23)
The biggest caveat on the whole sharps table: **a high conviction win% does not mean
you can profit copying the wallet.** The win%/record are computed from `curPrice ≥ 0.5`
on resolved positions — a *position snapshot*. For a high-frequency scalper that
massively over-counts: he buys ~$0.50, sells seconds later for ~+$1, and the snapshot
records a "win" even though he never held to resolution. `ArbTraderRookie` shows
**~100% conviction win (398-2)** yet a flat-$50 copy of his conviction bets, held to
**authoritative clob resolution (winner by token_id)**, nets **$790 (held 0-19)** —
two independent replays agree (live portfolio $687 ≈ standalone clob $790).
So `validate_timing.display_stats` now also computes **`copy_pnl`** — what a flat-$50
copier actually realizes since June 1: replay their conviction entries, mirror their
exits, settle held bets at clob resolution. This is surfaced as the **Copy P&L**
column on the dashboard (default sort). The verdict it delivers: **most "sharps" lose
when copied.** Of the ~31, only a handful are copy-positive — `Kruto2027 +$1,184` and
`fortuneking +$430` (true hold-to-resolution betters); names that looked great on win%
(`iohihoo` 88.7% → **$749**, `ArbTrader` 99.5% → **$790**) are scalpers that bleed.
The live tracker now follows **fortuneking + Kruto2027** — the two copy-positive
wallets — at $50/trade.
*Lesson: judge a copy target by Copy P&L (a trade-replay with real resolution), never
by position win%. Conviction must be measured at the position level (a wallet's total
stake in a market), not per individual buy — a scalper splits one position across many
small buys, so a per-trade threshold copies far more (and worse) bets than intended.*
## Capital recycling & the $1k book (2026-06-23)
The $1,000 paper book (`live/portfolio.py``portfolio.json`, rendered at
jaxperro.com/trading) surfaced two things:
- **"Saturation" was mostly a measurement artifact.** The old browser replay froze
capital in positions whose resolution date the data-api didn't return, so it
skipped bets it could afford (340 phantom misses on a 4-wallet book). Computing
the book **off the cache** — which stores each bet's resolution time (`res_t`) —
frees cash at the true resolution moment: misses dropped to ~0 and the book
recycled ~23× over the window. With *real* money this isn't even a problem (cash
returns on redemption); it was purely the paper sim mis-measuring.
- **More wallets help only up to the bankroll's slot count.** A combo backtest over
the copy-positive holders showed returns rise with basket size *until* peak
concurrent demand exceeds ~$1k ÷ $50 = 20 slots, after which a high-volume wallet
just crowds out the others. So: pick wallets that **fit** the bankroll, favor
**fast-resolving** markets (capital velocity > bet size on $1k), and don't
diversify past what you can fund. Two well-chosen holders beat four that overflow.
## The holder blind spot: two data bugs that hid the best copy targets (2026-07-04)
A clean re-run of the May→June train/test on a trusted subset of the cache
overturned two earlier verdicts. Two mechanisms were poisoning the data:
1. **The `res_t = ts` fallback.** When the data-api omits `endDate` on a closed
position, `insider.resolved_bets` stores the wallet's *sell time* as `res_t`
and `won = curPrice >= 0.5` *at pull time* — so a scalper's sold-at-profit
position looks like a resolved win at a fake resolution time.
ArbTraderRookie's 1,997 cached rows were 100% this. Fix: `live/trust.py`
only trust rows whose `res_t` matches the market's modal `res_t` across ≥2
wallets (endDate rows agree; sell-time rows scatter), market over, wallet
pulled after resolution, `resolved` not False. 13.5M of 19.2M rows pass.
2. **The held-leg window bug.** `validate_timing`'s Jun-1→now replay only
counted held bets entered *and* resolved inside the window; a ~7-day-lead
holder always showed `held 0-0, ~20 unresolved` and failed `held_n>=8`. And
before the 2026-07-02 `winner=False` settle fix, those unresolved held bets
were booked as **losses** — which is exactly where the "scalper trap"
numbers for iohihoo ($749) and ArbTrader ($790) came from. **Those two
verdicts were bug artifacts, not scalper traps.** (ArbTrader still deserved
rejection pre-fix — his *cache* stats were res_t=ts poison — but his real
trade record was a ~160h-lead holder.)
**What the clean test found** (select on ≤May trusted rows only, validate on
June, fees+slip): population baseline 1.4%/bet; the existing profile +8.7%
pooled; adding a **whole-book z gate (`z_all > 2`) roughly doubles it** at
every tier; a practical top-basket (also gated on med conviction stake ≥ $50
and holder/borderline lead verdicts) went **+80% pooled, 7/7 wallets
profitable**. A capital-aware $1k replay of the 8-wallet pre-June basket did
**+504% in June** (118 bets, 97W-21L, fees+slip, 53 missed for cash) — with the
three informed holders a combined 62-0 and two basket members *losing* money
(toosmart 4-12), so the selection is good, not magic.
**Where the edge lives:** the top holders (Stavenson, whale `0x73afc816…` with
$20120k clips, iohihoo; ArbTraderRookie until 2026-07-03) bet **low-tier
tennis (ITF/qualifiers/Wimbledon doubles) and tier-3 esports (CCT CS, Dota 2
EPL)** at ~0.5 entries, win 95100%, enter ~160h before resolution, and hold.
That's informed money — plausibly match-fixing-adjacent — which is copyable
precisely because of the long lead. The regime risk is real and demonstrated:
**ArbTraderRookie was wiped from every data-api endpoint mid-analysis** on
2026-07-03. Treat every month of this edge as possibly its last; re-select
weekly; never size as if the 100% win rates are permanent.
*Lesson: selection metrics are only as honest as the rows they read. Gate on
trusted rows, judge held edges on windows longer than the wallet's lead time,
and add `z_all` — skill must show in the whole book, not just the big bets.*
## Repo layout
- `insider.py` — the detector: z-score/p-value, timing/freshness/sizing signals,
Alchemy funding-cluster ring detection.
- `hunt.py` / `huntwide.py` — market sweeps that surface edge wallets.
- `copyback.py` / `oos.py` — in-sample and out-of-sample copy-trade backtests.
- `webhook_receiver.py` — push-based live trade watcher (Alchemy → Discord).
- `smart_money.py` — data foundation + dashboard (true-win-rate scanner).
- `live/` — current system: cache-backed finder + **copy-positive-holder sharps
selection** (`conviction_scan.py` + `validate_timing.py``watch_sharps.json`,
ranked by Copy P&L) + **$1k paper book** (`portfolio.py``portfolio.json`) +
daily refresh. The dashboard (jaxperro repo) renders those two JSON feeds. See
`live/README.md`. *Copy execution (`copybot.py`, `sync_floors.py`) is a separate,
in-progress system — this finder is selection + tracking only.*
- `wide/` — bulk subgraph→DuckDB scanner (survivorship-bias-free, all wallets);
public subgraph frozen at Jan 2026, so historical-only. See `wide/README.md`.
- `archive/` — the strategies that didn't work, kept for reference. See
`archive/README.md`.