产品配置
用户可以通过 GET /api/v5/public/instruments 获取交易所的产品配置。
后续的产品更新,例如最小变动价位变化、新上市,将通过websocket 产品 频道发布。
市场数据
用户能够从websocket频道接收实时的市场数据更新。
bbo-tbt和books5是每10毫秒和100毫秒发布一次的深度快照。当订单簿没有变化时,系统不会发送新的快照。
books、books-l2-tbt和books50-l2-tbt是增量订单簿频道,books每100毫秒发布订单簿的变化,books-l2-tbt和books50-l2-tbt每10毫秒发布订单簿的变化。为使用books-l2-tbt和books50-l2-tbt,用户需要在订阅之前登录,该功能分别限制VIP5或VIP4以上用户使用。
在系统内部,订单簿数据每10毫秒被创建一次,并根据用户订阅的频道发送相关数据。用户从所有websocket连接和频道接收到的订单簿数据都是相同的。
如果深度在间隔期间发生了如A->B->A一样的改变,则不会发送更新。如果订单簿长时间没有更新,快照频道会重推订单簿数据,增量订单簿频道会推送没有更新的信息,以通知用户连接仍处于活动状态。
订单管理
交易模式
交易账户交易系统的全仓/逐仓设置更为弹性,用户可以同时以全仓和逐仓交易同一产品。因此,用户需要在下单时指定该订单的交易模式(tdMode字段)。
各种情景下tdMode所需的值:
| 持仓模式 | 产品类型 | 交易模式(tdMode) |
|---|---|---|
| 现货模式 | 币币 | cash |
订阅订单频道
下单前,用户应先使用 WebSocket 订阅 订单 频道,这样才能够监察订单状态(如等待成交、完全成交)和作出相应的操作(如在完全成交后下新单)。
订单频道提供多种维度的订阅。要订阅以上 BTC-JPY 订单的数据,用户可在连接到和登入私有 WebSocket 后,传送下表任一请求:
| 产品类型 | 产品类型 + 产品 ID | |
| 请求 | { "op": "subscribe", "args": [ { "channel": "orders", "instType": "SPOT" } ] } |
{ "op": "subscribe", "args": [ { "channel": "orders", "instType": "SPOT", "instId": "BTC" } ] } |
| 成功返回 | { "event": "subscribe", "arg": { "channel": "orders", "instType": "SPOT" } } |
{ "event": "subscribe", "args": [ { "channel": "orders", "instType": "SPOT", "instId": "BTC" } ] } |
注:订单频道不设首次订阅全量数据推送,只会在订单状态改变时(如由等待成交到撤单成功)推送该订单的更新。
换言之,用户无法在订阅订单频道时得知当时的订单数据。要获取订阅订单频道前未完成订单的数据,可通过以下的 REST API 查看:
GET /api/v5/trade/orders-pending
下单
为了系统能够更容易地识别订单,我们建议用户在下单时填上客户自定义订单 ID(clOrdId字段)。客户自定义订单 ID 需由字母与数字组成,区分大小写,最长 32 位。
cloOrdId唯一性检查仅适用于所有挂单,但我们扔推荐用户始终使用唯一的cloOrdId以便于故障排除等工作。
此示例我们会在clOrdId字段填上 testBTC0123。
在订阅订单频道后,用户便可以准备 BTC-JPY 订单的下单。
用户可通过 REST 和 WebSocket 去下单。
REST API
用户可以通过以下的 REST API 下单,服务器收到请求后会返回订单 ID(ordId)。
| REST API | POST /api/v5/trade/order |
| 请求体 | { "instId": "BTC-JPY", "tdMode": "cash", "clOrdId": "testBTC0123", "side": "buy", "ordType": "limit", "px": "50912.4", "sz": "1" } |
| 成功返回 | { "code": "0", "msg": "", "data": [ { "clOrdId": "testBTC0123", "ordId": "288981657420439575", "tag": "", "sCode": "0", "sMsg": "" } ] } |
注:这只代表交易所已成功收取请求,并把订单 ID 指派到该订单。此时订单有可能还没到撮合系统,用户需要进一步检查订单状态去确认。
WebSocket
用户亦可以通过 WebSocket 下单,理论上比 REST 更有效率及节约资源。
由于 WebSocket 操作为异步通信,用户需要提供信息 ID(id)以便识别其返回。
于私有 WebSocket 登录后,传送以下 WebSocket 信息:
| { "id": "NEWtestBTC0123", "op": "order", "args": [ { "instId": "BTC-JPY", "tdMode": "cash", "clOrdId": "testBTC0123", "side": "buy", "ordType": "limit", "px": "50912.4", "sz": "1" } ] } |
服务器收到请求后,会连同信息 ID(即 NEWtestBTC012)返回结果,并附上交易所指派的订单 ID(ordId):
| { "id": "NEWtestBTC0123", "op": "order", "data": [ { "clOrdId": "", "ordId": "288981657420439575", "tag": "", "sCode": "0", "sMsg": "" } ], "code": "0", "msg": "" } |
注:这只代表交易所已成功收取请求,并把订单 ID 指派到该订单。此时订单有可能还没到撮合系统,用户需要进一步检查订单状态去确认。
检查订单状态
下单后,若订单未返回任何错误 ("sCode": "0")。用户会在 WebSocket 订单频道收到该订单状态为live的信息。
信息示例(以产品类型 + 产品 ID 维度订阅订单频道):
| { "arg": { "channel": "orders", "instType": "SPOT", "instId": "BTC-JPY", "uid": "614488474791936" }, "data": [ { "accFillSz": "0", "algoClOrdId": "", "algoId": "", "amendResult": "", "amendSource": "", "avgPx": "", "cancelSource": "", "category": "normal", "clOrdId": "testBTC0123", "code": "0", "cTime": "1615170596148", "execType": "", "fee": "0", "feeCcy": "BTC", "fillFee": "0", "fillFeeCcy": "BTC", "fillPx": "", "fillSz": "0", "fillTime": "", "instId": "BTC-JPY", "instType": "SPOT", "msg": "", "ordId": "288981657420439575", "ordType": "limit", "px": "50912.4", "rebate": "0", "rebateCcy": "JPY", "reqId": "", "side": "buy", "attachAlgoClOrdId": "", "slOrdPx": "", "slTriggerPx": "", "slTriggerPxType": "last", "source": "", "state": "live", "sz": "1", "tag": "", "tdMode": "cash", "tgtCcy": "", "tpOrdPx": "", "tpTriggerPx": "", "tpTriggerPxType": "last", "attachAlgoOrds": [], "tradeId": "", "lastPx": "", "uTime": "1615170596148", "isTpLimit": "false", "linkedAlgoOrd": {"algoId": ""} } ] } |
订单完全成交后,用户会收到以下的推送信息示例,订单状态变更为filled,并填上其他有关成交的字段。
如果订单部分或全部成交,websocket将分别返回 state = partially_filled and filled。
对于立即成交并取消剩余(IOC)、全部成交或立即取消(FOK)以及仅挂单的订单(post only),这些订单可能会被撮合引擎拒绝,用户将收到live然后是canceled的状态。
用户订单可能会由于各种原因被系统取消,例如清算或自成交。用户可以参考 cancelSource 以确定订单被取消的原因。
一个订单的终止状态为canceled或filled。
订单的每一笔成交都会被系统赋予一个成交 ID (tradeId),用于与持仓对账。
| { "arg": { "channel": "orders", "instType": "SPOT", "instId": "BTC-JPY", "uid": "614488474791936" }, "data": [ { "accFillSz": "1", "algoClOrdId": "", "algoId": "", "amendResult": "", "amendSource": "", "avgPx": "50912.4", "cancelSource": "", "category": "normal", "clOrdId": "testBTC0123", "code": "0", "cTime": "1615170596148", "execType": "M", "fee": "-0.001", "feeCcy": "BTC", "fillFee": "-0.001", "fillFeeCcy": "BTC", "fillPx": "50912.4", "fillSz": "1", "fillTime": "1615170598021", "instId": "BTC-JPY", "instType": "SPOT", "msg": "", "ordId": "288981657420439575", "ordType": "limit", "px": "50912.4", "rebate": "0", "rebateCcy": "JPY", "reqId": "", "side": "buy", "attachAlgoClOrdId": "", "slOrdPx": "", "slTriggerPx": "", "slTriggerPxType": "last", "source": "", "state": "filled", "sz": "1", "tag": "", "tdMode": "cash", "tgtCcy": "", "tpOrdPx": "", "tpTriggerPx": "", "tpTriggerPxType": "last", "attachAlgoOrds": [], "tradeId": "60477021", "lastPx": "50912.4", "uTime": "1615170598021", "isTpLimit": "false", "linkedAlgoOrd": {"algoId": ""} } ] } |
可能的订单状态:
- 在入口处被拒绝,
sCode不为零,websocket订单频道无更新推送 - 下单并立即全部成交:
live->filled - 下单并立即通过多笔交易成交:
live->partially_filled-> ... ->filled - 下单但立即被撮合引擎取消(如 IOC、FOK、仅挂单):
live->canceled(取消原因可从cancelSource查询) - 下单为 IOC,部分成交后因价格深度不足而被系统取消:
live->partially_filled->canceled
改单
改单接口支持所有产品类型的改单,允许用户修改订单的价格(newPx字段)和/或数量(newSz字段)。另外 API 也提供cxlOnFail参数,设置订单修改失败时自动撤单的操作。
REST:
POST /api/v5/trade/amend-order
WebSocket 业务操作请求参数:
与下单相似,用户应会收到服务器相应 REST / WebSocket 的成功返回,然后于 WebSocket 订单频道收到已填上amendResult字段的订单推送更新。
注:订单完全成交或撤单已成功时不能改单。
成功响应仅表示交易所已收到该请求,用户应参考websocket订单频道以进行确认。
撤单
用户可以以类似的方式,通过 REST 或 WebSocket 撤单。
REST:
POST /api/v5/trade/cancel-order
WebSocket 业务操作请求参数:
同样,用户应会收到服务器相应 REST / WebSocket 的成功返回。当用户从 WebSocket 订单频道收到订单状态为 canceled 的推送更新时,才代表订单撤单成功。
注:订单完全成交或撤单已成功时不能撤单。
成功响应仅表示交易所已收到该请求,用户应参考websocket订单频道以进行确认。
批量操作
下单、改单、撤单均支持批量操作,每次最多 20 张订单。批量操作的订单可包括不同的产品类型。
REST:
| 下单 | POST /api/v5/trade/batch-orders |
| 改单 | POST /api/v5/trade/amend-batch-orders |
| 撤单 | POST /api/v5/trade/cancel-batch-orders |
WebSocket 业务操作请求参数:
| 下单 | "op": "batch-orders" |
| 改单 | "op": "batch-amend-orders" |
| 撤单 | "op": "batch-cancel-orders" |
批量操作容许部分订单操作成功。在收到返回后,用户应检查返回结果内每个订单的sCode和sMsg字段来判段订单的执行结果。
订单时间戳
订单数据中有多个时间戳,供用户跟踪订单状态和延迟。
cTime 是订单管理系统在风险检查后的订单创建时间。
uTime 是订单管理系统最后一次更新订单的时间。在订单修改、成交和取消后进行更新。
fillTime 是订单成交的时间。fillTime 与公共交易数据的时间相同。
inTime 是 WebSocket / REST 网关接收请求时的时间戳。REST接口返回的时间是请求验证后的时间。
outTime 是 WebSocket / REST 网关发送响应时的时间戳。
分页
okj提供分页功能,以帮助用户从海量数据中轻松获得他们想要的数据。相关的请求参数如下:
| 参数名 | 类型 | 是否必须 | 描述 |
|---|---|---|---|
| before | String | 否 | 请求此ID之后(更新的数据)的分页内容,传的值为对应接口的ordId, billId, tradeId, ts etc. |
| after | String | 否 | 请求此ID之前(更旧的数据)的分页内容,传的值为对应接口的ordId, billId, tradeId, ts etc. |
| limit | String | 否 | 返回结果的数量,最大为100,默认100条 |
请参阅以下功能提示及示例,以便更好地理解该功能。假设原始数据为 [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]。
| 提示 | 示例 |
|---|---|
| 无论用户如何输入请求参数,总是返回最新数据 | 我们总是在最开始返回新数据,例如 [10, 9, 8, 7, ...] |
| 分页时,不包含before以及after | 若 before=6,after=10,返回的数据将会是 [9, 8, 7] |
| 若before及after之间的数据量超过limit,返回靠近after的数据记录 | 若 before=2,after=9,limit=3,返回的数据将会是 [8, 7, 6] |
| 若仅传入before,不传入after,靠近before的数据将被返回 | 若 before=6,limit=3,返回的数据将会是 [9, 8, 7] 该功能不适用于仓位历史接口,相同参数,仓位历史接口将返回 [10, 9, 8],不靠近before返回 |
为了获取特定时间范围内的数据,我们还提供了时间戳过滤功能,应用于before/after已被用于ID分页的场景。请求参数如下:
| 参数名 | 类型 | 是否必须 | 描述 |
|---|---|---|---|
| begin | String | No | 筛选的开始时间戳,Unix 时间戳为毫秒数格式,如 1597026383085 |
| end | String | No | 筛选的结束时间戳,Unix 时间戳为毫秒数格式,如 1597027383085 |
| limit | String | No | 分页返回的结果集数量,最大为100,不填默认返回100条 |
begin/end的使用方法与before/after略有不同。
| 提示 | 示例 |
|---|---|
| 过滤时间戳时,包含begin以及end | 若 begin=6,end=10,返回的数据将会是 [10, 9, 8, 7, 6] |
| 若begin及end之间的数据量超过limit,返回靠近end的数据记录。 若仅传入begin,不传入end,靠近begin的数据将被返回 |
若 begin=6,limit=3,返回的数据将会是 [8, 7, 6] 该功能不适用于成交明细接口,相同参数,成交明细接口将返回[10, 9, 8],不靠近begin返回。 |
若begin/end以及before/after被同时传入,我们将先根据begin/end进行时间戳过滤,并根据before/after对结果进行分页。
拥有分页功能的交易接口罗列如下。
- GET / 获取未成交订单列表
- GET / 获取历史订单记录(近七天)
- GET / 获取历史订单记录(近三个月)
- GET / 获取成交明细(近三天)
- GET / 获取成交明细(近三个月)
- 账单流水查询(近七天)
- 账单流水查询(近三月)
自成交保护
交易系统会以母账户维度实施强制自成交保护,同一母账户下所有账户,包括母账户本身和所有子账户,都无法进行自成交。订单的默认STP模式为Cancel Maker。
自成交保护模式
取消maker单
这是默认的 STP 模式。为防止自成交,maker单将被取消,然后taker单将继续与深度中的下一个订单成交。
交易账户和持仓
账户
WebSocket 订阅
我们建议使用 WebSocket 订阅 账户 频道收取账户更新。账户频道设有可选参数ccy,让用户可以仅收取指定账户币种的信息。
该端点返回用户以美元为单元的资产价值,以及其他由于标识价格变化而持续更新的参数。OKJ在估值变化时定期向用户发送更新数据。
连接到私有 WebScoket 和登入后的请求和返回示例:
| 账户 | 账户(仅指定的币种) | |
| 请求 | { "op": "subscribe", "args": [ { "channel": "account" } ] } |
{ "op": "subscribe", "args": [ { "channel": "account", "ccy": "BTC" } ] } |
| 成功返回 | { "event": "subscribe", "arg": { "channel": "account" } } |
{ "event": "subscribe", "arg": { "channel": "account", "ccy": "BTC" } } |
首次订阅全量数据
与订单频道不同,账户频道首次订阅会推送全量数据,推送币种层面资产不为 0 的账户信息。币种层面资产不为 0 指币种总权益(eq)、可用保证金(availEq)、可用余额(availBal)任一字段不为 0。
假设账户的 BTC 和 JPY 币种层面资产不为 0,用户应收到账户频道以下的信息示例:
| 账户 | 账户(仅指定的币种) |
| { "arg": { "channel": "account" }, "data": [ { "adjEq": "30979.1086748182657014", "details": [ { "availBal": "", "availEq": "18962.59868274799", "ccy": "JPY", "crossLiab": "0", "disEq": "18978.5272656414983116", "eq": "18962.59868274799", "frozenBal": "0", "interest": "0", "isoEq": "0", "isoLiab": "0", "liab": "0", "mgnRatio": "", "ordFrozen": "0", "upl": "0" }, { "availBal": "", "availEq": "0", "ccy": "BTC", "crossLiab": "0.509575622217854", "disEq": "-25408.4180739947324516", "eq": "-0.5096053466363398", "frozenBal": "0", "interest": "0.0000297244184858", "isoEq": "0", "isoLiab": "0", "liab": "0.509575622217854", "mgnRatio": "", "ordFrozen": "0", "upl": "0" } ], "imr": "8469.4726913315758219", "isoEq": "0", "mgnRatio": "39.9556239578938079", "mmr": "762.252542219842", "totalEq": "44480.5383005753085878", "uTime": "1615190165641" } ] } |
{ "arg": { "channel": "account", "ccy": "BTC" }, "data": [ { "adjEq": "30979.1086748182657014", "details": [ { "availBal": "", "availEq": "0", "ccy": "BTC", "crossLiab": "0.509575622217854", "disEq": "-25408.4180739947324516", "eq": "-0.5096053466363398", "frozenBal": "0", "interest": "0.0000297244184858", "isoEq": "0", "isoLiab": "0", "liab": "0.509575622217854", "mgnRatio": "", "ordFrozen": "0", "upl": "0" } ], "imr": "8469.4726913315758219", "isoEq": "0", "mgnRatio": "39.9556239578938079", "mmr": "762.252542219842", "totalEq": "44480.5383005753085878", "uTime": "1615190165641" } ] } |
后续推送
之后,用户会根据以下情况收到账户数据推送:
| 事件触发推送 | 下单、撤单等事件会触发推送。多项事件(如同时间有多个订单成交)有可能会聚合成单个账户信息推送。仅推送受事件变更的币种,包括币种资产变为 0。 |
| 定时推送 | 定时推送,目前为每 5 秒推送一次。与首次订阅一样,推送全量数据,即推送所有币种(或ccy参数指定的币种)层面资产不为 0 的账户信息。 |
REST API
用户亦可以通过 REST API 查看币种层面资产不为 0 的账户余额:
REST API 亦提供可选参数ccy,支持单个币种(如BTC)或多个以逗号分隔的币种(如 BTC,JPY,ETH)查询,最多 20 个。
示例:
GET /api/v5/account/balance?ccy=BTC,JPY,ETH
当用户于ccy参数指定币种时,无论该币种层面资产是否为 0,REST API 均会返回该币种的数据,与 WebSocket 账户频道不同。这只适用于曾经持有的币种。
最大可用数量
用户可以轮询以下的 REST API 得知最大可用数量(包括可用余额和交易所的最大可借):
GET /api/v5/account/max-avail-size
BTC-JPY 全仓的请求和返回示例:
| 请求 | GET /api/v5/account/max-avail-size?instId=BTC-JPY&tdMode=cash |
| 成功返回 | { "code": "0", "data": [ { "availBuy": "213800.4239369798722052", "availSell": "1.3539405224369181", "instId": "BTC-JPY" } ], "msg": "" } |
币币的availBuy为计价货币,availSell为交易货币。
以上的返回结果表示 BTC-JPY 最大买入可用数量为 213,800.42 JPY,最大卖出可用数量为 1.35394052 BTC。这应与网页上交易时显示的数量一样。
最大可转余额
为了获得交易账户或是某个子账户的最大可转余额,用户可以通过 GET /api/v5/account/max-withdrawal 获取余额。
此端点返回的数据考虑了未偿还的贷款和使用中的保证金。
余额和持仓
当特定事件(如订单成交、资金转移)被触发时,数据将被推送。
账户余额和持仓频道适用于获取账户余额和仓位资产的变化。
如果用户拥有了太多货币,且数据太大以至于无法在单个推送中发送,它将被拆分为多个消息。
在账户余额和持仓发生变化时,与账户频道和持仓频道相比,此频道的字段较少,以便以最低延迟将更改推送给客户。
标识符
| 标识符 | 描述 |
|---|---|
| ordId | 订单ID,全局唯一 |
| clOrdId | 客户自定义订单ID,所有交易产品挂单维度唯一 |
| billId | 账单ID,全局唯一 |
| tradeId | 最新成交ID,交易产品维度唯一 在强平、自动减仓场景下,tradeId字段的值为负数,以便和其他撮合成交场景区分 |