Skip to main content
GET
/
v2
/
trader
/
{wallet}
/
equity
Equity Curve
curl --request GET \
  --url https://api.polynode.dev/v2/trader/{wallet}/equity \
  --header 'x-api-key: <api-key>'
{
  "wallet": "0xb4ab48b451101a779bf8c644318bb17fe652571d",
  "period": "all",
  "source": "onchain",
  "positions_count": 564,
  "markets_count": 296,
  "open_count": 30,
  "applied_filters": {
    "fromTs": null,
    "toTs": null,
    "maxMarkets": null,
    "includeUnrealized": false
  },
  "partial": false,
  "raw": {
    "points": 500,
    "final_pnl": -857.48,
    "curve": [
      {
        "t": 1774555427,
        "pnl": 10.56
      },
      {
        "t": 1774555427,
        "pnl": -14.44
      },
      {
        "t": 1774555441,
        "pnl": -6.62
      }
    ]
  },
  "normalized": {
    "bet_size": 1,
    "positions": 564,
    "points": 500,
    "final_pnl": -18.4366,
    "curve": [
      {
        "t": 1774555427,
        "pnl": 0.1234
      },
      {
        "t": 1774555427,
        "pnl": -0.0466
      },
      {
        "t": 1774555441,
        "pnl": 0.5934
      }
    ]
  }
}

Documentation Index

Fetch the complete documentation index at: https://docs.polynode.dev/llms.txt

Use this file to discover all available pages before exploring further.

Returns a time-ordered equity curve showing cumulative profit and loss across every position a wallet has ever taken on Polymarket. By default, the curve is built from realized P&L only — the locked-in result from every closed position, every partial sell, every market resolution, every redemption. This makes the curve fully deterministic: the same query returns the same numbers regardless of when you call it. It’s also fast, typically returning in under a second. When normalize=1 is set, the response also includes a $1-normalized equity curve. Each position is scaled so its entry cost equals exactly $1, then summed. This shows what your returns would look like if you copied every trade with $1 of risk per position — the standard format for evaluating a wallet’s edge across thousands of trades.

Simple example

curl "https://api.polynode.dev/v2/trader/0xb4ab48b451101a779bf8c644318bb17fe652571d/equity?period=all&normalize=1" \
  -H "Authorization: Bearer YOUR_API_KEY"
Response (truncated for clarity — curve arrays contain up to 500 points each):
{
  "wallet": "0xb4ab48b451101a779bf8c644318bb17fe652571d",
  "period": "all",
  "source": "onchain",
  "positions_count": 564,
  "markets_count": 296,
  "open_count": 30,
  "applied_filters": {
    "fromTs": null,
    "toTs": null,
    "maxMarkets": null,
    "includeUnrealized": false
  },
  "partial": false,
  "raw": {
    "points": 500,
    "final_pnl": -857.48,
    "curve": [
      { "t": 1774555427, "pnl": 10.56 },
      { "t": 1774555427, "pnl": -14.44 },
      { "t": 1774555441, "pnl": -6.62 }
    ]
  },
  "normalized": {
    "bet_size": 1,
    "positions": 564,
    "points": 500,
    "final_pnl": -18.4366,
    "curve": [
      { "t": 1774555427, "pnl": 0.1234 },
      { "t": 1774555427, "pnl": -0.0466 },
      { "t": 1774555441, "pnl": 0.5934 }
    ]
  }
}

Query parameters

wallet
string
required
Polymarket wallet address.
period
string
default:"30d"
Time window. Positions whose first activity falls before the start of the window are excluded. One of: 7d, 30d, 90d, 1y, all.
normalize
string
default:"0"
Set to 1 to include the $1-normalized equity curve alongside the raw curve.
from
string
Start date. Accepts YYYY-MM-DD (treated as UTC midnight) or a unix timestamp in seconds. Drops positions whose first activity is before this date.
to
string
End date. Same format as from. Drops positions whose first activity is after this date.
max_markets
integer
Keep only the most recent N markets the wallet has touched. A “market” is a unique outcome group; binary markets count as one. Useful for quickly evaluating a wallet’s recent performance without scanning their full history.
include_unrealized
string
default:"0"
Set to 1 to mark currently-open positions to current market price and include the unrealized P&L in the curve. Off by default. See Realized vs unrealized below before turning this on.

Realized vs unrealized

The default response is realized-only. Every closed position contributes its locked-in P&L. Open positions contribute whatever they’ve already realized through partial sells (often zero if the wallet hasn’t sold any shares of that position yet). This is the right default for backtesting and for evaluating a wallet’s edge over time. It’s deterministic — the same query returns the same numbers regardless of when you call it — and it returns in under a second even for whales. If you want a current-portfolio snapshot that marks open positions to the latest market price, pass include_unrealized=1. The curve’s final point will reflect what the wallet would have if it closed all open positions right now. Tradeoffs:
  • Slower. Open positions need a current price each, fetched live.
  • Non-deterministic. Two queries five minutes apart return slightly different numbers as prices move.
  • Worth it when you specifically want a “what’s my position worth right now” view rather than a backtest signal.
