Wallet P&L time series
curl --request GET \
--url https://api.polynode.dev/v3/wallets/{address}/pnl/events \
--header 'x-api-key: <api-key>'import requests
url = "https://api.polynode.dev/v3/wallets/{address}/pnl/events"
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/events', 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/events",
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/events"
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/events")
.header("x-api-key", "<api-key>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.polynode.dev/v3/wallets/{address}/pnl/events")
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_bodyWallet P&L
Wallet P&L Time Series
Realized P&L bucketed by hour, day, week, or month — chart-ready time series for a wallet.
GET
/
v3
/
wallets
/
{address}
/
pnl
/
events
Wallet P&L time series
curl --request GET \
--url https://api.polynode.dev/v3/wallets/{address}/pnl/events \
--header 'x-api-key: <api-key>'import requests
url = "https://api.polynode.dev/v3/wallets/{address}/pnl/events"
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/events', 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/events",
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/events"
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/events")
.header("x-api-key", "<api-key>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.polynode.dev/v3/wallets/{address}/pnl/events")
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_bodyReturns wallet P&L buckets for charting. With
If
period, after, or before, each row is a fixed time window (hour, day, week, or month). A running cumulative_pnl is included so the response can be plotted directly.
These standard spot P&L buckets exclude separately reported trader-paid
fees, rebates, and rewards. cumulative_pnl accumulates the returned P&L;
it is not an after-fee account return. See Wallet P&L accounting scope
and Fees Paid for the separate fee data.
Event-series mode is separate from the boundary-state calculation used by time-filtered GET /v3/wallets/{address}/pnl. Each bucket sums recorded weighted-average-cost realized-P&L event deltas. It is not a historical all-time-portfolio snapshot: holdings that are only bought and held can contribute 0, even when a resolved holding contributes profit to the current all-time P&L. Baseline corrections without an event timestamp are not placed into a bucket.
Without an explicit time filter, the endpoint returns a single all-time summary bucket that matches GET /v3/wallets/{address}/pnl.
In event-series mode, wins, losses, and events count realized P&L events in the selected window. In default summary mode, counts are position counts and the response includes count_type: "positions" and summary_bucket: true.
Rows at timestamp 0 or earlier are ignored in event-series mode, so explicit event windows start at Unix second 1.
Request
GET /v3/wallets/{address}/pnl/events
Query parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
group | string | day | Bucket size: hour, day, week, month |
period | string | — | Shortcut for after: 1d, 7d, 30d, 1y |
after | integer | 1 | Start timestamp (Unix seconds, inclusive). Values below 1 are treated as 1. |
before | integer | now | End timestamp (Unix seconds, inclusive) |
limit | integer | 1000 | Max buckets returned, clamped to 1-1000 |
after and period are both set, after wins.
Examples
All-time summary bucket
curl "https://api.polynode.dev/v3/wallets/0xbddf61af533ff524d27154e589d2d7a81510c684/pnl/events"
{
"address": "0xbddf61af533ff524d27154e589d2d7a81510c684",
"granularity": "day",
"bucket_count": 1,
"buckets": [
{
"bucket": 1779908613,
"realized_pnl": 29035964.931344,
"cumulative_pnl": 29035964.931344,
"gross_profit": 29818047.886063,
"gross_loss": -782082.954719,
"wins": 482,
"losses": 33,
"events": 1016,
"position_count": 1016,
"open_positions": 511,
"unrealized_pnl": -26917534.501466,
"total_pnl": 2118430.429878,
"total_volume": 177203290.120101
}
],
"total_realized_pnl": 29035964.931344,
"total_events": 1016,
"total_wins": 482,
"total_losses": 33,
"total_positions": 1016,
"open_positions": 511,
"unrealized_pnl": -26917534.501466,
"total_pnl": 2118430.429878,
"source": "wallet_summary",
"count_type": "positions",
"summary_bucket": true,
"elapsed_ms": 3
}
Daily P&L for the last 7 days
curl "https://api.polynode.dev/v3/wallets/0x44c1dfe43260c94ed4f1d00de2e1f80fb113ebc1/pnl/events?period=7d&group=day"
{
"address": "0x44c1dfe43260c94ed4f1d00de2e1f80fb113ebc1",
"granularity": "day",
"after": 1778478745,
"before": 1779083545,
"bucket_count": 3,
"buckets": [
{
"bucket": 1778889600,
"realized_pnl": 0.000525,
"cumulative_pnl": 0.000525,
"gross_profit": 0.000525,
"gross_loss": 0,
"wins": 1,
"losses": 0,
"events": 1
},
{
"bucket": 1778976000,
"realized_pnl": 611.069702,
"cumulative_pnl": 611.070227,
"gross_profit": 618.41811,
"gross_loss": -7.348408,
"wins": 23,
"losses": 3,
"events": 26
},
{
"bucket": 1779062400,
"realized_pnl": 11.774724,
"cumulative_pnl": 622.844951,
"gross_profit": 11.774724,
"gross_loss": 0,
"wins": 2,
"losses": 0,
"events": 2
}
],
"total_realized_pnl": 622.844951,
"total_events": 29,
"total_wins": 26,
"total_losses": 3,
"elapsed_ms": 4
}
Hourly P&L for an explicit window
curl "https://api.polynode.dev/v3/wallets/0x44c1dfe43260c94ed4f1d00de2e1f80fb113ebc1/pnl/events?after=1778976000&before=1779062400&group=hour"
Weekly P&L for the last year
curl "https://api.polynode.dev/v3/wallets/0x44c1dfe43260c94ed4f1d00de2e1f80fb113ebc1/pnl/events?period=1y&group=week"
Response fields
| Field | Type | Description |
|---|---|---|
address | string | The wallet address (lowercased) |
granularity | string | Resolved bucket size (hour, day, week, month) |
after | integer | Start of the window (Unix seconds, inclusive) |
before | integer | End of the window (Unix seconds, inclusive) |
bucket_count | integer | Number of buckets returned |
buckets | array | Time-series rows, ordered oldest → newest |
buckets[].bucket | integer | Bucket start timestamp (Unix seconds, UTC, truncated to bucket boundary) |
buckets[].realized_pnl | number | Weighted-average-cost realized P&L changes from indexed events in that bucket (USD) |
buckets[].cumulative_pnl | number | Running sum of realized_pnl over the returned series (USD) |
buckets[].gross_profit | number | Sum of winning events in that bucket (USD) |
buckets[].gross_loss | number | Sum of losing events in that bucket (USD, negative) |
buckets[].wins | integer | Count of winning events in that bucket |
buckets[].losses | integer | Count of losing events in that bucket |
buckets[].events | integer | Total P&L events in event-series mode; position count in default summary mode |
buckets[].position_count | integer | Position count. Present in default summary mode. |
buckets[].open_positions | integer | Open position count. Present in default summary mode. |
buckets[].unrealized_pnl | number | Current unrealized P&L. Present in default summary mode. |
buckets[].total_pnl | number | realized_pnl + unrealized_pnl. Present in default summary mode. |
buckets[].total_volume | number | Wallet volume from the summary source. Present in default summary mode. |
total_realized_pnl | number | Sum of event-realized realized_pnl across all returned buckets (USD); it is not expected to equal the current all-time P&L |
total_events | integer | Sum of events across all returned buckets |
total_wins | integer | Sum of wins across all returned buckets |
total_losses | integer | Sum of losses across all returned buckets |
source | string | Dataset label. Present in default summary mode. |
count_type | string | positions in default summary mode |
summary_bucket | boolean | true in default summary mode |
elapsed_ms | integer | Server-side query time in milliseconds |
Errors
| HTTP | When |
|---|---|
400 | Invalid wallet address (must be 0x + 40 hex) |
400 | Invalid group value (must be hour, day, week, or month) |
400 | after greater than before |
Authorizations
Path Parameters
Wallet address
Query Parameters
Bucket size
Available options:
hour, day, week, month Time window shortcut
Available options:
1d, 7d, 30d, 1y Unix timestamp lower bound. Values below 1 are clamped to 1.
Unix timestamp upper bound
Maximum bucket count, clamped to 1000
Required range:
1 <= x <= 1000Response
Wallet P&L buckets

