Real-time position updates with initial snapshot.
Channel: positions
Authentication: Required
Subscribe
{
"method": "subscribe",
"params": {
"channel": "positions",
"market_ids": [1, 2],
"makers": ["0x1234567890123456789012345678901234567890"]
}
}| Parameter | Type | Required | Description |
|---|---|---|---|
market_ids | number[] | No | Filter by market IDs. Empty = all markets |
makers | string[] | No | Filter by account addresses. Empty = authenticated account only |
Message Format
Snapshot
Sent immediately after subscribing. Contains all positions matching your filters.
{
"method": "snapshot",
"channel": "positions",
"type": "snapshot",
"data": [
{
"@type": "type.googleapis.com/boom.v1.api.BuilderPosition",
"account": "0x1234567890123456789012345678901234567890",
"market_id": "1",
"size": "1000000000000000000",
"quote_amount": "50000000000000000000000",
"margin_mode": "CROSS",
"side": "BUY",
"isolated_usdc_balance": "0",
"last_funding_payment": "0",
"leverage": "5000000000000000000",
"avg_entry_price": "50000000000000000000000",
"block_number": "12345678",
"log_index": "0",
"block_timestamp": "1703123456000000000"
}
],
"position_count": 1,
"timestamp": "1703123456123456789"
}Update
Sent when a position changes (opened, modified, or closed).
{
"channel": "positions",
"type": "update",
"market_id": "1",
"data": [
{
"@type": "type.googleapis.com/boom.v1.api.BuilderPosition",
"account": "0x1234567890123456789012345678901234567890",
"market_id": "1",
"size": "1500000000000000000",
"quote_amount": "75000000000000000000000",
"margin_mode": "CROSS",
"side": "BUY",
"isolated_usdc_balance": "0",
"last_funding_payment": "-50000000000000000",
"leverage": "5000000000000000000",
"avg_entry_price": "50000000000000000000000",
"block_number": "12345679",
"log_index": "1",
"block_timestamp": "1703123457000000000"
}
],
"block_number": 12345679,
"log_index": 1,
"tx_hash": "0xabc123...",
"block_timestamp": "1703123457000000000",
"timestamp": "1703123457123456789"
}Snapshot Message Fields
| Field | Type | Description |
|---|---|---|
method | string | Always "snapshot" |
channel | string | Always "positions" |
type | string | Always "snapshot" |
data | array | Array of Position objects |
position_count | number | Total number of positions |
timestamp | string | Server timestamp (nanoseconds) |
Update Message Fields
| Field | Type | Description |
|---|---|---|
channel | string | Always "positions" |
type | string | Always "update" |
market_id | string | Market ID |
data | array | Array of Position objects |
block_number | number | Blockchain block number |
log_index | number | Log index within the block |
tx_hash | string | Transaction hash (optional) |
block_timestamp | string | Blockchain timestamp (nanoseconds) |
timestamp | string | Server timestamp (nanoseconds) |
Position Object Fields
| Field | Type | Description |
|---|---|---|
@type | string | Protobuf message type |
account | string | Position owner address |
market_id | string | Market ID |
size | string | Position size (wei, 18 decimals). "0" = closed |
quote_amount | string | Quote amount (wei, 18 decimals). Represents cost basis |
margin_mode | string | CROSS or ISOLATED |
side | string | BUY (long) or SELL (short) |
isolated_usdc_balance | string | USDC balance for isolated margin (wei, 18 decimals) |
last_funding_payment | string | Last funding payment amount (wei, 18 decimals). Can be negative |
leverage | string | Position leverage (wei, 18 decimals). e.g., "5000000000000000000" = 5x |
avg_entry_price | string | Weighted average entry price (wei, 18 decimals) |
block_number | string | Block number of last update |
log_index | string | Log index within the block |
block_timestamp | string | Block timestamp (nanoseconds) |
Margin Modes
| Mode | Description |
|---|---|
CROSS | Cross margin - shares margin across all positions |
ISOLATED | Isolated margin - separate margin per position |
Position Closed
When a position is closed, size becomes "0":
{
"channel": "positions",
"type": "update",
"market_id": "1",
"data": [
{
"@type": "type.googleapis.com/boom.v1.api.BuilderPosition",
"account": "0x1234567890123456789012345678901234567890",
"market_id": "1",
"size": "0",
"quote_amount": "0",
"margin_mode": "CROSS",
"side": "BUY",
"isolated_usdc_balance": "0",
"last_funding_payment": "0",
"leverage": "0",
"avg_entry_price": "0",
"block_number": "12345680",
"log_index": "2",
"block_timestamp": "1703123458000000000"
}
],
"block_number": 12345680,
"log_index": 2,
"tx_hash": "0xdef456...",
"block_timestamp": "1703123458000000000",
"timestamp": "1703123458123456789"
}Calculating PnL
For long positions (side = BUY):
unrealizedPnL = (size * markPrice / 10^18) - quoteAmount
For short positions (side = SELL):
unrealizedPnL = quoteAmount - (size * markPrice / 10^18)
Examples
Subscribe to all your positions
{
"method": "subscribe",
"params": {
"channel": "positions"
}
}Subscribe to specific markets
{
"method": "subscribe",
"params": {
"channel": "positions",
"market_ids": [1, 2]
}
}Subscribe to specific accounts
{
"method": "subscribe",
"params": {
"channel": "positions",
"market_ids": [1],
"makers": ["0x1234567890123456789012345678901234567890"]
}
}Unsubscribe
{
"method": "unsubscribe",
"params": {
"channel": "positions"
}
}