From 21acc957f950d03447f7635da22143389569edf6 Mon Sep 17 00:00:00 2001 From: jaxperro Date: Mon, 6 Jul 2026 13:17:11 -0400 Subject: [PATCH] =?UTF-8?q?sharps=20feed:=20pm=5Fpnl=20(Polymarket's=20own?= =?UTF-8?q?=20account=20P&L)=20+=20README=20gotcha=2010=20=E2=80=94=20ceil?= =?UTF-8?q?ing=20vs=20bank=20statement?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Fable 5 --- README.md | 12 ++++++++++++ live/validate_timing.py | 17 +++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/README.md b/README.md index ee6f7630..29ed1de9 100644 --- a/README.md +++ b/README.md @@ -272,6 +272,18 @@ runner is retired (GitHub throttled `*/5` to ~2h in practice — it copied 1 of a transiently failed re-pull then hides the wallet's whole history from exact `pulled_at` checks (trust.py has a 14-day fallback for this). +10. **Hold-to-resolution P&L is a copy ceiling, not the wallet's bank + statement.** The dashboard's Conv/All-Time P&L columns price every entry + held to resolution at the wallet's own stakes — the right yardstick for a + copier that holds, and the wrong one for judging the wallet itself. + Polymarket's own profile P&L (lb-api `/profit`, the **PM P&L** column) is + their actual cash-flow result. ~1× gap = true holder (LSB1 +$69.7k vs + +$68.5k); a huge gap = scalper whose entries resolve well but who never + holds (ArbTraderRookie: **+$8.6k real vs +$462k held, 53×** — a 0.5% + margin on $1.7M volume). For scalpers, whether a copier can reproduce + their fills is the open question — judge by the live book's measured + slippage, never the ceiling. + --- ## The research (how we got here) diff --git a/live/validate_timing.py b/live/validate_timing.py index b60f2764..fa7bd4cb 100644 --- a/live/validate_timing.py +++ b/live/validate_timing.py @@ -77,6 +77,22 @@ def _clob_winner(cond, token): return _CLOB[cond].get(str(token)) +def _pm_profit(w): + """The wallet's own all-time account P&L as Polymarket reports it + (lb-api /profit): cash-flow truth including early sells. The sanity anchor + next to the hold-to-resolution columns — a ~1x gap means true holder, a + huge gap means scalper (ArbTraderRookie: +$8.6k real vs +$462k held, 53x — + a 0.5% margin on $1.7M volume).""" + try: + req = urllib.request.Request( + "https://lb-api.polymarket.com/profit?window=all&limit=1&address=" + w, + headers={"User-Agent": "Mozilla/5.0"}) + r = json.loads(urllib.request.urlopen(req, timeout=15, context=_SSL).read()) + return round(r[0]["amount"]) if r else None + except Exception: + return None + + def _bet_pnl(b): """Resolved (outcome) P&L of one cache bet: a $size stake at avg price p pays size/p if won, else $0 — so P&L = size·(1−p)/p if won else −size.""" @@ -134,6 +150,7 @@ def display_stats(w): "realized_pnl": round(sum(_bet_pnl(b) for b in recent)), "all_win": round(100 * all_won / (all_won + all_lost), 1) if (all_won + all_lost) else None, "all_won": all_won, "all_lost": all_lost, "all_pnl": round(all_pnl), + "pm_pnl": _pm_profit(w), "avg_bet": round(sum(b["size"] for b in conv) / len(conv)) if conv else 0, "copy_pnl": 0, "held_pnl": 0, "held_won": 0, "held_lost": 0, "sold": 0, "name": None, "last_trade": 0, "last_conv_bet": 0,