Positions
View and manage open positions
Get Positions
Retrieve your current positions. By default returns open positions only.
GET /v1/positions
Authorization: Bearer <token>Query Parameters:
| Field | Type | Required | Description |
|---|---|---|---|
status | string | No | OPEN (default) or CLOSED |
Response:
{
"ok": true,
"positions": [
{
"id": "clx...",
"accountId": "clx...",
"venuePositionId": "33600",
"symbol": "BTCUSDT",
"quantity": "0.05",
"avgEntryPrice": "70500.00",
"markPrice": "71034.50",
"liquidationPrice": "51493.41",
"unrealizedPnl": "26.75",
"realizedPnl": "0",
"fundingFee": "-1.23",
"initialMargin": "176.25",
"maintenanceMargin": "14.10",
"leverage": 20,
"marginMode": "Isolated",
"positionSide": "LONG",
"status": "OPEN",
"closeReason": null,
"closedAt": null,
"updatedAt": "2026-04-02T22:35:25.456Z"
}
]
}| Field | Type | Description |
|---|---|---|
id | string | Internal position ID. Use this value when calling /v1/positions/close. |
venuePositionId | string | Exchange-assigned position ID |
quantity | string | Position size. Positive = long, negative = short |
avgEntryPrice | string | Average entry price |
markPrice | string | Current mark price from exchange |
liquidationPrice | string | Estimated liquidation price |
unrealizedPnl | string | Unrealized PnL from exchange |
realizedPnl | string | Realized PnL from exchange |
fundingFee | string | Accumulated funding fees |
initialMargin | string | Initial margin (collateral) for this position |
maintenanceMargin | string | Maintenance margin requirement |
leverage | number | Position leverage multiplier |
marginMode | string | Isolated or Cross |
positionSide | string | BOTH (one-way mode), LONG, or SHORT (hedge mode) |
status | string | OPEN or CLOSED |
closeReason | string|null | Why the position was closed: MANUAL, LIQUIDATED, RECONCILED, or UNKNOWN |
closedAt | string|null | ISO timestamp when position was closed |
Position History
Get closed positions by passing status=CLOSED:
GET /v1/positions?status=CLOSED
Authorization: Bearer <token>Closed positions include a closeReason field:
| Close Reason | Description |
|---|---|
MANUAL | User closed the position manually |
LIQUIDATED | Position was liquidated (mark price crossed liquidation price) |
RECONCILED | Exchange confirmed no open position for this record. The local row was cleaned up by the reconciler or the close endpoint's self-heal path. |
UNKNOWN | Closed during a period when WebSocket was disconnected |
Exchange Position History
Paginated closed-position history sourced directly from the exchange. Unlike /v1/positions?status=CLOSED (which returns the local DB view), this endpoint passes through the exchange's authoritative record and includes per-position realizedPnL, fundingFee, and fee fields that are not maintained locally.
GET /v1/futures/positionHistory
Authorization: Bearer <token>Query Parameters:
| Field | Type | Required | Description |
|---|---|---|---|
symbol | string | No | Filter to a single symbol. If omitted, results from every symbol the account has ever held are merged. |
subAccountId | string | No | Sub-account venue id. Resolved from auth context if omitted. |
page | integer | No | Page number, default 1 |
limit | integer | No | Results per page, default 500, max 1000 |
startTime | integer | No | Filter positions opened on or after this Unix ms |
endTime | integer | No | Filter positions opened on or before this Unix ms |
Response:
{
"ok": true,
"data": [
{
"positionHistoryId": 1001,
"positionId": 500,
"symbol": "BTCUSDT",
"baseAsset": "BTC",
"quoteAsset": "USDT",
"orderSide": 1,
"marginMode": 0,
"entryPrice": 50000.00,
"quoteQuantity": 50.00,
"contractSize": 1.0,
"leverage": 20,
"initialMargin": 2.5,
"maintenanceMargin": 0.5,
"liquidationPrice": 48000.00,
"fundingFee": -0.05,
"fee": 0.12,
"realizedPnL": 5.25,
"markPrice": 50500.00,
"openedAt": "2026-03-01T10:00:00Z",
"averageClosePrice": 50500.00,
"totalClosedQuantity": 0.001,
"closedAt": "2026-03-02T14:30:00Z",
"liquidatedAt": null
}
]
}| Field | Type | Description |
|---|---|---|
positionHistoryId | number | Exchange-assigned id for this history record |
positionId | number | Original exchange position id |
orderSide | number | 1 = Long, 2 = Short |
marginMode | number | 0 = Cross, 1 = Isolated |
entryPrice | number | Average entry price |
quoteQuantity | number | Total quote value |
leverage | number | Leverage used |
fundingFee | number | Total funding paid (negative) or received (positive) over the life of the position |
fee | number | Total trading fees paid |
realizedPnL | number | Realized profit and loss as reported by the exchange |
averageClosePrice | number | Average price across all closing fills |
totalClosedQuantity | number | Total quantity closed |
openedAt / closedAt | string | ISO timestamps (UTC); closedAt is null if liquidated |
liquidatedAt | string|null | Liquidation timestamp, or null if closed normally |
Results are sorted by closedAt descending. When symbol is omitted the server iterates every symbol the account has held and merges the pages returned for each — use the symbol parameter for lower latency.
Close Position
Close a specific position at market price by its id. In hedge mode, every position (LONG and SHORT on the same symbol) has its own id, so you close them independently.
POST /v1/positions/close
Authorization: Bearer <token>
Content-Type: application/json
{
"positionId": "clx..."
}Parameters:
| Field | Type | Required | Description |
|---|---|---|---|
positionId | string | Yes | The id field from GET /v1/positions. |
quantity | string | No | Amount to close. Omit for full close. |
No accountId, subAccountId, symbol, or positionSide needs to be sent — the server resolves everything from the authenticated positionId. The reduce-only market order is placed in the opposite direction of the position automatically.
Response — successful close:
{
"ok": true,
"closed": {
"symbol": "BTCUSDT",
"side": "SELL",
"quantity": "0.05",
"remainingPosition": "0"
},
"venue": { "orderId": 987654321 }
}Response — already closed on the exchange (self-heal):
If the exchange reports no open position for this record (error -2010), the server marks the row as CLOSED with closeReason: "RECONCILED" and returns success so the UI can clear it without the user retrying.
{
"ok": true,
"closed": {
"symbol": "BTCUSDT",
"reconciled": true,
"note": "Position was already closed on exchange"
}
}Response fields:
| Field | Type | Description |
|---|---|---|
closed.symbol | string | Trading pair of the closed position |
closed.side | string | Direction of the close order: BUY or SELL |
closed.quantity | string | Amount actually closed |
closed.remainingPosition | string | Remaining quantity after this close (partial close). "0" on full close. |
closed.reconciled | boolean | true only when the position was already closed on the exchange and the DB row was cleaned up without sending a new order |
venue | object | Raw order response from the exchange (omitted on reconciled closes) |
Risk Exposure
Get aggregated risk metrics across all open positions:
GET /v1/risk/exposure
Authorization: Bearer <token>{
"ok": true,
"grossExposure": "3525.00",
"positions": [...]
}