METHODOLOGY

How Fomo Api calculates Solana wallet PnL (and why coverage matters)

The methodology behind Fomo Api's realized PnL: FIFO cost basis, historical USD pricing, coverage as part of the number, and why we return null instead of guessing.

Published September 22, 2026 · Updated October 17, 2026 · 6 min read

Two products can look at the same wallet and publish PnL figures that differ by an order of magnitude. Neither is lying; they're measuring different things. This is what Fomo Api measures, and what it refuses to.

It applies to the numbers we compute: /v1/leaderboard?board=solana and the /v1/wallet endpoints. The default leaderboard serves FOMO's own figures as FOMO reports them, which are measured differently; more on that below.

Realized, not mark-to-market

realizedPnlUsd counts profit and loss from positions the wallet actually closed inside the window. A token bought and still held contributes nothing until it's sold. This is the conservative definition — it can't be inflated by a token that pumped this morning and hasn't been sold — and it's the one that matches what a trader could have withdrawn.

FOMO's own leaderboard reports a blended number: realized plus the unrealized mark-to-market value of open positions. Our default leaderboard serves that figure as FOMO reports it, with pnlBasis: "mark-to-market" on the response. It's useful, but it's a different figure, and it moves every time price moves. If two numbers for the same trader don't match, check which definition each one uses first.

FIFO cost basis

Every buy creates a lot: quantity plus USD cost at that moment. Every sell consumes the oldest open lots first (first-in, first-out) and realizes the difference between sale proceeds and those lots' cost. Lots and fills are persisted, so a wallet's PnL is reproducible, and a re-run over the same data produces the same answer.

USD pricing at trade time

Each leg of a swap is priced in USD at its block time from historical price data, with more than one source behind it. When no reliable price exists for a token at that moment, the trade is not priced at zero — it's flagged unpriced and counted against coverage.

Coverage is part of the number

A PnL figure without a coverage figure is a guess dressed up as a fact. coveragePct tells you what share of a wallet's activity the PnL is based on — trades we've ingested and priced versus trades we know exist. The board=solana leaderboard only ranks wallets whose window PnL is complete at or above a coverage floor, so a page can end before limit: that's the full ranked set, not a truncated one.

Null means unknown

When a metric can't be computed with enough confidence, the field is null. Not zero, not an estimate. A UI that renders our data should treat null as "—". This one rule prevents a whole class of embarrassing $0.00 rows.

Source vs venue

A trade's venue is where it executed — Jupiter, Pump AMM, Raydium, OKX DEX. Its source is where it originated — a trading bot, a wallet app, a direct program call. Most APIs collapse these; we keep both, because "which bots' users are profitable" and "which venues are profitable" are different questions.

What we don't do

  • We don't pass off anyone else's numbers as ours. FOMO's figures are served as FOMO's, labelled source: "fomo"; ours are computed chain → our ingestion → our analytics → you.
  • We don't infer social identities from wallet behaviour. Identity is an enrichment on a row, never a gate.
  • We don't round coverage up. If it's 62%, it says 62%.

See the fields in practice in the wallet PnL quickstart, or start with the docs.