Type/to search
Built-in Functions
Global
Version
Sleep
IsVirtual
Mail
Mail_Go
SetErrorFilter
GetPid
GetLastError
GetCommand
GetMeta
Dial
HttpQuery
HttpQuery_Go
Encode
UnixNano
Unix
GetOS
MD5
DBExec
UUID
EventLoop
__Serve
_G
_D
_N
_C
_Cross
JSON.parse
JSON.stringify
SetChannelData
GetChannelData
Log
Market
Trade
Account
Futures
NetSettings
Threads
threading
Thread
getThread
mainThread
currentThread
Lock
Condition
Event
Dict
pending
Thread
ThreadLock
ThreadEvent
ThreadCondition
ThreadDict
Web3
TA
Talib
talib.CDL2CROWS
talib.CDL3BLACKCROWS
talib.CDL3INSIDE
talib.CDL3LINESTRIKE
talib.CDL3OUTSIDE
talib.CDL3STARSINSOUTH
talib.CDL3WHITESOLDIERS
talib.CDLABANDONEDBABY
talib.CDLADVANCEBLOCK
talib.CDLBELTHOLD
talib.CDLBREAKAWAY
talib.CDLCLOSINGMARUBOZU
talib.CDLCONCEALBABYSWALL
talib.CDLCOUNTERATTACK
talib.CDLDARKCLOUDCOVER
talib.CDLDOJI
talib.CDLDOJISTAR
talib.CDLDRAGONFLYDOJI
talib.CDLENGULFING
talib.CDLEVENINGDOJISTAR
talib.CDLEVENINGSTAR
talib.CDLGAPSIDESIDEWHITE
talib.CDLGRAVESTONEDOJI
talib.CDLHAMMER
talib.CDLHANGINGMAN
talib.CDLHARAMI
talib.CDLHARAMICROSS
talib.CDLHIGHWAVE
talib.CDLHIKKAKE
talib.CDLHIKKAKEMOD
talib.CDLHOMINGPIGEON
talib.CDLIDENTICAL3CROWS
talib.CDLINNECK
talib.CDLINVERTEDHAMMER
talib.CDLKICKING
talib.CDLKICKINGBYLENGTH
talib.CDLLADDERBOTTOM
talib.CDLLONGLEGGEDDOJI
talib.CDLLONGLINE
talib.CDLMARUBOZU
talib.CDLMATCHINGLOW
talib.CDLMATHOLD
talib.CDLMORNINGDOJISTAR
talib.CDLMORNINGSTAR
talib.CDLONNECK
talib.CDLPIERCING
talib.CDLRICKSHAWMAN
talib.CDLRISEFALL3METHODS
talib.CDLSEPARATINGLINES
talib.CDLSHOOTINGSTAR
talib.CDLSHORTLINE
talib.CDLSPINNINGTOP
talib.CDLSTALLEDPATTERN
talib.CDLSTICKSANDWICH
talib.CDLTAKURI
talib.CDLTASUKIGAP
talib.CDLTHRUSTING
talib.CDLTRISTAR
talib.CDLUNIQUE3RIVER
talib.CDLUPSIDEGAP2CROWS
talib.CDLXSIDEGAP3METHODS
talib.AD
talib.ADOSC
talib.OBV
talib.ACOS
talib.ASIN
talib.ATAN
talib.CEIL
talib.COS
talib.COSH
talib.EXP
talib.FLOOR
talib.LN
talib.LOG10
talib.SIN
talib.SINH
talib.SQRT
talib.TAN
talib.TANH
talib.MAX
talib.MAXINDEX
talib.MIN
talib.MININDEX
talib.MINMAX
talib.MINMAXINDEX
talib.SUM
talib.HT_DCPERIOD
talib.HT_DCPHASE
talib.HT_PHASOR
talib.HT_SINE
talib.HT_TRENDMODE
talib.ATR
talib.NATR
talib.TRANGE
talib.BBANDS
talib.DEMA
talib.EMA
talib.HT_TRENDLINE
talib.KAMA
talib.MA
talib.MAMA
talib.MIDPOINT
talib.MIDPRICE
talib.SAR
talib.SAREXT
talib.SMA
talib.T3
talib.TEMA
talib.TRIMA
talib.WMA
talib.LINEARREG
talib.LINEARREG_ANGLE
talib.LINEARREG_INTERCEPT
talib.LINEARREG_SLOPE
talib.STDDEV
talib.TSF
talib.VAR
talib.ADX
talib.ADXR
talib.APO
talib.AROON
talib.AROONOSC
talib.BOP
talib.CCI
talib.CMO
talib.DX
talib.MACD
talib.MACDEXT
talib.MACDFIX
talib.MFI
talib.MINUS_DI
talib.MINUS_DM
talib.MOM
talib.PLUS_DI
talib.PLUS_DM
talib.PPO
talib.ROC
talib.ROCP
talib.ROCR
talib.ROCR100
talib.RSI
talib.STOCH
talib.STOCHF
talib.STOCHRSI
talib.TRIX
talib.ULTOSC
talib.WILLR
talib.AVGPRICE
talib.MEDPRICE
talib.TYPPRICE
talib.WCLPRICE
OS
Structures
Built-in Variables

