输入/搜索内容
内置函数
Global
Log
Market
Trade
Account
Futures
Exchange
IO
Network
Storage
Threads
exchange.Go
EventLoop
ctx.subscribe
ctx.poll
ctx.order
ctx.cancel
ctx.orderAsync
ctx.cancelAsync
Subscription
threading
Thread
ThreadLock
ThreadEvent
ThreadCondition
ThreadDict
Server
TA
Talib
OS
结构体
内置变量与常量
通用约定
交易所

多线程异步支持函数,可以把所有支持的函数的操作变成异步并发执行。

exchange.Go(method)
exchange.Go(method, ...args)

示例

  • exchange.Go()函数使用范例,判断undefined要用typeof(xx) === "undefined",因为null == undefined在JavaScript里是成立的。

    javascript
    function main(){ // 以下四种操作是并发多线程异步执行, 不会耗时, 立即返回的 var a = exchange.Go("GetTicker") var b = exchange.Go("GetDepth") var c = exchange.Go("Buy", 1000, 0.1) var d = exchange.Go("GetRecords", PERIOD_H1) // 调用wait方法等待返回异步获取ticker结果 var ticker = a.wait() // 返回深度, 如果获取失败也是有可能返回null的 var depth = b.wait() // 返回订单号, 限定1秒超时, 超时返回undefined, 此对象可以继续调用wait等待如果上次wait超时 var orderId = c.wait(1000) if(typeof(orderId) == "undefined") { // 超时,重新获取 orderId = c.wait() } var records = d.wait() }
    python
    def main(): a = exchange.Go("GetTicker") b = exchange.Go("GetDepth") c = exchange.Go("Buy", 1000, 0.1) d = exchange.Go("GetRecords", PERIOD_H1) ticker, ok = a.wait() depth, ok = b.wait() orderId, ok = c.wait(1000) if ok == False: orderId, ok = c.wait() records, ok = d.wait()
    rust
    fn main() { // Rust中exchange.Go为类型化写法:用Go::方法token指定并发函数,无参传(),有参传元组 // 以下四种操作是并发多线程异步执行, 不会耗时, 立即返回的 let a = exchange.Go(Go::GetTicker, ()); let b = exchange.Go(Go::GetDepth, ()); // Rust中没有Buy的token,等价于CreateOrder,第一个参数""表示当前交易对 let c = exchange.Go(Go::CreateOrder, ("", "buy", 1000, 0.1)); let d = exchange.Go(Go::GetRecords, ("", PERIOD_H1)); // 参数依次为交易对(""表示当前交易对)、K线周期 // 调用wait方法等待返回异步获取ticker结果,wait(0)阻塞直到并发线程运行完毕(对应JS的无参wait()) let ticker = a.wait(0); // 返回深度, 如果获取失败也是有可能返回Err的 let depth = b.wait(0); // 返回订单号, 限定1秒超时, 超时返回Err, 此对象可以继续调用wait等待如果上次wait超时 // 注意:Err也可能是下单本身失败(超时的错误信息为routine N not finished);下单失败时结果已被取走,再次wait会返回Err(routine N already finished) let mut orderId = c.wait(1000); if orderId.is_err() { // 超时,重新获取 orderId = c.wait(0); } let records = d.wait(0); }
  • 对已经释放的并发对象,调用其wait()方法会报错。

    javascript
    function main() { var d = exchange.Go("GetRecords", PERIOD_H1) // 等待K线结果 var records = d.wait() // 这里wait了一个已经wait过且结束的异步操作,会抛出异常:routine N already finished var ret = d.wait() }
    python
    def main(): d = exchange.Go("GetRecords", PERIOD_H1) records, ok = d.wait() ret, ok = d.wait()
    rust
    fn main() { // Rust中exchange.Go为类型化写法:用Go::方法token指定并发函数 let d = exchange.Go(Go::GetRecords, ("", PERIOD_H1)); // 参数依次为交易对(""表示当前交易对)、K线周期 // 等待K线结果,wait(0)阻塞直到运行完毕(对应JS的无参wait()) let records = d.wait(0); // 这里wait了一个已经wait过且结束的异步操作,会返回Err(routine N already finished) let ret = d.wait(0); }
  • 并发获取多个交易所行情。

    javascript
    function main() { while(true) { var beginTS = new Date().getTime() var arrRoutine = [] var arrTicker = [] var arrName = [] for(var i = 0; i < exchanges.length; i++) { arrRoutine.push(exchanges[i].Go("GetTicker")) arrName.push(exchanges[i].GetName()) } for(var i = 0; i < arrRoutine.length; i++) { arrTicker.push(arrRoutine[i].wait()) } var endTS = new Date().getTime() var tbl = { type: "table", title: "行情", cols: ["索引", "名称", "最新成交价"], rows: [] } for(var i = 0; i < arrTicker.length; i++) { tbl.rows.push([i, arrName[i], arrTicker[i].Last]) } LogStatus(_D(), "Total time for concurrent ticker retrieval:", endTS - beginTS, "ms", "\n", "`" + JSON.stringify(tbl) + "`") Sleep(500) } }
    python
    import time import json def main(): while True: beginTS = time.time() arrRoutine = [] arrTicker = [] arrName = [] for i in range(len(exchanges)): arrRoutine.append(exchanges[i].Go("GetTicker")) arrName.append(exchanges[i].GetName()) for i in range(len(exchanges)): ticker, ok = arrRoutine[i].wait() arrTicker.append(ticker) endTS = time.time() tbl = { "type": "table", "title": "行情", "cols": ["索引", "名称", "最新成交价"], "rows": [] } for i in range(len(arrTicker)): tbl["rows"].append([i, arrName[i], arrTicker[i]["Last"]]) LogStatus(_D(), "Total time for concurrent ticker retrieval:", endTS - beginTS, "seconds", "\n", "`" + json.dumps(tbl) + "`") Sleep(500)
    rust
    fn main() { loop { let beginTS = UnixNano() / 1000000; let mut arrRoutine = Vec::new(); let mut arrTicker = Vec::new(); let mut arrName = Vec::new(); for e in exchanges.iter() { // Rust中exchange.Go为类型化写法,token为Go::GetTicker arrRoutine.push(e.Go(Go::GetTicker, ())); arrName.push(e.GetName()); } // 失败时记None占位,保持与arrName按索引对齐 for r in arrRoutine.iter() { arrTicker.push(r.wait(0).ok()); } let endTS = UnixNano() / 1000000; // Rust无JSON序列化,用format!拼接表格的JSON文本 let mut rows = String::new(); for i in 0..arrTicker.len() { if let Some(ticker) = &arrTicker[i] { if !rows.is_empty() { rows.push(','); } rows += &format!(r#"[{}, "{}", {}]"#, i, arrName[i], ticker.Last); } } let tbl = format!(r#"{{"type": "table", "title": "行情", "cols": ["索引", "名称", "最新成交价"], "rows": [{}]}}"#, rows); LogStatus!(_D(None), "Total time for concurrent ticker retrieval:", endTS - beginTS, "ms", "\n", format!("`{}`", tbl)); Sleep(500); } }
  • 对exchange.IO("api", ...)函数并发调用。

    javascript
    function main() { /* 使用OKX期货下单接口测试 POST /api/v5/trade/order */ var beginTS = new Date().getTime() var param = {"instId":"BTC-USDT-SWAP","tdMode":"cross","side":"buy","ordType":"limit","px":"16000","sz":"1","posSide":"long"} var ret1 = exchange.Go("IO", "api", "POST", "/api/v5/trade/order", "", JSON.stringify(param)) var ret2 = exchange.Go("IO", "api", "POST", "/api/v5/trade/order", "", JSON.stringify(param)) var ret3 = exchange.Go("IO", "api", "POST", "/api/v5/trade/order", "", JSON.stringify(param)) var id1 = ret1.wait() var id2 = ret2.wait() var id3 = ret3.wait() var endTS = new Date().getTime() Log("id1:", id1) Log("id2:", id2) Log("id3:", id3) Log("Concurrent order time:", endTS - beginTS, "ms") }
    python
    import time import json def main(): beginTS = time.time() param = {"instId":"BTC-USDT-SWAP","tdMode":"cross","side":"buy","ordType":"limit","px":"16000","sz":"1","posSide":"long"} ret1 = exchange.Go("IO", "api", "POST", "/api/v5/trade/order", "", json.dumps(param)) ret2 = exchange.Go("IO", "api", "POST", "/api/v5/trade/order", "", json.dumps(param)) ret3 = exchange.Go("IO", "api", "POST", "/api/v5/trade/order", "", json.dumps(param)) id1, ok1 = ret1.wait() id2, ok2 = ret2.wait() id3, ok3 = ret3.wait() endTS = time.time() Log("id1:", id1) Log("id2:", id2) Log("id3:", id3) Log("Concurrent order time:", endTS - beginTS, "seconds")
    rust
    fn main() { /* 使用OKX期货下单接口测试 POST /api/v5/trade/order */ let beginTS = UnixNano() / 1000000; // Rust无JSON序列化,直接用原始字符串构造参数 let param = r#"{"instId":"BTC-USDT-SWAP","tdMode":"cross","side":"buy","ordType":"limit","px":"16000","sz":"1","posSide":"long"}"#; // Rust中exchange.Go为类型化写法,token为Go::IO,参数以元组传入 let ret1 = exchange.Go(Go::IO, ("api", "POST", "/api/v5/trade/order", "", param)); let ret2 = exchange.Go(Go::IO, ("api", "POST", "/api/v5/trade/order", "", param)); let ret3 = exchange.Go(Go::IO, ("api", "POST", "/api/v5/trade/order", "", param)); let id1 = ret1.wait(0); let id2 = ret2.wait(0); let id3 = ret3.wait(0); let endTS = UnixNano() / 1000000; Log!("id1:", id1); Log!("id2:", id2); Log!("id3:", id3); Log!("Concurrent order time:", endTS - beginTS, "ms"); }
  • 针对自动释放机制的测试

    javascript
    function main() { var counter = 0 var arr = [] // 用于测试持续引用并发的相关变量 var symbols = ["BTC_USDT", "ETH_USDT", "SOL_USDT", "LTC_USDT", "EOS_USDT"] while (true) { var arrRoutine = [] for (var symbol of symbols) { var r = exchange.Go("GetTicker", symbol) arrRoutine.push(r) // 记录并发对象用于调用 r.wait() 函数获取结果,每一轮循环都清空 // arr.push(r) // 如果使用这句代码,运行时持续引用并发的对象,无法自动释放;未取结果的并发任务达到2000个后,再调用exchange.Go()会报错:too many routine wait, max is 2000 counter++ } // 遍历 arrRoutine 调用 r.wait() LogStatus(_D(), "routine number:", counter) Sleep(50) } }
    rust
    fn main() { let mut counter = 0; let mut arr: Vec<TypedRoutine<Go::GetTicker>> = Vec::new(); // 用于测试持续引用并发的相关变量 let symbols = ["BTC_USDT", "ETH_USDT", "SOL_USDT", "LTC_USDT", "EOS_USDT"]; loop { let mut arrRoutine = Vec::new(); for symbol in symbols { // Rust中exchange.Go为类型化写法,token为Go::GetTicker let r = exchange.Go(Go::GetTicker, (symbol,)); arrRoutine.push(r); // 记录并发对象用于调用 r.wait(0) 函数获取结果,每一轮循环都清空 // arr.push(r); // 如果使用这句代码,运行时持续引用并发的对象,无法自动释放;未取结果的并发任务达到2000个后,再调用exchange.Go()会报错:too many routine wait, max is 2000 counter += 1; } // 遍历 arrRoutine 调用 r.wait(0) LogStatus!(_D(None), "routine number:", counter); Sleep(50); } }

返回值

类型描述

object

立即返回一个并发对象,用它的wait()方法取得并发调用的结果,见exchange.Go-return。

参数

名称类型必填描述

method

string

是

并发的函数名称,注意该参数是函数名称字符串,并非函数引用。

arg

string / number / bool / object / array / function / any

否

并发执行函数的参数,参数arg可能有多个。参数arg的类型与个数根据并发执行函数的参数而定。

参考

备注

该函数只在实盘运行时创建多线程执行任务,回测不支持多线程并发执行任务(回测可用,但是还是顺序执行)。

并发对象wait()方法的超时参数,以及各语言在完成、超时、重复调用时的返回值,见exchange.Go-return。Python中wait()返回(结果, 是否成功)两个值。

虽然系统底层有自动回收机制,但是如果持续引用相关变量,并发任务的结果并不会释放。未取结果的并发任务达到2000个时,再调用exchange.Go()提交新任务会当场报错:"too many routine wait, max is 2000",该任务不会执行。

支持的函数:GetTicker,GetDepth,GetTrades,GetRecords,GetAccount,GetOrders,GetOrder,CancelOrder,Buy,Sell,GetPositions,IO等。这些函数并发调用时都基于当前exchange交易所对象执行。