sharpside
LIVE--:--:-- UTCdata as of —24h vol —trades —whale trades —markets —Polymarket flow, ranked — who’s sharp, who’s early, where size is moving.
MethodologyReference · SharpScore v1

How the numbers are made

Every score on Sharpside is a deterministic function of public Polymarket data. This page gives the formulas, weights and thresholds exactly as the backend runs them, with the source file for each, so any number on the site can be checked by hand.

SharpScore
0–100 · v1
Sharp wallet
SharpScore ≥ 70
Insider-pattern flag
score ≥ 50
Whale trade
≥ $10k or market p99
Windows
30m · 1h · 6h · 12h · 24h
Trade tape
polled every 15 s

1SharpScore

source apps/api/src/analytics/smartScore.ts

SharpScore is a 0–100 composite of how well a wallet has traded on Polymarket, not how much. Five components are each normalised to 0–1 and weighted, then the total is discounted for drawdown and for small samples. A wallet with SharpScore ≥ 70 (SMART_SCORE_MIN) counts as sharp everywhere on the site: Smart Money Flow, sharp buyers and sellers, and the smart tag. API field: smartScore.

1.1Components and weights

ComponentWeightInputNormalised to 0–1Reference points
PnL30all-time PnL P(sign(P)·log₁₀(1+|P|)/log₁₀(1+$1M) + 1)/2−$10k 0.17 · $0 0.50 · $10k 0.83 · $1M 1.00
ROI20P ÷ traded volume0.5 + ROI / (2 × 20%)−20% 0 · 0% 0.5 · +20% 1
Win rate25Bayesian win rate, §1.2(wrAdj − 40) / 4040% 0 · 60% 0.5 · 80% 1
Sample10closed positions n1 − e^(−n/50)10 0.18 · 50 0.63 · 150 0.95
Recency15days since last trade de^(−d/30)today 1.00 · 30d 0.37 · 90d 0.05

Every component is clamped to 0–1, so no single input can push the score past its weight.

score
raw    = 30·pnl + 20·roi + 25·winRate + 10·sample + 15·recency    0–100
score  = raw × (1 − 0.3 · maxDrawdownPct / 100)                   drawdown penalty, §1.3
score  = score × (0.5 + 0.5 · sample)                             confidence gate
score  = round(clamp(score, 0, 100), 1)                           

The confidence gate reuses the sample component: a wallet keeps 53% of its score at 3 closed positions, 82% at 50 and 97.5% at 150. A three-trade lucky streak cannot read as sharp, however good the three trades were.

1.2Bayesian win rate

source apps/api/src/analytics/winRate.ts

Raw win rate is wins ÷ (wins + losses) over closed positions. A position is a win when its realised PnL is above zero and a loss when below; break-even positions are ignored. Small samples are shrunk toward 50% with a Beta(α = 10, β = 10) prior — as if every wallet started with ten wins and ten losses already on the books.

adjusted win rate
wrAdj = (wins + α) / (wins + losses + α + β) × 100    α = β = 10
RecordRawAdjustedwrAdjWin-rate component
3 / 3 wins100.0%(3 + 10) / (3 + 20)56.5%0.41
140 / 200 wins70.0%(140 + 10) / (200 + 20)68.2%0.71

The perfect three-for-three record ranks below the 70% record over 200 positions: three results are mostly prior.

40%50%60%70%80%90%100%01050100200400raw 100%raw 70%prior 50%3/3 → 56.5%140/200 → 68.2%closed positions (√ scale)
Fig. 1 — Adjusted win rate against closed positions, for a perfect record and a 70% record. At 20 positions the adjusted rate is exactly halfway between the 50% prior and the raw rate; by 200 it is within 2 points of it.

1.3Drawdown penalty

source apps/api/src/analytics/drawdown.ts

