GET /traders/{address}/pnl: Cumulative PnL Time Series
curl --request GET \
--url https://partner-api.bravadotrade.com/trader-analytics/traders/{address}/pnlimport requests
url = "https://partner-api.bravadotrade.com/trader-analytics/traders/{address}/pnl"
response = requests.get(url)
print(response.text)const options = {method: 'GET'};
fetch('https://partner-api.bravadotrade.com/trader-analytics/traders/{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://partner-api.bravadotrade.com/trader-analytics/traders/{address}/pnl",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
]);
$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://partner-api.bravadotrade.com/trader-analytics/traders/{address}/pnl"
req, _ := http.NewRequest("GET", url, nil)
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://partner-api.bravadotrade.com/trader-analytics/traders/{address}/pnl")
.asString();require 'uri'
require 'net/http'
url = URI("https://partner-api.bravadotrade.com/trader-analytics/traders/{address}/pnl")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
response = http.request(request)
puts response.read_body{
"interval": "<string>",
"fees_basis": "<string>",
"series_kind": "<string>",
"unrealized_marks": "<string>",
"empty_reason": "<string>",
"series": [
{
"ts": 123,
"pnl": "<string>"
}
]
}Trader Data API
GET /traders/{address}/pnl: Cumulative PnL Time Series
Gap-free, cumulative-all-time PnL time series for a wallet, suitable for plotting an equity curve — including intraday (hourly) resolution.
GET
/
trader-analytics
/
traders
/
{address}
/
pnl
GET /traders/{address}/pnl: Cumulative PnL Time Series
curl --request GET \
--url https://partner-api.bravadotrade.com/trader-analytics/traders/{address}/pnlimport requests
url = "https://partner-api.bravadotrade.com/trader-analytics/traders/{address}/pnl"
response = requests.get(url)
print(response.text)const options = {method: 'GET'};
fetch('https://partner-api.bravadotrade.com/trader-analytics/traders/{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://partner-api.bravadotrade.com/trader-analytics/traders/{address}/pnl",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
]);
$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://partner-api.bravadotrade.com/trader-analytics/traders/{address}/pnl"
req, _ := http.NewRequest("GET", url, nil)
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://partner-api.bravadotrade.com/trader-analytics/traders/{address}/pnl")
.asString();require 'uri'
require 'net/http'
url = URI("https://partner-api.bravadotrade.com/trader-analytics/traders/{address}/pnl")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
response = http.request(request)
puts response.read_body{
"interval": "<string>",
"fees_basis": "<string>",
"series_kind": "<string>",
"unrealized_marks": "<string>",
"empty_reason": "<string>",
"series": [
{
"ts": 123,
"pnl": "<string>"
}
]
}Sign each request with a fresh HMAC signature. The cURL and HTTP header values below are placeholders, not reusable credentials. For runnable signing code, use request signing examples. Python examples use the signed session from that page; Node.js examples use its
bravadoFetch helper.window only selects which slice of the curve comes back; it never
resets the curve to zero. A bucket with no new activity repeats the previous
total, so a wallet with real trading history but nothing inside the
requested window returns a flat line at its pre-window level, not an
empty array.
GET https://partner-api.bravadotrade.com/trader-analytics/traders/{address}/pnl
Changed 2026-09-11 — this page describes the default since 2026-09-12.
Before 2026-09-11, a bounded
window (e.g. 30d) returned a curve
relative to window start (starting near 0) rather than the wallet’s
cumulative total — and a wallet with no activity inside the window returned
series: [] even when it had a long trading history outside it. Both were
defects: a wallet whose only activity predates the window (e.g. it traded
heavily in 2024 and nothing since) now correctly renders as a flat line at
its historical level, and every window’s final point now agrees with
GET /traders/{address}’s all-time total. If
you previously computed your own baseline to splice windows together or to
backfill history before this endpoint’s coverage started, you can remove
that logic — a single call now returns the complete curve for the window
you ask for.On 2026-09-12 this became the default rather than the only option, via
?series_kind=cumulative_all_time. If your integration already adapted to
(or depends on) the pre-2026-09-11 relative-delta numbers, pass
?series_kind=window_delta to get them back exactly — still gap-filled, so
a wallet inactive in the window is a flat line at 0.000000, not []. See
the series_kind parameter below.Path Parameters
Query Parameters
string
default:"30d"
Time range. Accepted values:
1h, 4h, 24h, 7d, 30d, 90d, 365d,
all — plus 1y as an alias of 365d.string
default:"window-dependent"
Bucket resolution:
1h or 1d (alias: resolution, same values). Default
depends on window: 1h for 1h/4h/24h/7d/30d, 1d for
90d/365d/1y/all. There is no finer option (e.g. 5m) — no data
source in the platform resolves a wallet’s realized PnL more finely than
the hour, or its open-position mark more finely than the day, so this
endpoint does not invent resolution it does not have.string
default:"overall"
realized for the running realized-only curve; unrealized for the
open-position mark series alone (not cumulative — each point is that
bucket’s absolute mark, day-grained); overall for the realized curve plus
the unrealized mark at each bucket.string
default:"net"
net (fees deducted — exact, integrated over the wallet’s whole fee
history) or gross. net is automatically neutralized to gross at
interval=1h, because no fee source resolves finer than a day; check the
response’s fees_basis field rather than assuming your requested basis
held.string
default:"cumulative_all_time"
cumulative_all_time (default since 2026-09-12): the behavior described on
this page. window_delta: the pre-2026-09-12 numbers — each point is a
delta relative to window start (0 at the first bucket) — still gap-filled
and carried forward, so an inactive-in-window wallet is a flat line at
0.000000, never []. Use this if your integration depends on the older
relative-delta shape; the response always echoes which one you got.Response
string
The bucket resolution actually used (
1h or 1d) — the resolved value
even when you didn’t pass interval/resolution.string
Which fees were actually deducted:
all_time (exact, series_kind= cumulative_all_time + basis=net at interval=1d), window_daily
(series_kind=window_delta + basis=net at interval=1d — the window’s
own fees, cumulative from 0), unavailable_sub_day (basis=net was
neutralized to gross because interval=1h has no hourly fee source),
none (basis=gross was requested), or engine_net (predict.fun, whose
engine realized PnL is already fee-net).string
Echoes the
series_kind parameter you sent (or the default,
cumulative_all_time) — a marker so your integration can detect which
contract a response is on (see the changelog note above) without guessing
from the numbers.string
How the series’ unrealized component is sourced:
none (pnl_type=realized
— no unrealized component), day_grained (interval=1d — an exact daily
mark), day_grained_carried_forward (interval=1h — no hourly
unrealized-mark source exists, so the day’s mark is repeated across its
hours rather than interpolated).In every case the carried-forward mark has a staleness bound: once a mark
is older than that bound, points that would otherwise carry it forward
serve 0 for the unrealized component instead — a wallet whose
position-marking rollup has stopped updating is treated as “no current
mark,” never as “still holding whatever it last held.”string
Present only when
series is empty: no_wallet_history for a wallet
this platform has never observed any activity for. A wallet with real
history but nothing inside the requested window is not empty — see
above — so this field is otherwise omitted.array
The last point of every window’s series is the same number: the
wallet’s current all-time total for the requested
pnl_type/basis. That
also equals GET /traders/{address}’s
realized_pnl (for pnl_type=realized) or total_pnl (for
pnl_type=overall), same basis — a useful sanity check if you’re
reconciling a chart against the profile card next to it.Example: hourly resolution over the last 24 hours
curl -G https://partner-api.bravadotrade.com/trader-analytics/traders/0xabc.../pnl \
-H "X-BRAVADO-API-KEY: $BRAVADO_API_KEY" \
-H "X-BRAVADO-TIMESTAMP: <unix-ms>" \
-H "X-BRAVADO-SIGNATURE: <signature-for-this-request>" \
-d window=24h \
-d interval=1h \
-d pnl_type=overall
{
"trader": "0xabc...",
"window": "24h",
"interval": "1h",
"pnl_type": "overall",
"basis": "net",
"fees_basis": "unavailable_sub_day",
"series_kind": "cumulative_all_time",
"unrealized_marks": "day_grained_carried_forward",
"series": [
{ "ts": 1789084800, "pnl": "18543120.500000" },
{ "ts": 1789088400, "pnl": "18543120.500000" },
{ "ts": 1789092000, "pnl": "18545372.250000" }
]
}
Example: a wallet with no activity in the window
A wallet whose entire trading history predates the requested window still returns a full, gap-free series — a flat line at its historical level, not an empty array:curl -G https://partner-api.bravadotrade.com/trader-analytics/traders/0xdef.../pnl \
-H "X-BRAVADO-API-KEY: $BRAVADO_API_KEY" \
-H "X-BRAVADO-TIMESTAMP: <unix-ms>" \
-H "X-BRAVADO-SIGNATURE: <signature-for-this-request>" \
-d window=30d
{
"trader": "0xdef...",
"window": "30d",
"interval": "1h",
"pnl_type": "overall",
"basis": "net",
"fees_basis": "unavailable_sub_day",
"series_kind": "cumulative_all_time",
"unrealized_marks": "day_grained_carried_forward",
"series": [
{ "ts": 1786492800, "pnl": "22029972.635797" },
{ "ts": 1786496400, "pnl": "22029972.635797" },
{ "ts": 1789084800, "pnl": "22029972.635797" }
]
}
Example: the pre-2026-09-12 numbers via series_kind=window_delta
Same wallet and window as the previous example — with series_kind= window_delta, the flat line is at 0.000000 (delta from window start, its
pre-2026-09-12 meaning) instead of the wallet’s all-time total, and it is
still a full gap-filled series, never []:
curl -G https://partner-api.bravadotrade.com/trader-analytics/traders/0xdef.../pnl \
-H "X-BRAVADO-API-KEY: $BRAVADO_API_KEY" \
-H "X-BRAVADO-TIMESTAMP: <unix-ms>" \
-H "X-BRAVADO-SIGNATURE: <signature-for-this-request>" \
-d window=30d \
-d series_kind=window_delta
{
"trader": "0xdef...",
"window": "30d",
"interval": "1h",
"pnl_type": "overall",
"basis": "net",
"fees_basis": "unavailable_sub_day",
"series_kind": "window_delta",
"unrealized_marks": "day_grained_carried_forward",
"series": [
{ "ts": 1786492800, "pnl": "0.000000" },
{ "ts": 1786496400, "pnl": "0.000000" },
{ "ts": 1789084800, "pnl": "0.000000" }
]
}
Example: a wallet with no history at all
{
"trader": "0x000000000000000000000000000000000000dead",
"window": "30d",
"interval": "1h",
"pnl_type": "overall",
"basis": "net",
"fees_basis": "none",
"series_kind": "cumulative_all_time",
"unrealized_marks": "none",
"empty_reason": "no_wallet_history",
"series": []
}