Skip to navigation

Perpetual Queries & Pagination

Perpetual Queries & Pagination: Agent Java SDK v0.3.0 integration, examples, parameters and response semantics.

View as Markdown

This guide targets Agent Java SDK v0.3.0, Java 8+, and the tagged public contract. Examples run in a partner backend after initializing client in Quick Start.

Example prerequisites

The Java snippets share these imports. Initialize client using Quick Start and obtain platformUserId from the saved binding. Example user/order IDs must be replaced with your own persisted values.

import com.sixmm.agent.*;
import com.sixmm.agent.model.*;
import java.util.*;

Query perpetual contract data

Six types of interfaces and Java methods

All requests are signed POST with a common prefix of /v1/agent/perpetual.

path suffixJava Method/Request Typeplayer range
/orders/currentlistCurrentPerpetualOrders(CurrentPerpetualOrdersRequest)NORMAL Player can be omitted; CONDITIONAL Player must be specified
/orders/historylistPerpetualOrderHistory(PerpetualOrderHistoryRequest)Same as above
/tradeslistPerpetualTrades(PerpetualTradesRequest)Player must be specified
/positions/currentlistCurrentPerpetualPositions(CurrentPerpetualPositionsRequest)Players can be omitted
/positions/historylistPerpetualPositionHistory(PerpetualPositionHistoryRequest)Players can be omitted
/account/ledgerlistPerpetualLedger(PerpetualLedgerRequest)Players can be omitted

platformUserIds is a string array of public platform IDs. When specified, 1 to 100 unique players who have access are required; on endpoints that allow omission, only the range of direct players that the current merchant has access to is queried. Trade-fill queries always require this array; conditional-order queries also require explicit user IDs. Omission is not equivalent to [], and empty arrays are illegal. The scope is determined by the signing merchant, and other merchant IDs cannot be passed to expand the scope.

Array values are serialized as compact JSON before joining the signing payload. For example, platformUserIds signs as ["1188041528"], giving platformUserIds=["1188041528"] in the k=v payload. Preserve the array element order, double quotes and string IDs; do not insert formatting spaces or use Java List.toString() (such as [1188041528]). The SDK handles this serialization automatically.

The order query must pass orderCategory=NORMAL or CONDITIONAL. Use orderId for ordinary orders and conditionId for conditional orders. They cannot be mixed across categories. Conditional orders and the ordinary orders generated by triggering them are processed separately as entities.

Filter conditions

QueryAvailable business filters
Current orderorderCategory, symbol
historical orderorderCategory, symbol, startTime, endTime, orderId, conditionId, clientOrderId, side, status
make a dealsymbol, startTime, endTime, orderId
Current positionsymbol
Historical positionssymbol, startTime, endTime, positionSide
Contract changesstartTime, endTime, assetType, changeType

The time of historical query is Unix milliseconds, and the interval is [startTime, endTime); the time of requesting signature is timestamp is Unix seconds. It is recommended to fix the UTC time window and query in segments; use UTC for daily reconciliation. Status and type use platform contract enumeration and are not translated into Chinese strings by themselves.

limit Default is 500, range is 1~1000; the page size does not guarantee that the same number will be returned every time. The six interfaces currently share a query quota of 2 times per second and 4 bursts per merchant, and the maximum concurrency limit for each merchant within the instance is 2. The merchant side uses a unified queue, and it is recommended to start with sequential paging and a smaller history window.

Java query examples

Query a player’s current ordinary order:

CurrentPerpetualOrdersRequest current = new CurrentPerpetualOrdersRequest();
current.orderCategory = "NORMAL";
current.platformUserIds = Collections.singletonList(platformUserId);
current.symbol = "BTCUSDT";
current.limit = 100;
PerpetualResponse currentPage = client.listCurrentPerpetualOrders(current);

Query the contract changes in the last hour and process the cursor. The following example does not automatically retry; when the actual application encounters current limitation or temporary failure, follow the linked related guide to restore the same page.

