跳到主要内容

用户订单

通道名

spot:user:orders

鉴权:必须。参见鉴权

描述

为已鉴权用户推送所有现货市场的订单生命周期事件。服务端按钱包地址过滤推送 — 仅转发属于已鉴权用户的事件。订阅一次即可接收所有交易对的事件。

订阅

先完成鉴权,再订阅:

{ "type": "auth_token", "token": "eyJhbGciOiJIUzI1..." }
{ "type": "subscribe", "channel": "spot:user:orders" }

响应:

{ "type": "subscribed", "channel": "spot:user:orders" }

不发送快照。订阅后请调用 GET /spot/orders 初始化本地订单状态,再通过后续 spot_user_order 推送保持同步。

推送格式

spot_user_order

每次订单生命周期事件触发推送:下单、成交(每笔成交每侧各一条)、撤单、拒单。

示例 — 订单已下单(尚未成交):

{
"type": "spot_user_order",
"channel": "spot:user:orders",
"data": {
"id": "8b3d1a2c-4e5f-6789-abcd-ef0123456789",
"symbol": "DFUSDT",
"side": "buy",
"type": "limit",
"tif": "gtc",
"price": "0.5000",
"quantity": "100",
"quote_quantity": null,
"filled_qty": "0",
"avg_fill_price": "0",
"status": "open",
"reject_reason": null,
"updated_at": 1778400000
}
}

示例 — 部分成交(含 last_fill):

{
"type": "spot_user_order",
"channel": "spot:user:orders",
"data": {
"id": "8b3d1a2c-4e5f-6789-abcd-ef0123456789",
"symbol": "DFUSDT",
"side": "buy",
"type": "limit",
"tif": "gtc",
"price": "0.5000",
"quantity": "100",
"quote_quantity": null,
"filled_qty": "30",
"avg_fill_price": "0.5000",
"status": "partially_filled",
"reject_reason": null,
"updated_at": 1778400010,
"last_fill": {
"trade_id": "9f2a1b3c-4d5e-6f7a-8b9c-0d1e2f3a4b5c",
"price": "0.5000",
"quantity": "30",
"fee": "0.015",
"fee_token": "DF"
}
}
}

示例 — 订单已撤销:

{
"type": "spot_user_order",
"channel": "spot:user:orders",
"data": {
"id": "8b3d1a2c-4e5f-6789-abcd-ef0123456789",
"symbol": "DFUSDT",
"side": "buy",
"type": "limit",
"tif": "gtc",
"price": "0.5000",
"quantity": "100",
"quote_quantity": null,
"filled_qty": "30",
"avg_fill_price": "0.5000",
"status": "canceled",
"reject_reason": null,
"updated_at": 1778400020
}
}

示例 — 订单被拒单:

{
"type": "spot_user_order",
"channel": "spot:user:orders",
"data": {
"id": "7c4e2b1d-5f6a-7890-bcde-f01234567890",
"symbol": "DFUSDT",
"side": "buy",
"type": "limit",
"tif": "post_only",
"price": "0.5001",
"quantity": "50",
"quote_quantity": null,
"filled_qty": "0",
"avg_fill_price": "0",
"status": "rejected",
"reject_reason": "POST_ONLY_REJECT",
"updated_at": 1778400030
}
}

字段说明

字段类型描述
idstring (UUID)订单标识符。与 GET /spot/orders 返回值一致。
symbolstring交易对,如 DFUSDT
sidestringbuysell。参见 Enums — 订单方向
typestringlimitmarket。参见 Enums — 订单类型
tifstringgtciocpost_only。参见 Enums — 有效期类型
pricestring (decimal) 或 null限价单价格。市价单为 null
quantitystring (decimal) 或 null基础资产数量(DF)。使用 quote_quantity 下单的市价买单为 null
quote_quantitystring (decimal) 或 null市价买单的计价资产数量(USDT);其他情况为 null
filled_qtystring (decimal)累计已成交基础资产数量。
avg_fill_pricestring (decimal)成交量加权平均价格。尚无成交时为 "0"
statusstring当前订单状态。参见 Enums — 订单状态
reject_reasonstring 或 nullstatus == "rejected" 时的错误码,如 POST_ONLY_REJECT;否则为 null
updated_atinteger本次事件发生时间 — Unix
last_fillobject 或缺失仅在本次推送由成交触发时存在。 普通下单、撤单、拒单时省略。

last_fill 字段说明

字段类型描述
trade_idstring (UUID)成交标识符(与 GET /spot/trades/me 一致)。
pricestring (decimal)本次成交的执行价格。
quantitystring (decimal)本次成交的基础资产数量。
feestring (decimal)本次成交收取的手续费金额。
fee_tokenstring手续费收取的代币 — 买方(或卖方挂单方)收到 DF 时为 DF,收到 USDT(卖方或买方挂单方)时为 USDT。DFUSDT MVP 阶段硬编码;未来市场可能有所不同。

推送频率

事件触发时机
订单下单引擎接受后立即推送
部分成交每笔成交后立即推送(每笔成交每个用户各一条)
全部成交最后一笔成交后立即推送
订单撤销撤销时立即推送(用户请求、IOC 剩余部分或市场下架)
订单拒单拒单时立即推送

代码示例

const ws = new WebSocket('wss://api-sepolia.p99.world/ws');

// Local order map: id -> order data
const orders = new Map();

ws.onopen = () => {
// 1. Authenticate
ws.send(JSON.stringify({ type: 'auth_token', token: '<JWT>' }));
setInterval(() => ws.send(JSON.stringify({ type: 'ping' })), 30000);
};

ws.onmessage = (event) => {
const msg = JSON.parse(event.data);

if (msg.type === 'auth_result' && msg.success) {
// 2. Seed local state from REST
fetch('https://api-sepolia.p99.world/api/v1/spot/orders', {
headers: { Authorization: 'Bearer <JWT>' },
})
.then((r) => r.json())
.then((list) => list.forEach((o) => orders.set(o.id, o)));

// 3. Subscribe
ws.send(JSON.stringify({ type: 'subscribe', channel: 'spot:user:orders' }));
}

if (msg.type === 'spot_user_order') {
const o = msg.data;
orders.set(o.id, o);

if (o.last_fill) {
console.log(`Fill on order ${o.id}: qty=${o.last_fill.quantity} @ ${o.last_fill.price} fee=${o.last_fill.fee} ${o.last_fill.fee_token}`);
} else {
console.log(`Order ${o.id} → status=${o.status}${o.reject_reason ? ' (' + o.reject_reason + ')' : ''}`);
}
}
};