# Realized-only (default, fast, deterministic)
curl ".../equity?period=all&normalize=1"

# Mark-to-market (slower, current-snapshot)
curl ".../equity?period=all&normalize=1&include_unrealized=1"

Filtering examples

Last 30 days:
curl ".../equity?period=30d&normalize=1"
Specific date range — backtest the wallet’s behavior in early April 2026:
curl ".../equity?from=2026-04-01&to=2026-04-15&normalize=1"
Recent 50 markets only — fast scan of the wallet’s most recent activity:
curl ".../equity?period=all&max_markets=50&normalize=1"
Composed filters — fast realized-only curve over the last 100 markets in a specific window:
curl ".../equity?from=2026-04-01&max_markets=100"

Response fields

FieldTypeDescription
walletstringThe lowercased wallet address.
periodstringThe period filter that was applied (7d, 30d, 90d, 1y, or all).
sourcestringAlways "onchain".
positions_countintegerTotal positions included in the curve after all filters.
markets_countintegerDistinct markets (unique outcome groups). For binary markets, two positions (Yes + No) on the same market count as one market.
open_countintegerPositions that still hold a non-zero balance.
applied_filtersobjectEchoes back exactly which filters were applied — useful for debugging.
partialbooleantrue if the request hit the 10-second server-side timeout. The response will still contain whatever was computed; the error field will be set.
raw.pointsintegerNumber of points in the raw curve (downsampled to a max of 500).
raw.final_pnlnumberFinal cumulative P&L across the included positions, in USD.
raw.curve[].tintegerUnix timestamp (seconds) when the position was first opened.
raw.curve[].pnlnumberCumulative P&L at that point, in USD.
normalized.bet_sizenumberAlways 1. Each position is scaled to $1 of risk.
normalized.positionsintegerTotal positions in the normalized curve.
normalized.pointsintegerNumber of points (downsampled to a max of 500).
normalized.final_pnlnumberFinal cumulative $1-normalized P&L.
normalized.curve[].pnlnumberCumulative $1-normalized P&L at that point.

Performance

Query shapeTypical first-hit latencyCached
Default (any wallet)50ms – 2s<50ms
include_unrealized=1, large open-position count1s – 8s<50ms
Composed filters (from + max_markets)<1s<50ms
Responses are cached for 5 minutes per unique parameter combination. The cache key separates every filter, so two callers using different filters won’t collide.

Rate limit

This endpoint is rate-limited at 1 request per 10 seconds per API key. It’s a heavy endpoint — caching results client-side is recommended.

$1 normalization math

For every position in the included set:
  1. Take the position’s P&L (realized only by default; realized + unrealized when opted in).
  2. Divide by total_bought for that position. total_bought is the total number of shares ever acquired across every acquisition method.
  3. Add the result to the running normalized cumulative.
If a wallet put $500 into a market and made $50 realized, the normalized contribution is $50 / $500 = $0.10. For every dollar risked on that market, they made 10 cents. Sum across all positions and you get the normalized final P&L. A wallet with 2,000 positions and a normalized final P&L of +12.0 means each $1 risked returned about $0.006 on average. Across thousands of positions, that indicates a real and consistent edge.

Notes on coverage

  • NegRisk-split positions. When a wallet acquires tokens via a USDC split into a Yes/No pair (rather than a CLOB trade), there is no on-chain trade event for that token. We use sibling-token timestamps and redemption timestamps as fallbacks where available, but in rare cases a split-derived position with no sibling activity and no redemption record can fall back to “now” on the curve. This affects shape, not totals — final_pnl remains correct.
  • Curve downsampling. Both the raw and normalized curves are downsampled to a maximum of 500 points. The first and last points are always preserved.

Authorizations

x-api-key
string
header
required

Path Parameters

wallet
string
required

Polymarket wallet address

Query Parameters

period
enum<string>
default:30d

Time window. Positions whose first activity falls before the start of the window are excluded.

Available options:
7d,
30d,
90d,
1y,
all
normalize
enum<string>
default:0

Set to 1 to include the $1-normalized equity curve alongside the raw curve.

Available options:
0,
1
from
string

Start date. YYYY-MM-DD (treated as UTC midnight) or unix seconds.

to
string

End date. Same format as from.

max_markets
integer

Keep only the most recent N markets the wallet has touched.

Required range: x >= 1
include_unrealized
enum<string>
default:0

Set to 1 to mark open positions to current market price and include unrealized P&L. Off by default. Slower and non-deterministic.

Available options:
0,
1

Response

Equity curve

The response is of type object.