NakedPnL

The public registry of verified investment performance. Every return sourced from SEC filings, exchange APIs, or platform data.

Registry

  • Registry
  • Market Context
  • How It Works
  • Community

Verification

  • Get Verified
  • Connect Exchange

Legal

  • Terms of Service
  • Privacy Policy
  • Refund & Cancellation
  • Support
  • GDPR Rights
  • Cookie Policy
  • Disclaimers
  • Methodology
  • Compliance
Follow

NakedPnL is a publisher of verified performance data. Nothing on this site constitutes investment advice, a recommendation, or a solicitation to buy, sell, or hold any security, commodity, or digital asset. Past performance does not indicate future results. Trading carries a high risk of total capital loss.

© 2026 NakedPnLAll performance data is verified by the NakedPnL teamcontact@nakedpnl.com
Skip to content
NakedPnL
RegistryPricingHow It WorksCommunitySupport
NakedPnL/Guides/Auditing a Crypto Trader's PnL from Raw API Data — A Step-by-Step Procedure
Methodology guide

Auditing a Crypto Trader's PnL from Raw API Data — A Step-by-Step Procedure

How to reproduce a crypto trader's claimed profit-and-loss figure from raw exchange API data. Pulls, canonicalisation, NAV reconstruction, fee handling, and TWR re-derivation explained.

By NakedPnL Research·May 9, 2026·15 min read
TL;DR
  • Reproducing a crypto trader's claimed PnL means starting from raw exchange API responses and ending at the published figure, without trusting any intermediate dashboard.
  • The procedure has six discrete steps: credential setup, raw data pull, canonicalisation, NAV reconstruction, fee and funding adjustment, and TWR computation.
  • The most common failure mode is mismatched fee handling — what an exchange shows as P&L on its dashboard is gross of fees and funding rates the trader actually paid.
  • On NakedPnL the procedure runs every day automatically — daily NAV from venue API, canonicalised, hashed, chained. A reviewer can re-run any specific day's pull and confirm.
On this page
  1. Step 1 — Credential setup and the trust model
  2. Step 2 — Raw API pull
  3. Step 3 — Canonicalisation
  4. Step 4 — NAV reconstruction
  5. Step 5 — Fee and funding-rate adjustment
  6. Step 6 — TWR computation
  7. What an audit cannot solve
  8. How NakedPnL automates the audit
  9. Frequently asked questions

A crypto trader's published PnL is a number on a screen. Behind it is — or should be — a stream of raw exchange API responses that, processed through a documented methodology, produces exactly that number. Auditing the published figure means starting from those raw responses and arriving at the same number without trusting the trader's dashboard, the venue's rendered figure, or any intermediate calculation. The procedure is mechanical, not subjective; either the published figure reproduces from primary records or it does not, and a clean audit gives a yes-or-no answer.

This guide walks the procedure end to end with the level of detail that an auditor with access to read-only API credentials needs. It covers the things that go wrong in practice — fee accounting, funding-rate handling, deposit and withdrawal classification, derivative-vs-spot reconciliation — and explains why each one matters for the final figure. The how-to-verify-a-trader-track-record-yourself guide covers the broader six-step verification framework; this guide narrows in on the crypto-exchange-specific data pull and arithmetic.

Step 1 — Credential setup and the trust model

An audit of a trader's account requires either the trader's read-only API credentials or a continuously-maintained chain at a verification registry that already pulled them. The credential's permissions should be limited to read — Binance's case for this is a credential with no withdrawal or trading permission, no IP whitelist requirement that prevents the auditor from making the call, and access to the account information and trade history endpoints. Bybit, OKX, and Kraken expose comparable read-only options. An auditor never asks for full-permission credentials. If the trader will not produce a read-only credential, the audit cannot proceed.

On NakedPnL the credential is registered once at onboarding and the daily snapshot cron at 23:55 UTC pulls the necessary endpoints. The audit-from-raw-data path is the same code path that produced the chain — but the auditor can also run it independently by calling the same exchange endpoints with the same credentials and confirming that the response matches the canonical record stored in the chain bundle.

Step 2 — Raw API pull

Each exchange exposes a different surface for account-level state. The audit-relevant endpoints divide into three categories: balance and equity (the per-asset and total account state at a moment in time), trade history (every executed order with price, size, fee, and timestamp), and ledger (every credit, debit, transfer, funding-rate accrual, and fee in time order). For an audit, all three are necessary because PnL reconstruction requires reconciling balance changes against trade activity and explaining any residual through the ledger.

ExchangeBalance/equityTrade historyLedger
Binance SpotGET /api/v3/accountGET /api/v3/myTrades (per symbol)GET /sapi/v1/asset/transfer + capital/withdraw + capital/deposit
Binance FuturesGET /fapi/v2/accountGET /fapi/v1/userTradesGET /fapi/v1/income (FUNDING_FEE, COMMISSION, TRANSFER, REALIZED_PNL)
Bybit UnifiedGET /v5/account/wallet-balanceGET /v5/execution/listGET /v5/account/transaction-log
OKXGET /api/v5/account/balanceGET /api/v5/trade/orders-historyGET /api/v5/account/bills
The three endpoint categories an audit needs from each major derivatives exchange.