PerpetualLedgerRequest ledger = new PerpetualLedgerRequest();
ledger.platformUserIds = Collections.singletonList(platformUserId);
ledger.endTime = System.currentTimeMillis();
ledger.startTime = ledger.endTime - 3_600_000L;
ledger.limit = 100;
Set<String> seenCursors = new HashSet<>();
while (true) {
PerpetualResponse page = client.listPerpetualLedger(ledger);
for (PerpetualRecord row : page.data.items) {
// Persist records idempotently by platformUserId, entityType and entityId.
}
if (!page.data.hasMore) {
break;
}
String next = page.data.nextCursor;
if (next == null || next.isEmpty() || !seenCursors.add(next)) {
throw new IllegalStateException("游标未推进,停止查询并排查");
}
ledger.cursor = next;
Thread.sleep(650L); // Other queries must share the same partner rate-limit queue.
}

Return structure and saving rules

See Common response and pagination for shared fields. Resource fields are documented in Orders, Trade fills, Positions and Contract ledger.

The six interfaces uniformly return PerpetualResponse:

{
"code": 0,
"message": "success",
"data": {
"items": [],
"nextCursor": "",
"hasMore": false
}
}

Each items contains platformUserId, entityType, entityId, data. Entity types include ORDER, CONDITION_ORDER, TRADE_FILL, POSITION, ACCOUNT_LEDGER. Use these three identity fields to build an idempotent key; do not treat the conditional order ID, order ID, and fill ID as the same number.

data Provides fields such as price, quantity, status, expense, profit and loss, or balance change by resource. Amount, price, quantity, and entity ID are handled as strings; business time is in milliseconds. Missing fields are not filled in to 0 and are not inferred from other entities.

The cursor is the paging position of a query, not a reliable incremental subscription, nor a guaranteed cross-page atomic snapshot. The current cursor is valid for 24 hours from the first round of generation; subsequent paging retains the same merchants, resources, player collections and filter conditions. The fixed window for historical pull is idempotent when pulled repeatedly; the status of the current order/position is refreshed after re-querying. When a real-time interface is needed, the data mechanism of the platform front-end is used, and the polling six interface cannot be regarded as a high-frequency market interface.

Errors and recovery

HTTP success does not mean business success, you must check code. Java SDK will throw a business error as AgentApiException.

Business codeTypical meaningHandling
102001Required parameters are missing, for example, the conditional order query is missing players.Supply the missing parameters
102002Illegal parameters, empty array, mismatched cursor or expiredCorrect the parameters; recheck the fixed window after clearing the expired cursor and save it idempotently.
102003Illegal limit, number of players, or time rangeNarrow or correct scope
6001Signature errorCheck key, array serialization and signature fields
6009Merchant access method or access scope is not allowedCheck merchant permissions and player ownership
6904Service is temporarily unavailable, concurrency or query resource protectionReduce concurrency and shrink windows; contact support if the error persists
6905The shared quota for six types of queries has been exhaustedBack off, then retry the original failed page

The cursor and all filter conditions of the original failed page will be retained after current limiting, timeout or temporary failure; each time SDK is re-called, new timestamp, nonce, sign will be generated. You cannot jump directly to the next page, and you cannot treat failures as empty results. SDK is not responsible for automatically retrying fund transactions.

Common response and pagination

FieldJSON typeillustrate
codeintegerBusiness code, 0 means success; if it is not 0, it will be treated as an error, and failure will not be treated as an empty page.
messagestringThe description of the results is not the sole basis for business judgment.
dataobjectPaginated results on success
data.itemsarrayRecords on this page; the legal empty page is []
data.nextCursorstringNext page cursor; usually an empty string if there are no subsequent pages
data.hasMorebooleanWhether there are subsequent pages; when true, use nextCursor to continue the same query

The structure of each data.items[]:

