ctx.orderAsync
Asynchronous order placement: returns a request ID immediately without waiting for the exchange's response. The order result is delivered as a response event (kind is 20) to the thread that sent the request, and can be retrieved with ctx.poll. The parameters are the same as for ctx.order. Use it to send several orders at once, or to place orders without blocking market data processing.
ctx.orderAsync(ex, symbol, side, px, qty)
ctx.orderAsync(ex, symbol, side, px, qty, options)Examples
Asynchronously and concurrently place three tiers of limit buy orders, collect the order acks by request ID, and output the result and latency of each order.
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) // The call failed immediately; no ack will be received
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) // Never resend
} 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) # The call failed immediately; no ack will be received
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) # Never resend
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), // The call failed immediately; no ack will be received
}
}
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); // Never resend
} 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,
_ => {}
}
}
}Returns
| Type | Description |
number / object | The request ID, which matches the |
Arguments
| Name | Type | Required | Description |
ex | object / number | Yes | The account that places the order: either an exchange object or the index of that account in the |
symbol | string | Yes | Trading symbol code, for example |
side | string | Yes | Order side: |
px | number | Yes | Order price. Market orders do not use this price, so |
qty | number | Yes | Order quantity. It must be greater than |
options | object | No | Order options, with the same fields as |
See Also
Remarks
The acknowledgement event (kind is 20, both type and channel are ack) is delivered on the built-in event stream ctx.STREAM_ORDER_ACK. It goes only to the thread that called ctx.orderAsync(). Other threads cannot receive it and do not need to subscribe to it. ctx.poll([ctx.STREAM_ORDER_ACK], timeout) retrieves only acknowledgements, while ctx.poll([], timeout) retrieves acknowledgements together with the subscribed events. Besides the common fields, it contains the following fields:
| Field | Type | Description |
|---|---|---|
| reqId | number | Request ID, i.e. the return value of ctx.orderAsync() or ctx.cancelAsync() |
| op | string | place (order placement) or cancel (order cancellation) |
| status | string | ok means success, failed means failure (order rejected, rate limited, invalid parameters or call failure), unknown means the status is unknown (see below) |
| ok | bool | true when status is ok |
| via | string | The channel actually used: ws or rest (rest when WebSocket was unavailable before the request was sent and REST was used instead) |
| id | string | Exchange order ID: the new order ID when placement succeeds, the target order ID for a cancellation; an empty string when placement fails |
| clientId | string | Client order ID: always present for WebSocket orders; for REST orders, present only when clientId was specified |
| error | string | Failure reason, an empty string on success; at most 119 bytes. Use the synchronous interface ctx.order to get the full reason |
| reason | number | Unified reason code: 0 none, 1 request error, 2 credential error, 3 transport error or unknown, 4 rejected by exchange, 5 rate limited |
| reasonText | string | Text description of reason |
| exchTime | number | Exchange acknowledgement time (milliseconds); null when the exchange does not provide it (e.g. REST acknowledgements) |
| latencyMs | number | Time elapsed from calling ctx.orderAsync() to receiving the result (milliseconds) |
symbol and ex are the symbol and account index in the request. time is the exchange acknowledgement time. If that is not available, it equals ts.
A status of unknown means the request was sent over WebSocket but no acknowledgement arrived, and one query by client order ID still could not confirm the result. The order may already have been submitted to the exchange. Do not resend it. Instead, query the order by clientId, or wait for the order report on the private stream to confirm it. The other rules for WebSocket order placement are the same as ctx.order: an error is returned when WebSocket is not supported, REST is used when the connection is unavailable before the request is sent, and rate limits apply.
Asynchronous mode does not depend on the channel: when via is not passed, the order is still placed through the REST interface. Requests sent at the same time do not queue behind each other. Acknowledgements arrive in order of completion, which is not necessarily the order of the calls. If you need to place an order and then cancel it, wait for the placement acknowledgement before cancelling. Requests run on a background thread of the docker. Rate-limit rules still apply, but the calling thread is not blocked.
Both the main thread and threads created by threading.Thread() can call it, and each thread receives only the acknowledgements for its own requests. Acknowledgement events are not dropped when they are not read promptly. You must keep calling ctx.poll() to take them.
In Python the call is ctx.orderAsync(ex, symbol, side, px, qty, opts=None). It returns a request ID (int) or a CtxError object, and the acknowledgement event is a dictionary with the same fields as above. In Rust the call is ctx::order_async(ex, symbol, side, px, qty, opts_json: &str) -> Result<u64, String>. The acknowledgement event is read through 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), and the event stream ID is ctx::STREAM_ORDER_ACK.