Max drawdown is measured on the wallet’s cumulative-PnL curve from Polymarket’s user-pnl API, one point per UTC day for up to 730 days: the largest fall from a running peak, as a percentage of the wallet’s scale. Polymarket exposes cumulative PnL, not account equity, so the scale is the larger of the running peak, the largest absolute PnL anywhere on the curve, and $1,000. Without the floor a $5 early peak followed by a −$45 dip would read as a 1,000% drawdown; with it, 5%. Without the absolute-PnL term a wallet that peaked at +$17k, dipped to −$460k and grew to +$4.4M would read as 100%; with it, about 11%.

drawdown
dd      = max over t of (peak_t − pnl_t) / max(peak_t, max|pnl|, $1,000) × 100    capped at 100
factor  = 1 − 0.3 · dd / 100                                                      

dd   0% → × 1.00      dd  25% → × 0.925      dd  50% → × 0.85      dd 100% → × 0.70

1.4Recency decay

Recency is e−d/30, where d is days since the wallet’s last trade — a half-life of about 21 days (30 · ln 2 = 20.8). The component carries 15 points, so a wallet that stops trading gives back up to 15 raw points over a few months even if nothing else changes.

Days since last trade0721306090
recency component1.000.790.500.370.140.05
points of 1515.011.97.45.52.00.7

The traders-rank job recomputes every SharpScore from stored stats every 10 minutes, so decay applies without waiting for a wallet’s next full refresh.

1.5Worked example

Two wallets with the same PnL and ROI, both last trading two days ago, to isolate the effect of record size and drawdown: A won 140 of 200 closed positions with a 20% max drawdown; B won 3 of 3 with none.

ComponentWeightWallet A inputA ptsWallet B inputB pts
PnL30$50,000 → 0.89226.7$50,000 → 0.89226.7
ROI205% on $1M → 0.62512.55% on $1M → 0.62512.5
Win rate2568.2% → 0.70517.656.5% → 0.41310.3
Sample10200 → 0.9829.83 → 0.0580.6
Recency152 days → 0.93614.02 days → 0.93614.0
Raw80.764.2
× drawdown20% → × 0.9475.90% → × 1.0064.2
× confidence× 0.99175.2× 0.52934.0
SharpScoresharp (≥ 70)75.2not sharp34.0

Values are computed with the production function; intermediate points are rounded for display.

1.6Inputs

  • PnL and volume — Polymarket’s leaderboard for that wallet (all-time), taken as reported.
  • Wins, losses, sample — the wallet’s closed positions, newest first, up to 500 (10 pages of 50). See Limitations.
  • Drawdown — the daily cumulative-PnL curve from the user-pnl API.
  • Last trade — the wallet’s most recent trade on Polymarket, or on Sharpside’s own tape if newer.

1.7Versioning

The formula carries a version, currently v1, stored with every score and returned by the API as smartScoreVersion. Any change to a weight or curve bumps the version; the traders-rank job then re-scores every wallet from stored stats, so the leaderboard moves to the new formula in one pass. This page describes v1.

2Insider-pattern score

source apps/api/src/analytics/insiderScore.ts

The insider-pattern score (0–100) measures how closely one open position matches a pattern often seen before surprising resolutions: a new account, an outsized position, few other markets, a cheap entry, opened shortly before the end. It is the sum of five weighted signals. A signal contributes only once its threshold is met, and contributes more the further past the threshold the position is.

2.1Five signals

SignalWeightTriggered whenShare of weight earnedMeasured from
New account25age < 30 d1 − age / 30wallet’s first Polymarket activity
Outsized position25Z ≥ 3min(1, 0.5 + 0.5·(Z − 3) / 3)position Z-score in the market, §2.2
Few other markets20markets ≤ 51 − (n − 1) / 5markets the wallet has ever traded
Low entry price15entry < 30¢1 − entry / 0.30average entry price of the position
Close to resolution15≤ 72 h before end, last 25% of life1 − hours / 72first trade in this market vs. scheduled end
score
points_i  = weight_i × share_i      rounded to 0.1; 0 when not triggered
score     = min(100, Σ points_i)    rounded to 0.1
  • The size signal starts at half its weight at Z = 3 and reaches full weight at Z = 6. A wallet that has traded only this market earns the full 20 for focus; five markets earn 4.
  • The market-life condition keeps same-day sports and esports markets — where every position opens hours before the end — from tripping the timing signal. When a market’s start date is unknown, only the 72-hour rule applies.
  • Missing inputs (age unknown, too few holders for a Z-score) leave that signal at zero points.
  • Thresholds and weights are configuration (INSIDER_*, weights re-normalised to sum to 100). Each flag stores every signal’s weight as maxPoints, so a breakdown always shows the weights it was scored with.