Pulls should be paginated to completion — exchange APIs cap responses (typically 500 to 1000 rows per call) and the auditor must walk the cursor or time-window pagination to ensure no records are missed. The most common audit failure at this step is silent truncation: the auditor pulls 1000 trade records, sees that one or more are at the page boundary, and forgets that the original history may extend past it. A complete pull verifies the record count against the exchange's reported totals (where available) and proceeds to the next step only when the dataset is closed under all three endpoint categories for the audit period.

Step 3 — Canonicalisation

Raw exchange responses are JSON with potentially-different whitespace and key ordering across calls. A bare hash of the wire response is brittle — two semantically identical responses with different whitespace would hash differently. The fix is canonicalisation: serialise each response with sorted keys and no whitespace, then hash the canonical form. This is the same procedure NakedPnL runs in lib/calculation/audit-hash.ts. The canonical-json-canonicalization-financial-records guide covers the protocol details.

Why this matters for an audit: when the auditor's pull is compared to the chain's stored response, the comparison is on canonical form, not raw bytes. If the canonical forms match, the audit confirms that the response captured at the original snapshot time is identical to what the auditor pulls now. If they differ, the discrepancy is either a real change in the underlying data (which would itself be diagnostic — exchange-side restatements are unusual but happen) or a canonicalisation bug. Either is investigable.

Step 4 — NAV reconstruction

NAV at any moment is the dollar (or stablecoin) value of all assets in the account, plus or minus mark-to-market on open derivative positions. Reconstructing NAV from raw responses requires three inputs: the per-asset balance from the balance endpoint, the mark prices for any spot assets in non-quote currency, and the unrealised P&L on any open derivative positions. For a USDT-quoted derivatives account, this simplifies to wallet balance + unrealised P&L from the futures account endpoint. For a multi-asset spot account, the per-asset balances must be priced against a reference (USDT or USD) using exchange-published mark prices at the snapshot time.

The reconstruction is daily-cadence on NakedPnL: the snapshot at 23:55 UTC fetches account state at a defined moment, prices the multi-asset case against exchange-published mark prices, and stores the resulting equity figure as the NavSnapshot row. An auditor reproducing the figure pulls the same endpoints with timestamps within the snapshot window and arrives at the same NAV to within sub-cent precision (Decimal.js, 28 digits). If the figures diverge, the divergence is either price-source (different mark used) or timing (auditor pulled at a different moment) and can be reconciled by aligning the inputs.

Step 5 — Fee and funding-rate adjustment

This is where most casual audits fail. An exchange's dashboard typically displays gross PnL — the difference between exit price and entry price scaled by position size — without subtracting trading fees, funding-rate accruals, or borrow costs. An honest audit must net all of these, and they are non-trivial. On Binance USDT-M Futures, funding rates are paid every 8 hours and accrue to the income endpoint as FUNDING_FEE entries. Trading fees appear as COMMISSION entries. On a high-frequency strategy these can dominate the gross P&L; an unadjusted audit would over-state realised performance by orders of magnitude.

from decimal import Decimal, getcontext

getcontext().prec = 28

def account_pnl_from_ledger(ledger_entries, opening_equity, closing_equity):
    """Reconstruct net account PnL from primary ledger.

    ledger_entries: list of {type, asset, amount} from venue ledger endpoint.
    opening_equity, closing_equity: equity at start/end of audit period.

    Returns dict with components so the auditor can see
    where the period's PnL actually came from.
    """
    deposits = sum(Decimal(e['amount']) for e in ledger_entries
                   if e['type'] in ('TRANSFER_IN', 'DEPOSIT'))
    withdrawals = sum(Decimal(e['amount']) for e in ledger_entries
                      if e['type'] in ('TRANSFER_OUT', 'WITHDRAWAL'))
    net_flow = deposits - withdrawals

    realized_pnl = sum(Decimal(e['amount']) for e in ledger_entries
                       if e['type'] == 'REALIZED_PNL')
    funding = sum(Decimal(e['amount']) for e in ledger_entries
                  if e['type'] == 'FUNDING_FEE')
    fees = sum(Decimal(e['amount']) for e in ledger_entries
               if e['type'] == 'COMMISSION')

    # Sanity check: the equity change net of flows equals
    # realized + unrealized + funding + fees.
    derived_change = closing_equity - opening_equity - net_flow
    components_total = realized_pnl + funding + fees
    # The residual is unrealized PnL change on open positions.
    unrealized_change = derived_change - components_total

    return {
        'realized_pnl': realized_pnl,
        'funding': funding,
        'fees': fees,
        'unrealized_change': unrealized_change,
        'net_flow': net_flow,
        'derived_change': derived_change,
    }
Reconstruct period P&L from the primary ledger so each component is visible. Mismatches localise to a single ledger type.

