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

# Market Positions

> Your position in a market, after it changes.

A `prediction-position` message is sent when your position in a market changes.
It reports the **current state** of that position, not a delta.

## Access

Requires an API key with the `read` scope. Send an
[`authenticate`](/websockets/connection) frame; there is no separate subscribe
for the private stream.

## Fields

| Field | Type | Description |
| - | - | - |
| `type` | string | Always `"prediction-position"` |
| `eventMarketId` | string | UUID of the market |
| `outcome` | string | `"yes"` or `"no"` — which side this position is in |
| `qty` | number | Shares currently held |
| `avgEntryPrice` | number? | Average entry price in cents |
| `costBasis` | number? | `qty` × `avgEntryPrice`, in cents |
| `realizedPnl` | number? | Realized profit or loss, in cents |
| `ts` | number | Unix timestamp in **nanoseconds** |

<Note>
  Positions are keyed by **market and outcome together**. A market in which you
  hold both YES and NO reports two separate positions. Key your local state on
  the `(eventMarketId, outcome)` pair, not on `eventMarketId` alone, or the
  second message will overwrite the first.
</Note>

## Example

```json theme={null}
{
  "type": "prediction-market-update",
  "data": {
    "type": "prediction-position",
    "eventMarketId": "9f1c2d3e-4a5b-6c7d-8e9f-0a1b2c3d4e5f",
    "outcome": "yes",
    "qty": 140,
    "avgEntryPrice": 61,
    "costBasis": 8540,
    "realizedPnl": -320,
    "ts": 1789238400123456789
  }
}
```

## Notes

* **Snapshot, not delta.** `qty` is the position after the change, so replace
  your stored value rather than adding to it.
* `realizedPnl` covers closed quantity only. Unrealized P\&L is yours to compute,
  from `avgEntryPrice` against a current quote from
  [Market Ticker](/websockets/market-ticker).
* `costBasis` is derived as `qty` × `avgEntryPrice` at publish time, not a
  running sum of what you historically paid.
* `realizedPnl` is in cents and can be negative.
* A position that goes to zero is reported with `qty: 0` rather than being
  omitted, so you can clear it from your local state.
* Positions are published as the engine settles matches, so a single order
  crossing several resting orders may produce one position update rather than
  one per fill. Do not expect a 1:1 correspondence with
  [fills](/websockets/user-fills).


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