ctx.order
下单,并在交易所返回订单号后返回。默认通过交易所的REST接口下单;选项via设为ws时,通过交易所的WebSocket交易接口下单。订单后续的状态变化和成交情况由ctx.subscribe订阅的private私有流推送。调用前无需先订阅;主线程和threading.Thread()创建的线程均可调用。不等待结果的版本为ctx.orderAsync。
ctx.order(ex, symbol, side, px, qty)
ctx.order(ex, symbol, side, px, qty, options)示例
-
以比买一价低1%的价格挂出一张只做maker的限价买单,5秒后撤单;下单或撤单失败时均返回错误对象,而不抛出异常。
javascriptfunction main() { var t = exchange.GetTicker("BTC_USDT") if (!t) { return } var id = ctx.order(exchange, "BTC_USDT", "buy", _N(t.Buy * 0.99, 2), 0.001, {postOnly: true}) if (id instanceof Error) { Log("order failed:", id.message) return } Log("order id:", id) Sleep(5000) var r = ctx.cancel(exchange, "BTC_USDT", id) if (r instanceof Error) { Log("cancel failed:", r.message) // 例如订单已成交 } }pythondef main(): t = exchange.GetTicker("BTC_USDT") if not t: return oid = ctx.order(exchange, "BTC_USDT", "buy", _N(t["Buy"] * 0.99, 2), 0.001, {"postOnly": True}) if isinstance(oid, CtxError): Log("order failed:", oid) return Log("order id:", oid) Sleep(5000) r = ctx.cancel(exchange, "BTC_USDT", oid) if isinstance(r, CtxError): Log("cancel failed:", r) # 例如订单已成交rustfn main() { let Ok(t) = exchange.GetTicker("BTC_USDT") else { return }; // 选项以JSON字符串形式传入,无选项时传"{}" let px = _N(t.Buy * 0.99, 2); let id = match ctx::order(exchange, "BTC_USDT", "buy", px, 0.001, r#"{"postOnly":true}"#) { Ok(id) => id, Err(e) => { Log!("order failed:", e); return; } }; Log!("order id:", id); Sleep(5000); if let Err(e) = ctx::cancel(exchange, "BTC_USDT", &id) { Log!("cancel failed:", e); // 例如订单已成交 } } -
通过WebSocket下一张IOC买单并指定客户端订单号,再从私有流接收该订单的成交回报和最终状态;若订单状态未知,不要重新下单,应按客户端订单号核对订单。
javascriptfunction main() { var acct = ctx.subscribe(exchange, {channel: "private"}) var t = exchange.GetTicker("BTC_USDT") if (!t) { return } var cid = "demo" + Date.now() var px = _N(t.Sell * 1.001, 2) var id = ctx.order(exchange, "BTC_USDT", "buy", px, 0.001, {via: "ws", tif: "ioc", clientId: cid}) if (id instanceof Error) { if (id.message.indexOf("order state unknown") === 0) { Log("state unknown, check the order by clientId", cid) // 不要重复下单 } else { Log("order failed:", id.message) } return } var t0 = Date.now() while (Date.now() - t0 < 10000) { var ev = ctx.poll([acct], 1000) if (!ev) { continue } if (ev.kind === 19 && ev.orderId === id) { Log("fill", ev.tradeId, ev.px, ev.qty, ev.liquidity, "fee:", ev.fee, ev.feeCcy) } else if (ev.kind === 16 && ev.id === id) { if (ev.state === "filled" || ev.state === "canceled") { Log("order done:", ev.state, "filled:", ev.filledQty, "avgPx:", ev.avgPx) break } } } }pythonimport time def main(): acct = ctx.subscribe(exchange, {"channel": "private"}) t = exchange.GetTicker("BTC_USDT") if not t: return cid = "demo%d" % int(time.time() * 1000) opts = {"via": "ws", "tif": "ioc", "clientId": cid} oid = ctx.order(exchange, "BTC_USDT", "buy", _N(t["Sell"] * 1.001, 2), 0.001, opts) if isinstance(oid, CtxError): if str(oid).startswith("order state unknown"): Log("state unknown, check the order by clientId", cid) # 不要重复下单 else: Log("order failed:", oid) return t0 = time.time() while time.time() - t0 < 10: ev = ctx.poll([acct], 1000) if ev is None: continue if ev.kind == 19 and ev.orderId == oid: Log("fill", ev.tradeId, ev.px, ev.qty, ev.liquidity, "fee:", ev.get("fee"), ev.feeCcy) elif ev.kind == 16 and ev.id == oid and ev.state in ("filled", "canceled"): Log("order done:", ev.state, "filled:", ev.filledQty, "avgPx:", ev.avgPx) breakrustuse sdk::ctx::EventExt; fn main() { let acct = ctx::subscribe(exchange, ctx::SubOpts::private()).unwrap(); let Ok(t) = exchange.GetTicker("BTC_USDT") else { return }; let cid = format!("demo{}", UnixNano() / 1_000_000); let opts = format!(r#"{{"via":"ws","tif":"ioc","clientId":"{}"}}"#, cid); let id = match ctx::order(exchange, "BTC_USDT", "buy", _N(t.Sell * 1.001, 2), 0.001, &opts) { Ok(id) => id, Err(e) if e.contains("order state unknown") => { Log!("state unknown, check the order by clientId", cid); // 不要重复下单 return; } Err(e) => { Log!("order failed:", e); return; } }; let t0 = Unix(); while Unix() - t0 < 10 { match ctx::poll(&[acct.id()], Some(1000)) { ctx::Polled::Event(ev) => { if let Some(f) = ev.fill().filter(|f| f.order_id == id) { let fee = format!("{:?}", f.fee); // None:交易所未提供手续费 Log!("fill", f.trade_id, f.px, f.qty, f.liquidity, "fee:", fee, f.fee_ccy); } else if let Some(o) = ev.order().filter(|o| o.id == id) { if o.state == "filled" || o.state == "canceled" { Log!("order done:", o.state, "filled:", o.filled_qty, "avgPx:", o.avg_px); break; } } } ctx::Polled::Stopped => break, _ => {} } } }
返回值
| 类型 | 描述 |
string / object | 成功时返回交易所的订单号,与私有流订单回报中的 |
参数
| 名称 | 类型 | 必填 | 描述 |
ex | object / number | 是 | 下单账户:交易所对象( |
symbol | string | 是 | 品种代码,例如 |
side | string | 是 | 交易方向: |
px | number | 是 | 委托价格。市价单不使用该参数,可传入 |
qty | number | 是 | 委托数量,必须大于 |
options | object | 否 | 下单选项 |
参考
备注
options支持的字段:
| 字段 | 说明 |
|---|---|
| type | 订单类型:limit(默认,限价单)、market(市价单) |
| tif | 有效期类型:gtc(默认)、ioc、fak、fok、postOnly |
| reduceOnly | 是否只减仓,默认false |
| postOnly | 是否只做maker,默认false |
| extra | 交易所专属参数,原样透传给交易所 |
| clientId | 客户端订单号,原样透传给交易所,最长64字节。通过WebSocket下单且未指定时,按交易所要求的格式自动生成 |
| via | 下单通道:rest(默认)、ws(交易所的WebSocket交易接口) |
| timeout | 等待交易所应答的超时时间(毫秒),不传或传0时使用默认值 |
options只接受上表所列字段:包含未知字段(例如拼写错误的reduceonly)时不会下单,而是返回错误,不会忽略该字段。条件单与改单不使用本函数,请参见exchange.CreateConditionOrder、exchange.ModifyOrder。
失败时不抛出异常,一律通过返回值报告:参数有误、交易所拒单、触发限频或网络失败时均返回Error对象,绝不会返回虚假的订单号。使用返回值前,请先用instanceof Error判断。
via为ws时,通过交易所的WebSocket交易接口下单:
- 仅支持WebSocket下单的交易所可用,目前包括币安现货与U本位合约、OKX现货与合约、Bybit现货与合约(模拟盘不支持)、Gate.io现货与永续合约、Bitget现货与合约,具体以各交易所页面的说明为准。不支持的交易所返回错误,不会自动改用REST接口下单。
- 每个账户使用一条独立的交易连接,在首次WebSocket下单时建立。每笔WebSocket订单都携带客户端订单号,未指定
clientId时自动生成。 - 若请求发出前交易连接不可用(未连接或未登录),自动改用REST接口下单。
- 若请求发出后未收到应答(超时、连接中途断开或交易所返回执行状态未知),会按客户端订单号查询一次订单,查到即视为成功;仍无法确认时,返回
message以order state unknown (clientId ...)开头的错误。此时订单可能已提交到交易所:不要重复下单,应按客户端订单号查询订单,或等待私有流的订单回报确认。 - 交易所的下单频率限额通常与REST接口共用;超出限额时直接返回限频错误,不会排队等待,也不会改用REST接口。
调用会阻塞当前线程,直到收到交易所的应答(一次往返)。如需同时发出多笔订单,或不希望阻塞等待,请使用ctx.orderAsync。下单前无需订阅;如需接收订单状态变化和成交信息,请用ctx.subscribe订阅private频道,订单回报(kind为16)和成交回报(kind为19)的字段说明见ctx.poll。
在Python中为ctx.order(ex, symbol, side, px, qty, opts=None),opts为字典,字段相同;成功时返回订单号字符串,失败时返回CtxError对象(不抛出异常),可用isinstance(r, CtxError)判断。在Rust中为ctx::order(ex, symbol: &str, side: &str, px: f64, qty: f64, opts_json: &str) -> Result<String, String>,选项以JSON字符串传入(例如r#"{"via":"ws"}"#),无选项时传"{}";失败时返回Err,不会panic。