FieldJSON typeillustrate
platformUserIdstringPlatform public user ID, saved as a string; not internal database user ID
entityTypestringThe entity type to which the record belongs, see the table below
entityIdstringThe identifier of the current entity is combined with the platform user and entity type to construct a local idempotent key.
dataobjectThe business fields of this entity; different resource fields are different
Query resourcesentityTypeentityId Correspondence
Ordinary orderORDERdata.orderId
conditional ordersCONDITION_ORDERdata.conditionId
Trade fill detailsTRADE_FILLdata.fillId, not tradeId
Current/historical positionsPOSITIONdata.positionId
Contract ledger recordsACCOUNT_LEDGERSingle account change detail identification, ** is not data.ledgerId**

The same ledgerId can separate multiple details such as handling fees, profit and loss, etc.; pressing ledgerId to remove duplicates will cause data loss. IDs from different resources cannot be mixed. See the linked related guide of the Access Guide for paging and field saving rules.

Types, units and omitted fields

  • Amount, price, quantity, and entity ID use string; use decimal to process amounts, and cannot use floating point numbers or convert long IDs to JavaScript Numbers. The amount currency and quantity unit are explained according to the trading pair/contract specifications.
  • Business time uses integer (int64), both are Unix milliseconds; request authentication timestamp and entry credentials expireAt use seconds and cannot be confused.
  • String business fields are usually not output when they are empty, and some will be omitted when numeric fields are 0. The missing field does not mean that the business value is 0.
  • reduceOnly, closeOnly, makerOnly in the general record model do not omit false, so these three false may also appear in transactions or positions. They are only explained in the order resources; it cannot be considered that the transaction/position executed the corresponding order rules.
  • closePosition is an optional boolean: provided by conditional orders, usually omitted for other resources. Missing has a different meaning than false.
  • The table below “currently provided” means that the read logic has a field source; optional fields may still be omitted because they have no value. The fields that exist in the model are not guaranteed to be filled in every interface.

The difference between status and margin mode

resourcecurrent return value
Current ordinary order statusNEW, PENDING, PARTIALLY_FILLED
Historical ordinary order statusFILLED, CANCELED, REJECTED, PARTIAL_FILLED_CANCELED, or PARTIALLY_FILLED_CANCELED; keep the actual source spelling
Current condition order status / triggerStatusPENDING_ACTIVATION, PENDING, TRIGGERING
Historical condition order status / triggerStatusTRIGGERED, CANCELLED, REJECTED, FIRED
Current position statusNumeric string “1” is in position, “3” is in liquidation
Historical position statusNumeric string “2” has closed the position, “4” has forced liquidation

The spelling of CANCELED for an ordinary order is different from that of CANCELLED for a conditional order; triggering of a conditional order does not mean that the generated ordinary order has been filled. Do not reuse the same set of status translation tables for all resources.

Conditional order marginMode returns CROSS / ISOLATED; historical ordinary orders and positions currently return “1” / “2”, which are cross/isolated margin respectively. marginMode is currently not available for ordinary orders. Merchants can normalize by resource in their own display layer, and the original values ​​still need to be saved.

Fields declared in the model but not provided in this query

Generic RecordData / Java The PerpetualData model also declares the following fields, but the current six-category production read logic does not populate them. **Should not be listed as available business data, nor should field defaults be substituted for real results. **

FieldModel typecurrent boundary
closeReasonstringReasons for closing historical positions are not provided
walletDeltastringThe account change interface does not return wallet delta
frozenDeltastringThe account change interface does not return frozen delta
usedDeltastringThe account change interface does not return the used margin delta
feeDeltastringThe account change interface does not return the fee delta
pnlDeltastringThe account change interface does not return profit and loss delta
accountVersionstringThe account change interface does not return the account version and cannot be used for reliable incremental synchronization.
occurredAtintegerThe account change interface uses createdAt and does not provide another set of event occurrence times.

The actual field application scope is subject to the above resource tables; when the platform updates fields or enumerations, it shall be adapted according to the new interface description and SDK version.