Skip to main content
GET
/
v2
/
wallets
/
{address}
/
positions
/
onchain
Onchain positions & P&L
curl --request GET \
  --url https://api.polynode.dev/v2/wallets/{address}/positions/onchain \
  --header 'x-api-key: <api-key>'
{
  "wallet": "0xbddf61af533ff524d27154e589d2d7a81510c684",
  "source": "onchain",
  "count": 873,
  "open_count": 334,
  "closed_count": 288,
  "total_realized_pnl": 17183579.48,
  "positions_with_pnl": 309,
  "positions": [
    {
      "token_id": "34158857981196154020624191931838064546543114916900689904269497497174344049047",
      "size": 0,
      "avg_price": 0.316481,
      "realized_pnl": 447182.949852,
      "total_bought": 654236.312162
    }
  ]
}
Returns every position a wallet has ever held, including closed positions that no longer appear in the standard positions endpoint. Each position includes precomputed realized_pnl, avg_price, and total_bought from onchain data. The standard /v1/wallets/{addr}/positions endpoint only returns open positions. Once a position is fully exited or a market resolves, it disappears. This endpoint fills that gap.

Request

GET /v2/wallets/{address}/positions/onchain
ParameterTypeDescription
addresspathWallet address (0x-prefixed, 40 hex chars)

Response

{
  "wallet": "0xbddf61af533ff524d27154e589d2d7a81510c684",
  "source": "onchain",
  "count": 879,
  "open_count": 340,
  "closed_count": 288,
  "total_realized_pnl": 17183579.48,
  "positions_with_pnl": 309,
  "positions": [
    {
      "token_id": "100424505911492726143069668369640898890012859227903329249368753635028896002613",
      "size": 0,
      "avg_price": 0.63,
      "realized_pnl": 147588.53019,
      "total_bought": 398887.919433,
      "market": "Will Fulham FC win on 2026-03-21?",
      "slug": "epl-ful-bur-2026-03-21-ful",
      "outcome": "Yes",
      "image": "https://polymarket-upload.s3.us-east-2.amazonaws.com/Repetitive-markets/premier+league.jpg",
      "condition_id": "0xae68634cb01137acbe26e65790f7268a523ee1519601f2576bd7b067c7c9f9da"
    }
  ]
}
FieldTypeDescription
walletstringQueried wallet address (lowercased)
sourcestringAlways "onchain"
countnumberTotal positions returned
open_countnumberPositions with size > 0
closed_countnumberPositions with size = 0 and nonzero realized_pnl
total_realized_pnlnumberSum of realized_pnl across all positions
positions_with_pnlnumberPositions where realized_pnl != 0
positions[].token_idstringCTF token ID (called asset on the closed-positions endpoint)
positions[].sizenumberCurrent token balance (0 = fully exited)
positions[].avg_pricenumberVolume-weighted average entry price
positions[].realized_pnlnumberRealized profit/loss in USDC
positions[].total_boughtnumberTotal tokens acquired for this position
positions[].marketstringMarket question
positions[].slugstringMarket slug
positions[].outcomestringOutcome label (e.g. “Yes”, “No”, “Up”)
positions[].imagestringMarket image URL
positions[].condition_idstringMarket condition ID

How realized_pnl Works

Each position’s realized_pnl reflects the profit or loss after the position is closed (sold or redeemed). For a winning binary position bought at 0.40thatresolvesat0.40 that resolves at 1.00:
  • avg_price = 0.40
  • total_bought = 10,000 (tokens acquired)
  • Cost basis = 10,000 × 0.40=0.40 = 4,000 USDC
  • Payout at 1.00=10,000×1.00 = 10,000 × 1.00 = $10,000 USDC
  • realized_pnl = 10,00010,000 - 4,000 = $6,000
The formula: realized_pnl = total_bought × (1 - avg_price) for positions that resolve at $1. Per-position values (realized_pnl, avg_price, total_bought) come from the same onchain settlement data that Polymarket uses. Individual position P&L matches what Polymarket shows on its portfolio page.

total_realized_pnl vs Polymarket Profile PnL

total_realized_pnl is the sum of all individual position realized_pnl values. This number will be higher than the PnL shown on a Polymarket profile page because they measure different things. What total_realized_pnl measures: Total profit taken off the table from closed and resolved positions. This is money the wallet has already extracted. What Polymarket’s profile PnL measures: Net portfolio performance, which accounts for capital still deployed in open positions. A wallet with 17Minrealizedgainsbut17M in realized gains but 14M in cost basis locked in open positions shows ~$3M on Polymarket’s profile. Both numbers are correct:
MetricValueSource
Realized gains from closed positions$17,183,579total_realized_pnl from this endpoint
Cost basis deployed in open positions-$14,398,655sum(size × avg_price) for positions where size > 0
Unrealized gains on open positions+$51,653Current market prices vs entry prices
Net portfolio PnL$2,834,935Trader profile totalPnl
To get the Polymarket-equivalent net PnL number, subtract the cost basis of open positions and add any unrealized gains. Or use the trader profile endpoint which returns Polymarket’s own totalPnl directly.
Use total_realized_pnl when you want to know how much profit a wallet has actually extracted. Use the trader profile totalPnl when you want the number that matches a Polymarket profile page.

Performance

Responses are cached for 5 minutes per wallet. First request for a new wallet takes 200ms-3s depending on position count (up to 20,000 positions supported). Cached responses return in under 50ms.
PositionsFirst requestCached
< 500~1s< 50ms
500-1,000~1.5s< 50ms
1,000-5,000~3s< 50ms

Example

curl "https://api.polynode.dev/v2/wallets/0xbddf61af533ff524d27154e589d2d7a81510c684/positions/onchain" \
  -H "x-api-key: YOUR_KEY"

Authorizations

x-api-key
string
header
required

Path Parameters

address
string
required

Wallet address (0x-prefixed)

Response

Onchain positions with P&L