Skip to main content
Room ID: polymarket_trader_pnl
Endpoint: wss://api.struct.to/ws
Rate: 0.1 credits per message
Stream profit and loss for tracked traders. PnL is computed at three grains and maintained over four rolling windows, so you can drive a full portfolio view from a single subscription. The three grains are global (the whole portfolio), market (per condition), and category (per market category). Each grain is tracked over four windows: 1d, 7d, 30d, and lifetime.
Related guide: Live trader PnL dashboard builds a complete realized PnL view from this room.

Event families

Each grain emits three families of events. A given dirty row goes to exactly one family per block, so the families are disjoint. Updates are batched per block. Each envelope is shaped { type, room_id, block, [timeframe,] data: [ ...rows ] }, with one envelope per grain, family, and (for full-row batches) timeframe per block. Empty batches are not sent. Every row carries a dirty_kinds array naming what triggered it. Tick and resolution rows are window-agnostic and carry boundary snapshots, so any per-window delta is recoverable client-side without waiting for a full-row batch.

dirty_kinds

Subscribe

The traders filter is required. The remaining filters are optional and narrow the stream.

Filters

An unknown value in update_types, timeframes, or dirty_kinds rejects the whole subscription with an error.

Example

Response

The subscribe response (trader_pnl_stream_subscribe_response) echoes the resolved configuration.

Events

trader_global_pnl_batch

Full-row PnL across the whole portfolio. Carries a top-level timeframe.

trader_market_pnl_batch

Full-row PnL for a single market (condition). Carries a top-level timeframe.

trader_category_pnl_batch

Full-row PnL for a market category. Carries a top-level timeframe.

Price tick batches

trader_global_tick_batch, trader_market_tick_batch, and trader_category_tick_batch carry mark-to-market refreshes. They are window-agnostic and their dirty_kinds is always ["price"].

Resolution batches

trader_global_resolution_batch, trader_market_resolution_batch, and trader_category_resolution_batch fire when an owning market resolves without a trade. They are window-agnostic and their dirty_kinds is always ["market_resolved"].
Last modified on July 13, 2026