Multi-threaded asynchronous support function that can convert the operations of all supported functions into asynchronous concurrent execution.

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

Examples

  • exchange.Go() function usage example. When checking for undefined, you must use typeof(xx) === "undefined", because null == undefined holds true in JavaScript.

    javascript
    function main(){ // The following four operations execute concurrently in asynchronous multi-threaded mode; they take no time and return immediately 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) // Call the wait method to wait for the result of the asynchronous ticker retrieval var ticker = a.wait() // Returns the depth data; it may also return null if the retrieval fails var depth = b.wait() // Returns the order ID with a 1-second timeout; returns undefined on timeout. If the previous wait timed out, this object can continue calling wait var orderId = c.wait(1000) if(typeof(orderId) == "undefined") { // Timed out, retrieve again 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() { // In Rust, exchange.Go uses a typed form: use the Go:: method token to specify the concurrent function; pass () for no arguments and a tuple for arguments // The following four operations execute concurrently in asynchronous multi-threaded mode; they take no time and return immediately let a = exchange.Go(Go::GetTicker, ()); let b = exchange.Go(Go::GetDepth, ()); // There is no Buy token in Rust; it is equivalent to CreateOrder, where the first argument "" indicates the current trading pair let c = exchange.Go(Go::CreateOrder, ("", "buy", 1000, 0.1)); let d = exchange.Go(Go::GetRecords, (PERIOD_H1,)); // Call the wait method to wait for the result of the asynchronous ticker retrieval; wait(0) blocks until the concurrent thread finishes running (corresponding to the parameterless wait() in JS) let ticker = a.wait(0); // Returns the depth data; it may also return Err if the retrieval fails let depth = b.wait(0); // Returns the order ID with a 1-second timeout; returns Err on timeout. If the previous wait timed out, this object can continue calling wait // Note: Err may also indicate that the order placement itself failed (indistinguishable from a timeout); in this case, calling wait again will return Err and log the error message let mut orderId = c.wait(1000); if orderId.is_err() { // Timed out, retrieve again orderId = c.wait(0); } let records = d.wait(0); }
    c++
    void main() { auto a = exchange.Go("GetTicker"); auto b = exchange.Go("GetDepth"); auto c = exchange.Go("Buy", 1000, 0.1); auto d = exchange.Go("GetRecords", PERIOD_H1); Ticker ticker; Depth depth; Records records; TId orderId; a.wait(ticker); b.wait(depth); if(!c.wait(orderId, 300)) { c.wait(orderId); } d.wait(records); }
  • Calling the wait() method on a released concurrent object will raise an error:

    javascript
    function main() { var d = exchange.Go("GetRecords", PERIOD_H1) // Wait for the K-line data results to return var records = d.wait() // Calling wait again here on an asynchronous operation that has already been waited on and finished will return null and log an error message var ret = d.wait() }
    python
    def main(): d = exchange.Go("GetRecords", PERIOD_H1) records, ok = d.wait() ret, ok = d.wait()
    rust
    fn main() { // In Rust, exchange.Go uses a typed syntax: specify the concurrent function via the Go:: method token let d = exchange.Go(Go::GetRecords, (PERIOD_H1,)); // Wait for the K-line data results to return; wait(0) blocks until execution completes (equivalent to JS's parameterless wait()) let records = d.wait(0); // Calling wait again here on an asynchronous operation that has already been waited on and finished will return Err and log an error message let ret = d.wait(0); }
    c++
    void main() { auto d = exchange.Go("GetRecords", PERIOD_H1); Records records; d.wait(records); Records ret; d.wait(ret); }
  • Concurrently retrieve market data from multiple exchanges:

    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: "Market Data", cols: ["Index", "Name", "Last Price"], 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": "Market Data", "cols": ["Index", "Name", "Last Price"], "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() { // In Rust, exchange.Go is a typed form; the token is Go::GetTicker arrRoutine.push(e.Go(Go::GetTicker, ())); arrName.push(e.GetName()); } // On failure, record None as a placeholder to stay index-aligned with arrName for r in arrRoutine.iter() { arrTicker.push(r.wait(0).ok()); } let endTS = UnixNano() / 1000000; // Rust has no built-in JSON serialization; use format! to assemble the table's JSON text 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": "Market Data", "cols": ["Index", "Name", "Last Price"], "rows": [{}]}}"#, rows); LogStatus!(_D(None), "Total time for concurrent ticker retrieval:", endTS - beginTS, "ms", "\n", format!("`{}`", tbl)); Sleep(500); } }
    c++
    void main() { while(true) { int length = exchanges.size(); auto beginTS = UnixNano() / 1000000; vector<Ticker> arrTicker(length); vector<string> arrName(length); // Note: run the exchanges[n].Go function once for each exchange object you add. This example requires adding four exchange objects; adjust as needed auto r0 = exchanges[0].Go("GetTicker"); auto r1 = exchanges[1].Go("GetTicker"); auto r2 = exchanges[2].Go("GetTicker"); auto r3 = exchanges[3].Go("GetTicker"); vector<GoObj*> arrRoutine = {&r0, &r1, &r2, &r3}; for(int i = 0; i < length; i++) { arrName[i] = exchanges[i].GetName(); } for(int i = 0; i < length; i++) { Ticker ticker; arrRoutine[i]->wait(ticker); arrTicker[i] = ticker; } auto endTS = UnixNano() / 1000000; json tbl = R"({ "type": "table", "title": "Market Data", "cols": ["Index", "Name", "Last Price"], "rows": [] })"_json; for(int i = 0; i < length; i++) { json arr = R"(["", "", ""])"_json; arr[0] = str_format("%d", i); arr[1] = arrName[i]; arr[2] = str_format("%f", arrTicker[i].Last); tbl["rows"].push_back(arr); } LogStatus(_D(), "Total time for concurrent ticker retrieval:", str_format("%d", endTS - beginTS), "ms", "\n", "`" + tbl.dump() + "`"); Sleep(500); } }
  • Concurrently call the exchange.IO("api", ...) function:

    javascript
    function main() { /* Test the OKX futures order placement endpoint 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() { /* Test the OKX futures order placement endpoint POST /api/v5/trade/order */ let beginTS = UnixNano() / 1000000; // Rust does not support JSON serialization, so construct the parameters directly using a raw string let param = r#"{"instId":"BTC-USDT-SWAP","tdMode":"cross","side":"buy","ordType":"limit","px":"16000","sz":"1","posSide":"long"}"#; // In Rust, exchange.Go uses a typed form: the token is Go::IO, and the parameters are passed as a tuple 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"); }
    c++
    void main() { auto beginTS = UnixNano() / 1000000; json param = R"({"instId":"BTC-USDT-SWAP","tdMode":"cross","side":"buy","ordType":"limit","px":"16000","sz":"1","posSide":"long"})"_json; auto ret1 = exchange.Go("IO", "api", "POST", "/api/v5/trade/order", "", param.dump()); auto ret2 = exchange.Go("IO", "api", "POST", "/api/v5/trade/order", "", param.dump()); auto ret3 = exchange.Go("IO", "api", "POST", "/api/v5/trade/order", "", param.dump()); json id1 = R"({})"_json; json id2 = R"({})"_json; json id3 = R"({})"_json; ret1.wait(id1); ret2.wait(id2); ret3.wait(id3); auto endTS = UnixNano() / 1000000; Log("id1:", id1); Log("id2:", id2); Log("id3:", id3); Log("Concurrent order time:", endTS - beginTS, "ms"); }
  • Testing the automatic release mechanism

    javascript
    function main() { var counter = 0 var arr = [] // Variables used to test persistently referencing concurrent objects 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) // Record the concurrent object, used to call the r.wait() function to get the result; cleared every loop iteration // arr.push(r) // If this line is used, the runtime will persistently reference the concurrent objects, preventing them from being automatically released; when the number of concurrent tasks exceeds 2000, it will report an error: ```InternalError: too many routine wait, max is 2000```. counter++ } // Iterate over arrRoutine and call r.wait() to get the results LogStatus(_D(), "routine number:", counter) Sleep(50) } }
    rust
    fn main() { let mut counter = 0; let mut arr: Vec<TypedRoutine<Go::GetTicker>> = Vec::new(); // Variables used to test persistently referencing concurrent objects let symbols = ["BTC_USDT", "ETH_USDT", "SOL_USDT", "LTC_USDT", "EOS_USDT"]; loop { let mut arrRoutine = Vec::new(); for symbol in symbols { // In Rust, exchange.Go uses a typed form, with the token being Go::GetTicker let r = exchange.Go(Go::GetTicker, (symbol,)); arrRoutine.push(r); // Record the concurrent object, used to call the r.wait(0) function to get the result; cleared every loop iteration // arr.push(r); // If this line is used, the runtime will persistently reference the concurrent objects, preventing them from being automatically released; when the number of concurrent tasks exceeds 2000, it will report an error: InternalError: too many routine wait, max is 2000. counter += 1; } // Iterate over arrRoutine and call r.wait(0) to get the results LogStatus!(_D(None), "routine number:", counter); Sleep(50); } }

Returns

TypeDescription

object

The exchange.Go() function immediately returns a concurrent object. You can use the wait() method of this concurrent object to obtain the result of the concurrent request.

Arguments

NameTypeRequiredDescription

method

string

Yes

The method parameter is used to specify the name of the function to be executed concurrently. Please note that this parameter is a function name string, not a function reference.

arg

string / number / bool / object / array / function / any (any type supported by the platform)

No

The parameters of the concurrent execution function. The arg parameter can appear multiple times. The type and number of the arg parameters depend on the parameter definition of the concurrent execution function.

See Also

Mail_Go HttpQuery_Go EventLoop exchange.IO (API rate limiting control)

Remarks

This function only creates multi-threaded execution tasks when running in live trading. Backtesting does not support multi-threaded concurrent execution of tasks (it can be used in backtesting, but is still executed sequentially).

After the exchange.Go() function returns an object, you can call its wait() function through that object to obtain the data returned by the thread. When the concurrent multi-threaded tasks have finished executing and the related variables are no longer referenced, the underlying system will automatically handle resource reclamation.

The wait() method supports a timeout parameter:

  1. Do not set the timeout parameter, i.e. wait(), or set the timeout parameter to 0, i.e. wait(0). In this case, the wait() function will block and wait until the concurrent thread finishes running, and return the execution result of the concurrent thread.

  2. Set the timeout parameter to -1, i.e. wait(-1). In this case, the wait() function will return immediately. The return value differs across programming languages; for details, please refer to the call examples in this section.

  3. Set a specific timeout parameter, i.e. wait(300). In this case, the wait() function will wait at most 300 milliseconds before returning.

Although the underlying system has an automatic reclamation mechanism, if the related variables are continuously referenced, the concurrent threads will not be released. When the number of concurrent threads exceeds 2000, an error will be reported: "too many routine wait, max is 2000".

Supported functions: GetTicker, GetDepth, GetTrades, GetRecords, GetAccount, GetOrders, GetOrder, CancelOrder, Buy, Sell, GetPositions, IO, etc. When these functions are called concurrently, they are all executed based on the current exchange exchange object.

The difference between the Python language and the JavaScript language is that in Python, the wait() function of a concurrent object returns two values: the first is the result returned by the asynchronous API call, and the second indicates whether the asynchronous call is completed.

python
def main(): d = exchange.Go("GetRecords", PERIOD_D1) # ok is guaranteed to return True, unless the strategy is stopped ret, ok = d.wait() # If the wait times out, or you wait on an instance that has already finished, ok returns False ret, ok = d.wait(100)