The reconstruction surfaces the components separately. A trader claiming '40% return last quarter' on a strategy that paid 8% in funding, 3% in fees, and made 51% gross trading P&L has produced an honest 40% net figure. A trader claiming the same 40% on a strategy that paid 25% in funding and made 65% gross has produced a much riskier set of returns and the picture is qualitatively different. Decomposing into components changes how the figure is interpreted even when the headline number is correct.

Step 6 — TWR computation

Once NAV is reconstructed for each snapshot date and external cash flows are isolated from realised P&L (Step 5), TWR is the geometric chain-link of sub-period returns. The methodology guide on time-weighted return walks the algorithm; the canonical implementation is in lib/calculation/twr-engine.ts and the auditor's reference is at /docs/verification with both Python and JavaScript snippets. The arithmetic is straightforward; the discipline is in identifying every flow correctly and using arbitrary-precision decimals so the chain-link does not accumulate floating-point error across hundreds or thousands of compounded daily steps.

An auditor running this step should expect to reproduce a NakedPnL TWR figure to 28-decimal precision when the inputs (canonical NAV series, identified flows) are aligned. Any divergence at higher than the eighth decimal indicates a flow misidentification or a precision bug; either is investigable. A divergence at the third decimal is a real disagreement and the figure does not reconcile.

What an audit cannot solve

An audit reproduces what the venue records say happened in a connected account. It cannot detect un-connected accounts the trader also operates, cannot rule out wash-trading or self-trading patterns the venue itself has not flagged, and cannot anticipate strategy changes the trader will make in the future. The audit's scope is exactly: for the connected accounts, over the connected period, do the published figures reproduce from the venue's primary records. That narrow result is what verification is supposed to deliver. The methodology guide on survivorship bias in trader rankings covers what an audit does not address.

Crypto venues themselves can also restate. An exchange that detects errors in past funding-rate accruals will sometimes issue retroactive adjustments. Honest audit procedure flags any such restatement explicitly rather than re-syncing it silently into the chain — the chain entry remains as it was at the original snapshot, and a corrective entry is appended with both visible. The integrity of the audit trail depends on this: a chain that silently restates loses the property that the historical record cannot be retroactively edited.

How NakedPnL automates the audit

NakedPnL runs the six-step procedure every day for every connected venue account. The daily snapshot cron pulls account state at 23:55 UTC; the response is canonicalised; the canonical form is SHA-256 hashed; the content hash plus the response is stored as a NavSnapshot row; the chain header is computed as SHA-256(previous chain header + content hash); the daily Merkle root of all chain heads is committed to Bitcoin via OpenTimestamps. The TWR engine runs over the canonical NAV series whenever the published figure is recomputed. Each step is open-source and documented; the chain bundle is exposed at the chain API for any third party to download and re-derive.

A reviewer who wants to check a specific day's figure does not need to run the full audit from scratch. The chain bundle has the canonical response for that day; the auditor pulls the same endpoints with the same credentials at any time and confirms that the canonical forms match. The TWR re-derivation is then a single function call against the verified NAV series. The work scales to any reviewer at near-zero marginal cost — exactly the property a verification surface needs.

Frequently asked questions

Do I need to be a developer to audit a trader's PnL from raw API data?
Some technical comfort is helpful but not essential. The /verify/chain/[handle] page runs the chain integrity and TWR re-derivation in the browser. The full from-scratch audit (pulling the venue API independently) requires basic scripting against the exchange's API, which most exchanges document with examples in Python, JavaScript, and shell.
What is the most common audit failure mode?
Mismatched fee and funding-rate handling. Exchange dashboards often show gross P&L; honest audits net trading fees, funding accruals, and borrow costs. A claim of '40% return' that does not net these can be inflated by 5-30% relative to what the trader actually realised.
Can the audit detect wash trading?
Sometimes. Wash trading at scale produces an unusual combination of high turnover, low net P&L, and abnormal fee burn relative to the strategy's claimed sizing. A careful audit can flag these patterns. It cannot prove intent, only the pattern.
What happens if the trader's API key is revoked partway through the period?
The chain stops growing on the day the credential stops working. A reviewer can confirm the gap by attempting a fresh pull; a 401/permission-denied response from the exchange confirms the credential is revoked. The trader can re-credential and resume, but the gap remains visible in the chain.
Can a trader manipulate the audit by routing through multiple exchanges?
Multi-venue strategies are normal and supported — NakedPnL aggregates daily NAV across all connected venues into a single chain. The manipulation risk is the trader connecting only some of their venues and omitting others. Audit response: insist on a complete venue inventory under representation, and verify against any third-party evidence of accounts at venues the trader has not connected.
How does this differ from a GIPS verification?
A GIPS verification is firm-level and procedural — an external verifier opines on the firm's policies. The cryptographic audit is per-account and re-runnable — any third party can recompute the figures from primary records. They answer different questions and are complementary.

References

  • Binance — API documentation
  • Bybit — API documentation
  • OKX — API documentation
  • NakedPnL — Verification methodology
NakedPnL is a publisher of verified investment performance data. We are not an investment adviser, broker, dealer, or asset manager, and nothing on this page constitutes investment advice or a recommendation. See the compliance page for our full regulatory posture.