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

Returns the current system version number.

Version()

Examples

javascript
function main() { Log("version:", Version()) }
python
def main(): Log("version:", Version())
c++
void main() { Log("version:", Version()); }

Returns

TypeDescription

string

Current system version number, for example: 3.6.

Remarks

The system version number is the version number of the docker program.

Sleep function, used to pause program execution for a specified time.

Sleep(millisecond)

Examples

javascript
function main() { Sleep(1000 * 10) // Wait for 10 seconds Log("Waited for 10 seconds") }
python
def main(): Sleep(1000 * 10) Log("Waited for 10 seconds")
c++
void main() { Sleep(1000 * 10); Log("Waited for 10 seconds"); }

Arguments

NameTypeRequiredDescription

millisecond

number

Yes

The millisecond parameter is used to set the sleep duration in milliseconds.

Remarks

For example, when executing Sleep(1000) function, the program will sleep for 1 second. Sleep times less than 1 millisecond are supported, such as setting Sleep(0.1). The minimum supported parameter value is 0.000001, which is nanosecond-level sleep, where 1 nanosecond equals 1e-6 milliseconds.

When writing strategies in Python, the Sleep(millisecond) function should be used for operations such as polling intervals and time waiting. It is not recommended to use the time.sleep(second) function from Python's time library. This is because using time.sleep(second) in a strategy will cause the strategy program to actually wait for the corresponding time during backtesting (rather than skipping ahead in the backtest system's time sequence), resulting in extremely slow strategy backtesting.

Determine whether the strategy's runtime environment is a backtesting system.

IsVirtual()

Examples

javascript
function main() { if (IsVirtual()) { Log("Currently in backtest environment.") } else { Log("Currently in live trading environment.") } }
python
def main(): if IsVirtual(): Log("Currently in backtest environment.") else: Log("Currently in live trading environment.")
c++
void main() { if (IsVirtual()) { Log("Currently in backtest environment."); } else { Log("Currently in live trading environment."); } }

Returns

TypeDescription

bool

Returns true when the strategy is running in a backtesting system environment, for example: true. Returns false when the strategy is running in a live trading environment, for example: false.

Remarks

Determine whether the current runtime environment is a backtesting system, used to handle differences between backtesting and live trading environments.

Send email.

Mail(smtpServer, smtpUsername, smtpPassword, mailTo, title, body)

Examples

javascript
function main(){ Mail("smtp.163.com", "[email protected]", "password", "[email protected]", "title", "body") }
python
def main(): Mail("smtp.163.com", "[email protected]", "password", "[email protected]", "title", "body")
c++
void main() { Mail("smtp.163.com", "[email protected]", "password", "[email protected]", "title", "body"); }

Returns

TypeDescription

bool

Returns true if the email is sent successfully, returns false if sending fails.

Arguments

NameTypeRequiredDescription

smtpServer

string

Yes

Specify the SMTP server address of the email sender.

smtpUsername

string

Yes

Specify the email address of the email sender.

smtpPassword

string

Yes

The SMTP service password of the sender's email.

mailTo

string

Yes

Specify the email address of the email recipient.

title

string

Yes

Email subject.

body

string

Yes

Email body content.

See Also

Remarks

The smtpPassword parameter is set to the SMTP service password, not the email login password.

When setting the smtpServer parameter, if you need to change the port, you can directly specify the port number in the smtpServer parameter. For example: QQ Mail smtp.qq.com:587 (this port has been tested and is available).

If an error message appears: unencryped connection, you need to modify the smtpServer parameter of the Mail function. The parameter format is: ssl://xxx.com:xxx, for example, QQ Mail's SMTP SSL method: ssl://smtp.qq.com:465, or use the format smtp://xxx.com:xxx.

This function does not work in the backtesting system.

Asynchronous version of the Mail function.

Mail_Go(smtpServer, smtpUsername, smtpPassword, mailTo, title, body)

Examples

javascript
function main() { var r1 = Mail_Go("smtp.163.com", "[email protected]", "password", "[email protected]", "title", "body") var r2 = Mail_Go("smtp.163.com", "[email protected]", "password", "[email protected]", "title", "body") var ret1 = r1.wait() var ret2 = r2.wait() Log("ret1:", ret1) Log("ret2:", ret2) }
python
# Not supported
c++
// Not supported

Returns

TypeDescription

object

The Mail_Go function immediately returns a concurrent object. You can use the wait method of this concurrent object to get the email sending result. Returns a truthy value (e.g., true) if the email is sent successfully, and returns a falsy value (e.g., false) if sending fails.

Arguments

NameTypeRequiredDescription

smtpServer

string

Yes

Used to specify the SMTP server address of the email sender.

smtpUsername

string

Yes

Used to specify the email address of the email sender.

smtpPassword

string

Yes

The SMTP authorization password for the sender's email account.

mailTo

string

Yes

Used to specify the email address of the email recipient.

title

string

Yes

Email subject.

body

string

Yes

Email body content.

See Also

Remarks

Does not work in the backtesting system.

Filter error logs.

SetErrorFilter(filters)

