Wallet P&L
curl --request GET \
--url https://api.polynode.dev/v3/wallets/{address}/pnl \
--header 'x-api-key: <api-key>'import requests
url = "https://api.polynode.dev/v3/wallets/{address}/pnl"
headers = {"x-api-key": "<api-key>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {'x-api-key': '<api-key>'}};
fetch('https://api.polynode.dev/v3/wallets/{address}/pnl', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.polynode.dev/v3/wallets/{address}/pnl",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"x-api-key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.polynode.dev/v3/wallets/{address}/pnl"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("x-api-key", "<api-key>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.polynode.dev/v3/wallets/{address}/pnl")
.header("x-api-key", "<api-key>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.polynode.dev/v3/wallets/{address}/pnl")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["x-api-key"] = '<api-key>'
response = http.request(request)
puts response.read_body{
"wallets": [
{
"wallet": "<string>",
"type": "eoa"
}
]
}Wallet P&L
Wallet P&L
Get profit and loss for a wallet in USD. Supports time-windowed P&L with ?period=1d|7d|30d|1y plus tag, category, market, event, and condition filters.
GET
/
v3
/
wallets
/
{address}
/
pnl
Wallet P&L
curl --request GET \
--url https://api.polynode.dev/v3/wallets/{address}/pnl \
--header 'x-api-key: <api-key>'import requests
url = "https://api.polynode.dev/v3/wallets/{address}/pnl"
headers = {"x-api-key": "<api-key>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {'x-api-key': '<api-key>'}};
fetch('https://api.polynode.dev/v3/wallets/{address}/pnl', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.polynode.dev/v3/wallets/{address}/pnl",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"x-api-key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.polynode.dev/v3/wallets/{address}/pnl"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("x-api-key", "<api-key>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.polynode.dev/v3/wallets/{address}/pnl")
.header("x-api-key", "<api-key>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.polynode.dev/v3/wallets/{address}/pnl")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["x-api-key"] = '<api-key>'
response = http.request(request)
puts response.read_body{
"wallets": [
{
"wallet": "<string>",
"type": "eoa"
}
]
}Returns P&L data for a wallet in USD. Without a time parameter, it returns the wallet’s current all-time P&L. With
Both boundaries are inclusive. A state change timestamped exactly at
The boundary calculation uses Polynode’s recovered Polymarket weighted-average-cost state. The difference is scope and timing, not a simpler cost-basis formula: all-time P&L uses the current recovered portfolio state, including terminal treatment for resolved holdings and current unrealized P&L, while a time window reports only the change in realized state across its boundaries.
For time-windowed or tag-filtered P&L, the response stays successful. If combo P&L cannot be safely added to that filtered view,
Additional fields (with
Totals and counts are summed across the combined wallets. With
period, after, or before, it returns this boundary calculation across all matching positions:
time-window realized P&L = realized state at or before `before`
- realized state immediately before `after`
after or before is included.
Owner addresses. Pass an owner EOA as the wallet address and the response combines the EOA’s Polymarket wallets (Safe, proxy, deposit wallets) that have data for this endpoint. Passing a Safe, proxy or deposit wallet returns just that wallet, as before. Combined responses list the combined wallets in
wallets. See Owner addresses.Fees and accounting scope
For standard spot market positions, realized and unrealized P&L exclude separately reported trader-paid fees, rebates, and rewards.net_realized_pnl
means the combined realized gains and losses, not an after-fee return.
Use Fees Paid, Rebates, and
the optional Wallet Summary accounting fields when
you need those separate amounts.
include_combos=true adds a component with different fee treatment:
Combo P&L includes each signed order’s recorded
exchange fill fee in its cost basis or sale proceeds. That does not make the
standard spot component fee-inclusive. Perps has its own endpoint accounting
model; do not infer its fee or funding treatment from either component.
Time-window behavior
The two modes have different counting semantics: all-timewins and losses are current position counts; time-windowed wins, losses, and the legacy events field count positions whose realized state changed. Time-windowed responses declare count_type: "positions_changed". Do not compare the counts directly.
Time-windowed P&L is a realized-state change, not a historical snapshot of the all-time leaderboard. It captures realized changes reflected by sells, merges, redemptions, and timestamped corrections. A buy-and-hold position can therefore contribute
0 to a window even if terminal treatment makes the resolved position profitable in current all-time P&L. For the same reason, an after=1&before=now result is not expected to equal the all-time response or leaderboard total.Wallet P&L supports focused market filters such as
category, tags/tag_slug, market/market_slug, event_slug, and condition_id. For leaderboard views, use one primary filter dimension per request.Request
GET /v3/wallets/{address}/pnl
Query parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
period | string | — | Time window: 1d, 7d, 30d, 1y |
after | integer | — | Start timestamp (Unix seconds). Time-windowed queries clamp values below 1 to 1. |
before | integer | — | End timestamp (Unix seconds) |
category | string | — | Filter to one market category, case-insensitive |
tags | string | — | Comma-separated tag slugs to filter by, case-insensitive (e.g. politics,crypto, nfl, Iran) |
tag_slug | string | — | Alias for a single tags value |
market | string | — | Filter by condition ID or market slug |
market_slug | string | — | Filter by market slug |
event_slug | string | — | Filter by parent event slug |
condition_id | string | — | Filter by market condition ID |
include_unrealized | string | false | Set to true to add current unrealized P&L to the realized event-window result. This is the current value, not the change between the two requested boundaries. Only applies to time-filtered queries. |
include_combos | boolean | false | Add combo position P&L to all-time wallet P&L. If the wallet has no combo exposure, the response remains 200 with a zero combo contribution. |
Examples
All-time P&L
curl https://api.polynode.dev/v3/wallets/0x56687bf447db6ffa42ffe2204a05edaa20f55839/pnl
All-time P&L including combos
curl "https://api.polynode.dev/v3/wallets/0x63613e3b96f418332d43cd2af8dc321014d15907/pnl?include_combos=true"
{
"address": "0x63613e3b96f418332d43cd2af8dc321014d15907",
"net_realized_pnl": 113.510513,
"realized_pnl": 113.510513,
"gross_profit": 184.901354,
"gross_loss": -71.390841,
"unrealized_pnl": 0.0,
"total_pnl": 113.510513,
"position_count": 21496,
"open_positions": 1495,
"total_volume": 129.837476,
"include_combos": true,
"included_position_types": ["market", "combo"],
"combo_pnl": {
"position_type": "combo",
"included": true,
"realized_pnl": 113.510513,
"unrealized_pnl": 0.0,
"total_pnl": 113.510513,
"position_count": 21492,
"open_positions": 1495
}
}
combo_pnl.included is false and the standard market P&L fields remain unchanged.
{
"address": "0x56687bf447db6ffa42ffe2204a05edaa20f55839",
"net_realized_pnl": 22053845.825455,
"gross_profit": 22057977.181649,
"gross_loss": -4131.356194,
"unrealized_pnl": 0.000688755,
"total_pnl": 22053845.826143753,
"position_count": 22,
"open_positions": 1,
"total_volume": 43013258.515682,
"wins": 18,
"losses": 4,
"elapsed_ms": 41
}
30-day P&L
curl https://api.polynode.dev/v3/wallets/0xbddf61af533ff524d27154e589d2d7a81510c684/pnl?period=30d
{
"address": "0xbddf61af533ff524d27154e589d2d7a81510c684",
"realized_pnl": 1815261.28,
"gross_profit": 1918402.27,
"gross_loss": -103140.98,
"wins": 33039,
"losses": 58867,
"events": 91906,
"count_type": "positions_changed",
"source": "recovered_realized_boundaries",
"period": "30d",
"after": 1776134996,
"before": 1778726996,
"elapsed_ms": 5902
}
Filtered P&L
curl "https://api.polynode.dev/v3/wallets/0x952d11ebff81d6bd3185e608ed3515b94618ab8a/pnl?category=crypto"
curl "https://api.polynode.dev/v3/wallets/0x952d11ebff81d6bd3185e608ed3515b94618ab8a/pnl?tag_slug=us-election&period=30d"
curl "https://api.polynode.dev/v3/wallets/0x952d11ebff81d6bd3185e608ed3515b94618ab8a/pnl?market_slug=will-donald-trump-win-the-popular-vote-in-the-2024-presidential-election"
curl "https://api.polynode.dev/v3/wallets/0x952d11ebff81d6bd3185e608ed3515b94618ab8a/pnl?event_slug=presidential-election-popular-vote-winner-2024"
30-day P&L with unrealized
Passinclude_unrealized=true to add current unrealized P&L to the realized-state change. This does not turn the response into a historical portfolio-value change between after and before.
curl https://api.polynode.dev/v3/wallets/0xbddf61af533ff524d27154e589d2d7a81510c684/pnl?period=30d&include_unrealized=true
{
"address": "0xbddf61af533ff524d27154e589d2d7a81510c684",
"realized_pnl": 1815261.28,
"gross_profit": 1918402.27,
"gross_loss": -103140.98,
"unrealized_pnl": 14714.71,
"total_pnl": 1829975.99,
"open_positions_at_date": 363,
"wins": 33039,
"losses": 58867,
"events": 91906,
"count_type": "positions_changed",
"source": "recovered_realized_boundaries",
"period": "30d",
"after": 1776135002,
"before": 1778727002,
"elapsed_ms": 3803
}
Response fields (all-time)
| Field | Type | Description |
|---|---|---|
net_realized_pnl | number | Net realized P&L (USD) |
gross_profit | number | Sum of winning positions (USD) |
gross_loss | number | Sum of losing positions (USD, negative) |
unrealized_pnl | number | Paper P&L from open positions (USD) |
total_pnl | number | net_realized_pnl + unrealized_pnl (USD) |
wins | integer | Winning position count |
losses | integer | Losing position count |
position_count | integer | Total positions |
open_positions | integer | Currently held positions |
total_volume | number | Total volume traded (USD) |
include_combos | boolean | Present when include_combos=true was requested |
included_position_types | array | Position families included in aggregate totals |
combo_pnl | object | Combo-only contribution to the aggregate response |
Response fields (with period)
| Field | Type | Description |
|---|---|---|
realized_pnl | number | Weighted-average-cost realized state at before minus the state immediately before after (USD) |
gross_profit | number | Sum of positive changed-position deltas in the window (USD) |
gross_loss | number | Sum of negative changed-position deltas in the window (USD, negative) |
wins | integer | Positions with a positive realized-state delta |
losses | integer | Positions with a negative realized-state delta |
events | integer | Legacy field name; total positions with a nonzero realized-state delta |
count_type | string | positions_changed for time-windowed queries |
period | string | The requested period |
after | integer | Start timestamp (Unix seconds) |
before | integer | End timestamp (Unix seconds) |
source | string | Dataset label for time-windowed queries; currently recovered_realized_boundaries |
Additional fields (with include_unrealized=true)
| Field | Type | Description |
|---|---|---|
unrealized_pnl | number | Current unrealized P&L for open positions (USD), not the change in unrealized P&L between the requested boundaries. |
total_pnl | number | realized_pnl + unrealized_pnl (USD) |
open_positions_at_date | integer | Current open position count returned with the unrealized P&L estimate |
Owner address fields
Present only when you pass an owner EOA. See Owner addresses.| Field | Type | Description |
|---|---|---|
wallets | array | The combined wallets, in a fixed order, each {wallet, type} with type one of eoa, safe, proxy, or deposit_wallet |
period, after, or before, every wallet uses the same window, and address stays the address you passed. With include_combos=true, combo_pnl is included only when it is available for every combined wallet; otherwise the response covers market positions only. A wallet whose P&L is not loaded yet is left out of the combination and of wallets.
Errors
| HTTP | Error | When |
|---|---|---|
400 | Invalid request | The wallet address, period, filter, or boundary is invalid |
503 | time_filtered_pnl_unavailable | The selected wallet and window exceed the serving deadline. Retry with a narrower window. The response includes reason: "query_timeout". |
Authorizations
Path Parameters
Wallet address, or an owner EOA to combine every Polymarket wallet it owns
Query Parameters
Time window shortcut
Available options:
1d, 7d, 30d, 1y Inclusive Unix timestamp lower bound; the realized-state baseline is taken immediately before this timestamp
Inclusive Unix timestamp upper bound
Add current unrealized P&L to the time-windowed realized-state change; this is not the unrealized-P&L change between the requested boundaries
Response
Wallet P&L
Owner-address responses add the optional fields below. See the page for the full response.
Present only when you pass an owner EOA: the combined wallets, in a fixed order.
Show child attributes
Show child attributes

