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. When simulated: false, render its reason (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.tilt and summary.topTokens make 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.

UX rules

  1. Thin profiles explain themselves — let them. When coverage.reason !== 'ok' or simulated: 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.
  2. Null is never zero. winRate: null means unmeasured. Render , not 0%.
  3. Keep the page on one dead tile. On partial: true, render the slots you got and quietly drop the failed[] ones — one provider hiccup should cost a tile, not the screen.

Was this page helpful?