Get Trades For Position (WebSocket)
Retrieve trade execution history (fills) for a specific position within a subaccount through the WebSocket connection. Unlike getTrades, which returns all trades for a subaccount, this endpoint filters trades to those associated with a single position identified by positionId.
Request-Response vs Subscriptions
This method provides on-demand snapshots of trades for a specific position. For real-time updates when new trades execute, use SubAccount Updates Subscription.
| Method | Purpose | When to Use |
|---|---|---|
getTradesForPosition | Position-specific trade history | Analyzing fills for a single position |
getTrades | All trades for a subaccount | Broad trade history, reconciliation |
| Trade Updates Subscription | Real-time notifications | Live UI updates, trade event handling |
Endpoint
ws.send() wss://api.synthetix.io/v1/ws/tradeRequest
Request Format
{
"id": "trades-pos-1",
"method": "post",
"params": {
"action": "getTradesForPosition",
"subAccountId": "1867542890123456789",
"positionId": "42",
"limit": 100,
"offset": 0,
"expiresAfter": 1704067500,
"signature": {
"v": 28,
"r": "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
"s": "0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890"
}
}
}Parameters
Request Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Client-generated unique request identifier |
method | string | Yes | Must be "post" |
params | object | Yes | Contains all parameters for the request |
Params Object
| Parameter | Type | Required | Description |
|---|---|---|---|
action | string | Yes | Must be "getTradesForPosition" |
subAccountId | string | Yes | Subaccount identifier that owns the position |
positionId | string | Yes | Position ID to retrieve trades for (numeric string) |
limit | integer | No | Maximum number of trades to return (default: 100, max: 1000) |
offset | integer | No | Number of trades to skip for pagination (default: 0) |
expiresAfter | integer | No | Optional expiration timestamp in Unix seconds (use 0 for no expiration) |
signature | object | Yes | EIP-712 signature using SubAccountAction type |
- This endpoint uses
SubAccountActionEIP-712 type (no nonce required, onlyexpiresAfteris optional) positionIdis required and must be a valid numeric string- Unlike
getTrades, this endpoint does not supportsymbol,orderId,startTime, orendTimefilters
EIP-712 Signature
const domain = {
name: "Synthetix",
version: "1",
chainId: 1,
verifyingContract: "0x0000000000000000000000000000000000000000"
};
const types = {
SubAccountAction: [
{ name: "subAccountId", type: "uint256" },
{ name: "action", type: "string" },
{ name: "expiresAfter", type: "uint256" }
]
};
const message = {
subAccountId: "1867542890123456789",
action: "getTradesForPosition",
expiresAfter: 0
};
const signature = await signer._signTypedData(domain, types, message);Response Format
Success Response
{
"id": "trades-pos-1",
"status": 200,
"result": {
"status": "success",
"response": {
"trades": [
{
"tradeId": "123456789",
"order": {
"venueId": "1948058938469519360",
"clientId": "cli-1948058938469519360"
},
"orderId": "1948058938469519360",
"symbol": "BTC-USDT",
"side": "buy",
"direction": "open long",
"orderType": "limit",
"price": "50000.50",
"quantity": "0.1",
"realizedPnl": "0.00",
"fee": "5.00",
"feeRate": "0.001",
"markPrice": "50025.00",
"entryPrice": "50000.50",
"timestamp": 1704067200500,
"maker": false,
"reduceOnly": false,
"triggeredByLiquidation": false,
"postOnly": false
},
{
"tradeId": "123456790",
"order": {
"venueId": "1948058938469519361",
"clientId": "cli-1948058938469519361"
},
"orderId": "1948058938469519361",
"symbol": "BTC-USDT",
"side": "buy",
"direction": "open long",
"orderType": "market",
"price": "50100.00",
"quantity": "0.05",
"realizedPnl": "0.00",
"fee": "2.51",
"feeRate": "0.001",
"markPrice": "50110.00",
"entryPrice": "50033.67",
"timestamp": 1704067201000,
"maker": false,
"reduceOnly": false,
"triggeredByLiquidation": false,
"postOnly": false
}
],
"hasMore": false
}
}
}Empty Result
{
"id": "trades-pos-1",
"status": 200,
"result": {
"status": "success",
"response": {
"trades": [],
"hasMore": false
}
}
}Error Response
{
"id": "trades-pos-1",
"status": 400,
"result": null,
"error": {
"code": 400,
"message": "positionId is required"
}
}Response Fields
| Field | Type | Description |
|---|---|---|
id | string | Echoed request identifier |
status | integer | HTTP-style status code |
result.status | string | "success" on success |
result.response.trades | array | Array of trade objects for the specified position |
result.response.hasMore | boolean | Whether more trades exist beyond current result |
Trade Object Fields
| Field | Type | Description |
|---|---|---|
tradeId | string | Unique trade identifier |
order.venueId | string | Canonical venue-generated order ID |
order.clientId | string | Optional client-provided order ID |
orderId | string | Deprecated legacy order ID |
symbol | string | Trading pair symbol (e.g., "BTC-USDT") |
side | string | Trade side: "buy" or "sell" |
direction | string | Position effect (e.g., "open long", "close long", "open short", "close short") |
orderType | string | Order type that produced this trade: "limit", "market", "stopMarket", "takeProfitMarket", "stopLimit", or "takeProfitLimit" |
price | string | Execution price |
quantity | string | Filled quantity for this trade |
realizedPnl | string | Profit/loss realized from this trade |
fee | string | Trading fee charged |
feeRate | string | Fee rate applied (maker/taker rate) |
markPrice | string | Mark price at time of trade execution |
entryPrice | string | Position's average entry price at time of trade |
timestamp | integer | Trade execution timestamp (Unix milliseconds) |
maker | boolean | Whether this trade provided liquidity (maker) or took liquidity (taker) |
reduceOnly | boolean | Whether this trade reduced an existing position |
triggeredByLiquidation | boolean | Whether this trade was part of a liquidation |
postOnly | boolean | Whether this order was post-only (maker-only) |
Migration Note: Use order.venueId as canonical order reference. orderId remains for backward compatibility.
Code Examples
Get All Trades for a Position
{
"id": "trades-pos-all",
"method": "post",
"params": {
"action": "getTradesForPosition",
"subAccountId": "1867542890123456789",
"positionId": "42",
"expiresAfter": 0,
"signature": { "v": 28, "r": "0x...", "s": "0x..." }
}
}Paginated Request
{
"id": "trades-pos-page2",
"method": "post",
"params": {
"action": "getTradesForPosition",
"subAccountId": "1867542890123456789",
"positionId": "42",
"limit": 50,
"offset": 50,
"expiresAfter": 0,
"signature": { "v": 28, "r": "0x...", "s": "0x..." }
}
}Validation Rules
- Subaccount ID must be valid and accessible
positionIdis required and must be a valid numeric string- Limit must be between 0 and 1000 (default: 100)
- Offset must be non-negative (default: 0)
Common Errors
| Error | Description | Solution |
|---|---|---|
positionId is required | Missing position ID | Provide positionId in request params |
positionId must be a valid numeric value | Non-numeric position ID | Use a numeric string for positionId |
subaccountId is required | Missing subaccount | Include subAccountId in request params |
Invalid limit | Limit exceeds maximum or is negative | Use limit between 0 and 1000 |
Invalid offset | Negative offset value | Use offset >= 0 |
Authentication failed | Invalid signature | Verify signature generation |
500 Internal Server Error | Trade history contains an unrecognized direction value (e.g. "unknown", "", or any unexpected string) | Indicates corrupted trade direction data on the backend that requires operator investigation. Previously these cases were silently defaulted to side: "buy" in the response. |
| Error Code | Description | Retryable |
|---|---|---|
UNAUTHORIZED | EIP-712 signature validation failed | No |
VALIDATION_ERROR | Request validation failed | No |
MISSING_REQUIRED_FIELD | Required field is missing | No |
INVALID_FORMAT | Field format is invalid | No |
INVALID_VALUE | Invalid parameter value | No |
RATE_LIMIT_EXCEEDED | Too many requests in time window | Yes |
INSUFFICIENT_MARGIN | Not enough margin for trade | No |
ORDER_NOT_FOUND | Order does not exist | No |
OPERATION_TIMEOUT | Operation timed out | Yes |
Next Steps
- Get Trades - Retrieve all trades for a subaccount
- Get Positions - Query current positions
- Get Position History - Query closed position history
- SubAccount Updates Subscription - Real-time trade notifications
- REST Alternative - REST API comparison
