# Positions Channel


Source: https://docs.stxapp.io/websockets/channels/positions/

Topic: `positions:{user_id}`

Delivers your positions as they change. Money arrives as dollar strings and
contract counts as quantity strings; see
[Wire format](/websockets/channels/wire-format/).

:::tip[Need a one-off read? Use REST]
[`GET /api/v1/positions`](/api/rest/account/list-open-positions/) returns the same list
this channel sends as `all_positions` on join, with the same fields in the same
order, and takes the same optional `market_ids` filter as a comma-separated query
parameter. It is a snapshot of the moment you asked. This channel is the live
feed: take the REST snapshot to seed or reconcile your state, then apply
`updated_positions` deltas from here.
:::

## Position object

### Identity

- `id` : The unique id of the position record.
- `account_id` : The id of the account the position belongs to.
- `market_id` : The id of the market the position is on.
- `event_id` : The id of the event the market is attached to.

### Exposure

- `position` : The account's net position in the market: positive if long
  (bought), negative if short (sold). A quantity string.
- `premium` : The total premium paid or received for the **open** portion of the
  position.
- `average_open_premium` : The average premium per contract for the open portion.
- `buy_order_liability` : The liability from the account's open buy orders on this
  market.
- `sell_order_liability` : The liability from the account's open sell orders on this
  market.
- `position_premium_liability` : The liability from the position's premium that
  counts against available balance. Routinely negative.

### Risk and potential

- `max_risk` : The account-level risk on the position, netting in already settled
  profit and loss.
- `open_risk` : The risk on the position's currently open (unsettled) contracts;
  this is what's shown as "Risk" in the app.
- `max_potential_profit` : The total possible profit for the position if everything
  settles favorably.
- `open_potential_profit` : The possible profit on the position's open contracts.
- `max_potential_fee` : The total potential fee across the position's settlements.
- `open_potential_fee` : The potential fee on the position's open contracts when
  they settle.

### Realized

- `total_settlement_pnl` : The profit or loss the account has realized from
  settlements so far.
- `gross_pnl` : `total_settlement_pnl` plus any pending-close profit or loss that
  hasn't settled yet.
- `total_fee` : The total fees paid across the position's settlements.
- `contracts_settled` : The number of contracts settled in the position so far. A
  quantity string.

## Use Cases

| Use case | Message to send |
| --- | --- |
| Join and receive your open positions | `["3","3","positions:<user_id>","phx_join",{}]` |
| Join filtered to one market (see [filtering](/websockets/channels/wire-format/#filtering)) | `["3","3","positions:<user_id>","phx_join",{"market_ids":["<uuid>"]}]` |
| Change the market filter without rejoining | `["3","4","positions:<user_id>","select_market_ids",{"market_ids":null}]` |
| Check the connection is alive | `["3","5","positions:<user_id>","ping",{}]` |

### Joining

```json
["3","3","positions:<user_id>","phx_join",{}]
```

```json
{"status":"ok","response":{"selected_market_ids":null}}
```

### Initial response after joining

```json
[null, null, "positions:a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d", "all_positions", { "positions": [Position]}]
```

`positions` is a list of `Position` objects, described above, ordered by `position`
descending, empty if you have none open, and also empty when a `market_ids` filter
matches nothing.

```json
[
  null,
  null,
  "positions:a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
  "all_positions",
  {
    "positions": [
      {
        "id": "0e1f2a3b-4c5d-46a9-9d3a-7dc6671e2852",
        "account_id": "c1c3614c-32ae-4bea-bae4-fc3f52047790",
        "market_id": "687e9cdb-a391-4118-aa80-1122bb14779f",
        "event_id": "86c9d896-62ab-4c59-8f1c-4cc7850c19c3",
        "position": "-70.00",
        "premium": "49.0000",
        "average_open_premium": "0.7000",
        "buy_order_liability": "0.0000",
        "sell_order_liability": "0.0000",
        "position_premium_liability": "-49.0000",
        "max_risk": "21.0000",
        "open_risk": "21.0000",
        "max_potential_profit": "49.0000",
        "open_potential_profit": "49.0000",
        "max_potential_fee": "2.4500",
        "open_potential_fee": "2.4500",
        "total_settlement_pnl": "0.0000",
        "gross_pnl": "0.0000",
        "total_fee": "0.0000",
        "contracts_settled": "0.00"
      }
    ]
  }
]
```

### Pushed when the account's positions change

```json
[null, null, "positions:a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d", "updated_positions", { "positions": [Position]}]
```

This event is a **delta**: it carries only the positions that changed, not your
whole book. When a `market_ids` filter is active and none of the changed positions
match it, no frame is sent at all rather than one carrying an empty list.

```json
[
  null,
  null,
  "positions:a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
  "updated_positions",
  {
    "positions": [
      {
        "id": "0e1f2a3b-4c5d-46a9-9d3a-7dc6671e2852",
        "account_id": "c1c3614c-32ae-4bea-bae4-fc3f52047790",
        "market_id": "687e9cdb-a391-4118-aa80-1122bb14779f",
        "event_id": "86c9d896-62ab-4c59-8f1c-4cc7850c19c3",
        "position": "-50.00",
        "premium": "35.0000",
        "average_open_premium": "0.7000",
        "buy_order_liability": "0.0000",
        "sell_order_liability": "0.0000",
        "position_premium_liability": "-35.0000",
        "max_risk": "14.0000",
        "open_risk": "15.0000",
        "max_potential_profit": "36.0000",
        "open_potential_profit": "35.0000",
        "max_potential_fee": "1.8000",
        "open_potential_fee": "1.7500",
        "total_settlement_pnl": "1.0000",
        "gross_pnl": "1.0000",
        "total_fee": "0.0500",
        "contracts_settled": "20.00"
      }
    ]
  }
]
```

:::caution[Positions are not marked to market for you]
This channel fires on your own activity and on settlements, not on price moves.
Valuing an open position against the current book is your job, from
[`orderbook`](/websockets/channels/market-data/#orderbook).
:::