2.2Z-score

source apps/api/src/analytics/zscore.ts

position Z-score
Z = (x − μ) / σ

x   = the holder's position value in USD  (shares × current price of that outcome)
μ   = mean position value over all visible holders of the market, both outcomes
σ   = population standard deviation over the same set
      undefined when fewer than 3 holders, or σ = 0

Polymarket’s holders endpoint returns at most 500 holders per outcome, so μ and σ are over the visible set. Large holders inflate σ, which makes this a conservative Z: a position has to stand well clear of other large positions, not just of the small ones.

2.3Worked example

A wallet that is 4 days old holds a position 4.5σ above the market mean, has traded 2 markets in total, entered at an average of 12¢, and opened 18 hours before the scheduled end of a market that ran for 30 days.

SignalMeasuredSharePoints
New account4 days < 301 − 4/30 = 0.86721.7 / 25
Outsized positionZ 4.5 ≥ 30.5 + 0.5 · 1.5/3 = 0.7518.8 / 25
Few other markets2 ≤ 51 − 1/5 = 0.8016.0 / 20
Low entry price12¢ < 30¢1 − 0.12/0.30 = 0.609.0 / 15
Close to resolution18 h, last 2.5% of life1 − 18/72 = 0.7511.3 / 15
Insider-pattern scorelisted ≥ 50 · alert ≥ 7076.8
Why this was flagged — points per signal76.8 / 100
New accountAccount is 4 days old21.7 / 25
Outsized positionPosition is 4.5σ above market mean18.8 / 25
Few other marketsHas traded only 2 markets16 / 20
Low entry priceEntered at 12¢9 / 15
Close to resolutionOpened 18h before market end11.3 / 15
Fig. 2 — The same breakdown as it appears on the Insiders screen when a flag is expanded.

2.4Scanning and listing

Every 5 minutes the whales-insiders job scans up to 40 open markets: scans requested from market pages first, then markets with whale trades in the last 6 hours, then the largest markets by 24-hour volume. For each market it reads up to 500 holders per outcome, computes every holder’s Z-score, and evaluates the signals for the 15 largest holders with a position worth ≥ $10,000 (WHALE_POSITION_USD; positions under INSIDER_MIN_POSITION_USD = $5,000 or without a known entry price are never scored).

ThresholdSettingDefaultEffect
ListingINSIDER_SCORE_MIN50shown on Insiders, Pulse and market pages
AlertALERT_INSIDER_SCORE70a new flag at or above this goes to the alert feed

Positions are re-scored on every scan, so a listed flag’s numbers move while the position is open. A flag that falls below 50 leaves the list but keeps its record.

2.5Outcome tracking

source apps/api/src/jobs/resolutions.ts

Every 15 minutes the resolutions job re-checks markets that are past their end date or have dropped out of the synced set for 30 minutes. When Polymarket reports a market closed with a winner, every unsettled flag on it is settled: resolvedCorrect = true if the flagged outcome won, false if it lost. Until then the field is null and the flag reads open. The Insiders screen shows Correct / Wrong and can filter to settled flags, so the record of the flags themselves can be checked rather than taken on trust.

2.6What a flag is not

Insider-pattern flags are statistical patterns in public on-chain data (account age, size, focus, entry price, timing) — not accusations of wrongdoing. A flag does not identify a person. Large, late, cheap positions from new wallets are often just confident traders, hedgers or market makers moving to a fresh address.

