> ## Documentation Index
> Fetch the complete documentation index at: https://docs.struct.to/llms.txt
> Use this file to discover all available pages before exploring further.

# Trader Exit Markers

> Stream one marker per position close for tracked traders.

<Note>
  **Room ID:** `polymarket_trader_pnl_exits` \
  **Endpoint:** `wss://api.struct.to/ws` \
  **Rate:** 0.025 credits per message
</Note>

Stream one marker per position close for tracked traders, batched per block. Each marker captures the realized PnL and the reason a position closed, so you can overlay exits directly onto a PnL chart.

<Tip>
  **Related guide:** [PnL chart with exit markers](/guides/pnl-chart-with-exit-markers) plots realized PnL and annotates each close with its exit reason.
</Tip>

## Exit reasons

| Reason | Meaning |
| - | - |
| `resolved_win` | Held to market resolution and won by verdict |
| `resolved_loss` | Held to market resolution and lost by verdict |
| `sold_win` | Closed before resolution with positive realized PnL |
| `sold_loss` | Closed before resolution with negative realized PnL |

## Subscribe

The `traders` filter is required.

### Filters

| Filter | Type | Required | Description |
| - | - | - | - |
| `traders` | `string[]` | Yes | EVM wallet addresses (0x-prefixed), non-empty |
| `reasons` | `string[]` | No | Subset of `["resolved_win","resolved_loss","sold_win","sold_loss"]`, or `["all"]` |
| `subscribe_all` | `boolean` | No | Firehose: receive exits for every trader. The `traders` filter is ignored when set; `reasons` still applies |

### Example

```json theme={null}
{
  "type": "join_room",
  "payload": {
    "room_id": "polymarket_trader_pnl_exits"
  }
}
```

```json theme={null}
{
  "type": "room_message",
  "payload": {
    "room_id": "polymarket_trader_pnl_exits",
    "message": {
      "action": "subscribe",
      "traders": ["0x1234567890abcdef1234567890abcdef12345678"]
    }
  }
}
```

### Response

```json theme={null}
{
  "type": "trader_exit_markers_stream_subscribe_response",
  "room_id": "polymarket_trader_pnl_exits",
  "data": {
    "traders": ["0x1234567890abcdef1234567890abcdef12345678"],
    "rejected": [],
    "error": null
  }
}
```

## Events

### `trader_exit_marker_batch`

One marker per position close.

```json theme={null}
{
  "type": "trader_exit_marker_batch",
  "room_id": "polymarket_trader_pnl_exits",
  "block": 68420001,
  "data": [
    {
      "trader": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
      "position_id": "12345678901234567",
      "condition_id": "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
      "event_slug": "bitcoin-price-markets",
      "market_slug": "will-bitcoin-hit-100k",
      "title": "Will Bitcoin hit $100k?",
      "question": "Will Bitcoin hit $100k by end of year?",
      "image_url": "https://polymarket.com/images/market.png",
      "outcome": "Yes",
      "outcome_index": 0,
      "pnl_usd": 350.25,
      "pnl_pct": 35.9,
      "cost_basis_usd": 975.0,
      "reason": "sold_win",
      "block": 68420001,
      "ts": 1743500000
    }
  ]
}
```

| Field | Type | Description |
| - | - | - |
| `trader` | `string` | Wallet address |
| `position_id` | `string` | ERC-1155 token ID (decimal string) |
| `condition_id` | `string` | Condition ID |
| `event_slug` | `string` | Owning event slug |
| `market_slug` | `string` | Market slug |
| `title` | `string` | Market title |
| `question` | `string` | Market question |
| `image_url` | `string` | Market image URL |
| `outcome` | `string` | Outcome label (for example `Yes`) |
| `outcome_index` | `int \| null` | Outcome index |
| `pnl_usd` | `number` | Realized PnL at exit, in USD |
| `pnl_pct` | `number` | Realized PnL as a percentage |
| `cost_basis_usd` | `number` | Cost basis of the closed position, in USD |
| `reason` | `string` | Exit reason (see taxonomy above) |
| `block` | `int64` | Block of the exit |
| `ts` | `int64` | Exit timestamp (Unix seconds) |


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.