PMWallets
中文

Leaderboard

Who is making money, and how to filter for it.

How the board works

The board ranks Polymarket traders by what they actually made, computed from on-chain fills. A row is an entity: one trader, who may trade from several wallets. Two windows are published, the last 30 days and the last 7, each refreshed once a day. How the numbers are calculated.

  • Without an account you see a sample of the board. Signed in, you can page through all of it.
  • Every row shows a handle and a masked address. Unlocking shows the full address.
  • Without an active push subscription or plan, you can open the entity pages of the free sample and of the addresses you paid to unlock.

Query the board: who is making money

GET/v1/leaderboardno auth

Open without a key, which gets you a 20-row sample. Any key raises it to 200 rows a page, an offset up to 100,000, and 20,000 rows a day.period picks the window (30d or 7d, default 30d), sort and dir order it, limit and offset page it.

Rows carry a handle, not an address. Addresses are sold separately. Anyone with an address can look up the wallet on Polymarket for free. Each row carries its own revealCents, which is what that one address costs; buying it is its own page.

shell
# the board itself: who is making money, and on what. No key needed for the
# free sample; any key (a signed-in account) raises the caps.
curl -s "https://api.pmwallets.com/v1/leaderboard?sort=realizedPnl&dir=desc&limit=50" \
  -H "Authorization: Bearer $PMW_KEY"

# ...and the same endpoint filtered. Every filter is a floor or an exact match
# (bands: any of the listed unlock-price bands, 0 = free … 5); they combine with
# AND, and nothing here changes what a row CONTAINS.
curl -s "https://api.pmwallets.com/v1/leaderboard?\
minPnl=5000&\
minWinLo=0.55&\
minEligible=30&\
style=maker&\
category=sports&\
status=active&\
maxWallets=1&\
bands=0,1,2&\
sort=winLo&dir=desc&limit=50" -H "Authorization: Bearer $PMW_KEY"

The filters. Each is a floor or an exact match, and they combine with AND:

minPnlnumberRealised PnL floor, in USDC. May be negative, to include losing traders.
minRoinumberROI floor against money spent buying. 0.2 is 20%.
minWinLonumber 0–1The Wilson 95% LOWER bound on the win rate, not the win rate: 10–0 has a lower bound of 0.69. It is the only filter here that accounts for sample size.
minEligibleintSettled markets floor (breakevens included), default 5. Lowering it includes wallets with only two or three trades.
minWinsLossesintFloor on markets won or lost (breakevens left out); absent = no floor. Breakevens do not indicate skill; the website uses this floor (minWinsLosses=10). Sort by it with sort=winsLosses.
minFillsintFills in the window.
minVolumenumberUSDC spent buying, in the window.
maxWalletsintHow many of the entity’s addresses traded within the window. 1 = a single address in this window; it can still gain addresses later.
bandsint listComma-separated unlock price bands; a match in any band is enough. bands=0,1 selects the free and cheapest paid bands (0 = free … 5; prices are in pricing.bands). Prices always use the 30d window. An entity missing from 30d matches no band, even when querying another window. Omit to include all bands.
stylemaker | taker | two-sidedBy the share of traded VALUE (USDC) in which it was the maker, not the share of fills: 0.8 and above is maker, 0.2 and below taker, between is two-sided. A maker's edge usually cannot be copied.
statusactive | quiet | dormantBy how recent the last fill is; dormant is nothing for seven days.
categoryenumEntities that traded the selected category in the window: crypto, crypto-updown, sports, politics, geopolitics, economy, culture, esports, science-tech, other, unknown.

Sort keys: realizedPnl, roiOnBuys, winLo, nFills, fillsPerDay, grossBuyUsdc, eligible, winsLosses, conditions, unrealizedPnl, lastFill. An invalid filter, period, limit or offset that is out of range or unknown returns 400 with the parameter name. Three are lenient instead: an unknown sort falls back to realizedPnl, any dir other than asc means desc, and mine (only the addresses you have unlocked; needs a key) is read only when it is exactly 1. Parameters we do not know are ignored.

json
// GET /v1/leaderboard  →  200
{
  "periodId": "30d",
  "tier": "subscriber",
  "tracked": 186180,                 // entities in this window — coverage, NOT how many matched
  "pricing": {
    "revealCents": 50,               // the cheapest band; what a row costs is on the row
    "subscriptionCentsPerHour": 1,
    "bands": [                       // from = the pnlExTop the band starts at; null = no floor
      { "band": 0, "from": null, "cents": 0 },
      { "band": 1, "from": 0.01, "cents": 50 },
      { "band": 5, "from": 5000, "cents": 200 }
    ]
  },
  "limits": { "maxRows": 200, "maxOffset": 100000, "capped": false,
              "dailyRows": 20000, "usedToday": 1250 },
  "rows": [
    {
      "entityId": "7KQ2MF9X4B1C",    // a HANDLE until you buy the address; then the address itself
      "label": "0x4b96…984e",        // masked until then
      "revealed": false,
      "revealCents": 150,            // what THIS address costs, from its own band
      "subscribed": false,
      "realizedPnl": 48213.5, "unrealizedPnl": 1204.0, "roiOnBuys": 0.184,
      "wins": 312, "losses": 89, "eligible": 401,
      "wr": 0.778, "lo": 0.735, "hi": 0.815,   // Wilson 95% bounds on the win rate
      "pnlExTop": 41902.1,           // profit with its single best market removed — the price band
      "style": "maker", "makerShare": 0.91,
      "wallets": 2, "nFills": 18422,
      "categories": [{ "category": "sports", "share": 0.62 }],
      "status": "active",
      "activity": { "lastFillTs": "2026-09-24 01:05:47", "fills24h": 412, "fills7d": 2980 },
      "dataSource": "live", "dataPeriodId": "30d"
    }
  ]
}