Statistical pattern, not an accusation.

3Smart Money Flow

source apps/api/src/analytics/smartFlow.ts

Smart Money Flow is the net dollar direction of sharp wallets — SharpScore ≥ 70 (SMART_SCORE_MIN) — in one market over one window. Every trade is signed relative to the market’s primary outcome (outcome 0, usually “Yes”):

Trade by a sharp walletDirection
BUY the primary outcome+1 bullish
SELL the other outcome+1 bullish
SELL the primary outcome−1 bearish
BUY the other outcome−1 bearish
outcome unknown0 ignored
per market, per window
bull    = Σ USD of bullish trades by sharp wallets    
bear    = Σ USD of bearish trades by sharp wallets    
netUsd  = bull − bear                                 
score   = 100 × (bull − bear) / (bull + bear)         −100 … +100, rounded to 0.1
                                                      0 when bull + bear = 0

example: $30,000 bullish, $10,000 bearish  →  netUsd +$20,000, score +50
ScoreAs shownReads as
−100−$40.0k$0 bullish vs. $40k bearish — every sharp dollar against the primary outcome
−50−$20.0k$10k bullish vs. $30k bearish
0$0balanced, or no sharp volume at all
+50+$20.0k$30k bullish vs. $10k bearish
+100+$40.0k$40k bullish vs. $0 bearish — every sharp dollar for the primary outcome
Fig. 3 — Bars use a square-root scale so small but real flows stay visible. Net dollars are shown next to the bar; the score alone cannot tell $2k of flow from $2M.
  • Every sharp trade on the tape counts, not only those stored individually: flow is accumulated in the 1-minute bars (§5).
  • A wallet counts as sharp once it has been scored and its SharpScore is ≥ 70 at the time of the trade. Sharp buyers and sellers are distinct sharp addresses buying or selling in the window.
  • A 1-hour net flow of at least $25,000 with |score| ≥ 50 raises a smart-flow alert.

4Whales

source apps/api/src/analytics/whale.ts

A single fill on the tape is a whale trade when either rule holds:

  1. its value is ≥ WHALE_TRADE_USD = $10,000; or
  2. its value is ≥ WHALE_MIN_USD = $1,000 and at or above that market’s running 99th-percentile trade size (WHALE_PERCENTILE = 99).

The percentile rule catches trades that are large for a thin market; the $1,000 floor stops illiquid markets producing $40 “whales”. The 99th percentile is estimated per market without storing trades — a streaming quantile in log space (stochastic gradient on the pinball loss), checked before each trade updates it:

streaming p99, per market
x = ln(trade value in USD)          
q ← q + η · p          if x > q     p = 0.99
q ← q − η · (1 − p)    otherwise    η = 0.1
                                    q₀ = ln($10,000)

whale  ⇔  value ≥ $10,000   or   (value ≥ $1,000  and  value ≥ e^q)

On the Whales screen a whale is a position, not a trade: a holder whose position in one market is worth ≥ $10,000 (WHALE_POSITION_USD), from the holder scan in §2.4. A wallet carries the whale tag when its open positions are worth ≥ $100,000 or it holds a whale position.

5Windows and freshness

source apps/api/src/jobs/marketsAggregate.ts

Screener metrics come in five rolling windows: 30m, 1h, 6h, 12h and 24h. Every trade on the tape is rolled into a per-market 1-minute bar — volume, trade count, buy/sell split, whale counts and volume, the set of traders, sharp buyers and sellers, sharp bullish and bearish dollars, and the closing price. A window is the sum of the bars inside it; unique-trader counts are distinct addresses across those bars, not sums. Bars are kept for 26 hours.

Price changes come from a price tick recorded for every market on each market sync (every 2 minutes, kept 8 days); Polymarket’s own 1h/24h change is the fallback until enough ticks exist.

5.1Update cadence

