Recipe — Trader page
The trader dossier is nine reads: score, copy simulation, edge, PnL quality, archetype, style, health, netflow, recent trades. Our own terminal used to fan those out from the browser; wallet-overview runs the same fan-out server-side, so your page is one request — and it cannot disagree with the single endpoints, because each slot is the single endpoint's response.
One call paints the page
POST /v1/wallet-overview
{ "wallet": "0x…", "chain": "eth", "tradesLimit": 10 }
{
"wallet": "0x…", "chain": "eth", "bundle": "wallet-overview",
"traderScore": { "grade": "B", "verdict": "mirror-worthy", "score": 74, "subscores": { … } },
"copySimulate": { "simulated": true, "winRate": 0.7, "medianReturnPct": 12.4, "form": "strong" },
"traderEdge": { "edge": "…", "holdStyle": "swing", "bestAt": ["…"] },
"walletPnlQuality":{ "verdict": "skill" },
"walletArchetype": { "archetype": "diamond", "traits": ["…"] },
"traderStyle": { "style": "…", "tempo": "…" },
"walletHealth": { "health": "healthy", "healthScore": 88 },
"walletNetflow": { "posture": "accumulating", "buyShare": 0.71 },
"walletTrades": { "trades": [ … ], "summary": { "tilt": "accumulating", "topTokens": [ … ] } }
}
Every slot is named after the single endpoint it mirrors (traderScore ↔ /v1/trader-score, …), so anything documented for a single applies verbatim to its slot. A component that fails becomes an error object in its slot plus an entry in failed[] — drop that tile, keep the page. À la carte: call any of the nine singles with the same { wallet, chain } body.
What each slot gives you
- Name
traderScore- Type
- the headline
- Description
grade+verdict+confidence— the hero of the page. Everything else is supporting evidence.
- Name
copySimulate- Type
- the conversion receipt
- Description
"If you'd copied them":
winRate,medianReturnPct,best/worst,form. Whensimulated: false, render itsreason(e.g. "no closed positions to simulate") — see UX rules.
- Name
traderEdge- Type
- what they're good at
- Description
edge,holdStyle,bestAt[].edge: 'insufficient-data'is an honest answer — hide the tile or say "not enough history", don't show a blank.
- Name
walletPnlQuality- Type
- skill vs luck
- Description
verdict:skill/luck/wash-suspected. Wash-suspected deserves a warning tone — it changes the meaning of every other number.
- Name
walletTrades- Type
- recent activity
- Description
Derived rows:
action+symbol+sizeBand+minsAgo(banded, no raw USD).summary.tiltandsummary.topTokensmake a good header line.
- Name
walletHealth / walletNetflow / walletArchetype / traderStyle- Type
- texture
- Description
One-word verdicts (
healthy,accumulating,sniper, tempo) — render as small tiles or chips.
Perp traders
The on-chain dossier is spot evidence. For a Hyperliquid perp leader, call the perp profile instead of (or alongside) the bundle:
POST /v1/perp-wallet
{ "wallet": "0x…" }
Returns open positions (coin · side · leverage · size band · PnL direction), account band, long/short bias, win rate over closed fills — and a coverage object explaining thin results:
{ "winRate": null, "closedTrades": 0, "coverage": {
"reason": "account-too-new",
"note": "First fill only ~3d ago (0 closed trades) — too new to judge either way." } }
coverage.reason is machine-readable (ok · no-hl-history · open-positions-only · account-too-new · below-min-closed-trades); coverage.note is the line to render.
A wallet can be a great perp trader and grade F on-chain (or vice versa) — the venues are different games. If you show both, label which venue each verdict belongs to.
UX rules
- Thin profiles explain themselves — let them. When
coverage.reason !== 'ok'orsimulated: false, render the engine's own note under the stats instead of a grid of em-dashes. An unexplained empty card reads as broken; the same card with "no closed trades yet — win rate is unmeasurable until a position closes" reads as honest. - Null is never zero.
winRate: nullmeans unmeasured. Render—, not0%. - Keep the page on one dead tile. On
partial: true, render the slots you got and quietly drop thefailed[]ones — one provider hiccup should cost a tile, not the screen.