Examples

  • Filter common errors.

    javascript
    function main() { SetErrorFilter("502:|503:|tcp|character|unexpected|network|timeout|WSARecv|Connect|GetAddr|no such|reset|http|received|EOF|reused") }
    python
    def main(): SetErrorFilter("502:|503:|tcp|character|unexpected|network|timeout|WSARecv|Connect|GetAddr|no such|reset|http|received|EOF|reused")
    c++
    void main() { SetErrorFilter("502:|503:|tcp|character|unexpected|network|timeout|WSARecv|Connect|GetAddr|no such|reset|http|received|EOF|reused"); }
  • Filter specific API error messages.

    javascript
    function main() { // Query a non-existent order with id 123, intentionally causing an API error var order = exchange.GetOrder("123") Log(order) // Filter http502 errors and GetOrder API errors. After setting error filter, the second call to GetOrder will not report an error SetErrorFilter("502:|GetOrder") order = exchange.GetOrder("123") Log(order) }
    python
    def main(): order = exchange.GetOrder("123") Log(order) SetErrorFilter("502:|GetOrder") order = exchange.GetOrder("123") Log(order)
    c++
    void main() { TId orderId; Order order = exchange.GetOrder(orderId); Log(order); SetErrorFilter("502:|GetOrder"); order = exchange.GetOrder(orderId); Log(order); }

Arguments

NameTypeRequiredDescription

filters

string

Yes

Regular expression string.

Remarks

Error logs matched by this regular expression will not be uploaded to the log system. Can be called multiple times (no limit) to set multiple filter conditions, and the regular expressions set multiple times will accumulate and take effect. You can set an empty string to reset the error log filter regular expression: SetErrorFilter(""). Filtered logs will no longer be written to the database file of the corresponding live trading ID in the docker directory, preventing frequent errors from causing database file bloat.

Get the unique identifier of the live trading process.

GetPid()

Examples

javascript
function main(){ var id = GetPid() Log(id) }
python
def main(): id = GetPid() Log(id)
c++
void main() { auto id = GetPid(); Log(id); }

Returns

TypeDescription

string

Returns the unique identifier of the current live trading process.

Get the most recent error message.

GetLastError()

Examples

javascript
function main(){ // 因为不存在编号为123的订单,所以会产生错误 exchange.GetOrder("123") var error = GetLastError() Log(error) }
python
def main(): exchange.GetOrder("123") error = GetLastError() Log(error)
c++
void main() { // 订单ID类型:TId,因此不能传入字符串,我们下一个不符合交易所规范的订单来触发错误 exchange.GetOrder(exchange.Buy(1, 1)); auto error = GetLastError(); Log(error); }

Returns

TypeDescription

string

The most recent error message.

Remarks

Does not work in the backtesting system.

Get strategy interaction commands.

GetCommand()

Examples

  • Detect interactive commands and use the Log function to output the command when an interactive command is detected.

    javascript
    function main(){ while(true) { var cmd = GetCommand() if (cmd) { Log(cmd) } Sleep(1000) } }
    python
    def main(): while True: cmd = GetCommand() if cmd: Log(cmd) Sleep(1000)
    c++
    void main() { while(true) { auto cmd = GetCommand(); if(cmd != "") { Log(cmd); } Sleep(1000); } }
  • For example, add a control without an input box in the strategy interaction controls, name the interaction control: buy, control description: Buy, this is a button control. Continue to add a control with an input box, name the interaction control: sell, control description: Sell, this is an interaction control composed of a button and an input box. Design interaction code in the strategy to respond to different interaction controls:

    javascript
    function main() { while (true) { LogStatus(_D()) var cmd = GetCommand() if (cmd) { Log("cmd:", cmd) var arr = cmd.split(":") if (arr[0] == "buy") { Log("Buy, this control has no quantity") } else if (arr[0] == "sell") { Log("Sell, this control has quantity:", arr[1]) } else { Log("Other control triggered:", arr) } } Sleep(1000) } }
    python
    def main(): while True: LogStatus(_D()) cmd = GetCommand() if cmd: Log("cmd:", cmd) arr = cmd.split(":") if arr[0] == "buy": Log("Buy, this control has no quantity") elif arr[0] == "sell": Log("Sell, this control has quantity:", arr[1]) else: Log("Other control triggered:", arr) Sleep(1000)
    c++
    #include <iostream> #include <sstream> #include <string> #include <vector> using namespace std; void split(const string& s,vector<string>& sv,const char flag = ' ') { sv.clear(); istringstream iss(s); string temp; while (getline(iss, temp, flag)) { sv.push_back(temp); } return; } void main() { while(true) { LogStatus(_D()); auto cmd = GetCommand(); if (cmd != "") { vector<string> arr; split(cmd, arr, ':'); if(arr[0] == "buy") { Log("Buy, this control has no quantity"); } else if (arr[0] == "sell") { Log("Sell, this control has quantity:", arr[1]); } else { Log("Other control triggered:", arr); } } Sleep(1000); } }

Returns

TypeDescription

string

The returned command format is ControlName:Data. ControlName is the control name, Data is the data entered in the control. If the interactive control does not contain input boxes, dropdown boxes, or other components (for example: button controls without input boxes), the returned command format is ControlName, returning only the control name.

Remarks

Not effective in the backtesting system.

Get the Meta value written when generating the strategy registration code.

GetMeta()

Examples

Application scenario example: Using Meta to limit the asset quantity that a strategy can operate.

javascript
function main() { // Maximum quote currency asset value allowed by the strategy var maxBaseCurrency = null // Get metadata from when the registration code was created var level = GetMeta() // Check conditions corresponding to Meta if (level == "level1") { // -1 means no limit maxBaseCurrency = -1 } else if (level == "level2") { maxBaseCurrency = 10 } else if (level == "level3") { maxBaseCurrency = 1 } else { maxBaseCurrency = 0.5 } while(1) { Sleep(1000) var ticker = exchange.GetTicker() // Check asset value var acc = exchange.GetAccount() if (maxBaseCurrency != -1 && maxBaseCurrency < acc.Stocks + acc.FrozenStocks) { // Stop executing strategy trading logic LogStatus(_D(), "level:", level, "Position exceeds registration code limit, strategy trading logic will not execute!") continue } // Other trading logic // Normal status bar information output LogStatus(_D(), "level:", level, "Strategy running normally! ticker data:\n", ticker) } }
python
def main(): maxBaseCurrency = null level = GetMeta() if level == "level1": maxBaseCurrency = -1 elif level == "level2": maxBaseCurrency = 10 elif level == "level3": maxBaseCurrency = 1 else: maxBaseCurrency = 0.5 while True: Sleep(1000) ticker = exchange.GetTicker() acc = exchange.GetAccount() if maxBaseCurrency != -1 and maxBaseCurrency < acc["Stocks"] + acc["FrozenStocks"]: LogStatus(_D(), "level:", level, "Position exceeds registration code limit, strategy trading logic will not execute!") continue # Other trading logic # Normal status bar information output LogStatus(_D(), "level:", level, "Strategy running normally! ticker data:\n", ticker)
c++
void main() { auto maxBaseCurrency = 0.0; auto level = GetMeta(); if (level == "level1") { maxBaseCurrency = -1; } else if (level == "level2") { maxBaseCurrency = 10; } else if (level == "level3") { maxBaseCurrency = 1; } else { maxBaseCurrency = 0.5; } while(1) { Sleep(1000); auto ticker = exchange.GetTicker(); auto acc = exchange.GetAccount(); if (maxBaseCurrency != -1 && maxBaseCurrency < acc.Stocks + acc.FrozenStocks) { // Stop executing strategy trading logic LogStatus(_D(), "level:", level, "Position exceeds registration code limit, strategy trading logic will not execute!"); continue; } // Other trading logic // Normal status bar information output LogStatus(_D(), "level:", level, "Strategy running normally! ticker data:\n", ticker); } }

Returns

TypeDescription

string

Meta data.

Remarks

Application scenario: When you need to impose capital limits on different strategy renters. The Meta value set when generating the registration code cannot exceed 190 characters. The GetMeta() function only supports live trading. If no metadata (Meta) was set when generating the strategy registration code, the GetMeta() function returns null. This function does not work in the backtesting system.

Used for raw Socket access, supporting tcp, udp, tls, unix protocols. Supports 4 popular communication protocols: mqtt, nats, amqp, kafka. Supports database connections, including: sqlite3, mysql, postgres, clickhouse.

Dial(address)
Dial(address, timeout)
Dial(address, options)

Examples

  • Dial function call example:

    javascript
    function main(){ // Dial supports tcp://, udp://, tls://, unix:// protocols, can add a parameter to specify timeout in seconds var client = Dial("tls://www.baidu.com:443") if (client) { // write can append a numeric parameter to specify timeout, returns the number of bytes successfully sent client.write("GET / HTTP/1.1\nConnection: Closed\n\n") while (true) { // read can append a numeric parameter to specify timeout, unit: milliseconds. Returns null indicating error, timeout, or socket closed var buf = client.read() if (!buf) { break } Log(buf) } client.close() } }
    python
    def main(): client = Dial("tls://www.baidu.com:443") if client: client.write("GET / HTTP/1.1\nConnection: Closed\n\n") while True: buf = client.read() if not buf: break Log(buf) client.close()
    c++
    void main() { auto client = Dial("tls://www.baidu.com:443"); if(client.Valid) { client.write("GET / HTTP/1.1\nConnection: Closed\n\n"); while(true) { auto buf = client.read(); if(buf == "") { break; } Log(buf); } client.close(); } }
  • Accessing Binance WebSocket market data interface:

    javascript
    function main() { LogStatus("Connecting...") // Access Binance WebSocket interface var client = Dial("wss://stream.binance.com:9443/ws/!ticker@arr") if (!client) { Log("Connection failed, exiting") return } while (true) { // read only returns data obtained after calling read var buf = client.read() if (!buf) { break } var table = { type: 'table', title: 'Market Chart', cols: ['Symbol', 'High', 'Low', 'Bid', 'Ask', 'Last Price', 'Volume', 'Update Time'], rows: [] } var obj = JSON.parse(buf) _.each(obj, function(ticker) { table.rows.push([ticker.s, ticker.h, ticker.l, ticker.b, ticker.a, ticker.c, ticker.q, _D(ticker.E)]) }) LogStatus('`' + JSON.stringify(table) + '`') } client.close() }
    python
    import json def main(): LogStatus("Connecting...") client = Dial("wss://stream.binance.com:9443/ws/!ticker@arr") if not client: Log("Connection failed, exiting") return while True: buf = client.read() if not buf: break table = { "type" : "table", "title" : "Market Chart", "cols" : ["Symbol", "High", "Low", "Bid", "Ask", "Last Price", "Volume", "Update Time"], "rows" : [] } obj = json.loads(buf) for i in range(len(obj)): table["rows"].append([obj[i]["s"], obj[i]["h"], obj[i]["l"], obj[i]["b"], obj[i]["a"], obj[i]["c"], obj[i]["q"], _D(int(obj[i]["E"]))]) LogStatus('`' + json.dumps(table) + '`') client.close()
    c++
    void main() { LogStatus("Connecting..."); auto client = Dial("wss://stream.binance.com:9443/ws/!ticker@arr"); if(!client.Valid) { Log("Connection failed, exiting"); return; } while(true) { auto buf = client.read(); if(buf == "") { break; } json table = R"({ "type" : "table", "title" : "Market Chart", "cols" : ["Symbol", "High", "Low", "Bid", "Ask", "Last Price", "Volume", "Update Time"], "rows" : [] })"_json; json obj = json::parse(buf); for(auto& ele : obj.items()) { table["rows"].push_back({ele.value()["s"], ele.value()["h"], ele.value()["l"], ele.value()["b"], ele.value()["a"], ele.value()["c"], ele.value()["q"], _D(ele.value()["E"])}); } LogStatus("`" + table.dump() + "`"); } client.close(); }
  • Access Binance's WebSocket interface and set wss request headers.

    javascript
    function main() { let options = {"headers": {"X-MBX-APIKEY": "your access key"}} let random = `fmz${UnixNano()}` let ts = new Date().getTime() let secretKey = "your secret key" let topic = "com_announcement_en" let payload = `random=${random}&topic=${topic}&recvWindow=30000&timestamp=${ts}` let signature = Encode("sha256", "string", "hex", payload, "string", secretKey) let query = `?${payload}&signature=${signature}` Log("query:", query) let conn = Dial(`wss://api.binance.com/sapi/wss${query}`, options) for (var i = 0 ; i < 10 ; i++) { let ret = conn.read() Log(ret) } }
    python
    import time def main(): options = {"headers": {"X-MBX-APIKEY": "your access key"}} random = "fmz" + str(UnixNano()) ts = int(time.time() * 1000) secretKey = "your secret key" topic = "com_announcement_en" payload = f"random={random}&topic={topic}&recvWindow=30000&timestamp={ts}" signature = Encode("sha256", "string", "hex", payload, "string", secretKey) query = f"?{payload}&signature={signature}" Log("query:", query) conn = Dial(f"wss://api.binance.com/sapi/wss{query}", options) for i in range(10): ret = conn.read() Log(ret)
    c++
    // Not supported currently
  • Accessing OKX WebSocket market data interface:

    javascript
    var ws = null function main(){ var param = { "op": "subscribe", "args": [{ "channel": "tickers", "instId": "BTC-USDT" }] } // When calling the Dial function, specify reconnect=true to set reconnection mode, and specify payload as the message to send upon reconnection. After the WebSocket connection is disconnected, it will automatically reconnect and automatically send the message ws = Dial("wss://ws.okx.com:8443/ws/v5/public|compress=gzip_raw&mode=recv&reconnect=true&payload=" + JSON.stringify(param)) if(ws){ var pingCyc = 1000 * 20 var lastPingTime = new Date().getTime() while(true){ var nowTime = new Date().getTime() var ret = ws.read() Log("ret:", ret) if(nowTime - lastPingTime > pingCyc){ var retPing = ws.write("ping") lastPingTime = nowTime Log("Sending: ping", "#FF0000") } LogStatus("Current time:", _D()) Sleep(1000) } } } function onexit() { ws.close() Log("Exiting") }
    python
    import json import time ws = None def main(): global ws param = { "op": "subscribe", "args": [{ "channel": "tickers", "instId": "BTC-USDT" }] } ws = Dial("wss://ws.okx.com:8443/ws/v5/public|compress=gzip_raw&mode=recv&reconnect=true&payload=" + json.dumps(param)) if ws: pingCyc = 1000 * 20 lastPingTime = time.time() * 1000 while True: nowTime = time.time() * 1000 ret = ws.read() Log("ret:", ret) if nowTime - lastPingTime > pingCyc: retPing = ws.write("ping") lastPingTime = nowTime Log("Sending: ping", "#FF0000") LogStatus("Current time:", _D()) Sleep(1000) def onexit(): ws.close() Log("Exiting")
    c++
    auto objWS = Dial("wss://ws.okx.com:8443/ws/v5/public|compress=gzip_raw&mode=recv&reconnect=true"); void main() { json param = R"({ "op": "subscribe", "args": [{ "channel": "tickers", "instId": "BTC-USDT" }] })"_json; objWS.write(param.dump()); if(objWS.Valid) { uint64_t pingCyc = 1000 * 20; uint64_t lastPingTime = Unix() * 1000; while(true) { uint64_t nowTime = Unix() * 1000; auto ret = objWS.read(); Log("ret:", ret); if(nowTime - lastPingTime > pingCyc) { auto retPing = objWS.write("ping"); lastPingTime = nowTime; Log("Sending: ping", "#FF0000"); } LogStatus("Current time:", _D()); Sleep(1000); } } } void onexit() { objWS.close(); Log("Exiting"); }
  • Accessing Huobi's WebSocket market data interface:

    javascript
    var ws = null function main(){ var param = {"sub": "market.btcusdt.detail", "id": "id1"} ws = Dial("wss://api.huobi.pro/ws|compress=gzip&mode=recv&reconnect=true&payload=" + JSON.stringify(param)) if(ws){ while(1){ var ret = ws.read() Log("ret:", ret) // Respond to heartbeat packet try { var jsonRet = JSON.parse(ret) if(typeof(jsonRet.ping) == "number") { var strPong = JSON.stringify({"pong" : jsonRet.ping}) ws.write(strPong) Log("Responding to ping, sending pong:", strPong, "#FF0000") } } catch(e) { Log("e.name:", e.name, "e.stack:", e.stack, "e.message:", e.message) } LogStatus("Current time:", _D()) Sleep(1000) } } } function onexit() { ws.close() Log("Executing ws.close()") }
    python
    import json ws = None def main(): global ws param = {"sub" : "market.btcusdt.detail", "id" : "id1"} ws = Dial("wss://api.huobi.pro/ws|compress=gzip&mode=recv&reconnect=true&payload=" + json.dumps(param)) if ws: while True: ret = ws.read() Log("ret:", ret) # Respond to heartbeat packet try: jsonRet = json.loads(ret) if "ping" in jsonRet and type(jsonRet["ping"]) == int: strPong = json.dumps({"pong" : jsonRet["ping"]}) ws.write(strPong) Log("Responding to ping, sending pong:", strPong, "#FF0000") except Exception as e: Log("e:", e) LogStatus("Current time:", _D()) Sleep(1000) def onexit(): ws.close() Log("Executing ws.close()")
    c++
    using namespace std; void main() { json param = R"({"sub" : "market.btcusdt.detail", "id" : "id1"})"_json; auto ws = Dial("wss://api.huobi.pro/ws|compress=gzip&mode=recv&reconnect=true&payload=" + param.dump()); if(ws.Valid) { while(true) { auto ret = ws.read(); Log("ret:", ret); // Respond to heartbeat packet try { auto jsonRet = json::parse(ret); if(jsonRet["ping"].is_number()) { json pong = R"({"pong" : 0})"_json; pong["pong"] = jsonRet["ping"]; auto strPong = pong.dump(); ws.write(strPong); Log("Responding to ping, sending pong:", strPong, "#FF0000"); } } catch(exception &e) { Log("e:", e.what()); } LogStatus("Current time:", _D()); Sleep(1000); } } } void onexit() { // ws.close(); Log("Executing ws.close()"); }
  • Accessing OKX's WebSocket authentication interface:

    javascript
    function getLogin(pAccessKey, pSecretKey, pPassphrase) { // Signature function for login var ts = (new Date().getTime() / 1000).toString() var login = { "op": "login", "args":[{ "apiKey" : pAccessKey, "passphrase" : pPassphrase, "timestamp" : ts, "sign" : exchange.Encode("sha256", "string", "base64", ts + "GET" + "/users/self/verify", "string", pSecretKey) }] } return login } var client_private = null function main() { // Since the read function uses timeout settings, timeout errors need to be filtered, otherwise redundant error output will be generated SetErrorFilter("timeout") // Position channel subscription information var posSubscribe = { "op": "subscribe", "args": [{ "channel": "positions", "instType": "ANY" }] } var accessKey = "xxx" var secretKey = "xxx" var passphrase = "xxx" client_private = Dial("wss://ws.okx.com:8443/ws/v5/private") client_private.write(JSON.stringify(getLogin(accessKey, secretKey, passphrase))) Sleep(3000) // Cannot subscribe to private channels immediately after login, need to wait for server response client_private.write(JSON.stringify(posSubscribe)) if (client_private) { var lastPingTS = new Date().getTime() while (true) { var buf = client_private.read(-1) if (buf) { Log(buf) } // Detect disconnection and reconnect if (buf == "" && client_private.write(JSON.stringify(posSubscribe)) == 0) { Log("Detected disconnection, closing connection, reconnecting") client_private.close() client_private = Dial("wss://ws.okx.com:8443/ws/v5/private") client_private.write(JSON.stringify(getLogin(accessKey, secretKey, passphrase))) Sleep(3000) client_private.write(JSON.stringify(posSubscribe)) } // Send heartbeat packet var nowPingTS = new Date().getTime() if (nowPingTS - lastPingTS > 10 * 1000) { client_private.write("ping") lastPingTS = nowPingTS } } } } function onexit() { var ret = client_private.close() Log("Connection closed!", ret) }
    python
    import json import time def getLogin(pAccessKey, pSecretKey, pPassphrase): ts = str(time.time()) login = { "op": "login", "args":[{ "apiKey" : pAccessKey, "passphrase" : pPassphrase, "timestamp" : ts, "sign" : exchange.Encode("sha256", "string", "base64", ts + "GET" + "/users/self/verify", "string", pSecretKey) }] } return login client_private = None def main(): global client_private SetErrorFilter("timeout") posSubscribe = { "op": "subscribe", "args": [{ "channel": "positions", "instType": "ANY" }] } accessKey = "xxx" secretKey = "xxx" passphrase = "xxx" client_private = Dial("wss://ws.okx.com:8443/ws/v5/private") client_private.write(json.dumps(getLogin(accessKey, secretKey, passphrase))) Sleep(3000) client_private.write(json.dumps(posSubscribe)) if client_private: lastPingTS = time.time() * 1000 while True: buf = client_private.read(-1) if buf: Log(buf) if buf == "" and client_private.write(json.dumps(posSubscribe)) == 0: Log("Detected disconnection, closing connection, reconnecting") ret = client_private.close() client_private = Dial("wss://ws.okx.com:8443/ws/v5/private") client_private.write(json.dumps(getLogin(accessKey, secretKey, passphrase))) Sleep(3000) client_private.write(json.dumps(posSubscribe)) nowPingTS = time.time() * 1000 if nowPingTS - lastPingTS > 10 * 1000: client_private.write("ping") lastPingTS = nowPingTS def onexit(): ret = client_private.close() Log("Connection closed!", ret)
    c++
    auto client_private = Dial("wss://ws.okx.com:8443/ws/v5/private"); json getLogin(string pAccessKey, string pSecretKey, string pPassphrase) { auto ts = std::to_string(Unix()); json login = R"({ "op": "login", "args": [{ "apiKey": "", "passphrase": "", "timestamp": "", "sign": "" }] })"_json; login["args"][0]["apiKey"] = pAccessKey; login["args"][0]["passphrase"] = pPassphrase; login["args"][0]["timestamp"] = ts; login["args"][0]["sign"] = exchange.Encode("sha256", "string", "base64", ts + "GET" + "/users/self/verify", "string", pSecretKey); return login; } void main() { SetErrorFilter("timeout"); json posSubscribe = R"({ "op": "subscribe", "args": [{ "channel": "positions", "instType": "ANY" }] })"_json; auto accessKey = "xxx"; auto secretKey = "xxx"; auto passphrase = "xxx"; client_private.write(getLogin(accessKey, secretKey, passphrase).dump()); Sleep(3000); client_private.write(posSubscribe.dump()); if (client_private.Valid) { uint64_t lastPingTS = Unix() * 1000; while (true) { auto buf = client_private.read(-1); if (buf != "") { Log(buf); } if (buf == "") { if (client_private.write(posSubscribe.dump()) == 0) { Log("Detected disconnection, closing connection, reconnecting"); client_private.close(); client_private = Dial("wss://ws.okx.com:8443/ws/v5/private"); client_private.write(getLogin(accessKey, secretKey, passphrase).dump()); Sleep(3000); client_private.write(posSubscribe.dump()); } } uint64_t nowPingTS = Unix() * 1000; if (nowPingTS - lastPingTS > 10 * 1000) { client_private.write("ping"); lastPingTS = nowPingTS; } } } } void onexit() { client_private.close(); Log("Exiting"); }
  • Access CoinEx's WebSocket authentication interface:

    javascript
    var conn = null function main() { var accessKey = "your accessKey" var ts = new Date().getTime() var signature = exchange.Encode("sha256", "string", "hex", String(ts), "string", "{{secretkey}}") Log("signature:", signature) var payload = { "id": 1, "method": "server.sign", "params": { "access_id": accessKey, "signed_str": signature, "timestamp": ts, } } Log(`JSON.stringify(payload):`, JSON.stringify(payload)) conn = Dial("wss://socket.coinex.com/v2/futures|compress=gzip&mode=recv&payload=" + JSON.stringify(payload)) if (!conn) { throw "stop" } Log("Dial ... ", conn.read()) // Subscribe to position updates conn.write(JSON.stringify({ "method": "position.subscribe", "params": {"market_list": ["BTCUSDT"]}, "id": 1 })) while (true) { var msg = conn.read() if (msg) { Log("msg:", msg) } } } function onexit() { conn.close() }
    python
    // Omitted
    c++
    // Omitted
  • Example of accessing the MEXC exchange Websocket interface, subscribing to the public.aggre.deals.v3.api.pb channel, and using protobuf.js to decode binary data:

    javascript
    let strPushDataV3ApiWrapper = `syntax = "proto3"; option java_package = "com.mxc.push.common.protobuf"; option optimize_for = SPEED; option java_multiple_files = true; option java_outer_classname = "PushDataV3ApiWrapperProto"; message PublicAggreDealsV3Api { repeated PublicAggreDealsV3ApiItem deals = 1; string eventType = 2; } message PublicAggreDealsV3ApiItem { string price = 1; string quantity = 2; int32 tradeType = 3; int64 time = 4; } message PushDataV3ApiWrapper { string channel = 1; oneof body { PublicAggreDealsV3Api publicAggreDeals = 314; } optional string symbol = 3; optional string symbolId = 4; optional int64 createTime = 5; optional int64 sendTime = 6; }` let code = HttpQuery("https://cdnjs.cloudflare.com/ajax/libs/protobufjs/7.5.3/protobuf.js") let exports = {} let module = { exports } new Function("module", "exports", code)(module, exports) let protobuf = module.exports function main() { const PushDataV3ApiWrapper = protobuf.parse(strPushDataV3ApiWrapper).root.lookupType("PushDataV3ApiWrapper") var payload = { "method": "SUBSCRIPTION", "params": [ "[email protected]@100ms@BTCUSDT" ] } // proxy=socks5://x.x.x.x:xxxx var conn = Dial("wss://wbs-api.mexc.com/ws|payload=" + JSON.stringify(payload)) var data = null while (true) { var ret = conn.read() if (ret) { const uint8arrayData = new Uint8Array(ret) const message = PushDataV3ApiWrapper.decode(uint8arrayData) data = PushDataV3ApiWrapper.toObject(message, { longs: String, enums: String, bytes: String, defaults: true, arrays: true, objects: true }) Log("data:", data) } LogStatus(_D(), data) } }
    python
    # You can use the corresponding libraries in Python to implement encoding and decoding.
    c++
    // Omitted
  • The connection object returned by the Dial function when connecting to a database has 2 unique method functions:

    • exec(sqlString): Used to execute SQL statements, similar to the DBExec() function.

    • fd(): The fd() function returns a handle (e.g., handle variable is handle), which can be used by other threads to reconnect (even if the object created by Dial has already executed the close() function to close the connection). Pass the handle to the Dial() function, e.g., Dial(handle) to reuse the connection.

    The following is an example of using the Dial function to connect to a sqlite3 database.

    javascript
    var client = null function main() { // client = Dial("sqlite3://:memory:") // Use in-memory database client = Dial("sqlite3://test1.db") // Open/connect to the database file in the docker's directory // Record the handle var sqlite3Handle = client.fd() Log("sqlite3Handle:", sqlite3Handle) // Query tables in the database var ret = client.exec("SELECT name FROM sqlite_master WHERE type='table'") Log(ret) } function onexit() { Log("Executing client.close()") client.close() }
    python
    // Not supported
    c++
    // Not supported

Returns

TypeDescription

object

If timeout occurs, the Dial() function returns null. When called normally, it returns a connection object containing three methods: read, write, and close. The read method is used to read data, the write method is used to send data, and the close method is used to close the connection.The read method supports the following parameters:

  • When no parameter is passed, it blocks until a message is received and then returns. For example: ws.read().
  • When a parameter is passed, the unit is milliseconds, specifying the message wait timeout. For example: ws.read(2000) specifies a timeout of two seconds (2000 milliseconds).
  • The following two parameters are only valid for WebSocket:
    Passing parameter -1 means the function returns immediately regardless of whether there is a message. For example: ws.read(-1).
    Passing parameter -2 means the function returns immediately regardless of whether there is a message, but only returns the latest message, and messages in the buffer will be discarded. For example: ws.read(-2).read() function buffer description:

For data pushed via WebSocket protocol, if the time interval between read() function calls in the strategy is too long, data accumulation may occur. This data is stored in a buffer with a queue data structure, with an upper limit of 2000 entries. When exceeding 2000 entries, the newest data enters the buffer and the oldest data is cleared.

ScenarioNo parameterParameter: -1Parameter: -2Parameter: 2000, unit is milliseconds
Buffer has dataImmediately returns oldest dataImmediately returns oldest dataImmediately returns newest dataImmediately returns oldest data
Buffer has no dataBlocks until data is available and returnsImmediately returns nullImmediately returns nullWaits 2000 milliseconds, returns null if no data, returns data if available
WebSocket connection disconnected or underlying reconnectionread() function returns empty string, i.e.: "", write() function returns 0. When this situation is detected, you can use the close() function to close the connection; if auto-reconnect is set, no need to close, the underlying system will automatically reconnect.------

Arguments

NameTypeRequiredDescription

address

string

Yes

Request address.

timeout

number

No

Timeout period, in seconds.

options

object

No

Configuration options.

Remarks

Detailed explanation of the address parameter: After the normal address wss://ws.okx.com:8443/ws/v5/public, use the | symbol as a separator. If the parameter string contains the | character, use || as the separator. The part after it is the function parameter settings, with each parameter connected by the & character.

For example, when setting both ss5 proxy and compression parameters simultaneously, you can write:
Dial("wss://ws.okx.com:8443/ws/v5/public|proxy=socks5://xxx:9999&compress=gzip_raw&mode=recv")

Features supported by the address parameter of the Dial functionParameter description
Parameters related to WebSocket protocol data compression: compress=parameter valuecompress is the compression method, the compress parameter can be gzip_raw, gzip, etc. If the gzip method is non-standard gzip, you can use the extended method: gzip_raw
Parameters related to WebSocket protocol data compression: mode=parameter valuemode is the compression mode, the mode parameter can be one of three options: dual, send, recv. dual is bidirectional compression, both sending and receiving are compressed data; send is sending compressed data; recv is receiving compressed data and decompressing locally.
WebSocket protocol enable compression setting: enableCompression=trueUse enableCompression=false to disable this setting, not enabled by default.
Parameters related to WebSocket protocol underlying automatic reconnection: reconnect=parameter valuereconnect indicates whether to enable reconnection, reconnect=true means enabling reconnection. When this parameter is not set, reconnection is disabled by default.
Parameters related to WebSocket protocol underlying automatic reconnection: interval=parameter valueinterval is the retry time interval in milliseconds. interval=10000 means the retry interval is 10 seconds, when not set the default is 1 second, i.e., interval=1000.
Parameters related to WebSocket protocol underlying automatic reconnection: payload=parameter valuepayload is the subscription message that needs to be sent when WebSocket reconnects, for example: payload=okok.
Parameters related to socks5 proxy: proxy=parameter valueproxy is the ss5 proxy setting, parameter value format: socks5://name:[email protected]:1080, where name is the ss5 server username, pwd is the ss5 server login password, 1080 is the ss5 service port.

The Dial() function only supports live trading.

When using the Dial function to connect to a database, please refer to the Go language driver project for each database for writing the connection string.

Supported databasesDriver projectConnection StringRemarks
sqlite3github.com/mattn/go-sqlite3sqlite3://file:test.db?cache=shared&mode=memoryThe sqlite3:// prefix indicates using the sqlite3 database, call example: Dial("sqlite3://test1.db")
mysqlgithub.com/go-sql-driver/mysqlmysql://username:yourpassword@tcp(localhost:3306)/yourdatabase?charset=utf8mb4--
postgresgithub.com/lib/pqpostgres://user=postgres dbname=yourdatabase sslmode=disable password=yourpassword host=localhost port=5432--
clickhousegithub.com/ClickHouse/clickhouse-goclickhouse://tcp://host:9000?username=username&password=yourpassword&database=youdatabase--

Note that when the payload content set in the address parameter contains the character = or other special characters, it may affect the parsing of the address parameter in the Dial function. For example:

BackPack Exchange WebSocket private interface call example:

javascript
var client = null function main() { // base64-encoded public key of the key pair, i.e., the access key configured on FMZ var base64ApiKey = "xxx" var ts = String(new Date().getTime()) var data = "instruction=subscribe&timestamp=" + ts + "&window=5000" // Since signEd25519 ultimately returns base64 encoding, it may contain the character "=" var signature = signEd25519(data) // payload may contain the character "=" after JSON encoding payload = { "method": "SUBSCRIBE", "params": ["account.orderUpdate"], "signature": [base64ApiKey, signature, ts, "5000"] } client = Dial("wss://ws.backpack.exchange") client.write(JSON.stringify(payload)) if (!client) { Log("Connection failed, exiting") return } while (true) { var buf = client.read() Log(buf) } } function onexit() { client.close() } function signEd25519(data) { return exchange.Encode("ed25519.seed", "raw", "base64", data, "base64", "{{secretkey}}") }

The following calling method in the code works correctly:

javascript
client = Dial("wss://ws.backpack.exchange") client.write(JSON.stringify(payload))

If written directly in payload, it will not work properly, for example:

javascript
client = Dial("wss://ws.backpack.exchange|payload=" + JSON.stringify(payload))

Currently, only JavaScript supports using mqtt, nats, amqp, kafka communication protocols in the Dial function. The following uses JavaScript strategy code as an example to demonstrate usage examples of the four protocols mqtt, nats, amqp, kafka:

javascript
// You need to configure and deploy the proxy servers for each protocol first // For demonstration purposes, the subscription (read operation) and publishing (write operation) of topic test_topic are both performed in this strategy var arrConn = [] var arrName = [] function main() { LogReset(1) conn_nats = Dial("nats://[email protected]:4222?topic=test_topic") conn_mqtt = Dial("mqtt://127.0.0.1:1883?topic=test_topic") conn_amqp = Dial("amqp://q:[email protected]:5672/?queue=test_Queue") conn_kafka = Dial("kafka://localhost:9092/test_topic") arrConn = [conn_nats, conn_amqp, conn_mqtt, conn_kafka] arrName = ["nats", "amqp", "mqtt", "kafka"] while (true) { for (var i in arrConn) { var conn = arrConn[i] var name = arrName[i] // Write data conn.write(name + ", time: " + _D() + ", test msg.") // Read data var readMsg = conn.read(1000) Log(name + " readMsg: ", readMsg, "#FF0000") } Sleep(1000) } } function onexit() { for (var i in arrConn) { arrConn[i].close() Log("Closing", arrName[i], "connection") } }

For detailed documentation, please refer to: Exploring FMZ: Communication Protocol Practice Between Live Trading Strategies

Send HTTP request.

HttpQuery(url)
HttpQuery(url, options)

Examples

  • Example of accessing OKX public market API endpoints.

    javascript
    function main(){ // 一个不带参数的GET请求示例 var info = JSON.parse(HttpQuery("https://www.okx.com/api/v5/public/time")) Log(info) // 一个带参数的GET请求示例 var ticker = JSON.parse(HttpQuery("https://www.okx.com/api/v5/market/books?instId=BTC-USDT")) Log(ticker) }
    python
    import json import urllib.request def main(): # HttpQuery不支持Python,可以使用urllib/urllib2库替代 info = json.loads(urllib.request.urlopen("https://www.okx.com/api/v5/public/time").read().decode('utf-8')) Log(info) ticker = json.loads(urllib.request.urlopen("https://www.okx.com/api/v5/market/books?instId=BTC-USDT").read().decode('utf-8')) Log(ticker)
    c++
    void main() { auto info = json::parse(HttpQuery("https://www.okx.com/api/v5/public/time")); Log(info); auto ticker = json::parse(HttpQuery("https://www.okx.com/api/v5/market/books?instId=BTC-USDT")); Log(ticker); }
  • Example of using proxy settings with HttpQuery function.

    javascript
    function main() { // 本次设置代理并发送HTTP请求,无用户名、无密码,此次HTTP请求将通过代理发送 HttpQuery("socks5://127.0.0.1:8889/http://www.baidu.com/") // 本次设置代理并发送HTTP请求,包含用户名和密码,仅对当前HttpQuery调用生效,后续调用HttpQuery("http://www.baidu.com")将不会使用代理 HttpQuery("socks5://username:[email protected]:8889/http://www.baidu.com/") }
    python
    # HttpQuery不支持Python,可以使用Python的urllib2库
    c++
    void main() { HttpQuery("socks5://127.0.0.1:8889/http://www.baidu.com/"); HttpQuery("socks5://username:[email protected]:8889/http://www.baidu.com/"); }

Returns

TypeDescription

string / object

Returns the response data of the request. If the return value is a JSON string, it can be parsed using the JSON.parse() function in JavaScript language strategies, and the json::parse() function in C++ language strategies. If debug is set to true in the options structure parameter, the return value is an object (JSON); if debug is set to false, the return value is a string.

Arguments

NameTypeRequiredDescription

url

string

Yes

URL address for the HTTP request.

options

object

No

HTTP request configuration parameters, can use the following structure:

json
{ method: "POST", body: "a=10&b=20&c=30", charset: "UTF-8", cookie: "session_id=12345; lang=en", debug: false, headers: {"TEST-HTTP-QUERY": "123"}, timeout: 1000 }
  • method: Set the request method.
  • body: Set the request body content, typically used for POST, PUT requests.
  • cookie: Set the Cookie in the request, generally used to carry authentication information or session identifiers.
  • headers: Set request header information, can be used to specify content type, authentication information, etc.
  • debug: When set to true, this HttpQuery function call returns the complete response message; when set to false, only returns the data in the response message Body.
  • timeout: Timeout setting in milliseconds, setting 1000 means 1 second timeout.
  • charset: Supports transcoding of request response data, for example: GB18030. Supports common encoding formats.

All fields in this structure are optional, for example, the headers field can be omitted.

See Also

Remarks

The HttpQuery() function only supports JavaScript and C++ languages. Python language can use the urllib library to send HTTP requests directly. HttpQuery() is mainly used to access exchange interfaces that do not require signatures, such as public interfaces like market data.

In the backtesting system, HttpQuery() can be used to send requests (only GET requests are supported) to obtain data. During backtesting, access to different URLs is limited to a maximum of 20 times, and HttpQuery() access will cache data. When the same URL is accessed for the second time, the HttpQuery() function returns cached data without initiating an actual network request.

Send HTTP request, asynchronous version of the HttpQuery function.

HttpQuery_Go(url)
HttpQuery_Go(url, options)

Examples

Asynchronously access exchange public interface to get aggregated market data.

javascript
function main() { // 创建第一个异步线程 var r1 = HttpQuery_Go("https://www.okx.com/api/v5/market/tickers?instType=SPOT") // 创建第二个异步线程 var r2 = HttpQuery_Go("https://api.huobi.pro/market/tickers") // 获取第一个异步线程调用的返回值 var tickers1 = r1.wait() // 获取第二个异步线程调用的返回值 var tickers2 = r2.wait() // 打印结果 Log("tickers1:", tickers1) Log("tickers2:", tickers2) }
python
# 不支持
c++
// 不支持

Returns

TypeDescription

object

The HttpQuery_Go() function immediately returns a concurrent object, and you can use the wait method of this concurrent object to get the result of the HTTP request. In JavaScript language strategies, you can use the JSON.parse() function to parse the returned data.

Arguments

NameTypeRequiredDescription

url

string

Yes

URL address for the HTTP request.

options

object

No

HTTP request configuration parameters, can use the following structure:

json
{ method: "POST", body: "a=10&b=20&c=30", charset: "UTF-8", cookie: "session_id=12345; lang=en", debug: false, headers: {"TEST-HTTP-QUERY": "123"}, timeout: 1000 }
  • debug: When set to true, this HttpQuery_Go function call returns the complete response message. When set to false, it only returns the data in the response message Body.
  • timeout: Timeout setting, setting 1000 means 1 second timeout.

All fields in this structure are optional, for example, you don't need to set the headers field.
The options parameter of the HttpQuery_Go function is consistent with the options parameter of the HttpQuery function and will not be repeated here.

See Also

Remarks

The HttpQuery_Go() function only supports JavaScript language, Python language can use the urllib library to send HTTP requests directly. HttpQuery_Go() is mainly used to access exchange interfaces that do not require signatures, such as public interfaces like market data. The backtesting system does not support the HttpQuery_Go function.

This function encodes data based on the parameters passed in.

Encode(algo, inputFormat, outputFormat, data)
Encode(algo, inputFormat, outputFormat, data, keyFormat, key)

Examples

  • Encode function call example.

    javascript
    function main() { Log(Encode("raw", "raw", "hex", "example", "raw", "123")) // 6578616d706c65 Log(Encode("raw", "raw", "hex", "example")) // 6578616d706c65 Log(Encode("sha256", "raw", "hex", "example", "raw", "123")) // 698d54f0494528a759f19c8e87a9f99e75a5881b9267ee3926bcf62c992d84ba Log(Encode("sha256", "raw", "hex", "example", "", "123")) // 50d858e0985ecc7f60418aaf0cc5ab587f42c2570a884095a9e8ccacd0f6545c Log(Encode("sha256", "raw", "hex", "example", null, "123")) // 50d858e0985ecc7f60418aaf0cc5ab587f42c2570a884095a9e8ccacd0f6545c Log(Encode("sha256", "raw", "hex", "example", "string", "123")) // 698d54f0494528a759f19c8e87a9f99e75a5881b9267ee3926bcf62c992d84ba Log(Encode("raw", "raw", "hex", "123")) // 313233 Log(Encode("raw", "raw", "base64", "123")) // MTIz Log(Encode("sha256", "raw", "hex", "example", "hex", "313233")) // 698d54f0494528a759f19c8e87a9f99e75a5881b9267ee3926bcf62c992d84ba Log(Encode("sha256", "raw", "hex", "example", "base64", "MTIz")) // 698d54f0494528a759f19c8e87a9f99e75a5881b9267ee3926bcf62c992d84ba }
    python
    def main(): Log(Encode("raw", "raw", "hex", "example", "raw", "123")) # 6578616d706c65 Log(Encode("raw", "raw", "hex", "example", "", "")) # 6578616d706c65 Log(Encode("sha256", "raw", "hex", "example", "raw", "123")) # 698d54f0494528a759f19c8e87a9f99e75a5881b9267ee3926bcf62c992d84ba Log(Encode("sha256", "raw", "hex", "example", "", "123")) # 50d858e0985ecc7f60418aaf0cc5ab587f42c2570a884095a9e8ccacd0f6545c Log(Encode("sha256", "raw", "hex", "example", "string", "123")) # 698d54f0494528a759f19c8e87a9f99e75a5881b9267ee3926bcf62c992d84ba Log(Encode("raw", "raw", "hex", "123", "", "")) # 313233 Log(Encode("raw", "raw", "base64", "123", "", "")) # MTIz Log(Encode("sha256", "raw", "hex", "example", "hex", "313233")) # 698d54f0494528a759f19c8e87a9f99e75a5881b9267ee3926bcf62c992d84ba Log(Encode("sha256", "raw", "hex", "example", "base64", "MTIz")) # 698d54f0494528a759f19c8e87a9f99e75a5881b9267ee3926bcf62c992d84ba
    c++
    void main() { Log(Encode("raw", "raw", "hex", "example", "raw", "123")); // 6578616d706c65 Log(Encode("raw", "raw", "hex", "example")); // 6578616d706c65 Log(Encode("sha256", "raw", "hex", "example", "raw", "123")); // 698d54f0494528a759f19c8e87a9f99e75a5881b9267ee3926bcf62c992d84ba Log(Encode("sha256", "raw", "hex", "example", "", "123")); // 50d858e0985ecc7f60418aaf0cc5ab587f42c2570a884095a9e8ccacd0f6545c Log(Encode("sha256", "raw", "hex", "example", "string", "123")); // 698d54f0494528a759f19c8e87a9f99e75a5881b9267ee3926bcf62c992d84ba Log(Encode("raw", "raw", "hex", "123")); // 313233 Log(Encode("raw", "raw", "base64", "123")); // MTIz Log(Encode("sha256", "raw", "hex", "example", "hex", "313233")); // 698d54f0494528a759f19c8e87a9f99e75a5881b9267ee3926bcf62c992d84ba Log(Encode("sha256", "raw", "hex", "example", "base64", "MTIz")); // 698d54f0494528a759f19c8e87a9f99e75a5881b9267ee3926bcf62c992d84ba }
  • The parameter algo also supports the following values: "text.encoder.utf8", "text.decoder.utf8", "text.encoder.gbk", "text.decoder.gbk", for encoding and decoding strings.

    javascript
    function main(){ var ret1 = Encode("text.encoder.utf8", "raw", "hex", "你好") // e4bda0e5a5bd Log(ret1) var ret2 = Encode("text.decoder.utf8", "hex", "string", ret1) Log(ret2) var ret3 = Encode("text.encoder.gbk", "raw", "hex", "你好") // c4e3bac3 Log(ret3) var ret4 = Encode("text.decoder.gbk", "hex", "string", ret3) Log(ret4) }
    python
    def main(): ret1 = Encode("text.encoder.utf8", "raw", "hex", "你好", "", "") # e4bda0e5a5bd Log(ret1) ret2 = Encode("text.decoder.utf8", "hex", "string", ret1, "", "") Log(ret2) ret3 = Encode("text.encoder.gbk", "raw", "hex", "你好", "", "") # c4e3bac3 Log(ret3) ret4 = Encode("text.decoder.gbk", "hex", "string", ret3, "", "") Log(ret4)
    c++
    void main(){ auto ret1 = Encode("text.encoder.utf8", "raw", "hex", "你好"); // e4bda0e5a5bd Log(ret1); auto ret2 = Encode("text.decoder.utf8", "hex", "string", ret1); Log(ret2); auto ret3 = Encode("text.encoder.gbk", "raw", "hex", "你好"); // c4e3bac3 Log(ret3); auto ret4 = Encode("text.decoder.gbk", "hex", "string", ret3); Log(ret4); }

Returns

TypeDescription

string

The Encode function returns the encoded and encrypted data.

Arguments

NameTypeRequiredDescription

algo

string

Yes

The parameter algo specifies the algorithm used for encoding calculation. Supported algorithms include: "raw" (no algorithm), "sign", "signTx", "md4", "md5", "sha256", "sha512", "sha1", "keccak256", "sha3.224", "sha3.256", "sha3.384", "sha3.512", "sha3.keccak256", "sha3.keccak512", "sha512.384", "sha512.256", "sha512.224", "ripemd160", "blake2b.256", "blake2b.512", "blake2s.128", "blake2s.256".

The parameter algo also supports string encoding/decoding: "text.encoder.utf8", "text.decoder.utf8", "text.encoder.gbk", "text.decoder.gbk".

The parameter algo also supports the "ed25519" algorithm, which can be used with different hash algorithms, for example: "ed25519.md5", "ed25519.sha512", etc. It also supports ed25519.seed calculation.

inputFormat

string

Yes

Specifies the data format of the data parameter. The inputFormat parameter can be set to one of: "raw", "hex", "base64", "string". "raw" represents raw data, "hex" represents hex encoded data, "base64" represents base64 encoded data, "string" represents string data.

outputFormat

string

Yes

Specifies the output data format. The outputFormat parameter can be set to one of: "raw", "hex", "base64", "string". "raw" represents raw data, "hex" represents hex encoded data, "base64" represents base64 encoded data, "string" represents string data.

data

string

Yes

The parameter data is the data to be processed.

keyFormat

string

No

Specifies the data format of the key parameter. The keyFormat parameter can be set to one of: "raw", "hex", "base64", "string". "raw" represents raw data, "hex" represents hex encoded data, "base64" represents base64 encoded data, "string" represents string data.

key

string

No

The parameter key is the key used for HMAC encryption.

When the parameter algo is set to "sign" or "signTx", the key parameter needs to be provided.

When the parameter algo is set to "raw", the key parameter will not be used for HMAC encryption (because HMAC encryption must specify an algorithm).

Remarks

The Encode() function only supports live trading. If the key and keyFormat parameters are not passed, key encryption is not used.

Get the current Unix timestamp in nanoseconds.

UnixNano()

Examples

To get a millisecond timestamp, use the following code:

javascript
function main() { var time = UnixNano() / 1000000 Log(_N(time, 0)) }
python
def main(): time = UnixNano() Log(time)
c++
void main() { auto time = UnixNano(); Log(time); }

Returns

TypeDescription

number

The UnixNano() function returns the current Unix timestamp in nanoseconds.

See Also

Get the current timestamp in seconds.

Unix()

Examples

javascript
function main() { var t = Unix() Log(t) }
python
def main(): t = Unix() Log(t)
c++
void main() { auto t = Unix(); Log(t); }

Returns

TypeDescription

number

Returns timestamp in seconds.

See Also

Get the operating system information of the device where the docker is located.

GetOS()

Examples

javascript
function main() { Log("GetOS:", GetOS()) }
python
def main(): Log("GetOS:", GetOS())
c++
void main() { Log("GetOS:", GetOS()); }

Returns

TypeDescription

string

Operating system information.

Remarks

For example, when calling GetOS() function on a docker running on Mac OS operating system, it may return: darwin/amd64, because Apple computers support multiple hardware architectures. Where darwin is the kernel name of the Mac OS system.

Calculate the MD5 hash value of the parameter data.

MD5(data)

Examples

javascript
function main() { Log("MD5", MD5("hello world")) }
python
def main(): Log("MD5", MD5("hello world"))
c++
void main() { Log("MD5", MD5("hello world")); }

Returns

TypeDescription

string

MD5 hash value.

Arguments

NameTypeRequiredDescription

data

string

Yes

The data to be MD5 calculated.

See Also

Remarks

Calling the MD5("hello world") function returns: 5eb63bbbe01eeed093cb22bb8f5acdc3.

Database interface function.

DBExec(sql)

Examples

  • Supports in-memory database. For the DBExec function parameters, if the SQL statement starts with :, it operates in the in-memory database without writing to files, which is faster. Suitable for database operations that don't require persistent storage, for example:

    javascript
    function main() { var strSql = [ ":CREATE TABLE TEST_TABLE(", "TS INT PRIMARY KEY NOT NULL,", "HIGH REAL NOT NULL,", "OPEN REAL NOT NULL,", "LOW REAL NOT NULL,", "CLOSE REAL NOT NULL,", "VOLUME REAL NOT NULL)" ].join("") var ret = DBExec(strSql) Log(ret) // 增加一条数据 Log(DBExec(":INSERT INTO TEST_TABLE (TS, HIGH, OPEN, LOW, CLOSE, VOLUME) VALUES (1518970320000, 100, 99.1, 90, 100, 12345.6);")) // 查询数据 Log(DBExec(":SELECT * FROM TEST_TABLE;")) }
    python
    def main(): arr = [ ":CREATE TABLE TEST_TABLE(", "TS INT PRIMARY KEY NOT NULL,", "HIGH REAL NOT NULL,", "OPEN REAL NOT NULL,", "LOW REAL NOT NULL,", "CLOSE REAL NOT NULL,", "VOLUME REAL NOT NULL)" ] strSql = "" for i in range(len(arr)): strSql += arr[i] ret = DBExec(strSql) Log(ret) # 增加一条数据 Log(DBExec(":INSERT INTO TEST_TABLE (TS, HIGH, OPEN, LOW, CLOSE, VOLUME) VALUES (1518970320000, 100, 99.1, 90, 100, 12345.6);")) # 查询数据 Log(DBExec(":SELECT * FROM TEST_TABLE;"))
    c++
    void main() { string strSql = ":CREATE TABLE TEST_TABLE(\n TS INT PRIMARY KEY NOT NULL,\n HIGH REAL NOT NULL,\n OPEN REAL NOT NULL,\n LOW REAL NOT NULL,\n CLOSE REAL NOT NULL,\n VOLUME REAL NOT NULL)"; auto ret = DBExec(strSql); Log(ret); // 增加一条数据 Log(DBExec(":INSERT INTO TEST_TABLE (TS, HIGH, OPEN, LOW, CLOSE, VOLUME) VALUES (1518970320000, 100, 99.1, 90, 100, 12345.6);")); // 查询数据 Log(DBExec(":SELECT * FROM TEST_TABLE;")); }
  • Use the DBExec() function to create a table.

    javascript
    function main() { var strSql = [ "CREATE TABLE TEST_TABLE(", "TS INT PRIMARY KEY NOT NULL,", "HIGH REAL NOT NULL,", "OPEN REAL NOT NULL,", "LOW REAL NOT NULL,", "CLOSE REAL NOT NULL,", "VOLUME REAL NOT NULL)" ].join("") var ret = DBExec(strSql) Log(ret) }
    python
    def main(): arr = [ "CREATE TABLE TEST_TABLE(", "TS INT PRIMARY KEY NOT NULL,", "HIGH REAL NOT NULL,", "OPEN REAL NOT NULL,", "LOW REAL NOT NULL,", "CLOSE REAL NOT NULL,", "VOLUME REAL NOT NULL)" ] strSql = "" for i in range(len(arr)): strSql += arr[i] ret = DBExec(strSql) Log(ret)
    c++
    void main() { string strSql = "CREATE TABLE TEST_TABLE(\ TS INT PRIMARY KEY NOT NULL,\ HIGH REAL NOT NULL,\ OPEN REAL NOT NULL,\ LOW REAL NOT NULL,\ CLOSE REAL NOT NULL,\ VOLUME REAL NOT NULL)"; auto ret = DBExec(strSql); Log(ret); }
  • CRUD operations on table records.

    javascript
    function main() { var strSql = [ "CREATE TABLE TEST_TABLE(", "TS INT PRIMARY KEY NOT NULL,", "HIGH REAL NOT NULL,", "OPEN REAL NOT NULL,", "LOW REAL NOT NULL,", "CLOSE REAL NOT NULL,", "VOLUME REAL NOT NULL)" ].join("") Log(DBExec(strSql)) // 增加一条数据 Log(DBExec("INSERT INTO TEST_TABLE (TS, HIGH, OPEN, LOW, CLOSE, VOLUME) VALUES (1518970320000, 100, 99.1, 90, 100, 12345.6);")) // 查询数据 Log(DBExec("SELECT * FROM TEST_TABLE;")) // 修改数据 Log(DBExec("UPDATE TEST_TABLE SET HIGH=? WHERE TS=?", 110, 1518970320000)) // 删除数据 Log(DBExec("DELETE FROM TEST_TABLE WHERE HIGH=?", 110)) }
    python
    def main(): arr = [ "CREATE TABLE TEST_TABLE(", "TS INT PRIMARY KEY NOT NULL,", "HIGH REAL NOT NULL,", "OPEN REAL NOT NULL,", "LOW REAL NOT NULL,", "CLOSE REAL NOT NULL,", "VOLUME REAL NOT NULL)" ] strSql = "" for i in range(len(arr)): strSql += arr[i] Log(DBExec(strSql)) # 增加一条数据 Log(DBExec("INSERT INTO TEST_TABLE (TS, HIGH, OPEN, LOW, CLOSE, VOLUME) VALUES (1518970320000, 100, 99.1, 90, 100, 12345.6);")) # 查询数据 Log(DBExec("SELECT * FROM TEST_TABLE;")) # 修改数据 Log(DBExec("UPDATE TEST_TABLE SET HIGH=? WHERE TS=?", 110, 1518970320000)) # 删除数据 Log(DBExec("DELETE FROM TEST_TABLE WHERE HIGH=?", 110))
    c++
    void main() { string strSql = "CREATE TABLE TEST_TABLE(\ TS INT PRIMARY KEY NOT NULL,\ HIGH REAL NOT NULL,\ OPEN REAL NOT NULL,\ LOW REAL NOT NULL,\ CLOSE REAL NOT NULL,\ VOLUME REAL NOT NULL)"; Log(DBExec(strSql)); // 增加一条数据 Log(DBExec("INSERT INTO TEST_TABLE (TS, HIGH, OPEN, LOW, CLOSE, VOLUME) VALUES (1518970320000, 100, 99.1, 90, 100, 12345.6);")); // 查询数据 Log(DBExec("SELECT * FROM TEST_TABLE;")); // 修改数据 Log(DBExec("UPDATE TEST_TABLE SET HIGH=? WHERE TS=?", 110, 1518970320000)); // 删除数据 Log(DBExec("DELETE FROM TEST_TABLE WHERE HIGH=?", 110)); }

Returns

TypeDescription

object

Object containing SQL statement execution results, for example:

json
{"columns":["TS","HIGH","OPEN","LOW","CLOSE","VOLUME"],"values":[[1518970320000,100,99.1,90,100,12345.6]]}

Arguments

NameTypeRequiredDescription

sql

string

Yes

SQL statement string.

See Also

Remarks

  • The function DBExec() can operate on the live trading database (SQLite database) through passed parameters.

  • Implements operations such as insert, delete, query, and update on data in the live trading database, supporting SQLite syntax.

  • System reserved tables in the live trading database: kvdb, cfg, log, profit, chart. Please do not operate on these tables.

  • Currently does not support transactions. Such operations are not recommended as they may cause system conflicts.

  • The DBExec() function only supports live trading environment.

Create a UUID.

UUID()

Examples

javascript
function main() { var uuid1 = UUID() var uuid2 = UUID() Log(uuid1, uuid2) }
python
def main(): uuid1 = UUID() uuid2 = UUID() Log(uuid1, uuid2)
c++
void main() { auto uuid1 = UUID(); auto uuid2 = UUID(); Log(uuid1, uuid2); }

Returns

TypeDescription

string

Returns a 32-character UUID string.

Remarks

The UUID() function is only supported in live trading environment.

Listens for events and returns when any WebSocket has readable data or when concurrent tasks such as exchange.Go(), HttpQuery_Go(), etc. are completed.

EventLoop()
EventLoop(timeout)

Examples

javascript
function main() { var routine_getTicker = exchange.Go("GetTicker") var routine_getDepth = exchange.Go("GetDepth") var routine_getTrades = exchange.Go("GetTrades") // Sleep(2000), if you use the Sleep statement here, it will cause the subsequent EventLoop function to miss previous events, because after waiting for 2 seconds, the concurrent functions have already received data, and the EventLoop listening mechanism starts afterwards, thus missing these events // Unless you call EventLoop(-1) at the very first line of code to initialize the EventLoop listening mechanism first, then these events will not be missed // Log("GetDepth:", routine_getDepth.wait()) If you call the wait function here in advance to retrieve the result of the GetDepth concurrent call, the event of GetDepth function receiving the request result will not be returned in the EventLoop function var ts1 = new Date().getTime() var ret1 = EventLoop(0) var ts2 = new Date().getTime() var ret2 = EventLoop(0) var ts3 = new Date().getTime() var ret3 = EventLoop(0) Log("First concurrent task completed:", _D(ts1), ret1) Log("Second concurrent task completed:", _D(ts2), ret2) Log("Third concurrent task completed:", _D(ts3), ret3) Log("GetTicker:", routine_getTicker.wait()) Log("GetDepth:", routine_getDepth.wait()) Log("GetTrades:", routine_getTrades.wait()) }
python
import time def main(): routine_getTicker = exchange.Go("GetTicker") routine_getDepth = exchange.Go("GetDepth") routine_getTrades = exchange.Go("GetTrades") ts1 = time.time() ret1 = EventLoop(0) ts2 = time.time() ret2 = EventLoop(0) ts3 = time.time() ret3 = EventLoop(0) Log("First concurrent task completed:", _D(ts1), ret1) Log("Second concurrent task completed:", _D(ts2), ret2) Log("Third concurrent task completed:", _D(ts3), ret3) Log("GetTicker:", routine_getTicker.wait()) Log("GetDepth:", routine_getDepth.wait()) Log("GetTrades:", routine_getTrades.wait())
c++
void main() { auto routine_getTicker = exchange.Go("GetTicker"); auto routine_getDepth = exchange.Go("GetDepth"); auto routine_getTrades = exchange.Go("GetTrades"); auto ts1 = Unix() * 1000; auto ret1 = EventLoop(0); auto ts2 = Unix() * 1000; auto ret2 = EventLoop(0); auto ts3 = Unix() * 1000; auto ret3 = EventLoop(0); Log("First concurrent task completed:", _D(ts1), ret1); Log("Second concurrent task completed:", _D(ts2), ret2); Log("Third concurrent task completed:", _D(ts3), ret3); Ticker ticker; Depth depth; Trades trades; routine_getTicker.wait(ticker); routine_getDepth.wait(depth); routine_getTrades.wait(trades); Log("GetTicker:", ticker); Log("GetDepth:", depth); Log("GetTrades:", trades); }

Returns

TypeDescription

object

If the returned object is not null, the Event contained in the return content indicates the event trigger type. For example, the following return value structure:

json
{"Seq":1,"Event":"Exchange_GetTrades","ThreadId":0,"Index":3,"Nano":1682068771309583400}

Arguments

NameTypeRequiredDescription

timeout

number

No

The parameter timeout is the timeout setting in milliseconds.
If the parameter timeout is set to 0, it waits until an event occurs before returning; if greater than 0, it sets the event wait timeout; if less than 0, it immediately returns the most recent event.

See Also

Remarks

The event listening mechanism is initialized only when the EventLoop() function is called for the first time in the code. If EventLoop() is called for the first time after event callbacks have occurred, previous events will be missed. The underlying system's encapsulated queue structure caches up to 500 event callbacks. If the EventLoop() function is not called in time during program execution to retrieve events, later event callbacks exceeding the 500 cache limit will be lost.
Calling the EventLoop() function does not affect the underlying system's WebSocket cache queue, nor does it affect the cache of concurrent functions such as exchange.Go(). For these caches, you still need to use their respective methods to retrieve data. Data that has been retrieved before the EventLoop() function returns will not generate return events in the EventLoop() function.
The main purpose of the EventLoop() function is to notify the strategy layer that the underlying system has received new network data, driving the entire strategy through events. When the EventLoop() function returns an event, simply iterate through all data sources, such as WebSocket connections and objects created by exchange.Go(), to attempt to retrieve data.
The EventLoop() function only supports live trading environments.

When called in the main function main(), it listens for events in the main thread. In strategies written in JavaScript, threads created by the threading.Thread() function can call this function within their execution functions to listen for events in the current thread.

The __Serve function is used to create HTTP services, TCP services, and WebSocket services (based on HTTP protocol).

__Serve(serveURI, handler)
__Serve(serveURI, handler, ...args)

Examples

javascript
function main() { let httpServer = __Serve("http://:8088?gzip=true", function (ctx) { Log("http connect from: ", ctx.remoteAddr(), "->", ctx.localAddr()) let path = ctx.path() if (path == "/") { ctx.write(JSON.stringify({ path: ctx.path(), method: ctx.method(), headers: ctx.headers(), cookie: ctx.header("Cookie"), remote: ctx.remoteAddr(), query: ctx.rawQuery() })) } else if (path == "/tickers") { let ret = exchange.GetTickers() if (!ret) { ctx.setStatus(500) ctx.write(GetLastError()) } else { ctx.write(JSON.stringify(ret)) } } else if (path == "/wss") { if (ctx.upgrade("websocket")) { // upgrade to websocket while (true) { let r = ctx.read(10) if (r == "") { break } else if (r) { if (r == "ticker") { ctx.write(JSON.stringify(exchange.GetTicker())) } else { ctx.write("not support") } } } Log("websocket closed", ctx.remoteAddr()) } } else { ctx.setStatus(404) } }) let echoServer = __Serve("tcp://:8089", function (ctx) { Log("tcp connect from: ", ctx.remoteAddr(), "->", ctx.localAddr()) while (true) { let d = ctx.read() if (!d) { break } ctx.write(d) } Log("connect closed") }) Log("http serve on", httpServer, "tcp serve on", echoServer) for (var i = 0; i < 5; i++) { if (i == 2) { // test Http var retHttp = HttpQuery("http://127.0.0.1:8088?num=123&limit=100", {"debug": true}) Log("retHttp:", retHttp) } else if (i == 3) { // test TCP var tcpConn = Dial("tcp://127.0.0.1:8089") tcpConn.write("Hello TCP Server") var retTCP = tcpConn.read() Log("retTCP:", retTCP) } else if (i == 4) { // test Websocket var wsConn = Dial("ws://127.0.0.1:8088/wss|compress=gzip") wsConn.write("ticker") var retWS = wsConn.read(1000) Log("retWS:", retWS) // no depth wsConn.write("depth") retWS = wsConn.read(1000) Log("retWS:", retWS) } Sleep(1000) } }
python
# Not supported
c++
// Not supported

Returns

TypeDescription

string

Returns a string recording the IP address and port of the created service. For example: 127.0.0.1:8088, [::]:8089.

Arguments

NameTypeRequiredDescription

serveURI

string

Yes

The serveURI parameter is used to configure the protocol, IP address, port and other settings for service binding, for example: http://0.0.0.0:8088?gzip=true, i.e.: http://:8088?gzip=true.

  • TCP Protocol
    serveURI parameter setting example: tcp://127.0.0.1:6666?tls=true; certificates and private keys can be added, for example: tls=true&cert_pem=xxxx&cert_key_pem=xxxx.
  • HTTP Protocol
    serveURI parameter setting example: http://127.0.0.1:6666?gzip=true; compression settings can be configured: gzip=true.
    serveURI parameter for HTTPS example: https://127.0.0.1:6666?tls=true&gzip=true; cert_pem and cert_key_pem parameters can be added to load certificates.

handler

function

Yes

The handler parameter is used to pass in the route handler function (HTTP protocol), message handler function (TCP protocol), or Stream handler function (WebSocket).

The callback function passed in via the handler parameter can define multiple parameters, with the first parameter being the ctx object (context object).

arg

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

No

As the actual arguments for the parameters of the callback function passed in via the handler parameter, there may be multiple arg parameters, for example:

javascript
__Serve("http://:8088", function(ctx, a, b, c) { Log(`ctx.host():`, ctx.host(), ", a=", a, ", b=", b, ", c=", c) }, 1, 2, 3)

The parameters 1, 2, 3 passed when calling the __Serve() function correspond to the parameters a, b, c of the callback function.

See Also

Remarks

  • This function only supports JavaScript language strategies.

    • The service thread is isolated from the global scope, so it does not support closures or references to external variables, custom functions, etc.; however, all platform API functions can be called.

    • WebSocket service is implemented based on HTTP protocol. You can set a routing branch in the path and design the implementation code for WebSocket message subscription/push. Please refer to the example code in this section.

The callback handler function passed in the handler parameter receives a ctx parameter. The ctx parameter is a context object used to get data and write data, with the following methods:

  • ctx.proto()
    Applies to HTTP/TCP protocol, returns the protocol name when called. For example: HTTP/1.1, tcp.
  • ctx.host()
    Applies to HTTP protocol, returns host information when called: IP address, port.
  • ctx.path()
    Applies to HTTP protocol, returns the request path when called.
  • ctx.query(key)
    Applies to HTTP protocol, returns the value corresponding to the key in the query of the request when called. For example, if the request sent is: http://127.0.0.1:8088?num=123, calling ctx.query("num") in the callback handler function passed in the handler parameter returns "123".
  • ctx.rawQuery()
    Applies to HTTP protocol, returns the raw query in the request (query of the HTTP request) when called.
  • ctx.headers()
    Applies to HTTP protocol, returns the request header information in the request when called.
  • ctx.header(key)
    Applies to HTTP protocol, returns the value corresponding to a specific key in the specified request header when called. For example, to get the User-Agent in the headers of the current request: ctx.header("User-Agent").
  • ctx.method()
    Applies to HTTP protocol, returns the request method when called, such as GET, POST, etc.
  • ctx.body()
    Applies to POST requests of HTTP protocol, returns the body of the request when called.
  • ctx.setHeader(key, value)
    Applies to HTTP protocol, sets the request header information of the response message.
  • ctx.setStatus(code)
    Applies to HTTP protocol, sets the HTTP message status code. Usually the HTTP status code is set at the end of the routing branch, default is 200.
  • ctx.remoteAddr()
    Applies to HTTP/TCP protocol, returns the remote client address and port in the request when called.
  • ctx.localAddr()
    Applies to HTTP/TCP protocol, returns the local service address and port when called.
  • ctx.upgrade("websocket")
    Applies to WebSocket protocol implementation based on HTTP protocol, switches the ctx context object to WebSocket protocol; returns boolean value (true) on successful switch, boolean value (false) on failure.
  • ctx.read(timeout_ms)
    Applies to WebSocket protocol implementation based on HTTP protocol/TCP protocol, reads data from WebSocket connection or TCP connection. The read method is not supported in regular HTTP protocol; you can specify the timeout parameter timeout_ms in milliseconds.
  • ctx.write(s)
    Applies to HTTP/TCP protocol, used to write string data. You can use JSON.stringify() to encode JSON objects as strings before writing. For WebSocket protocol, this method can be used to pass the encoded string to the client.

Persistently save data. This function implements a savable global dictionary feature. The data structure is a key-value pair table, permanently saved in the docker's local database file.

_G()
_G(k)
_G(k, v)

Examples

javascript
function main(){ // 设置一个全局变量num,值为1 _G("num", 1) // 更改一个全局变量num,值为字符串ok _G("num", "ok") // 删除全局变量num _G("num", null) // 返回全局变量num的值 Log(_G("num")) // 删除所有全局变量 _G(null) // 返回实盘ID var robotId = _G() }
python
def main(): _G("num", 1) _G("num", "ok") _G("num", None) Log(_G("num")) _G(None) robotId = _G()
c++
void main() { _G("num", 1); _G("num", "ok"); _G("num", NULL); Log(_G("num")); _G(NULL); // 不支持 auto robotId = _G(); }

Returns

TypeDescription

string / number / bool / object / array / null

The key value data in the persistently saved k-v key-value pair.

Arguments

NameTypeRequiredDescription

k

string / null

No

The parameter k is the key name in the saved key-value pair, case-insensitive.

v

string / number / bool / object / array / null

No

The parameter v is the key value in the saved key-value pair, can be any data type that supports JSON serialization.

See Also

Remarks

Each live trading uses a separate database. When the strategy restarts or the docker stops running, the data saved by the _G() function will persist. If the backtest ends, the data saved by the _G() function in the backtest system will be cleared. When using the _G() function to persistently save data, it should be used reasonably according to the memory and disk space of the hardware device to avoid abuse.

In live trading, when calling the _G() function without passing any parameters, the _G() function returns the Id of the current live trading.

When calling the _G() function, passing null for parameter v means deleting the k-v key-value pair.

When calling the _G() function and only passing parameter k (string type), the _G() function returns the saved key value corresponding to parameter k.

When calling the _G() function and only passing null for parameter k, it means deleting all recorded k-v key-value pairs.

After a k-v key-value pair has been persistently saved, calling the _G() function again with the already persistently saved key name as parameter k and a new key value as parameter v will update the k-v key-value pair.

Taking live trading Id 123456 as an example, the key-value pair data persistently saved using the _G() function is stored in the database file /logs/storage/123456/123456.db3 under the docker directory to which the live trading (i.e., strategy instance program) belongs, and the data is recorded in the kvdb table.

Convert millisecond timestamp or Date object to time string.

_D()
_D(timestamp)
_D(timestamp, fmt)

Examples

  • Get and print current time string:

    javascript
    function main(){ var time = _D() Log(time) }
    python
    def main(): strTime = _D() Log(strTime)
    c++
    void main() { auto strTime = _D(); Log(strTime); }
  • Timestamp is 1574993606000, convert using code:

    javascript
    function main() { Log(_D(1574993606000)) }
    python
    def main(): # Running on Beijing time server: 2019-11-29 10:13:26, running this code on a docker on another regional server results in: 2019-11-29 02:13:26 Log(_D(1574993606))
    c++
    void main() { Log(_D(1574993606000)); }
  • Use parameter fmt for formatting. Format strings differ between JavaScript, Python, and C++ languages. See the following examples for details:

    javascript
    function main() { Log(_D(1574993606000, "yyyy--MM--dd hh--mm--ss")) // 2019--11--29 10--13--26 }
    python
    def main(): # 1574993606 is a second-level timestamp Log(_D(1574993606, "%Y--%m--%d %H--%M--%S")) # 2019--11--29 10--13--26
    c++
    void main() { Log(_D(1574993606000, "%Y--%m--%d %H--%M--%S")); // 2019--11--29 10--13--26 }

Returns

TypeDescription

string

Time string.

Arguments

NameTypeRequiredDescription

timestamp

number / object

No

Millisecond timestamp or Date object.

fmt

string

No

Format string. JavaScript default format: yyyy-MM-dd hh:mm:ss; Python default format: %Y-%m-%d %H:%M:%S; C++ default format: %Y-%m-%d %H:%M:%S.

See Also

Remarks

Returns current time string when no parameters are passed. When using _D() function in Python strategies, note that the parameter passed should be a second-level timestamp (JavaScript and C++ strategies use millisecond-level timestamps, 1 second equals 1000 milliseconds). When using _D() function in live trading environment to parse timestamps into readable time strings, pay attention to the timezone and time settings of the operating system where the docker is located. The _D() function parses timestamps into readable time strings based on the local time of the docker system.

Format floating-point numbers.

_N()
_N(num)
_N(num, precision)

Examples

  • For example, _N(3.1415, 2) will remove digits beyond two decimal places from 3.1415, and the function returns 3.14.

    javascript
    function main(){ var i = 3.1415 Log(i) var ii = _N(i, 2) Log(ii) }
    python
    def main(): i = 3.1415 Log(i) ii = _N(i, 2) Log(ii)
    c++
    void main() { auto i = 3.1415; Log(i); auto ii = _N(i, 2); Log(ii); }
  • To set N digits to the left of the decimal point to 0, you can use negative precision:

    javascript
    function main(){ var i = 1300 Log(i) var ii = _N(i, -3) // 查看日志得知为1000 Log(ii) }
    python
    def main(): i = 1300 Log(i) ii = _N(i, -3) Log(ii)
    c++
    void main() { auto i = 1300; Log(i); auto ii = _N(i, -3); Log(ii); }

Returns

TypeDescription

number

The formatted floating-point number according to the precision setting.

Arguments

NameTypeRequiredDescription

num

number

Yes

The floating-point number to be formatted.

precision

number

No

The precision setting for formatting. The parameter precision is an integer with a default value of 4.

See Also

Remarks

The parameter precision can be a positive or negative integer.

Retry function for interface fault tolerance handling.

_C(pfn)
_C(pfn, ...args)

Examples

  • For fault tolerance of functions without parameters:

    javascript
    function main(){ var ticker = _C(exchange.GetTicker) // Adjust the retry interval of _C() function to 2 seconds _CDelay(2000) var depth = _C(exchange.GetDepth) Log(ticker) Log(depth) }
    python
    def main(): ticker = _C(exchange.GetTicker) _CDelay(2000) depth = _C(exchange.GetDepth) Log(ticker) Log(depth)
    c++
    void main() { auto ticker = _C(exchange.GetTicker); _CDelay(2000); auto depth = _C(exchange.GetDepth); Log(ticker); Log(depth); }
  • For fault tolerance of functions with parameters:

    javascript
    function main(){ var records = _C(exchange.GetRecords, PERIOD_D1) Log(records) }
    python
    def main(): records = _C(exchange.GetRecords, PERIOD_D1) Log(records)
    c++
    void main() { auto records = _C(exchange.GetRecords, PERIOD_D1); Log(records); }
  • Can also be used for fault tolerance handling of custom functions:

    javascript
    var test = function(a, b){ var time = new Date().getTime() / 1000 if(time % b == 3){ Log("Condition met!", "#FF0000") return true } Log("Retrying!", "#FF0000") return false } function main(){ var ret = _C(test, 1, 5) Log(ret) }
    python
    import time def test(a, b): ts = time.time() if ts % b == 3: Log("Condition met!", "#FF0000") return True Log("Retrying!", "#FF0000") return False def main(): ret = _C(test, 1, 5) Log(ret)
    c++
    // C++ does not support this method for custom function fault tolerance

Returns

TypeDescription

All platform-supported types except false values and null values (any).

The return value when the callback function is executed.

Arguments

NameTypeRequiredDescription

pfn

function

Yes

The parameter pfn is a function reference, which is a callback function.

arg

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

No

Parameters for the callback function. There may be multiple arg parameters. The type and number of arg parameters depend on the parameter definition of the callback function.

Remarks

The _C() function will continuously call the specified function until it returns successfully (it will retry calling pfn when the function referenced by parameter pfn returns null or false).

For example _C(exchange.GetTicker). The default retry interval is 3 seconds. You can call the _CDelay() function to set the retry interval.

For example _CDelay(1000) means changing the retry interval of the _C() function to 1 second.

The following functions can be (but are not limited to) handled for fault tolerance:

  • exchange.GetTicker()
  • exchange.GetDepth()
  • exchange.GetTrades()
  • exchange.GetRecords()
  • exchange.GetAccount()
  • exchange.GetOrders()
  • exchange.GetOrder()
  • exchange.GetPositions()

All the above functions can be called through the _C() function to achieve fault tolerance. The _C() function is not limited to fault tolerance for the above functions. The parameter pfn is a function reference, not a function call. Note that you should use _C(exchange.GetTicker) instead of _C(exchange.GetTicker()).

Returns the number of periods since array arr1 crossed array arr2.

_Cross(arr1, arr2)

Examples

You can simulate a set of data to test the _Cross(Arr1, Arr2) function:

javascript
// 快线指标 var arr1 = [1,2,3,4,5,6,8,8,9] // 慢线指标 var arr2 = [2,3,4,5,6,7,7,7,7] function main(){ Log("_Cross(arr1, arr2) : ", _Cross(arr1, arr2)) Log("_Cross(arr2, arr1) : ", _Cross(arr2, arr1)) }
python
arr1 = [1,2,3,4,5,6,8,8,9] arr2 = [2,3,4,5,6,7,7,7,7] def main(): Log("_Cross(arr1, arr2) : ", _Cross(arr1, arr2)) Log("_Cross(arr2, arr1) : ", _Cross(arr2, arr1))
c++
void main() { vector<double> arr1 = {1,2,3,4,5,6,8,8,9}; vector<double> arr2 = {2,3,4,5,6,7,7,7,7}; Log("_Cross(arr1, arr2) : ", _Cross(arr1, arr2)); Log("_Cross(arr2, arr1) : ", _Cross(arr2, arr1)); }

Returns

TypeDescription

number

The number of periods since array arr1 crossed array arr2.

Arguments

NameTypeRequiredDescription

arr1

array

Yes

Array with elements of type number.

arr2

array

Yes

Array with elements of type number.

Remarks

When the return value of _Cross() function is positive, it indicates the number of periods since upward crossover; when negative, it indicates the number of periods since downward crossover; when 0, it indicates the current values are equal. For detailed usage instructions: Built-in Function _Cross Analysis and Usage Guide.

The JSON.parse function is a method of the ECMAScript standard built-in object JSON, used for parsing JSON strings. The FMZ Quant Trading Platform has extended it by adding a safeStr parameter.

JSON.parse(s)
JSON.parse(s, safeStr)

Examples

Parse JSON strings containing large numeric values.

javascript
function main() { let s1 = '{"num": 8754613216564987646512354656874651651358}' Log("JSON.parse:", JSON.parse(s1)) // JSON.parse: {"num":8.754613216564987e+39} Log("JSON.parse:", JSON.parse(s1, true)) // JSON.parse: {"num":"8754613216564987646512354656874651651358"} let s2 = '{"num": 123}' Log("JSON.parse:", JSON.parse(s2)) // JSON.parse: {"num":123} Log("JSON.parse:", JSON.parse(s2, true)) // JSON.parse: {"num":123} }
python
# 可以使用Python的第三方库处理大数值数据。
c++
// 可以使用其它方案处理。

Returns

TypeDescription

object

Returns the parsed JSON object.

Arguments

NameTypeRequiredDescription

s

string

Yes

The JSON string to be parsed.

safeStr

bool

No

When this parameter is set to true, if numeric values that may exceed the precision range are encountered during parsing, they will be returned as strings to avoid precision loss or overflow issues.

Remarks

The JSON.parse() function can correctly parse JSON strings containing large numeric values. When the safeStr parameter is set to a truthy value, large numeric values will be parsed as string types.

The safeStr parameter also supports being used as a reviver parameter, i.e., a function that transforms the result. This function will be called for each member of the object. Please refer to relevant documentation for details.

Only supported in JavaScript language.

The safeStr parameter feature of the JSON.parse() function is not supported in the backtesting system.

The JSON.stringify function is a method of the ECMAScript standard built-in object JSON, used to convert JavaScript values to JSON strings.

JSON.stringify(obj)

Examples

Serialize an object to a JSON string and output it.

javascript
function main() { let s1 = {"num": "8754613216564987646512354656874651651358"} Log("JSON.stringify:", JSON.stringify(s1)) // JSON.stringify: {"num":"8754613216564987646512354656874651651358"} // The variable returned by JSON.stringify(s1) is of string type }
python
// Omitted
c++
// Omitted

Returns

TypeDescription

string

Returns the serialized JSON string.

Arguments

NameTypeRequiredDescription

obj

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

Yes

The value to be serialized into a JSON string.

Remarks

Only supported in JavaScript language.

Publishes the latest status data to a channel. This function is used for inter-live trading communication, allowing the current live trading instance to broadcast its status data to a channel for other live trading instances to subscribe and retrieve.

SetChannelData(data)

Examples

  • Channel Broadcaster Example - Publishing BTC Price Market Data

    javascript
    function main() { var updateId = 0 var robotId = _G() // Get current live trading bot ID while(true) { // Get actual market price var ticker = exchange.GetTicker("BTC_USDT") if (!ticker) { Sleep(5000) continue } // Prepare current channel state data var channelState = { robotId: robotId, updateId: ++updateId, timestamp: Date.now(), symbol: "BTC_USDT", lastPrice: ticker.Last, volume: ticker.Volume, high: ticker.High, low: ticker.Low } // Publish latest state on channel (overwrites old state) SetChannelData(channelState) // Display current channel state LogStatus("Channel Broadcaster [Bot ID: " + robotId + "]\n" + "Update ID: #" + channelState.updateId + "\n" + "Time: " + _D(channelState.timestamp) + "\n" + "Symbol: " + channelState.symbol + "\n" + "Last Price: $" + channelState.lastPrice.toFixed(2) + "\n" + "Volume: " + channelState.volume.toFixed(4) + "\n" + "High: $" + channelState.high.toFixed(2) + "\n" + "Low: $" + channelState.low.toFixed(2)) Sleep(60000) // Update channel state every minute } }
    python
    def main(): updateId = 0 robotId = _G() # Get current live trading bot ID while True: # Get actual market price ticker = exchange.GetTicker("BTC_USDT") if not ticker: Sleep(5000) continue # Prepare current channel state data channelState = { "robotId": robotId, "updateId": updateId + 1, "timestamp": time.time() * 1000, "symbol": "BTC_USDT", "lastPrice": ticker["Last"], "volume": ticker["Volume"], "high": ticker["High"], "low": ticker["Low"] } updateId += 1 # Publish latest state on channel (overwrites old state) SetChannelData(channelState) # Display current channel state LogStatus("Channel Broadcaster [Bot ID: {}]\n".format(robotId) + "Update ID: #{}\n".format(channelState["updateId"]) + "Time: {}\n".format(_D(channelState["timestamp"])) + "Symbol: {}\n".format(channelState["symbol"]) + "Last Price: ${:.2f}\n".format(channelState["lastPrice"]) + "Volume: {:.4f}\n".format(channelState["volume"]) + "High: ${:.2f}\n".format(channelState["high"]) + "Low: ${:.2f}".format(channelState["low"])) Sleep(60000) # Update channel state every minute
    c++
  • Cross-platform sending example - Simulating external platform (e.g., TradingView) sending data to FMZ live trading

    javascript
    // This example demonstrates how to use HttpQuery to send HTTP POST requests, simulating external platforms sending data to FMZ live trading // In actual scenarios, external platforms (such as TradingView's Webhook alert URL, third-party trading systems, etc.) would directly call the FMZ API endpoint function main() { let uuid = "6BC42A119B5DBFA2188A8279DA3B5C30" let robotId = 123456 // Target live trading ID (the live trading instance that needs to receive data) let baseUrl = "https://www.fmz.com" while (true) { // Prepare the data to send (can be JSON, text, or other formats) let sendData = { "action": "buy", "symbol": "BTC_USDT", "price": 50000, "timestamp": Date.now() } // Construct HTTP POST request let options = { method: "POST", body: JSON.stringify(sendData) // body can be JSON string, plain text, etc. } let url = `${baseUrl}/api/v1?method=pub&robot=${robotId}&channel=${uuid}` // Send data let ret = HttpQuery(url, options) Log("Simulated external platform sending data, result:", ret) Sleep(10000) // Send every 10 seconds } }
    python
    # This example demonstrates how to use HttpQuery to send HTTP POST requests, simulating external platforms sending data to FMZ live trading # In actual scenarios, external platforms (such as TradingView's Webhook alert URL, third-party trading systems, etc.) would directly call the FMZ API endpoint import json def main(): uuid = "6BC42A119B5DBFA2188A8279DA3B5C30" robotId = 123456 # Target live trading ID (the live trading instance that needs to receive data) baseUrl = "https://www.fmz.com" while True: # Prepare the data to send (can be JSON, text, or other formats) sendData = { "action": "buy", "symbol": "BTC_USDT", "price": 50000, "timestamp": time.time() * 1000 } # Construct HTTP POST request options = { "method": "POST", "body": json.dumps(sendData) # body can be JSON string, plain text, etc. } url = "{}/api/v1?method=pub&robot={}&channel={}".format(baseUrl, robotId, uuid) # Send data ret = HttpQuery(url, options) Log("Simulated external platform sending data, result:", ret) Sleep(10000) # Send every 10 seconds
    c++

Returns

TypeDescription

null value

The function has no return value.

Arguments

NameTypeRequiredDescription

data

object / array / string / number / bool / null value

Yes

The data to be published to the channel, can be any data structure that can be JSON serialized, typically an object containing live trading status information.

See Also

Remarks

The SetChannelData() function is a non-blocking call that returns immediately after invocation without waiting for data transmission to complete.

Each live trading instance has an independent channel, and the channel ID is the live trading ID (which can be obtained through the _G() function).

Only the latest status data is saved on the channel. Each call to SetChannelData() overwrites the previously published data rather than appending historical messages.

Channel data can be broadcast across live trading instances, across dockers, and across servers. Multiple live trading instances can subscribe to the same channel.

The subscriber uses the GetChannelData() function to subscribe to channel data.

Channel communication is applicable to live trading environments; this feature may be limited in the backtesting system.

The byte length of the data parameter data after JSON serialization must not exceed 1024 bytes. Exceeding this limit may cause data publishing to fail. It is recommended to transmit only necessary status information and avoid transmitting overly large data objects.

Published data should be used reasonably according to the memory and network bandwidth of hardware devices. Avoid publishing overly large data objects.

In addition to being subscribed by other live trading instances within the FMZ platform, data published by the SetChannelData() function also supports cross-platform data sending functionality. External platforms (such as TradingView Webhook alerts, third-party trading systems, monitoring software, etc.) can send data to a specified FMZ live trading instance via HTTP POST requests.

Cross-platform data sending method: External systems send data to the FMZ platform API endpoint via HTTP POST request: https://www.fmz.com/api/v1?method=pub&robot={robotId}&channel={uuid}, where robotId is the target live trading ID, and uuid is a 32-character channel identifier. The data to be sent is passed in the request body and can be in JSON format, text, or other formats. Note: A live trading instance must first subscribe to the UUID channel before external systems can successfully send data; the broadcast data will be sent to all live trading instances under the docker where the robotId live trading instance is located, and all live trading instances under the same docker that have subscribed to the UUID channel can receive the data.

Subscribe to channel data from a specified live trading instance. This function is used for inter-instance communication, allowing retrieval of the latest status data published by other live trading instances via the SetChannelData() function.

GetChannelData(channelId)

Examples

  • Channel Subscriber Example - Subscribe to channel data from two live trading bots

    javascript
    function main() { // Two channel IDs to subscribe to (modify according to actual situation) var channelId1 = "632799" // Live trading bot ID for channel 1 var channelId2 = "632800" // Live trading bot ID for channel 2 while(true) { // Subscribe to current state of channel 1 var state1 = GetChannelData(channelId1) // Subscribe to current state of channel 2 var state2 = GetChannelData(channelId2) // Build status display var statusMsg = "Channel Subscriber - Current Subscription Status\n\n" // Display channel 1 status statusMsg += "═══ Channel 1 [" + channelId1 + "] ═══\n" if (state1 !== null) { statusMsg += "Update ID: #" + state1.updateId + "\n" statusMsg += "Time: " + _D(state1.timestamp) + "\n" statusMsg += "Symbol: " + state1.symbol + "\n" statusMsg += "Last Price: $" + state1.lastPrice.toFixed(2) + "\n" statusMsg += "Volume: " + state1.volume.toFixed(4) + "\n" } else { statusMsg += "Status: Waiting... (first call returns null)\n" } statusMsg += "\n" // Display channel 2 status statusMsg += "═══ Channel 2 [" + channelId2 + "] ═══\n" if (state2 !== null) { statusMsg += "Update ID: #" + state2.updateId + "\n" statusMsg += "Time: " + _D(state2.timestamp) + "\n" statusMsg += "Symbol: " + state2.symbol + "\n" statusMsg += "Last Price: $" + state2.lastPrice.toFixed(2) + "\n" statusMsg += "Volume: " + state2.volume.toFixed(4) + "\n" } else { statusMsg += "Status: Waiting... (first call returns null)\n" } LogStatus(statusMsg) Sleep(5000) // Subscribe to channels every 5 seconds } }
    python
    def main(): # Two channel IDs to subscribe to (modify according to actual situation) channelId1 = "632799" # Live trading bot ID for channel 1 channelId2 = "632800" # Live trading bot ID for channel 2 while True: # Subscribe to current state of channel 1 state1 = GetChannelData(channelId1) # Subscribe to current state of channel 2 state2 = GetChannelData(channelId2) # Build status display statusMsg = "Channel Subscriber - Current Subscription Status\n\n" # Display channel 1 status statusMsg += "═══ Channel 1 [{}] ═══\n".format(channelId1) if state1 is not None: statusMsg += "Update ID: #{}\n".format(state1["updateId"]) statusMsg += "Time: {}\n".format(_D(state1["timestamp"])) statusMsg += "Symbol: {}\n".format(state1["symbol"]) statusMsg += "Last Price: ${:.2f}\n".format(state1["lastPrice"]) statusMsg += "Volume: {:.4f}\n".format(state1["volume"]) else: statusMsg += "Status: Waiting... (first call returns None)\n" statusMsg += "\n" # Display channel 2 status statusMsg += "═══ Channel 2 [{}] ═══\n".format(channelId2) if state2 is not None: statusMsg += "Update ID: #{}\n".format(state2["updateId"]) statusMsg += "Time: {}\n".format(_D(state2["timestamp"])) statusMsg += "Symbol: {}\n".format(state2["symbol"]) statusMsg += "Last Price: ${:.2f}\n".format(state2["lastPrice"]) statusMsg += "Volume: {:.4f}\n".format(state2["volume"]) else: statusMsg += "Status: Waiting... (first call returns None)\n" LogStatus(statusMsg) Sleep(5000) # Subscribe to channels every 5 seconds
    c++
  • Cross-platform subscription example - Subscribe to data sent from external systems using UUID

    javascript
    function main() { // Use 32-bit UUID as channel identifier let uuid = "6BC42A119B5DBFA2188A8279DA3B5C30" while (true) { // Subscribe to data from UUID channel let data = GetChannelData(uuid) if (data !== null) { Log("Received cross-platform data:", data) } else { Log("Waiting for data... (first call returns null)") } Sleep(10000) // Check every 10 seconds } }
    python
    def main(): # Use 32-bit UUID as channel identifier uuid = "6BC42A119B5DBFA2188A8279DA3B5C30" while True: # Subscribe to data from UUID channel data = GetChannelData(uuid) if data is not None: Log("Received cross-platform data:", data) else: Log("Waiting for data... (first call returns None)") Sleep(10000) # Check every 10 seconds
    c++

Returns

TypeDescription

object / array / string / number / bool / null value

Returns the latest status data from the subscribed channel. The first call returns null, requiring retries. The data structure is determined by the data published by the broadcasting side.

Arguments

NameTypeRequiredDescription

channelId

string / number

Yes

Channel identifier, supports two types:

  1. Live Trading ID: Used to subscribe to channel data from other live trading instances (inter-instance communication). The live trading ID can be obtained via the _G() function.

  2. 32-bit UUID: Used to subscribe to data sent cross-platform (external systems send data to the FMZ platform via HTTP API).

See Also

Remarks

The GetChannelData() function is a non-blocking call that returns immediately without waiting for data reception to complete.

The first call to the GetChannelData() function will return null, requiring retries to wait for channel data synchronization to complete.

Each call retrieves the latest status data on the channel, not a historical message queue.

A live trading instance can subscribe to channels from multiple different live trading instances simultaneously by calling GetChannelData() multiple times with different live trading IDs.

The current live trading instance can also subscribe to its own channel, meaning the robotId parameter can be the current live trading ID.

Channel data can be transmitted across live trading instances, across dockers, and across servers.

The broadcasting side uses the SetChannelData() function to publish channel data.

Channel communication is designed for live trading environments; this feature may be limited in the backtesting system.

The GetChannelData() function supports cross-platform subscription functionality. When using a 32-bit UUID as the channel identifier, it can receive data sent from external systems outside the FMZ platform via HTTP API. External systems need to specify the live trading ID and UUID to send data. All live trading instances under the same docker can subscribe to data from that UUID channel, while live trading instances under different dockers cannot subscribe.