JobScheduleRefreshes
trades-ingestevery 15 strade tape → 1-minute bars, stored trades, whale trades, alerts
markets-aggregateevery minute30m and 1h windows each run; 6h, 12h, 24h every 5 minutes (short windows act as lower bounds in between)
markets-syncevery 2 minmarket list, prices, price ticks, categories
traders-refreshevery minutewallet stats and SharpScore, 40 wallets per run: hot wallets every 30 min, others every 6 h, dormant (> 30 d) every 24 h
traders-rankevery 10 minleaderboard rank, SharpScore re-score (recency), tags
whales-insidersevery 5 minwhale positions, Z-scores, insider-pattern flags
resolutionsevery 15 minclosed markets, winners, resolvedCorrect
alerts-dispatchevery 30 sTelegram and X delivery
traders-seedevery 6 hwallet universe from Polymarket leaderboards
prices-backfilldaily 04:00 UTC24 h of CLOB price history for the top 200 markets

“Hot” wallets are the top 500 by rank, favourited wallets and wallets that traded in the last 24 hours. The API caches public responses for 15 seconds and Pulse polls every 15 seconds. Every list carries asOf, the last successful run of the job behind it; the status strip switches from LIVE to DELAYED when data is more than 2 minutes old.

5.2Warm-up after deploy

On a fresh deploy the worker runs market sync, trader seed, tape ingest and aggregation once, in that order, then backfills prices if fewer than 5,000 price ticks exist. Because windows are built from Sharpside’s own bars, the 30m and 1h windows are complete after an hour, while 6h, 12h and 24h volume and trader counts fill in over the first day. The first full SharpScore pass over ~3,000 seeded wallets takes 2–3 hours; until wallets are scored, Smart Money Flow and sharp counts read near zero.

5.3Stored trades

The tape runs at roughly 1,500–2,000 trades a minute. Every trade feeds the bars, but only trades ≥ STORE_TRADE_MIN_USD = $100 are stored individually, for 14 days — about 7% of trades and 95% of volume. The Activity feed therefore starts at $100.

6Data sources

source docs/POLYMARKET_DATA.md

SourceHostUsed for
Gammagamma-api.polymarket.commarkets, outcomes, prices, end dates, tags → categories, resolutions
Data APIdata-api.polymarket.comglobal trade tape, open and closed positions, holders, first activity (account age), portfolio value, markets traded, open interest, leaderboards
CLOBclob.polymarket.comprice history
user-pnluser-pnl-api.polymarket.comcumulative PnL curve → drawdown, PnL charts

All four are public endpoints: no API keys, no private data. Requests share one budget of 8 per second across all jobs. Sharpside is independent and not affiliated with Polymarket.

7Limitations

  • Hot-set market sync.Polymarket lists ~260,000 “active” markets, most with no volume. Sharpside syncs the top 2,000 by 24-hour volume plus every market that appears on the trade tape — about 2,500 in practice. A market that never trades is not listed.
  • Closed positions are sampled.The newest 500 closed positions per wallet are read. Win rate, gains, losses and the sample component are exact for wallets with up to 500 closed positions and “most recent 500” for larger ones.
  • No cash balance.A wallet’s USDC balance (currentBalance) is not available from public APIs and is always empty. Open value is the marked-to-market value of open positions.
  • Leaderboard PnL is Polymarket’s.All-time, monthly and weekly PnL and volume come from Polymarket’s leaderboard as reported. Sharpside does not recompute them, and inherits any error in them.
  • Z-scores use visible holders.At most 500 holders per outcome are visible, so σ is over that set (§2.2).
  • The sharp set lags.Smart Money Flow counts a wallet only once it has been scored; a new sharp wallet is invisible until its refresh.

8Not financial advice

Sharpside describes what has happened on Polymarket. Nothing on the site is a recommendation to buy, sell or hold anything. A high SharpScore describes a wallet’s past record, not its next trade, and an insider-pattern flag is not a signal to follow. Prediction-market positions can lose their full stake.

Free. Not financial advice. Not affiliated with Polymarket.