Get a trader's realized-PnL time series
Returns a time-series of realized PnL data points for charting a trader’s PnL progression over the requested window, bucketed by time_range. The wallet address is validated as either an Ethereum (0x…) address (Polymarket/Opinion/predictfun) or a Solana base58 address (Kalshi) and normalized (lower-cased for EVM) before lookup; if it matches neither format the request is rejected with 400. provider is optional — if omitted, the provider is auto-detected from the address format; pass it explicitly to disambiguate EVM venues other than Polymarket. Provider values are validated against the live set of active providers rather than a fixed enum, so an inactive/unknown id is rejected with 400. Responses are cacheable at the edge and briefly cached server-side. Public endpoint — no authentication required. Rate-limited per client IP (X-Forwarded-For, falling back to the socket peer) at 30 requests/minute, independent of the global 100/minute default.
curl --request GET \
--url https://data.kairos.trade/trader-stats/pnl-history/{wallet_address}import requests
url = "https://data.kairos.trade/trader-stats/pnl-history/{wallet_address}"
response = requests.get(url)
print(response.text)const options = {method: 'GET'};
fetch('https://data.kairos.trade/trader-stats/pnl-history/{wallet_address}', 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://data.kairos.trade/trader-stats/pnl-history/{wallet_address}",
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://data.kairos.trade/trader-stats/pnl-history/{wallet_address}"
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://data.kairos.trade/trader-stats/pnl-history/{wallet_address}")
.asString();require 'uri'
require 'net/http'
url = URI("https://data.kairos.trade/trader-stats/pnl-history/{wallet_address}")
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{
"wallet_address": "0x1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b",
"time_range": "1W",
"data_points": [
{
"timestamp": "2026-07-15T00:00:00Z",
"realized_pnl": "1250.4382"
}
],
"start_pnl": "800.00",
"end_pnl": "1250.4382",
"pnl_change": "450.4382",
"current_realized_pnl": "1250.4382",
"pnl_change_percent": "56.30",
"current_total_pnl": "1875.10"
}{
"detail": [
{}
]
}{
"error": "Rate limit exceeded: 100 per 1 minute"
}Path Parameters
Ethereum (0x-prefixed, 42 chars) or Solana (base58) wallet address. Normalized (EVM lower-cased) before use. Returns 400 if it matches neither format.
Query Parameters
Time window for the PnL series.
1D, 1W, 1M, ALL Provider override (e.g. polymarket, kalshi, opinion, predictfun). Validated against the live active-provider registry. Auto-detected from address format when omitted.
Response
PnL time series for the wallet and time range.
Time-series realized-PnL data for a wallet over a requested time range, plus a summary of the change over that range.
"0x1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b"
1D, 1W, 1M, ALL "1W"
Show child attributes
Show child attributes
Realized PnL at the start of the window.
"800.00"
Realized PnL at the end of the window.
"1250.4382"
Absolute change in realized PnL over the window (end_pnl - start_pnl).
"450.4382"
Wallet's current total realized PnL (as of now, not bounded to the window).
"1250.4382"
Percentage change over the window; null if start_pnl is zero/undefined.
"56.30"
Current realized + unrealized PnL combined, when available.
"1875.10"
Was this page helpful?
curl --request GET \
--url https://data.kairos.trade/trader-stats/pnl-history/{wallet_address}import requests
url = "https://data.kairos.trade/trader-stats/pnl-history/{wallet_address}"
response = requests.get(url)
print(response.text)const options = {method: 'GET'};
fetch('https://data.kairos.trade/trader-stats/pnl-history/{wallet_address}', 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://data.kairos.trade/trader-stats/pnl-history/{wallet_address}",
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://data.kairos.trade/trader-stats/pnl-history/{wallet_address}"
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://data.kairos.trade/trader-stats/pnl-history/{wallet_address}")
.asString();require 'uri'
require 'net/http'
url = URI("https://data.kairos.trade/trader-stats/pnl-history/{wallet_address}")
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{
"wallet_address": "0x1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b",
"time_range": "1W",
"data_points": [
{
"timestamp": "2026-07-15T00:00:00Z",
"realized_pnl": "1250.4382"
}
],
"start_pnl": "800.00",
"end_pnl": "1250.4382",
"pnl_change": "450.4382",
"current_realized_pnl": "1250.4382",
"pnl_change_percent": "56.30",
"current_total_pnl": "1875.10"
}{
"detail": [
{}
]
}{
"error": "Rate limit exceeded: 100 per 1 minute"
}
