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

# spot.positions

> A wallet's whole position in a token, each time a trade or transfer changes it.

Subscribe on an open stream connection. See [Connecting to streams](/streams/overview) for the connection, frames and reconnecting.

## Filters

<ParamField body="chain" type="string" required>
  The [chain slug](/concepts/chains) the positions are on.
</ParamField>

<ParamField body="wallets" type="string[]" required>
  One or more wallet addresses on `chain`. For one wallet, you can send `wallet` with a single address instead. Each wallet spends one unit of the [address budget](/streams/filters#the-address-budget).
</ParamField>

## Update

Each update's `data` is a wallet's whole position in one token after a change, in the row shape [Positions](/reference/rest/positions) returns. Keep one row per `chain`, `walletAddress` and token, and keep the row with the highest `version`.

A streamed position carries no price. `value`, `unrealizedPnl`, `totalPnl` and `pnlPct` are `null`, and so is every `token` field except `chain` and `address`. To price a row, follow its token on [`spot.tokens`](/reference/streams/spot-tokens) and use the formulas the REST read uses:

* `value` is `holdings` times the token's price.
* `unrealizedPnl` is `value` minus `holdings` times `avgCost`.
* `totalPnl` is `realizedPnl` plus `unrealizedPnl`.
* `pnlPct` is `totalPnl.usd` divided by `invested.usd`, times 100. It stays `null` when `invested.usd` is zero.

## Snapshot, then stream

1. Subscribe.
2. Read every page of [Positions](/reference/rest/positions) with the same wallets, `chains` set to the subscription's chain, and `hideLowLiquidity=false`. The stream filters nothing out, so the read must not either. The read returns open positions only; read `lifecycle=closed` as well if you keep closed rows.
3. Merge the read and the updates on `version`.

Read again after every reconnect.

## Errors

| Code | When |
| - | - |
| `VALIDATION_ERROR` | `chain` missing; no wallet; an address in the wrong format for the chain; an unknown filter field; the [address budget](/streams/filters#the-address-budget) is spent |
| `UNSUPPORTED_CHAIN` | `chain` is not a supported slug |

<RequestExample>
  ```json Subscribe theme={null}
  {
    "action": "subscribe",
    "channel": "spot.positions",
    "filters": {
      "chain": "solana",
      "wallets": ["7YttLkHDoNj9wyDur5pM1ejNaAvT9X4eqaYcHQqtj2G5"]
    }
  }
  ```
</RequestExample>


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