Public-data surveillance pipeline. Scopes event-driven Polymarket markets, engineers per-trader features, applies named explainable heuristics, and ranks accounts by insider-pattern likelihood.
Ethics & redaction. Outputs are investigative leads, not accusations. Wallet addresses in this repo are truncated (
0xabc123…); only publicly documented / charged cases are referred to by name. The machine-readable lead lists (flagged_accounts.csv,trader_scores.csv,wallet_funding.csv, …) are git-ignored and not published — they regenerate from the code against live public data.
- Python 3.10+, standard library only (
urllib,json,csv,math,datetime). Nopip install. - No API keys. All endpoints are public: Gamma, Data-API, CLOB, and a keyless Polygon RPC.
- Network access. Be patient: the collector self-throttles and caches.
# 1. Scope the universe (event-driven markets in the window) -> markets.csv, info_timestamps.csv
python3 collect.py scope
# 2. Collect the scored example end-to-end (the Axiom / ZachXBT complex).
# Rebuilds cache/axiom_complex.json + cache/axiom_participants.json + trade/user caches.
python3 collect.py complex axiom
# 3. Rank -> writes ALL FOUR trader CSVs: trader_scores.csv, flagged_accounts.csv,
# trader_features.csv, trades.csv (runs feature engineering internally)
python3 rank.py
# (optional) features.py standalone also writes trader_features.csv + trades.csv
# python3 features.py
# 4. On-chain funding & cohort-clustering forensics for the flagged set -> wallet_funding.csv
python3 funding.py
# (optional) raw-RPC funding for a single wallet (capped at 10k-block getLogs windows)
# python3 collect.py funding 0x1d9af6…Steps 1–4 regenerate every result and CSV in the report. Everything is idempotent and cached in ./cache/ — re-running never re-downloads. To force a clean rebuild,
delete ./cache/.
| File | Role |
|---|---|
collect.py |
All data pulls (Gamma/Data/CLOB/Polygon-RPC), caching, scope + complex collection, on-chain funding |
features.py |
Per-trader feature engineering (lifecycle, timing-vs-info, concentration, conviction, evasion) |
heuristics.py |
Named rules → 0–1 sub-scores, with documented thresholds and the case each is calibrated against |
rank.py |
Composite score, tiers, two-axis view; writes the scoring CSVs |
funding.py |
On-chain funding + cohort clustering (Blockscout) for flagged wallets |
report.md |
Methodology + findings |
markets.csv, info_timestamps.csv, trades.csv, trader_features.csv, trader_scores.csv,
flagged_accounts.csv, wallet_funding.csv. trader_scores.csv carries the per-heuristic breakdown, so any row can be
read as why the account is flagged.
- Gamma
/public-search,/events?slug=,/markets—/markets?slug=is unreliable (returns empty for some markets), so the complex is built by fetching the event by slug and reading its child markets. Page size caps at 100; paginate withoffset. - Data-API
/trades?market=and/trades?user=(cap 500). For mega-markets the collector usesfilterType=CASH&filterAmount=to keep the pull to material players. Post-resolution/holdersshows only losing/dust balances (winners redeem to ~0), so winners are found via trades, not holdings. - CLOB
/prices-history— pass boundedstartTs/endTs;interval=maxcan hang. - Polygon RPC —
polygon-rpc.comis keyed off; keyless working endpoints are rotated (publicnode,1rpc,drpc,onfinality).eth_getLogsranges are capped, so funding pulls are chunked and run only for flagged candidates.
- The scored population is one event (the Axiom complex) — a worked example, not the platform. Broadening to the Maduro / d4vd / Iran families is the obvious next step.
- Trade pulls for the complex are cash-filtered (≥$1k); micro-bettors are excluded from scoring.
- On-chain funding is optional here; "fresh account" uses Polymarket trade-history tenure (with a censoring guard for ≥500-trade wallets) rather than the wallet's on-chain birth.
- The information timestamp is semi-manual and is the dominant error source for novel markets.
- Outputs are investigative leads, not accusations.