# Trader dashboard

> Top wallets on Arc, one wallet's PnL and history, its calendar, and its liquidity positions — a Nansen-style page from five calls.

Source: https://getchord.xyz/docs/recipes/trader-dashboard/

**Goal**: a "who is winning" board and a wallet profile page.

## Top wallets

```ts
const board = await fetch(`${A}/smart-money/top?chain=5042&source=onchain&window=7d&limit=50`).then((r) => r.json());
```

`wallets` are ranked by [Smart Score](/docs/concepts/wallet-pnl/#smart-score), with routers and bots already removed (`botsRemoved` says how many). Show `pnlUsd` (realized + open), `realizedUsd`, `winRate`, `trades`, `topToken` and `archetype`. `totalWallets` is how many qualified; `indexedToBlock` is the tape's head when the board was built. `503 CHAIN_NOT_ENABLED` means the board is not published for the chain yet.

Windows: `24h` (rebuilt every 15 minutes), `7d` and `30d` (hourly), `all` (three-hourly). On Arc a live delta sits on top of the last rebuild, so polling every 30 s shows movement.

## Wallet profile

Four calls in parallel:

| Panel | Call |
| --- | --- |
| Holdings and PnL per token | `GET /portfolio/{wallet}/pnl?chain=5042` |
| Trade history (chart markers, activity list) | `GET /portfolio/{wallet}/trades?chain=5042` |
| Calendar (realized PnL by day) | `GET /portfolio/{wallet}/pnl-calendar?chain=5042` |
| Liquidity positions | `GET /lp/positions?chain=5042&owner={wallet}&status=all` |

```ts
const [pnl, trades, cal, lp] = await Promise.all([
  `${A}/portfolio/${w}/pnl?chain=5042`, `${A}/portfolio/${w}/trades?chain=5042`,
  `${A}/portfolio/${w}/pnl-calendar?chain=5042`, `${A}/lp/positions?chain=5042&owner=${w}&status=all`,
].map((u) => fetch(u).then((r) => r.json())));
```

- `pnl.tokens[]` gives realized, unrealized, average cost, current amount and value, ROI, and the **untracked** balance that arrived by transfer (no cost basis). Show untracked separately; it is not a loss or a gain.
- `pnl` is cached stale-while-revalidate: `updatedAt` tells you how old the answer is; a first view of a busy wallet may take a few seconds.
- `cal.days[]` (`date`, `realizedUsd`, `trades`) draws the calendar; `realizedTotal` reconciles with `pnl.realized`.
- `lp.summary` (open, closed, wins, win rate, realized LP PnL, fees, open value) and `lp.positions[]` (each with live value, in-range, fees, `jit` / `unreconciled` flags) make the liquidity tab.

## Is this wallet a bot?

The board already removed bots. For a wallet you look up directly, the tells are in the data: hundreds of trades a day from the first trade, buy-then-sell inside a minute, dozens of launches sniped. The Ask agent can answer "is 0x… a bot" with its wallet profile tool if you would rather not implement the heuristics.

## Follow a trader

There is no server-side follow. Poll `GET /portfolio/{wallet}/trades?chain=5042` every 30–60 s and diff by `tx`, or subscribe to the WebSocket `trades` channel for the tokens the wallet holds and match `wallet` on incoming items.
