# Wallet PnL and Smart Score

> How portfolio PnL is computed from the tape, what is excluded, and how the top-wallets board ranks.

Source: https://getchord.xyz/docs/concepts/wallet-pnl/

## Average-cost PnL

`/v1/portfolio/{wallet}/pnl` replays the wallet's swaps from the tape, in order, with an average-cost basis per token:

- A **buy** adds to the position and raises or lowers the average cost.
- A **sell** realizes `(price − average cost) × amount` against that average and reduces the position.
- What is still held is marked at the current price (`priceUsd` on the token's dominant venue) as **unrealized**.

`realized`, `unrealized` and `total` are the sums; per token you also get `avgCost`, `curAmount`, `curValue`, `costRemaining` and `roiPct`. The calendar (`/pnl-calendar`) sums the same realized events by UTC day, so it reconciles with `realized` by construction.

### What is excluded

- **Transfers.** A balance that arrived by transfer has no cost basis. It is reported as `untrackedAmount` / `untrackedValue` and left out of PnL. Airdrops, bridged funds and CEX withdrawals fall here.
- **Liquidity.** Adding to or removing from a pool is not a swap. LP results live in `/v1/lp/positions`.
- **Gas.** Not deducted.

### Freshness

The compute walks the wallet's whole tape and is cached with stale-while-revalidate: a fresh answer for a minute, a stale one served for up to a day while a refresh runs behind it. An empty result is never cached over a real one. If the tape read fails you get an empty 200 shape, not a 5xx.

## Smart Score

`/v1/smart-money/top` ranks wallets on the tape by a **Smart Score**, not raw profit:

- **Realized-weighted.** Money taken off the table counts more than paper gains.
- **Luck-corrected.** Win rate is shrunk toward the mean for wallets with few trades (`winRateAdj`), so one lucky launch does not top the board.
- **Recency-decayed.** Recent skill counts more than old.

Before ranking, routers, executors and bots are removed — by cadence (hundreds of transactions a day from a wallet's first trade), by nonce rate and deny lists, and by behaviour (bursts, sub-minute round trips, sniping dozens of launches). `botsRemoved` counts each pass; `totalWallets` is what qualified. Each row carries its archetype (`degen`, `allrounder`, …), meme share, and top token.

The board is rebuilt per window (15 minutes for 24h, hourly for 7d and 30d, three hours for all) and served from cache between rebuilds. On Arc a live delta of the last minutes' trades sits on top, so the board moves between polls; `live` in the response shows its state.
