ctx.orderAsync
异步下单:立即返回请求号,不等待交易所应答。下单结果以一条应答事件(kind为20)投递给发起请求的线程,可通过ctx.poll取出。参数与ctx.order相同,适用于同时发出多笔订单,或下单时不阻塞行情处理的场景。
ctx.orderAsync(ex, symbol, side, px, qty)
ctx.orderAsync(ex, symbol, side, px, qty, options)示例
异步并发挂出三档限价买单,按请求号收集下单应答,并输出每笔订单的结果与耗时。
javascript
function main() {
var t = exchange.GetTicker("BTC_USDT")
if (!t) {
return
}
var pending = {}
for (var i = 1; i <= 3; i++) {
var px = _N(t.Buy * (1 - 0.01 * i), 2)
var req = ctx.orderAsync(exchange, "BTC_USDT", "buy", px, 0.001,
{via: "ws", postOnly: true})
if (req instanceof Error) {
Log("not sent:", req.message) // 调用即失败,不会收到应答
continue
}
pending[req] = px
}
while (Object.keys(pending).length > 0) {
var ack = ctx.poll([ctx.STREAM_ORDER_ACK], 10000)
if (!ack) {
Log("no ack in 10 seconds")
break
}
if (ack.kind !== 20) {
continue
}
if (ack.ok) {
Log("placed", ack.id, "px:", pending[ack.reqId], ack.via, ack.latencyMs, "ms")
} else if (ack.status === "unknown") {
Log("state unknown, check the order by clientId", ack.clientId) // 切勿重发
} else {
Log("failed:", ack.error, ack.reasonText)
}
delete pending[ack.reqId]
}
}
python
def main():
t = exchange.GetTicker("BTC_USDT")
if not t:
return
pending = {}
for i in range(1, 4):
px = _N(t["Buy"] * (1 - 0.01 * i), 2)
opts = {"via": "ws", "postOnly": True}
req = ctx.orderAsync(exchange, "BTC_USDT", "buy", px, 0.001, opts)
if isinstance(req, CtxError):
Log("not sent:", req) # 调用即失败,不会收到应答
continue
pending[req] = px
while pending:
ack = ctx.poll([ctx.STREAM_ORDER_ACK], 10000)
if ack is None:
Log("no ack in 10 seconds")
break
if ack.kind != 20:
continue
if ack.ok:
Log("placed", ack.id, "px:", pending.get(ack.reqId), ack.via, ack.latencyMs, "ms")
elif ack.status == "unknown":
Log("state unknown, check the order by clientId", ack.clientId) # 切勿重发
else:
Log("failed:", ack.error, ack.reasonText)
pending.pop(ack.reqId, None)
rust
use sdk::ctx::EventExt;
use std::collections::HashMap;
fn main() {
let Ok(t) = exchange.GetTicker("BTC_USDT") else { return };
let mut pending: HashMap<u64, f64> = HashMap::new();
for i in 1..=3 {
let px = _N(t.Buy * (1.0 - 0.01 * i as f64), 2);
let opts = r#"{"via":"ws","postOnly":true}"#;
match ctx::order_async(exchange, "BTC_USDT", "buy", px, 0.001, opts) {
Ok(req) => {
pending.insert(req, px);
}
Err(e) => Log!("not sent:", e), // 调用即失败,不会收到应答
}
}
while !pending.is_empty() {
match ctx::poll(&[ctx::STREAM_ORDER_ACK], Some(10000)) {
ctx::Polled::Event(ev) => {
let Some(ack) = ev.order_ack() else { continue };
if ack.ok {
Log!("placed", ack.id, ack.via, ack.latency_ms, "ms");
} else if ack.status == "unknown" {
Log!("state unknown, check the order by clientId", ack.client_id); // 切勿重发
} else {
Log!("failed:", ack.error, ack.reason_text);
}
pending.remove(&ack.req_id);
}
ctx::Polled::Empty => {
Log!("no ack in 10 seconds");
break;
}
ctx::Polled::Stopped => break,
_ => {}
}
}
}返回值
| 类型 | 描述 |
number / object | 请求号,与应答事件中的 |
参数
| 名称 | 类型 | 必填 | 描述 |
ex | object / number | 是 | 下单账户:可传入交易所对象,或该账户在 |
symbol | string | 是 | 交易品种代码,例如 |
side | string | 是 | 交易方向: |
px | number | 是 | 委托价格。市价单不使用该价格,可传入 |
qty | number | 是 | 委托数量,必须大于 |
options | object | 否 | 下单选项,字段与 |
参考
备注
应答事件(kind为20,type与channel均为ack)位于内置事件流ctx.STREAM_ORDER_ACK上,只投递给调用ctx.orderAsync()的线程,其他线程无法获取,也无需订阅。ctx.poll([ctx.STREAM_ORDER_ACK], timeout)只获取应答,ctx.poll([], timeout)则将应答与已订阅的事件一并获取。除公共字段外,还包含以下字段:
| 字段 | 类型 | 说明 |
|---|---|---|
| reqId | number | 请求号,即ctx.orderAsync()、ctx.cancelAsync()的返回值 |
| op | string | place(下单)或cancel(撤单) |
| status | string | ok表示成功,failed表示失败(拒单、限频、参数错误或调用失败),unknown表示状态未知(见下文) |
| ok | bool | status为ok时为true |
| via | string | 实际使用的通道:ws或rest(WebSocket在请求发出前不可用、转而使用REST时为rest) |
| id | string | 交易所订单号:下单成功时为新订单号,撤单时为目标订单号;下单失败时为空字符串 |
| clientId | string | 客户端订单号:WebSocket下单时必定存在;REST下单仅在指定了clientId时存在 |
| error | string | 失败原因,成功时为空字符串;最长119字节,完整原因请通过同步接口ctx.order获取 |
| reason | number | 统一原因码:0无,1请求错误,2凭据错误,3传输错误或未知,4交易所拒绝,5限频 |
| reasonText | string | reason的文字说明 |
| exchTime | number | 交易所应答时间(毫秒);交易所未提供时(例如REST应答)为空值 |
| latencyMs | number | 从调用ctx.orderAsync()到获得结果的耗时(毫秒) |
symbol、ex分别为请求中的品种与账户索引;time为交易所应答时间,若无则与ts相同。
status为unknown表示请求已通过WebSocket发出,但未等到应答,且按客户端订单号查询一次后仍无法确认。订单可能已提交到交易所:请勿重发,应按clientId查询订单,或等待私有流的订单回报进行确认。WebSocket下单的其他规则(不支持时返回错误、请求发出前连接不可用时改用REST、限频)与ctx.order相同。
异步与通道无关:不传via时,同样通过REST接口下单。同时发出的请求互不排队,应答按完成顺序到达,不一定与调用顺序一致;如需先下单再撤单,应等收到下单应答后再撤单。请求在托管者的后台线程上执行,限频规则照常生效,但不会阻塞调用线程。
主线程和threading.Thread()创建的线程均可调用,每个线程只会收到自己所发请求的应答。应答事件不会因读取不及时而被丢弃,需持续调用ctx.poll()将其取走。
Python中为ctx.orderAsync(ex, symbol, side, px, qty, opts=None),返回请求号(int)或CtxError对象,应答事件为字典,字段同上。Rust中为ctx::order_async(ex, symbol, side, px, qty, opts_json: &str) -> Result<u64, String>,应答事件通过ev.order_ack()读取(OrderAckView:req_id、op、status、ok、via、id、client_id、symbol、error、reason、reason_text、exch_time(Option<i64>)、latency_ms、time),事件流ID为ctx::STREAM_ORDER_ACK。