输入/搜索内容
内置函数
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
Threads
threading
Thread
getThread
mainThread
currentThread
Lock
Condition
Event
Dict
pending
Thread
ThreadLock
ThreadEvent
ThreadCondition
ThreadDict
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
结构体
内置变量

返回系统当前的版本号。

Version()

示例

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

返回值

类型描述

string

当前系统的版本号,例如:3.6

备注

系统版本号即托管者程序的版本号。

休眠函数,使程序暂停运行一段时间。

Sleep(millisecond)

示例

javascript
function main() { Sleep(1000 * 10) // 等待10秒钟 Log("等待了10秒钟") }
python
def main(): Sleep(1000 * 10) Log("等待了10秒钟")
rust
fn main() { Sleep(1000 * 10); // 等待10秒钟 Log!("等待了10秒钟"); }
c++
void main() { Sleep(1000 * 10); Log("等待了10秒钟"); }

参数

名称类型必填描述

millisecond

number

millisecond参数用于设置休眠时长,单位为毫秒。

备注

例如,执行Sleep(1000)函数时,程序将休眠1秒。该函数支持小于1毫秒的休眠操作,例如Sleep(0.1);支持的最小参数为0.000001,即纳秒级休眠,1纳秒等于1e-6毫秒。

在使用Python语言编写策略时,对于轮询间隔、时间等待等操作,应当使用Sleep(millisecond)函数,而不建议使用Pythontime库的time.sleep(second)函数。因为在回测时,策略中的time.sleep(second)函数会使策略程序实际等待相应的时间(而非在回测系统的时间序列上跳过),从而导致回测速度非常缓慢。

判断策略当前的运行环境是否为回测系统。

IsVirtual()

示例

javascript
function main() { if (IsVirtual()) { Log("当前为回测系统环境。") } else { Log("当前为实盘环境。") } }
python
def main(): if IsVirtual(): Log("当前为回测系统环境。") else: Log("当前为实盘环境。")
rust
fn main() { if IsVirtual() { Log!("当前为回测系统环境。"); } else { Log!("当前为实盘环境。"); } }
c++
void main() { if (IsVirtual()) { Log("当前为回测系统环境。"); } else { Log("当前为实盘环境。"); } }

返回值

类型描述

bool

当策略运行在回测系统环境时返回真值,例如:true;当策略运行在实盘环境时返回假值,例如:false

备注

用于判断当前运行环境是否为回测系统,以便兼容回测与实盘之间的差异。

发送邮件。

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

示例

javascript
function main(){ Mail("smtp.163.com", "asdf@163.com", "password", "111@163.com", "title", "body") }
python
def main(): Mail("smtp.163.com", "asdf@163.com", "password", "111@163.com", "title", "body")
rust
fn main() { Mail("smtp.163.com", "asdf@163.com", "password", "111@163.com", "title", "body"); }
c++
void main() { Mail("smtp.163.com", "asdf@163.com", "password", "111@163.com", "title", "body"); }

返回值

类型描述

bool

邮件发送成功时返回真值,例如:true;发送失败时返回假值,例如:false

参数

名称类型必填描述

smtpServer

string

用于指定邮件发送方的SMTP服务器地址。

smtpUsername

string

用于指定邮件发送方的邮箱地址。

smtpPassword

string

用于指定邮件发送方邮箱的SMTP服务密码。

mailTo

string

用于指定邮件接收方的邮箱地址。

title

string

邮件标题。

body

string

邮件正文。

参考

备注

smtpPassword参数设置的是SMTP服务的密码,而非邮箱登录密码。

设置smtpServer参数时,如果需要更改端口,可以直接在smtpServer参数中加入端口号。例如:QQ邮箱smtp.qq.com:587,该端口经测试可用。

如果出现报错:unencryped connection,需要修改Mail函数的smtpServer参数。参数格式为:ssl://xxx.com:xxx,例如QQ邮箱SMTPssl连接方式:ssl://smtp.qq.com:465,或者smtp://xxx.com:xxx

该函数在回测系统中不起作用。

Mail函数的异步版本。

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

示例

javascript
function main() { var r1 = Mail_Go("smtp.163.com", "asdf@163.com", "password", "111@163.com", "title", "body") var r2 = Mail_Go("smtp.163.com", "asdf@163.com", "password", "111@163.com", "title", "body") var ret1 = r1.wait() var ret2 = r2.wait() Log("ret1:", ret1) Log("ret2:", ret2) }
python
# 不支持
c++
// 不支持

返回值

类型描述

object

Mail_Go函数立即返回一个并发对象,可以使用该并发对象的wait方法获取邮件发送结果。邮件发送成功返回真值(例如:true),发送失败返回假值(例如:false)。

参数

名称类型必填描述

smtpServer

string

用于指定邮件发送方的SMTP服务地址。

smtpUsername

string

用于指定邮件发送方的邮箱地址。

smtpPassword

string

邮件发送方邮箱的SMTP密码。

mailTo

string

用于指定邮件接收方的邮箱地址。

title

string

邮件标题。

body

string

邮件正文。

参考

备注

在回测系统中不起作用。

过滤错误日志。

SetErrorFilter(filters)

示例

  • 过滤常见错误信息。

    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")
    rust
    fn 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"); }
  • 过滤某个接口的错误信息。

    javascript
    function main() { // 由于这是测试代码,未采用商品期货策略的通用架构,此处仅通过 exchange.IO("status") 函数判断是否成功连接期货公司前置机,连接成功后立即执行测试代码。股票、证券交易无需使用 exchange.IO("status") 判断连接状态 while(!exchange.IO("status")) { Sleep(1000) } // 设置合约代码 exchange.SetContractType("rb888") // 查询一个不存在的订单(id 为 123),故意触发接口报错 var order = exchange.GetOrder("123") Log(order) // 过滤 http 502 错误及 GetOrder 接口错误;设置错误过滤后,再次调用 GetOrder 将不再报错 SetErrorFilter("502:|GetOrder") order = exchange.GetOrder("123") Log(order) }
    python
    def main(): while not exchange.IO("status"): Sleep(1000) exchange.SetContractType("rb888") order = exchange.GetOrder("123") Log(order) SetErrorFilter("502:|GetOrder") order = exchange.GetOrder("123") Log(order)
    rust
    fn main() { // 由于这是测试代码,未采用商品期货策略的通用架构,此处仅通过 exchange.IO("status") 函数判断是否成功连接期货公司前置机,连接成功后立即执行测试代码。股票、证券交易无需使用 exchange.IO("status") 判断连接状态 while exchange.IO("status").unwrap_or_default() != "true" { Sleep(1000); } // 设置合约代码 let _ = exchange.SetContractType("rb888"); // 查询一个不存在的订单(id 为 123),故意触发接口报错 let orderId = OrderId { S: "123".to_string(), ..Default::default() }; let order = exchange.GetOrder(&orderId); Log!(order); // 过滤 http 502 错误及 GetOrder 接口错误;设置错误过滤后,再次调用 GetOrder 将不再报错 SetErrorFilter("502:|GetOrder"); let order = exchange.GetOrder(&orderId); Log!(order); }
    c++
    void main() { while(exchange.IO("status") == 0) { Sleep(1000); } exchange.SetContractType("rb888"); TId orderId; Order order = exchange.GetOrder(orderId); Log(order); SetErrorFilter("502:|GetOrder"); order = exchange.GetOrder(orderId); Log(order); }

参数

名称类型必填描述

filters

string

正则表达式字符串。

备注

被此正则表达式匹配的错误日志将不会上传至日志系统。该方法可多次调用(无次数限制)以设置多个过滤条件,多次设置的正则表达式会累积生效。若需重置用于过滤错误日志的正则表达式,可传入空字符串:SetErrorFilter("")

被过滤的日志将不再写入托管者目录下对应实盘 Id 的数据库文件中,从而避免因频繁报错导致数据库文件膨胀。

获取实盘进程的 Id。

GetPid()

示例

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

返回值

类型描述

string

返回实盘进程的 Id。

获取最近一次的错误信息。

GetLastError()

示例

javascript
function main(){ // 由于这是测试代码,未采用商品期货策略的通用架构,此处仅通过 exchange.IO("status") 函数进行判断,在成功连接期货公司前置机后立即执行测试代码。股票、证券交易无需使用 exchange.IO("status") 判断连接状态 while(!exchange.IO("status")) { Sleep(1000) } exchange.SetContractType("rb888") // 由于不存在编号为 123 的订单,因此会触发错误 exchange.GetOrder("123") var error = GetLastError() Log(error) }
python
def main(): while not exchange.IO("status"): Sleep(1000) exchange.SetContractType("rb888") exchange.GetOrder("123") error = GetLastError() Log(error)
rust
fn main() { // 由于这是测试代码,未采用商品期货策略的通用架构,此处仅通过 exchange.IO("status") 函数进行判断,在成功连接期货公司前置机后立即执行测试代码。股票、证券交易无需使用 exchange.IO("status") 判断连接状态 while exchange.IO("status").unwrap_or_default() != "true" { Sleep(1000); } exchange.SetContractType("rb888").unwrap(); // 由于不存在编号为 123 的订单,因此会触发错误 let id = OrderId { S: "123".to_string(), ..Default::default() }; let _ = exchange.GetOrder(&id); let error = GetLastError(); Log!(error); }
c++
void main() { while(exchange.IO("status") == 0) { Sleep(1000); } exchange.SetContractType("rb888"); // 订单 ID 类型为 TId,因此不能传入字符串,此处通过下一个不符合交易所规范的订单来触发错误 exchange.GetOrder(exchange.Buy(1, 1)); auto error = GetLastError(); Log(error); }

返回值

类型描述

string

最近一次的错误信息。

备注

该函数在回测系统中不起作用。

获取策略的交互命令。

GetCommand()

示例

  • 检测交互命令,并在检测到交互命令时使用Log函数输出该交互命令。

    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)
    rust
    fn main() { loop { if let Some(cmd) = GetCommand(0) { Log!(cmd); } Sleep(1000); } }
    c++
    void main() { while(true) { auto cmd = GetCommand(); if(cmd != "") { Log(cmd); } Sleep(1000); } }
  • 例如,在策略交互控件中添加一个不带输入框的控件,将交互控件命名为:buy,控件描述信息设置为:买入,这是一个按钮控件。接着再添加一个带输入框的控件,将交互控件命名为:sell,控件描述信息设置为:卖出,这是一个由按钮和输入框组合而成的交互控件。

    在策略中编写交互代码,以响应不同的交互控件:

    javascript
    function main() { while (true) { LogStatus(_D()) var cmd = GetCommand() if (cmd) { Log("cmd:", cmd) var arr = cmd.split(":") if (arr[0] == "buy") { Log("买入,该控件不带数量") } else if (arr[0] == "sell") { Log("卖出,该控件带数量:", arr[1]) } else { Log("其它控件触发:", 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("买入,该控件不带数量") elif arr[0] == "sell": Log("卖出,该控件带数量:", arr[1]) else: Log("其它控件触发:", arr) Sleep(1000)
    rust
    fn main() { loop { LogStatus!(_D(None)); if let Some(cmd) = GetCommand(0) { Log!("cmd:", cmd); let arr: Vec<&str> = cmd.split(':').collect(); if arr[0] == "buy" { Log!("买入,该控件不带数量"); } else if arr[0] == "sell" { Log!("卖出,该控件带数量:", arr[1]); } else { Log!("其它控件触发:", 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("买入,该控件不带数量"); } else if (arr[0] == "sell") { Log("卖出,该控件带数量:", arr[1]); } else { Log("其它控件触发:", arr); } } Sleep(1000); } }

返回值

类型描述

string

返回的命令格式为ControlName:Data,其中ControlName为控件名称,Data为控件中输入的数据。如果交互控件不包含输入框、下拉框等输入组件(例如:不带输入框的按钮控件),则返回的命令格式为ControlName,即仅返回控件名称。

备注

该函数在回测系统中不起作用。

获取生成策略注册码时写入的 Meta 值。

GetMeta()

示例

应用场景示例:使用 Meta 限制策略可操作的资产数量。

javascript
function main() { // 策略允许的计价币最大资产数量 var maxBaseCurrency = null // 获取创建注册码时的元数据 var level = GetMeta() // 检测 Meta 对应的条件 if (level == "level1") { // -1 表示不限制 maxBaseCurrency = -1 } else if (level == "level2") { maxBaseCurrency = 10 } else if (level == "level3") { maxBaseCurrency = 1 } else { maxBaseCurrency = 0.5 } // 鉴于此为测试代码,未采用商品期货策略的通用架构,这里仅通过 exchange.IO("status") 函数判断连接期货公司前置机成功后,立即执行测试代码。股票证券无需使用 exchange.IO("status") 判断连接状态 while(!exchange.IO("status")) { Sleep(1000) } exchange.SetContractType("rb888") while(true) { Sleep(1000) var ticker = exchange.GetTicker() // 检测资产数值 var acc = exchange.GetAccount() if (maxBaseCurrency != -1 && maxBaseCurrency < acc.Balance + acc.FrozenBalance) { // 停止执行策略交易逻辑 LogStatus(_D(), "level:", level, "持仓超过注册码的使用限制,不再执行策略交易逻辑!") continue } // 其他交易逻辑 // 正常输出状态栏信息 LogStatus(_D(), "level:", level, "策略正常运行!ticker 数据:\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 not exchange.IO("status"): Sleep(1000) exchange.SetContractType("rb888") while True: Sleep(1000) ticker = exchange.GetTicker() acc = exchange.GetAccount() if maxBaseCurrency != -1 and maxBaseCurrency < acc["Balance"] + acc["FrozenBalance"]: LogStatus(_D(), "level:", level, "持仓超过注册码的使用限制,不再执行策略交易逻辑!") continue # 其他交易逻辑 # 正常输出状态栏信息 LogStatus(_D(), "level:", level, "策略正常运行!ticker 数据:\n", ticker)
rust
fn main() { // 策略允许的计价币最大资产数量 let maxBaseCurrency; // 获取创建注册码时的元数据 let meta = GetMeta(); let level = meta.as_str().unwrap_or(""); // 检测 Meta 对应的条件 if level == "level1" { // -1 表示不限制 maxBaseCurrency = -1.0; } else if level == "level2" { maxBaseCurrency = 10.0; } else if level == "level3" { maxBaseCurrency = 1.0; } else { maxBaseCurrency = 0.5; } // 鉴于此为测试代码,未采用商品期货策略的通用架构,这里仅通过 exchange.IO("status") 函数判断连接期货公司前置机成功后,立即执行测试代码。股票证券无需使用 exchange.IO("status") 判断连接状态 while exchange.IO("status").unwrap_or_default() != "true" { Sleep(1000); } exchange.SetContractType("rb888").unwrap(); loop { Sleep(1000); let ticker = exchange.GetTicker(None).unwrap(); // 检测资产数值 let acc = exchange.GetAccount().unwrap(); if maxBaseCurrency != -1.0 && maxBaseCurrency < acc.Balance + acc.FrozenBalance { // 停止执行策略交易逻辑 LogStatus!(_D(None), "level:", level, "持仓超过注册码的使用限制,不再执行策略交易逻辑!"); continue; } // 其他交易逻辑 // 正常输出状态栏信息 LogStatus!(_D(None), "level:", level, "策略正常运行!ticker 数据:\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(exchange.IO("status") == 0) { Sleep(1000); } exchange.SetContractType("rb888"); while(true) { Sleep(1000); auto ticker = exchange.GetTicker(); auto acc = exchange.GetAccount(); if (maxBaseCurrency != -1 && maxBaseCurrency < acc.Balance + acc.FrozenBalance) { // 停止执行策略交易逻辑 LogStatus(_D(), "level:", level, "持仓超过注册码的使用限制,不再执行策略交易逻辑!"); continue; } // 其他交易逻辑 // 正常输出状态栏信息 LogStatus(_D(), "level:", level, "策略正常运行!ticker 数据:\n", ticker); } }

返回值

类型描述

string

Meta数据。

备注

应用场景:需要对不同的策略租用者进行资金限制。生成注册码时设置的Meta值长度不能超过 190 个字符,GetMeta()函数仅支持实盘环境。

如果生成策略注册码时未设置元数据(Meta),则GetMeta()函数返回空值。

该函数在回测系统中不起作用。

用于原始的Socket访问,支持tcpudptlsunix协议。

支持 4 种主流的通信协议:mqttnatsamqpkafka

支持连接数据库,可连接的数据库包括:sqlite3mysqlpostgresclickhouse

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

示例

  • Dial 函数调用示例:

    javascript
    function main(){ // Dial 支持 tcp://、udp://、tls://、unix:// 协议,可传入一个参数指定超时的秒数 var client = Dial("tls://www.baidu.com:443") if (client) { // write 可再跟一个数字参数指定超时,write 返回成功发送的字节数 client.write("GET / HTTP/1.1\nConnection: Closed\n\n") while (true) { // read 可再跟一个数字参数指定超时,单位:毫秒。返回 null 表示出错、超时或 socket 已关闭 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()
    rust
    fn main() { // Dial 支持 tcp://、udp://、tls://、unix:// 协议,可使用 Dial::new(addr, timeout) 指定超时的秒数 let mut client = Dial("tls://www.baidu.com:443"); if client.Valid() { // write 的第二个数字参数指定超时,write 返回成功发送的字节数 client.write("GET / HTTP/1.1\nConnection: Closed\n\n", 0); loop { // read 的数字参数指定超时,单位:毫秒。返回空字符串表示出错、超时或 socket 已关闭 let buf = client.read(0); if 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(); } }
  • Dial函数连接数据库时返回的连接对象具有2个独有的方法函数:

    - exec(sqlString): 用于执行SQL语句,使用方式与DBExec()函数类似。

    - fd(): fd()函数返回一个句柄(例如:句柄变量为handle),用于在其它线程中重连(即使Dial创建的连接对象已通过close()函数关闭连接),只需将该句柄传入Dial()函数即可重用连接,例如:Dial(handle)

    以下是使用Dial函数连接sqlite3数据库的示例。

    javascript
    var client = null function main() { // client = Dial("sqlite3://:memory:") // 使用内存数据库 client = Dial("sqlite3://test1.db") // 打开/连接托管者所在目录的数据库文件 // 记录句柄 var sqlite3Handle = client.fd() Log("sqlite3Handle:", sqlite3Handle) // 查询数据库中的表 var ret = client.exec("SELECT name FROM sqlite_master WHERE type='table'") Log(ret) } function onexit() { Log("执行client.close()") client.close() }
    python
    // 不支持
    rust
    fn main() { // let mut client = Dial("sqlite3://:memory:"); // 使用内存数据库 let mut client = Dial("sqlite3://test1.db"); // 打开/连接托管者所在目录的数据库文件 // Rust 的连接对象不支持 fd() 方法 // 查询数据库中的表 let ret = client.exec("SELECT name FROM sqlite_master WHERE type='table'"); Log!(format!("{:?}", ret)); Log!("执行client.close()"); client.close(); }
    c++
    // 不支持

返回值

类型描述

object

如果连接超时,Dial()函数返回空值;正常调用时返回一个连接对象,该对象包含三个方法:readwritecloseread方法用于读取数据,write方法用于发送数据,close方法用于关闭连接。read方法支持以下参数:

  • 不传参数时,函数将阻塞等待,直到有消息到达时才返回。例如:ws.read()
  • 传入参数时,参数单位为毫秒,用于指定消息等待的超时时间。例如:ws.read(2000)表示超时时间为两秒(2000毫秒)。
  • 以下两个参数仅对WebSocket有效:
    传入参数-1表示无论是否有消息,函数都立即返回。例如:ws.read(-1)
    传入参数-2表示无论是否有消息,函数都立即返回,但仅返回最新的消息,缓冲区中的其余消息将被丢弃。例如:ws.read(-2)read()函数缓冲区说明:

WebSocket协议推送过来的数据,如果策略中两次read()函数调用之间的时间间隔过长,可能会造成数据累积。这些数据存储在缓冲区中,缓冲区的数据结构为队列,上限为2000个。超出2000个后,最新的数据进入缓冲区,最旧的数据将被清除。

场景无参数参数:-1参数:-2参数:2000,单位是毫秒
缓冲区已有数据立即返回最旧数据立即返回最旧数据立即返回最新数据立即返回最旧数据
缓冲区无数据阻塞到有数据时返回立即返回空值立即返回空值等待2000毫秒,无数据则返回空值,有数据则返回
WebSocket连接断开或者底层重连时当WebSocket连接断开或底层重连时,read()函数返回空字符串(即:""),write()函数返回0,可据此检测到该情况。此时可以使用close()函数关闭连接;如果已设置自动重连,则无需手动关闭,系统底层会自动重连。
---

参数

名称类型必填描述

address

string

请求地址。

timeout

number

超时时间,单位为秒。

options

object

连接配置选项。

备注

address参数的详细说明:在标准地址wss://xxx.xxx.xxx:10441/websocket?compress之后,以|符号进行分隔。如果参数字符串中包含|字符,则使用||作为分隔符。分隔符之后的部分为功能参数设置,各参数之间使用&字符连接。

例如,同时设置ss5代理与压缩参数时,可写作:

Dial("wss://baidu.com/stream|proxy=socks5://xxx:9999&compress=gzip_raw&mode=recv")

Dial函数的address参数支持的功能参数说明
WebSocket协议数据压缩相关的参数:compress=参数值compress用于指定压缩方式,可选值包括gzip_raw、gzip等。如果所用的gzip并非标准gzip,可使用扩展方式:gzip_raw
WebSocket协议数据压缩相关的参数:mode=参数值mode用于指定压缩模式,可选dual、send、recv三种。dual为双向压缩,即发送和接收均使用压缩数据;send为仅发送压缩数据;recv为接收压缩数据并在本地解压缩。
WebSocket协议启用compression设置:enableCompression=true设置enableCompression=false可关闭该功能,默认不启用。
WebSocket协议设置底层自动重连相关的参数:reconnect=参数值reconnect用于设置是否自动重连,reconnect=true表示启用重连。未设置该参数时默认不重连。
WebSocket协议设置底层自动重连相关的参数:interval=参数值interval为重试时间间隔,单位为毫秒。例如interval=10000表示重试间隔为10秒;未设置时默认为1秒,即interval=1000。
WebSocket协议设置底层自动重连相关的参数:payload=参数值payload为WebSocket重连时需要发送的订阅消息,例如:payload=okok。
socks5代理的相关参数:proxy=参数值proxy用于设置ss5代理,参数值格式为:socks5://name:pwd@192.168.0.1:1080,其中name为ss5服务端用户名,pwd为ss5服务端登录密码,1080为ss5服务的端口。

Dial()函数仅支持实盘。

使用Dial函数连接数据库时,连接字符串的编写可参考各数据库的Go语言驱动项目。

支持的数据库驱动项目连接字符串(Connection String)备注

| sqlite3 | github.com/mattn/go-sqlite3 | sqlite3://file:test.db?cache=shared&mode=memory
| sqlite3://前缀表示使用sqlite3数据库,调用示例:Dial("sqlite3://test1.db") |

mysql

| postgres | github.com/lib/pq | postgres://user=postgres dbname=yourdatabase sslmode=disable
password=yourpassword host=localhost port=5432 | -- |

clickhouse

目前仅JavaScript语言支持在Dial函数中使用mqttnatsamqpkafka通信协议。以下以JavaScript语言的策略代码为例,展示mqttnatsamqpkafka四种协议的使用示例:

javascript
// 需要先配置并部署完成各个协议的代理服务器 // 为便于演示,主题test_topic的订阅(read操作)与发布(write操作)均在当前策略中进行 var arrConn = [] var arrName = [] function main() { LogReset(1) conn_nats = Dial("nats://admin@127.0.0.1:4222?topic=test_topic") conn_mqtt = Dial("mqtt://127.0.0.1:1883?topic=test_topic") conn_amqp = Dial("amqp://q:admin@127.0.0.1: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] // 写数据 conn.write(name + ", time: " + _D() + ", test msg.") // 读数据 var readMsg = conn.read(1000) Log(name + " readMsg: ", readMsg, "#FF0000") } Sleep(1000) } } function onexit() { for (var i in arrConn) { arrConn[i].close() Log("关闭", arrName[i], "连接") } }

Dial函数在访问Websocket接口时,支持设置wss请求头:

javascript
let options = {"headers": {"Authorization": "Bearer token123"}} let conn = Dial("wss://api.example.com/ws", options)
python
options = {"headers": {"Authorization": "Bearer token123"}} conn = Dial("wss://api.example.com/ws", options)
c++
// 暂不支持

发送Http请求。

HttpQuery(url)
HttpQuery(url, options)

示例

HttpQuery函数使用代理设置的示例。

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:password@127.0.0.1:8889/http://www.baidu.com/") }
python
# HttpQuery不支持Python,可以使用Python的urllib2库
rust
fn main() { // 本次设置代理并发送http请求,无用户名,无密码,此次http请求会通过代理发送 let ret1: String = HttpQuery("socks5://127.0.0.1:8889/http://www.baidu.com/", None); // 本次设置代理并发送http请求,输入用户名和密码,仅HttpQuery当前调用生效,之后再次调用HttpQuery("http://www.baidu.com")这样不会使用代理 let ret2: String = HttpQuery("socks5://username:password@127.0.0.1:8889/http://www.baidu.com/", None); }
c++
void main() { HttpQuery("socks5://127.0.0.1:8889/http://www.baidu.com/"); HttpQuery("socks5://username:password@127.0.0.1:8889/http://www.baidu.com/"); }

返回值

类型描述

string / object

返回请求的应答数据。如果返回值为JSON字符串,JavaScript语言的策略中可以使用JSON.parse()函数解析,C++语言的策略中可以使用json::parse()函数解析。

在参数options结构中,如果debug设置为true,返回值为对象(JSON);如果debug设置为false,返回值为字符串。

参数

名称类型必填描述

url

string

Http请求的url。

options

object

Http请求的相关设置,例如可以是以下结构:

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: 用于设置请求的方法。
  • body: 用于设置请求体内容,通常用于 POST、PUT 等请求。
  • cookie: 用于设置请求中的 Cookie,通常用于携带身份验证信息或会话标识。
  • headers: 用于设置请求头信息,可用于指定内容类型、身份验证信息等。
  • debug: 设置为true时,本次HttpQuery函数调用返回完整的应答报文;设置为false时,仅返回应答报文Body中的数据。
  • timeout: 超时设置,设置为1000表示1秒钟超时。
  • charset: 支持对请求的应答数据进行转码,例如:GB18030,支持常用编码。

此结构中的所有字段均为可选,例如可以不设置headers字段。

参考

备注

HttpQuery()函数仅支持JavaScriptC++语言;Python语言可以使用urllib库,直接发送Http请求。

回测系统中可以使用HttpQuery()发送请求(仅支持GET请求)以获取数据。

回测时限制访问20个不同的URL,并且HttpQuery()访问会缓存数据,

相同的URL第二次访问时,HttpQuery()函数将返回缓存数据,不再发起实际的网络请求。

发送HTTP请求,是HttpQuery函数的异步版本。

HttpQuery_Go(url)
HttpQuery_Go(url, options)

示例

HttpQuery_Go()函数使用示例:

javascript
function main() { // 创建第一个异步线程 var r1 = HttpQuery_Go("https://xxx.xxx.xxx") // https://xxx.xxx.xxx 仅为演示地址,可以是某个数据源 // 创建第二个异步线程 var r2 = HttpQuery_Go("https://xxx.xxx.xxx") // 获取第一个异步线程调用的返回值 var tickers1 = r1.wait() // 获取第二个异步线程调用的返回值 var tickers2 = r2.wait() // 打印结果 Log("tickers1:", tickers1) Log("tickers2:", tickers2) }
python
# 不支持
c++
// 不支持

返回值

类型描述

object

HttpQuery_Go()函数立即返回一个并发对象,可以使用该并发对象的wait方法获取HTTP请求的结果。
JavaScript语言的策略中可以使用JSON.parse()函数解析返回的数据。

参数

名称类型必填描述

url

string

HTTP请求的URL地址。

options

object

HTTP请求相关配置参数,可以使用以下结构:

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:设置为true时,此次HttpQuery_Go函数调用返回完整的响应报文。设置为false时仅返回响应报文Body中的数据。
  • timeout:超时设置,设置1000表示1秒超时。

此结构中的所有字段均为可选字段,例如可以不设置headers字段。
HttpQuery_Go函数的options参数与HttpQuery函数的options参数保持一致。

参考

备注

HttpQuery_Go()函数仅支持JavaScript语言,Python语言可以使用urllib库直接发送HTTP请求。
HttpQuery_Go()主要用于访问交易所无需签名的接口,例如行情信息等公共接口。回测系统不支持HttpQuery_Go函数。

此函数根据传入的参数对数据进行编码。

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

示例

  • Encode 函数调用示例。

    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
    rust
    fn 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 }
  • 参数algo还支持以下编码器与解码器:"text.encoder.utf8"、"text.decoder.utf8"、"text.encoder.gbk"、"text.decoder.gbk",用于对字符串进行编码和解码。

    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)
    rust
    fn main() { let ret1 = Encode("text.encoder.utf8", "raw", "hex", "你好", "", ""); // e4bda0e5a5bd Log!(ret1); let ret2 = Encode("text.decoder.utf8", "hex", "string", &ret1, "", ""); Log!(ret2); let ret3 = Encode("text.encoder.gbk", "raw", "hex", "你好", "", ""); // c4e3bac3 Log!(ret3); let 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); }

返回值

类型描述

string

Encode函数返回编码、加密之后的数据。

参数

名称类型必填描述

algo

string

参数algo用于指定编码计算所使用的算法。

支持设置为:"raw"(不使用算法)、"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"。

参数algo还支持:"text.encoder.utf8"、"text.decoder.utf8"、"text.encoder.gbk"、"text.decoder.gbk",用于对字符串进行编码与解码。

参数algo同样支持"ed25519"算法,并可搭配不同的哈希算法使用,例如可将参数algo设置为"ed25519.md5"、"ed25519.sha512"等,同时支持ed25519.seed计算。

inputFormat

string

用于指定data参数的数据格式。inputFormat参数支持设置为"raw"、"hex"、"base64"、"string"其中之一。"raw"表示原始数据,"hex"表示hex编码数据,"base64"表示base64编码数据,"string"表示字符串数据。

outputFormat

string

用于指定输出的数据格式。outputFormat参数支持设置为"raw"、"hex"、"base64"、"string"其中之一。"raw"表示原始数据,"hex"表示hex编码数据,"base64"表示base64编码数据,"string"表示字符串数据。

data

string

参数data为所要处理的数据。

keyFormat

string

用于指定key参数的数据格式。keyFormat参数支持设置为"raw"、"hex"、"base64"、"string"其中之一。"raw"表示原始数据,"hex"表示hex编码数据,"base64"表示base64编码数据,"string"表示字符串数据。

key

string

参数key为进行HMAC加密时使用的密钥。

当参数algo设置为"sign"或"signTx"时,需要提供参数key

当参数algo设置为"raw"时,不会使用参数key进行HMAC加密(因为HMAC加密必须指定算法)。

备注

Encode()函数仅支持实盘。若不传入keykeyFormat参数,则不使用key进行加密。

获取当前时刻的纳秒级时间戳。

UnixNano()

示例

如需获取毫秒级时间戳,可参考以下代码:

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

返回值

类型描述

number

UnixNano()函数返回纳秒级时间戳。

参考

获取当前时刻的秒级时间戳。

Unix()

示例

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

返回值

类型描述

number

返回秒级时间戳。

参考

获取托管者所在设备的操作系统信息。

GetOS()

示例

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

返回值

类型描述

string

操作系统信息。

备注

例如,运行在 Mac OS 操作系统上的托管者,调用 GetOS() 函数可能返回:darwin/amd64。由于苹果电脑采用多种硬件架构,返回值中会一并包含具体的架构信息。其中 darwinMac OS 系统的名称。

计算参数data的MD5哈希值。

MD5(data)

示例

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

返回值

类型描述

string

MD5哈希值。

参数

名称类型必填描述

data

string

需要进行MD5计算的数据。

参考

备注

调用MD5("hello world")函数后,返回值为:5eb63bbbe01eeed093cb22bb8f5acdc3

数据库接口函数。

DBExec(sql)

示例

  • 支持内存数据库。对于DBExec函数的参数,如果sql语句以:开头,则在内存数据库中执行操作,无需写入文件,速度更快。

    适用于无需持久化保存的数据库操作,例如:

    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;"))
    rust
    fn main() { let 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)", ]; let strSql = arr.join(""); let ret = DBExec(&strSql); Log!(format!("{:?}", ret)); // 增加一条数据 Log!(format!("{:?}", DBExec(":INSERT INTO TEST_TABLE (TS, HIGH, OPEN, LOW, CLOSE, VOLUME) VALUES (1518970320000, 100, 99.1, 90, 100, 12345.6);"))); // 查询数据 Log!(format!("{:?}", DBExec(":SELECT * FROM TEST_TABLE;"))); }
    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); // 增加一条数据 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;")); }
  • 创建数据表。

    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)
    rust
    fn main() { let 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)", ]; let strSql = arr.join(""); let ret = DBExec(&strSql); Log!(format!("{:?}", 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); }
  • 对数据表中记录进行增、删、改、查(增删改查)操作。

    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))
    rust
    fn main() { let 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)", ]; let strSql = arr.join(""); Log!(format!("{:?}", DBExec(&strSql))); // 增加一条数据 Log!(format!("{:?}", DBExec("INSERT INTO TEST_TABLE (TS, HIGH, OPEN, LOW, CLOSE, VOLUME) VALUES (1518970320000, 100, 99.1, 90, 100, 12345.6);"))); // 查询数据 Log!(format!("{:?}", DBExec("SELECT * FROM TEST_TABLE;"))); // 修改数据,Rust 的 DBExec() 函数只接受单个 SQL 语句字符串参数,不支持 ? 占位符传参,参数值需直接写入语句中 Log!(format!("{:?}", DBExec("UPDATE TEST_TABLE SET HIGH=110 WHERE TS=1518970320000;"))); // 删除数据 Log!(format!("{:?}", 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)); }

返回值

类型描述

object

包含 sql 语句执行结果的对象,例如:

```json

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

```

参数

名称类型必填描述

sql

string

sql 语句字符串。

参考

备注

函数 DBExec() 通过传入参数操作实盘数据库(SQLite 数据库),可对实盘数据库中的数据执行增、删、查、改等操作,并支持 SQLite 语法。实盘数据库中的系统保留表包括 kvdbcfglogprofitchart,请勿对这些表进行任何操作。目前不支持事务,不建议执行此类操作,否则会引发系统冲突。
DBExec() 函数仅支持实盘。

生成一个 UUID。

UUID()

示例

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

返回值

类型描述

string

32 位的 UUID 字符串。

备注

UUID() 函数仅支持在实盘中使用。

监听事件,当有任意事件发生时返回。

EventLoop()
EventLoop(timeout)

示例

javascript
function main(){ while(true){ // 需要在判断exchange.IO("status")函数返回true,即为真值时才可调用行情、交易等函数 if(exchange.IO("status")){ exchange.SetContractType("rb888") LogStatus(_D(), "已经连接CTP !") var msg = EventLoop() Log(msg) } else { LogStatus(_D(), "未连接CTP !") } } }
python
# 不支持EventLoop函数
rust
fn main() { loop { // 需要在判断exchange.IO("status")函数返回true,即为真值时才可调用行情、交易等函数 if exchange.IO("status").unwrap_or_default() == "true" { exchange.SetContractType("rb888").unwrap(); LogStatus!(_D(None), "已经连接CTP !"); let msg = EventLoop(0); Log!(msg); } else { LogStatus!(_D(None), "未连接CTP !"); } } }
c++
// 不支持EventLoop函数

返回值

类型描述

object

如果返回的对象不为空值,则返回内容中包含的Event字段表示事件的触发类型。例如以下返回值结构:

json
{"Seq":10,"Event":"tick","ThreadId":0,"Index":0,"Nano":1689216222796834300,"Symbol":"rb2311","Ticker": {...}}

参数

名称类型必填描述

timeout

number

参数timeout用于设置超时时间,单位为毫秒。
当参数timeout设置为0时,函数会持续等待,直到有事件发生才返回;当设置为大于0的值时,表示事件等待的超时时间;当设置为小于0的值时,立即返回最近的事件。

参考

备注

只有在代码中第一次调用EventLoop()函数时,才会初始化该事件监听机制。如果在事件回调发生之后才首次调用EventLoop()函数,则会错过此前发生的事件。底层系统封装的队列结构最多可缓存500个事件回调,如果程序运行过程中未及时调用EventLoop()函数取出,超出500个缓存容量的较晚事件回调将会丢失。EventLoop()函数的调用不会影响系统底层WebSocket的缓存队列。

对于这些缓存,仍需使用各自对应的方法取出数据。对于在EventLoop()函数返回之前已经取出的数据,不会在EventLoop()函数中产生返回事件。EventLoop()函数的主要用途是通知策略层:系统底层已接收到新的网络数据,从而以事件驱动整个策略。当EventLoop()函数返回事件时,只需遍历所有数据来源即可。EventLoop()函数仅支持实盘。

在主函数main()中调用时,监听主线程的事件。在使用JavaScript语言编写的策略中,对于由threading.Thread()函数创建的线程,也可以在其执行函数中调用该函数,以监听当前线程的事件。

__Serve函数用于创建Http服务、TCP服务、Websocket服务(基于Http协议)。

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

示例

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
# 不支持
c++
// 不支持

返回值

类型描述

string

返回一个字符串,记录创建的服务的IP地址、端口。例如:127.0.0.1:8088[::]:8089

参数

名称类型必填描述

serveURI

string

serveURI参数用于配置服务绑定的协议、IP地址、端口等设置,例如:http://0.0.0.0:8088?gzip=true,或:http://:8088?gzip=true

  • TCP协议
    serveURI参数设置例如:tcp://127.0.0.1:6666?tls=true;可以添加证书、私钥,例如:tls=true&cert_pem=xxxx&cert_key_pem=xxxx
  • Http协议
    serveURI参数设置例如:http://127.0.0.1:6666?gzip=true;可以设置压缩选项:gzip=true
    serveURI参数用于Https,例如:https://127.0.0.1:6666?tls=true&gzip=true;可以加入cert_pemcert_key_pem参数来加载证书。

handler

function

handler参数用于传入路由处理函数(Http协议)、消息处理函数(TCP协议)、Stream处理函数(Websocket)。参数handler传入的回调函数可以定义多个参数,第一个参数为ctx对象(上下文对象)。

arg

string / number / bool / object / array / function / any (系统支持的所有类型)

作为参数handler传入的回调函数的参数的实参,参数arg可能有多个,例如:

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

调用__Serve()函数时传入的参数1, 2, 3对应传入回调函数的参数a, b, c

参考

备注

  • 该函数仅支持JavaScript语言策略。

    • 服务线程与全局作用域隔离,因此不支持闭包或引用外部变量、自定义函数等;但是可以调用平台所有的API函数。

    • Websocket服务基于Http协议实现,可以在path中设置一个路由分支,设计Websocket消息订阅/推送的实现代码,可以参考本节范例代码。

参数handler传入的回调处理函数接收一个ctx参数。ctx参数为一个上下文对象,用于获取数据和写入数据,有以下方法:

  • ctx.proto()
    适用于Http/TCP协议,调用时返回协议名称。例如:HTTP/1.1tcp
  • ctx.host()
    适用于Http协议,调用时返回主机信息:IP地址、端口。
  • ctx.path()
    适用于Http协议,调用时返回请求路径。
  • ctx.query(key)
    适用于Http协议,调用时返回请求中query查询中key对应的值。例如发送的请求为:http://127.0.0.1:8088?num=123,参数handler传入的回调处理函数中ctx.query("num")调用时返回"123"
  • ctx.rawQuery()
    适用于Http协议,调用时返回请求中的原始查询(Http请求的query)。
    • ctx.headers()
      适用于Http协议,调用时返回请求中的请求头信息。
  • ctx.header(key)
    适用于Http协议,调用时返回指定的请求头中的某个key对应的值。例如获取当前请求的headers中的User-Agentctx.header("User-Agent")
  • ctx.method()
    适用于Http协议,调用时返回请求方法,例如GETPOST等。
    • ctx.body()
      适用于Http协议的POST请求,调用时返回请求的正文。
  • ctx.setHeader(key, value)
    适用于Http协议,设置应答报文的请求头信息。
    • ctx.setStatus(code)
      适用于Http协议,设置Http报文状态码,通常在路由分支最后设置Http状态码,默认为200。
  • ctx.remoteAddr()
    适用于Http/TCP协议,调用时返回请求中的远程客户端地址、端口。
  • ctx.localAddr()
    适用于Http/TCP协议,调用时返回服务本地地址、端口。
    • ctx.upgrade("websocket")
      适用于基于Http协议的Websocket协议实现,切换ctx上下文对象为Websocket协议;切换成功返回布尔值(真),失败返回布尔值(假)。
    • ctx.read(timeout_ms)
      适用于基于Http协议的Websocket协议实现/TCP协议,读取Websocket连接的数据,TCP连接的数据,普通Http协议中不支持使用该read方法;可以指定超时时间参数timeout_ms,单位毫秒。
    • ctx.write(s)
      适用于Http/TCP协议,用于写入字符串数据,可以使用JSON.stringify()编码JSON对象为字符串之后写入。对于WebSocket协议,可以使用该方法将编码后的字符串传递给客户端。

该函数用于持久化保存数据,实现了一个可保存的全局字典功能。数据以键值对(KV)表的结构存储,并永久保存在托管者的本地数据库文件中。

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

示例

javascript
// 不使用接口获取数据的测试,就无需使用exchange.IO("status")函数判断连接状态,也不用设置合约代码,因为这里仅仅是测试 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()
rust
fn main() { // 设置一个全局变量num,值为1 _G!("num", 1); // 更改一个全局变量num,值为字符串ok _G!("num", "ok"); // 删除全局变量num _G!("num", null); // 返回全局变量num的值 Log!(_G!("num")); // Rust 不支持 _G!(null) 删除所有全局变量的形式 // 返回实盘ID let robotId = _G!(); }
c++
void main() { _G("num", 1); _G("num", "ok"); _G("num", NULL); Log(_G("num")); _G(NULL); // 不支持 auto robotId = _G(); }

返回值

类型描述

string / number / bool / object / array / 空值

持久化保存的k-v键值对中的键值数据。

参数

名称类型必填描述

k

string / 空值

参数k为键值对中的键名,不区分大小写。

v

string / number / bool / object / array / 空值

参数v为键值对中的键值,可以是任何能够进行JSON序列化的数据。

参考

备注

每个实盘单独使用一个数据库。策略重启或托管者停止运行后,_G()函数保存的数据依然会保留。而回测结束后,_G()函数在回测系统中保存的数据将被清除。使用_G()函数持久化保存数据时,应根据硬件设备的内存和硬盘空间合理使用,切勿滥用。

在实盘运行中,当调用_G()函数且不传入任何参数时,_G()函数返回当前实盘的Id

调用_G()函数时,若参数v传入空值,表示删除该k-v键值对。

调用_G()函数时,若仅传入字符串参数k_G()函数返回参数k对应的已保存键值。

调用_G()函数时,若仅参数k传入空值,表示删除所有已记录的k-v键值对。

k-v键值对已经持久化保存后,再次调用_G()函数,传入已持久化保存的键名作为参数k,并传入新的键值作为参数v,即可更新该k-v键值对。

以实盘Id为123456为例,使用_G()函数持久化保存的K-V键值数据存储在实盘(即策略实例程序)所属托管者目录下的/logs/storage/123456/123456.db3数据库文件中(123456.db3),数据记录在kvdb表中。

将毫秒时间戳或Date对象转换为时间字符串。

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

示例

  • 获取并打印当前时间字符串:

    javascript
    // 不使用接口获取数据的测试,就无需使用exchange.IO("status")函数判断连接状态,也不用设置合约代码,因为这里仅仅是测试 function main(){ var time = _D() Log(time) }
    python
    def main(): strTime = _D() Log(strTime)
    rust
    fn main() { let strTime = _D(None); Log!(strTime); }
    c++
    void main() { auto strTime = _D(); Log(strTime); }
  • 时间戳为1574993606000,使用代码进行转换:

    javascript
    // 不使用接口获取数据的测试,就无需使用exchange.IO("status")函数判断连接状态,也不用设置合约代码,因为这里仅仅是测试 function main() { Log(_D(1574993606000)) }
    python
    def main(): # 北京时间的服务器上运行:2019-11-29 10:13:26 ,另一台其它地区的服务器上的托管者运行此代码结果则为:2019-11-29 02:13:26 Log(_D(1574993606))
    rust
    fn main() { Log!(_D(1574993606000)); }
    c++
    void main() { Log(_D(1574993606000)); }
  • 使用参数fmt进行格式化,JavaScriptPythonC++语言的格式化字符串有所不同,具体请参看以下示例:

    javascript
    function main() { Log(_D(1574993606000, "yyyy--MM--dd hh--mm--ss")) // 2019--11--29 10--13--26 }
    python
    def main(): # 1574993606为秒级别时间戳 Log(_D(1574993606, "%Y--%m--%d %H--%M--%S")) # 2019--11--29 10--13--26
    rust
    fn main() { // Rust 的 _D() 函数不支持 fmt 参数,仅支持默认格式:yyyy-MM-dd hh:mm:ss Log!(_D(1574993606000)); // 2019-11-29 10:13:26 }
    c++
    void main() { Log(_D(1574993606000, "%Y--%m--%d %H--%M--%S")); // 2019--11--29 10--13--26 }

返回值

类型描述

string

时间字符串。

参数

名称类型必填描述

timestamp

number / object

毫秒时间戳或Date对象。

fmt

string

格式化字符串,默认格式为:yyyy-MM-dd hh:mm:ss

参考

备注

若不传入任何参数,则返回当前时间字符串。在Python策略中使用_D()函数时,需要注意传入的参数为秒级别时间戳(在JavaScriptC++策略中为毫秒级别时间戳,1秒等于1000毫秒)。

在实盘中使用_D()函数将时间戳解析为可读的时间字符串时,需要注意托管者程序所在操作系统的时区与时间设置。_D()函数将时间戳解析为可读时间字符串时,是依据托管者系统的时间而定的。

格式化浮点数。

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

示例

  • 例如_N(3.1415, 2)会舍弃3.1415小数点后第二位以后的数值,函数返回3.14

    javascript
    // 不使用接口获取数据的测试,就无需使用exchange.IO("status")函数判断连接状态,也不用设置合约代码,因为这里仅仅是测试 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)
    rust
    // 不使用接口获取数据的测试,就无需使用exchange.IO("status")函数判断连接状态,也不用设置合约代码,因为这里仅仅是测试 fn main() { let i = 3.1415; Log!(i); let ii = _N(i, 2); Log!(ii); }
    c++
    void main() { auto i = 3.1415; Log(i); auto ii = _N(i, 2); Log(ii); }
  • 如果需要将小数点左边的N位数字都置为0,可以这样写:

    javascript
    // 不使用接口获取数据的测试,就无需使用exchange.IO("status")函数判断连接状态,也不用设置合约代码,因为这里仅仅是测试 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)
    rust
    // 不使用接口获取数据的测试,就无需使用exchange.IO("status")函数判断连接状态,也不用设置合约代码,因为这里仅仅是测试 fn main() { let i = 1300; Log!(i); let ii = _N(i, -3); // 查看日志得知为1000 Log!(ii); }
    c++
    void main() { auto i = 1300; Log(i); auto ii = _N(i, -3); Log(ii); }

返回值

类型描述

number

根据精度设置格式化后的浮点数。

参数

名称类型必填描述

num

number

需要格式化的浮点数。

precision

number

用于设置格式化精度,参数precision为整数,默认值为4。

参考

备注

参数precision可以为正整数,也可以为负整数。

容错重试函数,用于对接口调用进行容错处理。

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

示例

  • 针对无参数函数的容错处理:

    javascript
    function main(){ // 由于是测试代码,未采用商品期货策略的通用架构,此处仅通过exchange.IO("status")函数进行判断,在成功连接期货公司前置机后立即执行测试代码。股票证券无需使用exchange.IO("status")判断连接状态 while(!exchange.IO("status")) { Sleep(1000) } // 测试代码部分 // 将合约设置为rb888,即螺纹钢主力连续合约;或设置为股票代码 exchange.SetContractType("rb888") var ticker = _C(exchange.GetTicker) // 将_C()函数的重试时间间隔调整为2秒 _CDelay(2000) var depth = _C(exchange.GetDepth) Log(ticker) Log(depth) }
    python
    def main(): while not exchange.IO("status"): Sleep(1000) exchange.SetContractType("rb888") ticker = _C(exchange.GetTicker) _CDelay(2000) depth = _C(exchange.GetDepth) Log(ticker) Log(depth)
    rust
    fn main() { // 由于是测试代码,未采用商品期货策略的通用架构,此处仅通过exchange.IO("status")函数进行判断,在成功连接期货公司前置机后立即执行测试代码。股票证券无需使用exchange.IO("status")判断连接状态 while exchange.IO("status").unwrap_or_default() != "true" { Sleep(1000); } // 测试代码部分 // 将合约设置为rb888,即螺纹钢主力连续合约;或设置为股票代码 exchange.SetContractType("rb888").unwrap(); let ticker = _C!(exchange.GetTicker(None)); // 将_C!()宏的重试时间间隔调整为2秒 _CDelay(2000); let depth = _C!(exchange.GetDepth(None)); Log!(ticker); Log!(depth); }
    c++
    void main() { while(exchange.IO("status") == 0) { Sleep(1000); } exchange.SetContractType("rb888"); auto ticker = _C(exchange.GetTicker); _CDelay(2000); auto depth = _C(exchange.GetDepth); Log(ticker); Log(depth); }
  • 针对有参数函数的容错处理:

    javascript
    function main(){ // 由于是测试代码,未采用商品期货策略的通用架构,此处仅通过exchange.IO("status")函数进行判断,在成功连接期货公司前置机后立即执行测试代码。股票证券无需使用exchange.IO("status")判断连接状态 while(!exchange.IO("status")) { Sleep(1000) } // 测试代码部分 // 将合约设置为rb888,即螺纹钢主力连续合约;或设置为股票代码 exchange.SetContractType("rb888") var records = _C(exchange.GetRecords, PERIOD_D1) Log(records) }
    python
    def main(): while not exchange.IO("status"): Sleep(1000) exchange.SetContractType("rb888") records = _C(exchange.GetRecords, PERIOD_D1) Log(records)
    rust
    fn main() { while exchange.IO("status").unwrap_or_default() != "true" { Sleep(1000); } exchange.SetContractType("rb888").unwrap(); let records = _C!(exchange.GetRecords(None, PERIOD_D1, None)); Log!(records); }
    c++
    void main() { while(exchange.IO("status") == 0) { Sleep(1000); } exchange.SetContractType("rb888"); auto records = _C(exchange.GetRecords, PERIOD_D1); Log(records); }
  • 也可用于自定义函数的容错处理:

    javascript
    var test = function(a, b){ var time = new Date().getTime() / 1000 if(time % b == 3){ Log("符合条件!", "#FF0000") return true } Log("重试!", "#FF0000") return false } function main(){ // 此测试不通过接口获取数据,因此无需调用 exchange.IO("status") 函数判断连接状态,也无需设置合约代码,因为这里仅用于测试自定义函数 var ret = _C(test, 1, 5) Log(ret) }
    python
    import time def test(a, b): ts = time.time() if ts % b == 3: Log("符合条件!", "#FF0000") return True Log("重试!", "#FF0000") return False def main(): ret = _C(test, 1, 5) Log(ret)
    rust
    fn test(a: i64, b: i64) -> Result<bool> { let time = Unix(); if time % b == 3 { Log!("符合条件!", "#FF0000"); return Ok(true); } Log!("重试!", "#FF0000"); Err(Error::Api("retry".to_string())) } fn main() { // 此测试不通过接口获取数据,因此无需调用 exchange.IO("status") 函数判断连接状态,也无需设置合约代码,因为这里仅用于测试自定义函数 // 在 Rust 中,自定义函数返回 Result 类型即可使用 _C! 宏进行容错,返回 Err 时会自动重试 let ret = _C!(test(1, 5)); Log!(ret); }
    c++
    // C++ 不支持以这种方式对自定义函数进行容错处理

返回值

类型描述

假值空值以外的所有平台支持类型(any)。

回调函数执行后的返回值。

参数

名称类型必填描述

pfn

function

参数pfn为函数引用,即一个回调函数

arg

string / number / bool / object / array / function / any (系统支持的所有类型)

回调函数的参数,参数arg可以有多个。参数arg的类型与个数取决于回调函数所需的参数。

备注

_C()函数会反复调用指定的函数,直到其成功返回为止(当参数pfn所引用的函数返回空值假值时,_C()会重试调用pfn)。

例如_C(exchange.GetTicker)。默认的重试间隔为3秒,可以调用_CDelay()函数来设置重试间隔。

例如_CDelay(1000),表示将_C()函数的重试间隔改为1秒。

可以对以下函数进行容错处理,但不限于此:

  • exchange.GetTicker()

  • exchange.GetDepth()

  • exchange.GetTrades()

  • exchange.GetRecords()

  • exchange.GetAccount()

  • exchange.GetOrders()

  • exchange.GetOrder()

  • exchange.GetPositions()

以上函数均可通过_C()函数调用来实现容错。_C()函数的容错能力并不局限于上述列出的函数。参数pfn为函数引用而非函数调用,请注意应写作_C(exchange.GetTicker),而不是_C(exchange.GetTicker())

返回数组arr1与数组arr2的交叉周期数。

_Cross(arr1, arr2)

示例

可以模拟一组数据来测试_Cross(Arr1, Arr2)函数:

javascript
// 快线指标 var arr1 = [1,2,3,4,5,6,8,8,9] // 慢线指标 var arr2 = [2,3,4,5,6,7,7,7,7] // 不使用接口获取数据的测试,就无需使用exchange.IO("status")函数判断连接状态,也不用设置合约代码,因为这里仅仅是测试 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))
rust
fn main() { // 快线指标 let arr1 = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 8.0, 8.0, 9.0]; // 慢线指标 let arr2 = [2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 7.0, 7.0, 7.0]; 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)); }

返回值

类型描述

number

数组arr1与数组arr2的交叉周期数。

参数

名称类型必填描述

arr1

array

元素为number类型的数组。

arr2

array

元素为number类型的数组。

备注

_Cross()函数的返回值为正数时表示上穿的周期数,为负数时表示下穿的周期数,为0时表示当前价格相等。详细使用说明请参阅:内置函数_Cross分析及使用说明

JSON.parse 函数是 ECMAScript 标准内建对象 JSON 的方法,用于解码(解析)JSON 字符串。优宽量化交易平台为其扩展了一个 safeStr 参数。

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

示例

解码(解析)一个包含大数值的 JSON 字符串。

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 的第三方库处理大数值数据。
rust
fn main() { let s1 = r#"{"num": 8754613216564987646512354656874651651358}"#; Log!("JSONParse:", JSONParse(s1).unwrap()); // JSONParse: {"num":8.754613216564987e+39} // Rust 的 JSONParse() 函数不支持 safeStr 参数,大数值可使用第三方库处理 let s2 = r#"{"num": 123}"#; Log!("JSONParse:", JSONParse(s2).unwrap()); // JSONParse: {"num":123} }
c++
// 可以使用其它方案处理。

返回值

类型描述

object

返回值为 JSON 对象。

参数

名称类型必填描述

s

string

该参数为需要解码(解析)的 JSON 字符串。

safeStr

bool

当该参数设置为 true 时,若在解析过程中遇到可能超出精度范围的数值,会将其以字符串形式返回,以避免精度丢失或数值溢出问题。

备注

JSON.parse() 函数可以正确解析包含较大数值的 JSON 字符串;当 safeStr 参数设置为真值时,会将较大的数值解析为字符串类型。

safeStr 参数位也支持作为 reviver 参数使用,即一个用于转换解析结果的函数,该函数会为对象的每个成员被调用。具体用法可查阅相关资料,此处不再赘述。

仅支持 JavaScript 语言。

回测系统中不支持 JSON.parse() 函数的 safeStr 参数功能。

JSON.stringify函数是ECMAScript标准内置对象JSON的方法,用于将JavaScript值编码为JSON字符串。

JSON.stringify(obj)

示例

编码一个对象,输出编码后的JSON字符串。

javascript
function main() { let s1 = {"num": "8754613216564987646512354656874651651358"} Log("JSON.stringify:", JSON.stringify(s1)) // JSON.stringify: {"num":"8754613216564987646512354656874651651358"} // JSON.stringify(s1) 返回的变量为一个字符串类型 }
python
// 略
c++
// 略

返回值

类型描述

string

返回编码后的JSON字符串。

参数

名称类型必填描述

obj

string / number / bool / object / array / function / any (平台支持的任意类型)

需要编码为JSON字符串的值。

备注

仅支持JavaScript语言。

在频道上发布最新的状态数据。该函数用于实盘之间的通信,可将当前实盘的状态数据广播到频道上,供其他实盘订阅获取。

SetChannelData(data)

示例

  • 频道广播端示例 - 发布市场行情数据

    javascript
    function main() { var updateId = 0 var robotId = _G() // 获取当前实盘ID while(true) { if (!exchange.IO("status")) { Sleep(1000) continue } // 获取实时市场价格 var ticker = exchange.GetTicker("rb888") if (!ticker) { Sleep(5000) continue } // 构建当前频道状态数据 var channelState = { robotId: robotId, updateId: ++updateId, timestamp: Date.now(), symbol: "rb888", lastPrice: ticker.Last, volume: ticker.Volume, high: ticker.High, low: ticker.Low } // 向频道发布最新状态(覆盖旧状态) SetChannelData(channelState) // 显示当前频道状态 LogStatus("频道广播端 [实盘ID: " + robotId + "]\n" + "更新ID: #" + channelState.updateId + "\n" + "时间: " + _D(channelState.timestamp) + "\n" + "交易对: " + channelState.symbol + "\n" + "最新价: $" + channelState.lastPrice.toFixed(2) + "\n" + "成交量: " + channelState.volume.toFixed(4) + "\n" + "最高价: $" + channelState.high.toFixed(2) + "\n" + "最低价: $" + channelState.low.toFixed(2)) Sleep(60000) // 每分钟更新一次频道状态 } }
    python
    def main(): updateId = 0 robotId = _G() # 获取当前实盘ID while True: if not exchange.IO("status"): Sleep(1000) continue # 获取实时市场价格 ticker = exchange.GetTicker("rb888") if not ticker: Sleep(5000) continue # 构建当前频道状态数据 channelState = { "robotId": robotId, "updateId": updateId + 1, "timestamp": time.time() * 1000, "symbol": "rb888", "lastPrice": ticker["Last"], "volume": ticker["Volume"], "high": ticker["High"], "low": ticker["Low"] } updateId += 1 # 向频道发布最新状态(覆盖旧状态) SetChannelData(channelState) # 显示当前频道状态 LogStatus("频道广播端 [实盘ID: {}]\n".format(robotId) + "更新ID: #{}\n".format(channelState["updateId"]) + "时间: {}\n".format(_D(channelState["timestamp"])) + "交易对: {}\n".format(channelState["symbol"]) + "最新价: ${:.2f}\n".format(channelState["lastPrice"]) + "成交量: {:.4f}\n".format(channelState["volume"]) + "最高价: ${:.2f}\n".format(channelState["high"]) + "最低价: ${:.2f}".format(channelState["low"])) Sleep(60000) # 每分钟更新一次频道状态
    rust
    fn main() { let mut updateId = 0; let robotId = _G!(); // 获取当前实盘ID loop { if exchange.IO("status").unwrap_or_default() != "true" { Sleep(1000); continue; } // 获取实时市场价格 let ticker = match exchange.GetTicker("rb888") { Ok(t) => t, Err(_) => { Sleep(5000); continue; } }; // 构建当前频道状态数据 updateId += 1; let timestamp = Unix() * 1000; let channelState = format!( r#"{{"robotId": {}, "updateId": {}, "timestamp": {}, "symbol": "rb888", "lastPrice": {}, "volume": {}, "high": {}, "low": {}}}"#, robotId, updateId, timestamp, ticker.Last, ticker.Volume, ticker.High, ticker.Low ); // 向频道发布最新状态(覆盖旧状态) SetChannelData(&channelState); // 显示当前频道状态 LogStatus!(format!( "频道广播端 [实盘ID: {}]\n更新ID: #{}\n时间: {}\n交易对: rb888\n最新价: ${:.2}\n成交量: {:.4}\n最高价: ${:.2}\n最低价: ${:.2}", robotId, updateId, _D(timestamp), ticker.Last, ticker.Volume, ticker.High, ticker.Low )); Sleep(60000); // 每分钟更新一次频道状态 } }
    c++
  • 跨平台发送示例 - 模拟外部平台(如 TradingView)向优宽量化实盘发送数据

    javascript
    // 本示例演示如何使用 HttpQuery 发送 HTTP POST 请求,模拟外部平台向优宽量化实盘发送数据 // 在实际场景中,外部平台(如 TradingView 的 Webhook 告警 URL、第三方交易系统等)会直接调用优宽量化 API 端点 function main() { let uuid = "6BC42A119B5DBFA2188A8279DA3B5C30" let robotId = 123456 // 目标实盘 ID(即需要接收数据的实盘) let baseUrl = "https://www.youquant.com" while (true) { // 准备要发送的数据(可以是 JSON、文本或其他格式) let sendData = { "action": "buy", "symbol": "rb888", "price": 3500, "timestamp": Date.now() } // 构造 HTTP POST 请求 let options = { method: "POST", body: JSON.stringify(sendData) // body 可以是 JSON 字符串、普通文本等 } let url = `${baseUrl}/api/v1?method=pub&robot=${robotId}&channel=${uuid}` // 发送数据 let ret = HttpQuery(url, options) Log("Simulated external platform sending data, result:", ret) Sleep(10000) // 每 10 秒发送一次 } }
    python
    # 本示例演示如何使用 HttpQuery 发送 HTTP POST 请求,模拟外部平台向优宽量化实盘发送数据 # 在实际场景中,外部平台(如 TradingView 的 Webhook 告警 URL、第三方交易系统等)会直接调用优宽量化 API 端点 import json def main(): uuid = "6BC42A119B5DBFA2188A8279DA3B5C30" robotId = 123456 # 目标实盘 ID(即需要接收数据的实盘) baseUrl = "https://www.youquant.com" while True: # 准备要发送的数据(可以是 JSON、文本或其他格式) sendData = { "action": "buy", "symbol": "rb888", "price": 3500, "timestamp": time.time() * 1000 } # 构造 HTTP POST 请求 options = { "method": "POST", "body": json.dumps(sendData) # body 可以是 JSON 字符串、普通文本等 } url = "{}/api/v1?method=pub&robot={}&channel={}".format(baseUrl, robotId, uuid) # 发送数据 ret = HttpQuery(url, options) Log("Simulated external platform sending data, result:", ret) Sleep(10000) # 每 10 秒发送一次
    rust
    // 本示例演示如何使用 HttpQuery 发送 HTTP POST 请求,模拟外部平台向优宽量化实盘发送数据 // 在实际场景中,外部平台(如 TradingView 的 Webhook 告警 URL、第三方交易系统等)会直接调用优宽量化 API 端点 fn main() { let uuid = "6BC42A119B5DBFA2188A8279DA3B5C30"; let robotId = 123456; // 目标实盘 ID(即需要接收数据的实盘) let baseUrl = "https://www.youquant.com"; loop { // 准备要发送的数据(可以是 JSON、文本或其他格式) let sendData = format!( r#"{{"action": "buy", "symbol": "rb888", "price": 3500, "timestamp": {}}}"#, Unix() * 1000 ); // 构造 HTTP POST 请求 let options = format!(r#"{{"method": "POST", "body": {:?}}}"#, sendData); let url = format!("{}/api/v1?method=pub&robot={}&channel={}", baseUrl, robotId, uuid); // 发送数据 let ret: String = HttpQuery(&url, options.as_str()); Log!("Simulated external platform sending data, result:", ret); Sleep(10000); // 每 10 秒发送一次 } }
    c++

返回值

类型描述

空值

此函数无返回值。

参数

名称类型必填描述

data

object / array / string / number / bool / 空值

需要发布到频道的数据,可以是任何能够通过JSON序列化的数据结构,通常为包含实盘状态信息的对象。

参考

备注

SetChannelData()函数为非阻塞调用,调用后立即返回,不会等待数据传输完成。

每个实盘都拥有一个独立的频道,频道ID即为实盘ID(可通过_G()函数获取)。

频道上仅保存最新的状态数据,每次调用SetChannelData()都会覆盖之前发布的数据,而非追加历史消息。

频道数据可跨实盘、跨托管者、跨服务器进行广播,多个实盘可订阅同一个频道。

订阅端使用GetChannelData()函数订阅频道数据。

频道通信适用于实盘环境,在回测系统中该功能可能受限。

传入的数据参数data经JSON序列化后的字节长度不得超过1024字节,超出该限制可能导致数据发布失败。建议仅传输必要的状态信息,避免传输过大的数据对象。

发布数据时应根据硬件设备的内存及网络带宽合理使用,避免发布过大的数据对象。

SetChannelData()函数发布的数据除可被优宽量化平台内的其它实盘订阅外,还支持跨平台数据发送功能。外部平台(如TradingView的Webhook告警、第三方交易系统、监控软件等)可通过HTTP POST请求向指定的优宽量化实盘发送数据。

跨平台发送数据的方式: 外部系统通过HTTP POST请求将数据发送到优宽量化平台API端点:https://www.youquant.com/api/v1?method=pub&robot={robotId}&channel={uuid},其中robotId为目标实盘ID,uuid为32位字符的频道标识符。发送的数据在请求body中传递,可以是JSON格式、文本或其它格式。注意:必须先有实盘订阅该UUID频道,外部系统才能成功发送数据;广播的数据会发送至robotId实盘所在托管者下的所有实盘,同一托管者下订阅了该UUID频道的实盘均可接收数据。

订阅指定实盘的频道数据。该函数用于实盘间通信,可获取其他实盘通过SetChannelData()函数发布的最新状态数据。

GetChannelData(channelId)

示例

  • 频道订阅端示例 - 订阅两个实盘的频道数据

    javascript
    function main() { // 需要订阅的两个频道ID(请根据实际情况修改) var channelId1 = "632799" // 频道1的实盘ID var channelId2 = "632800" // 频道2的实盘ID while(true) { // 读取频道1的当前状态 var state1 = GetChannelData(channelId1) // 读取频道2的当前状态 var state2 = GetChannelData(channelId2) // 构建状态显示内容 var statusMsg = "频道订阅端 - 当前订阅状态\n\n" // 显示频道1状态 statusMsg += "═══ 频道1 [" + channelId1 + "] ═══\n" if (state1 !== null) { statusMsg += "更新ID: #" + state1.updateId + "\n" statusMsg += "时间: " + _D(state1.timestamp) + "\n" statusMsg += "交易对: " + state1.symbol + "\n" statusMsg += "最新价: $" + state1.lastPrice.toFixed(2) + "\n" statusMsg += "成交量: " + state1.volume.toFixed(4) + "\n" } else { statusMsg += "状态: 等待中... (首次调用返回 null)\n" } statusMsg += "\n" // 显示频道2状态 statusMsg += "═══ 频道2 [" + channelId2 + "] ═══\n" if (state2 !== null) { statusMsg += "更新ID: #" + state2.updateId + "\n" statusMsg += "时间: " + _D(state2.timestamp) + "\n" statusMsg += "交易对: " + state2.symbol + "\n" statusMsg += "最新价: $" + state2.lastPrice.toFixed(2) + "\n" statusMsg += "成交量: " + state2.volume.toFixed(4) + "\n" } else { statusMsg += "状态: 等待中... (首次调用返回 null)\n" } LogStatus(statusMsg) Sleep(5000) // 每5秒读取一次频道数据 } }
    python
    def main(): # 需要订阅的两个频道ID(请根据实际情况修改) channelId1 = "632799" # 频道1的实盘ID channelId2 = "632800" # 频道2的实盘ID while True: # 读取频道1的当前状态 state1 = GetChannelData(channelId1) # 读取频道2的当前状态 state2 = GetChannelData(channelId2) # 构建状态显示内容 statusMsg = "频道订阅端 - 当前订阅状态\n\n" # 显示频道1状态 statusMsg += "═══ 频道1 [{}] ═══\n".format(channelId1) if state1 is not None: statusMsg += "更新ID: #{}\n".format(state1["updateId"]) statusMsg += "时间: {}\n".format(_D(state1["timestamp"])) statusMsg += "交易对: {}\n".format(state1["symbol"]) statusMsg += "最新价: ${:.2f}\n".format(state1["lastPrice"]) statusMsg += "成交量: {:.4f}\n".format(state1["volume"]) else: statusMsg += "状态: 等待中... (首次调用返回 None)\n" statusMsg += "\n" # 显示频道2状态 statusMsg += "═══ 频道2 [{}] ═══\n".format(channelId2) if state2 is not None: statusMsg += "更新ID: #{}\n".format(state2["updateId"]) statusMsg += "时间: {}\n".format(_D(state2["timestamp"])) statusMsg += "交易对: {}\n".format(state2["symbol"]) statusMsg += "最新价: ${:.2f}\n".format(state2["lastPrice"]) statusMsg += "成交量: {:.4f}\n".format(state2["volume"]) else: statusMsg += "状态: 等待中... (首次调用返回 None)\n" LogStatus(statusMsg) Sleep(5000) # 每5秒读取一次频道数据
    rust
    fn main() { // Rust 的 GetChannelData() 函数不接受频道 ID 参数,只能读取当前实盘自身频道 // (即本实盘通过 SetChannelData() 发布)的最新数据,无法订阅其它实盘或 UUID 频道 loop { // 读取频道的当前状态 let state = GetChannelData(); // 构建状态显示内容 let mut statusMsg = String::from("频道订阅端 - 当前订阅状态\n\n"); if !state.is_null() { statusMsg += &format!("更新ID: #{}\n", state["updateId"].as_i64().unwrap_or(0)); statusMsg += &format!("时间: {}\n", _D(state["timestamp"].as_i64().unwrap_or(0))); statusMsg += &format!("交易对: {}\n", state["symbol"].as_str().unwrap_or("")); statusMsg += &format!("最新价: ${:.2}\n", state["lastPrice"].as_f64().unwrap_or(0.0)); statusMsg += &format!("成交量: {:.4}\n", state["volume"].as_f64().unwrap_or(0.0)); } else { statusMsg += "状态: 等待中... (首次调用返回 null)\n"; } LogStatus!(statusMsg); Sleep(5000); // 每5秒读取一次频道数据 } }
    c++
  • 跨平台订阅示例 —— 使用 UUID 订阅外部系统发送的数据

    javascript
    function main() { // 使用 32 位 UUID 作为频道标识符 let uuid = "6BC42A119B5DBFA2188A8279DA3B5C30" while (true) { // 订阅该 UUID 频道的数据 let data = GetChannelData(uuid) if (data !== null) { Log("Received cross-platform data:", data) } else { Log("Waiting for data... (first call returns null)") } Sleep(10000) // 每 10 秒检查一次 } }
    python
    def main(): # 使用 32 位 UUID 作为频道标识符 uuid = "6BC42A119B5DBFA2188A8279DA3B5C30" while True: # 订阅该 UUID 频道的数据 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) # 每 10 秒检查一次
    rust
    fn main() { // Rust 的 GetChannelData() 函数不接受频道 ID 参数,只能读取当前实盘自身频道 // (即本实盘通过 SetChannelData() 发布)的最新数据,无法订阅其它实盘或 UUID 频道 loop { // 订阅当前频道的数据 let data = GetChannelData(); if !data.is_null() { Log!("Received cross-platform data:", data); } else { Log!("Waiting for data... (first call returns null)"); } Sleep(10000); // 每 10 秒检查一次 } }
    c++

返回值

类型描述

object / array / string / number / bool / 空值

返回所订阅频道的最新状态数据。首次调用返回null,需重试。数据结构由广播端发布的数据决定。

参数

名称类型必填描述

channelId

string / number

频道标识符,支持两种类型:

  1. 实盘ID:用于订阅其它实盘的频道数据(实盘间通信)。可通过_G()函数获取实盘ID。

  2. 32位UUID:用于订阅跨平台发送的数据(由外部系统通过HTTP API向优宽量化平台发送数据)。

参考

备注

GetChannelData()函数为非阻塞调用,调用后立即返回,不会等待数据接收完成。

首次调用GetChannelData()函数时会返回null,需重试以等待频道数据同步完成。

每次调用获取的均为频道上的最新状态数据,而非历史消息队列。

一个实盘可同时订阅多个不同实盘的频道,只需多次调用GetChannelData()并传入不同的实盘ID即可。

当前实盘也可订阅自身的频道,即robotId参数可为当前实盘ID。

频道数据可跨实盘、跨托管者、跨服务器进行传输。

广播端使用SetChannelData()函数发布频道数据。

频道通信适用于实盘环境,在回测系统中该功能可能受限。

GetChannelData()函数支持跨平台订阅功能。当使用32位UUID作为频道标识符时,可接收来自优宽量化平台外部系统通过HTTP API发送的数据。外部系统需同时指定实盘ID和UUID才能发送数据;同一托管者下的所有实盘均可订阅该UUID频道的数据,而不同托管者的实盘则无法订阅。