资源加载中... loading...

内置函数

Global

Version

返回系统当前版本号。

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

Version()

function main() {
    Log("version:", Version())
}
def main():
    Log("version:", Version())
void main() {
    Log("version:", Version());
}

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

Sleep

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

Sleep(millisecond)

millisecond
true
number

```javascript
function main() {
    Sleep(1000 * 10)   // 等待10秒钟
    Log("等待了10秒钟")
}
def main():
    Sleep(1000 * 10)
    Log("等待了10秒钟")
void main() {
    Sleep(1000 * 10);
    Log("等待了10秒钟");
}

例如执行Sleep(1000)函数时,程序会休眠1秒。 支持休眠时间小于1毫秒的操作,例如设置Sleep(0.1)。 支持最小参数为0.000001,即纳秒级休眠,1纳秒等于1e-6毫秒。 在使用Python语言编写策略时,对于轮询间隔、时间等待的操作应当使用Sleep(millisecond)函数。 不建议使用Pythontime库的time.sleep(second)函数。 因为策略中使用time.sleep(second)函数在回测时会让策略程序实际等待一段时间(并非在回测系统的时间序列上跳过),所以导致策略回测非常慢。

IsVirtual

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

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

IsVirtual()

function main() {
    if (IsVirtual()) {
        Log("当前为回测系统环境。")
    } else {
        Log("当前为实盘环境。")
    }
}
def main():
    if IsVirtual():
        Log("当前为回测系统环境。")
    else:
        Log("当前为实盘环境。")
void main() {
    if (IsVirtual()) {
        Log("当前为回测系统环境。");
    } else {
        Log("当前为实盘环境。");
    }
}

判断当前运行环境是否是回测系统,用来兼容回测与实盘的差异。

Mail

发送邮件。

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

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

用于指定邮件发送方的SMTP服务地址。 smtpServer true string 用于指定邮件发送方的邮箱地址。 smtpUsername true string 邮件发送方邮箱的SMTP密码。 smtpPassword true string 用于指定邮件接收方的邮箱地址。 mailTo true string 邮件标题。 title true string 邮件正文。 body true string

function main(){
    Mail("smtp.163.com", "asdf@163.com", "password", "111@163.com", "title", "body")
}
def main():
    Mail("smtp.163.com", "asdf@163.com", "password", "111@163.com", "title", "body")
void main() {
    Mail("smtp.163.com", "asdf@163.com", "password", "111@163.com", "title", "body");
}
设置```smtpServer```参数时,如果需要更改端口可以直接在参数```smtpServer```中加入端口号。 例如:QQ邮箱```smtp.qq.com:587```该端口测试可用。
如果出现报错:```unencryped connection```,需要修改```Mail```函数的```smtpServer```。 参数格式为:```ssl://xxx.com:xxx```,例如QQ邮箱的```SMTP```的```ssl```方式:```ssl://smtp.qq.com:465```或者```smtp://xxx.com:xxx```。
回测系统中不起作用。

{@fun/Global/Mail_Go Mail_Go}

### Mail_Go

```Mail```函数的异步版本。

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

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

用于指定邮件发送方的```SMTP```服务地址。
smtpServer
true
string
用于指定邮件发送方的邮箱地址。
smtpUsername
true
string
邮件发送方邮箱的```SMTP```密码。
smtpPassword
true
string
用于指定邮件接收方的邮箱地址。
mailTo
true
string
邮件标题。
title
true
string
邮件正文。
body
true
string

```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)
}
# 不支持
// 不支持

回测系统中不起作用。

{@fun/Global/Mail Mail}

SetErrorFilter

过滤错误日志。

SetErrorFilter(filters)

正则表达式字符串。 filters true string

function main() {
    SetErrorFilter("502:|503:|tcp|character|unexpected|network|timeout|WSARecv|Connect|GetAddr|no such|reset|http|received|EOF|reused")
}
def main():
    SetErrorFilter("502:|503:|tcp|character|unexpected|network|timeout|WSARecv|Connect|GetAddr|no such|reset|http|received|EOF|reused")
void main() {
    SetErrorFilter("502:|503:|tcp|character|unexpected|network|timeout|WSARecv|Connect|GetAddr|no such|reset|http|received|EOF|reused");
}

过滤常见错误。

function main() {
    // 随便查询一个不存在的订单,id为123,故意让接口报错
    var order = exchange.GetOrder("123")
    Log(order)
    // 过滤http502错误、GetOrder接口错误,设置错误过滤之后,第二次调用GetOrder不再报错
    SetErrorFilter("502:|GetOrder")
    order = exchange.GetOrder("123")
    Log(order)
}
def main():
    order = exchange.GetOrder("123")
    Log(order)
    SetErrorFilter("502:|GetOrder")
    order = exchange.GetOrder("123")
    Log(order)
void main() {
    TId orderId;
    Order order = exchange.GetOrder(orderId);
    Log(order);
    SetErrorFilter("502:|GetOrder");
    order = exchange.GetOrder(orderId);
    Log(order);
}

过滤某个接口错误信息。

被此正则表达式匹配的错误日志将不上传到日志系统,可多次调用(没有次数限制)设置多个过滤条件。多次设置的正则表达式会累积在一起同时生效。可以设置空字符串来重置用以过滤错误日志的正则表达式:SetErrorFilter("")。 被过滤的日志不再写入托管者目录下对应实盘Id的数据库文件中,防止频繁报错导致数据库文件膨胀。

GetPid

获取实盘进程Id。

返回实盘进程Id。 string

GetPid()

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

GetLastError

获取最近一次出错信息。

最近一次出错信息。 string

GetLastError()

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

回测系统中不起作用。

GetCommand

获取策略交互命令。

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

GetCommand()

function main(){
    while(true) { 
        var cmd = GetCommand()
        if (cmd) { 
            Log(cmd)
        }
        Sleep(1000) 
    }
}
def main():
    while True:
        cmd = GetCommand()
        if cmd:
            Log(cmd)
        Sleep(1000)
void main() {
    while(true) {
        auto cmd = GetCommand();
        if(cmd != "") {
            Log(cmd);
        }
        Sleep(1000);
    }
}

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

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)
    } 
}
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)
#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);
    }
}

例如策略交互控件中添加了一个不带输入框的控件,交互控件命名为:buy,控件描述信息为:买入,这是一个按钮控件。 继续添加一个带输入框的控件,交互控件名为:sell,控件描述信息为:卖出,这是一个由按钮和输入框组合起来的交互控件。 策略中设计交互代码来响应不同交互控件:

回测系统中不起作用。

GetMeta

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

string

GetMeta()

```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
    }
    
    while(1) {
        Sleep(1000)
        var ticker = exchange.GetTicker()
        
        // 检测资产数值
        var acc = exchange.GetAccount()
        if (maxBaseCurrency != -1 && maxBaseCurrency < acc.Stocks + acc.FrozenStocks) {
            // 停止执行策略交易逻辑
            LogStatus(_D(), "level:", level, "持仓超过注册码的使用限定,不再执行策略交易逻辑!")
            continue
        }
        
        // 其它交易逻辑
        
        // 正常输出状态栏信息
        LogStatus(_D(), "level:", level, "策略正常运行!ticker数据:\n", ticker)
    }
}
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, "持仓超过注册码的使用限定,不再执行策略交易逻辑!")
            continue        
        
        # 其它交易逻辑
        
        # 正常输出状态栏信息
        LogStatus(_D(), "level:", level, "策略正常运行!ticker数据:\n", ticker)
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) {
            // 停止执行策略交易逻辑
            LogStatus(_D(), "level:", level, "持仓超过注册码的使用限定,不再执行策略交易逻辑!");
            continue;
        }
        
        // 其它交易逻辑
        
        // 正常输出状态栏信息
        LogStatus(_D(), "level:", level, "策略正常运行!ticker数据:\n", ticker);
    }
}

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

应用场景:需要对不同的策略租用者做资金限制。 生成注册码时设置的Meta值长度不能超过190个字符,GetMeta()函数仅支持实盘。 如果生成策略注册码时没有设置元数据(Meta),GetMeta()函数返回空值。 回测系统中不起作用。

Dial

用于原始的Socket访问,支持tcpudptlsunix协议。 支持4种流行的通信协议:mqttnatsamqpkafka。 支持连接数据库,支持的数据库有:sqlite3mysqlpostgresclickhouse

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

- 不传参数时,阻塞到有消息时就返回。例如:```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连接断开或者底层重连时|read()函数返回空字符串,即:"",write()函数返回0,检测到该情况。可以使用close()函数关闭连接,如果设置了自动重连则不用关闭,系统底层会自动重连。||||

object

Dial(address)
Dial(address, timeout)

请求地址。
address
true
string
超时秒数,
timeout
false
number

```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()
    }
}
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()
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函数调用例子:

function main() {
    LogStatus("正在连接...")
    // 访问币安的WebSocket接口
    var client = Dial("wss://stream.binance.com:9443/ws/!ticker@arr")
    if (!client) {
        Log("连接失败, 程序退出")
        return
    }
    
    while (true) {
        // read只返回调用read之后获取的数据
        var buf = client.read()      
        if (!buf) {
            break
        }
        var table = {
            type: 'table',
            title: '行情图表',
            cols: ['币种', '最高', '最低', '买一', '卖一', '最后成交价', '成交量', '更新时间'],
            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()
}
import json
def main():
    LogStatus("正在连接...")
    client = Dial("wss://stream.binance.com:9443/ws/!ticker@arr")
    if not client:
        Log("连接失败, 程序退出")
        return 
    
    while True:
        buf = client.read()
        if not buf:
            break
        table = {
            "type" : "table", 
            "title" : "行情图表", 
            "cols" : ["币种", "最高", "最低", "买一", "卖一", "最后成交价", "成交量", "更新时间"], 
            "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()
void main() {
    LogStatus("正在连接...");
    auto client = Dial("wss://stream.binance.com:9443/ws/!ticker@arr");
    if(!client.Valid) {
        Log("连接失败, 程序退出");
        return;
    }
    
    while(true) {
        auto buf = client.read();
        if(buf == "") {
            break;
        }
        json table = R"({
            "type" : "table", 
            "title" : "行情图表", 
            "cols" : ["币种", "最高", "最低", "买一", "卖一", "最后成交价", "成交量", "更新时间"], 
            "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();
}

访问币安(binance)的WebSocket行情接口:

var ws = null 
function main(){
    var param = {
        "op": "subscribe",
        "args": [{
            "channel": "tickers",
            "instId": "BTC-USDT"
        }]
    }
    // 在调用Dial函数时,指定reconnect=true即设置为重连模式,指定payload即为重连时发送的消息。在WebSocket连接断开后,会自动重连,自动发送消息
    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("发送 :ping", "#FF0000")
            }
            LogStatus("当前时间:", _D())
            Sleep(1000)
        }
    }
}              

function onexit() {
    ws.close() 
    Log("退出")
}
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("发送:ping", "#FF0000")
            LogStatus("当前时间:", _D())
            Sleep(1000)              

def onexit():
    ws.close()
    Log("退出")
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("发送:ping", "#FF0000");
            }
            LogStatus("当前时间:", _D());
            Sleep(1000);
        }
    }
}              

void onexit() {
    objWS.close();
    Log("退出");
}

访问OKX的WebSocket行情接口:

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)
            // 响应心跳包操作
            try {
                var jsonRet = JSON.parse(ret)
                if(typeof(jsonRet.ping) == "number") {
                    var strPong = JSON.stringify({"pong" : jsonRet.ping})
                    ws.write(strPong)
                    Log("响应ping,发送pong:", strPong, "#FF0000")
                }
            } catch(e) {
                Log("e.name:", e.name, "e.stack:", e.stack, "e.message:", e.message)
            }
            
            LogStatus("当前时间:", _D())
            Sleep(1000)
        }
    }
}              

function onexit() {
    ws.close() 
    Log("执行ws.close()函数")
}
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)              
            # 响应心跳包操作
            try:
                jsonRet = json.loads(ret)
                if "ping" in jsonRet and type(jsonRet["ping"]) == int:
                    strPong = json.dumps({"pong" : jsonRet["ping"]})
                    ws.write(strPong)
                    Log("响应ping,发送pong:", strPong, "#FF0000")
            except Exception as e:
                Log("e:", e)
                
            LogStatus("当前时间:", _D())
            Sleep(1000)
    
def onexit():
    ws.close()
    Log("执行ws.close()函数")  
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);              
            // 响应心跳包操作
            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("响应ping,发送pong:", strPong, "#FF0000");
                }
            } catch(exception &e) 
            {
                Log("e:", e.what());
            }
            
            LogStatus("当前时间:", _D());
            Sleep(1000);
        }
    }
}              

void onexit() {
    // ws.close();
    Log("执行ws.close()函数");
}

访问火币的WebSocket行情接口:

function getLogin(pAccessKey, pSecretKey, pPassphrase) {
    // 签名函数,用于登录
    var ts = (new Date().getTime() / 1000).toString()
    var login = {
        "op": "login",
        "args":[{
            "apiKey"    : pAccessKey,
            "passphrase" : pPassphrase,
            "timestamp" : ts,
            "sign" : exchange.HMAC("sha256", "base64", ts + "GET" + "/users/self/verify", pSecretKey)   // exchange.HMAC已经废弃,暂时支持。请替换使用最新的exchange.Encode函数 
        }]
    }    
    return login
}                

var client_private = null 
function main() {
    // 因为read函数使用了超时设置,过滤超时的报错,否则会有冗余错误输出
    SetErrorFilter("timeout")
    
    // 持仓频道订阅信息
    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)  // 登录时,不能立即订阅私有频道,需要等待服务器反应
    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)
            }
            
            // 检测断开,重连
            if (buf == "" && client_private.write(JSON.stringify(posSubscribe)) == 0) {
                Log("检测到断开,关闭连接,重连")
                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))
            }
            
            // 发送心跳包
            var nowPingTS = new Date().getTime()
            if (nowPingTS - lastPingTS > 10 * 1000) {
                client_private.write("ping")
                lastPingTS = nowPingTS
            }            
        }        
    }
}                

function onexit() {    
    var ret = client_private.close()
    Log("关闭连接!", ret)
}
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.HMAC("sha256", "base64", ts + "GET" + "/users/self/verify", 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("检测到断开,关闭连接,重连")
                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("关闭连接!", ret)
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.HMAC("sha256", "base64", ts + "GET" + "/users/self/verify", 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("检测到断开,关闭连接,重连");
                    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("退出");
}

访问OKX的WebSocket验证接口:

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()
}
// 不支持
// 不支持

Dial函数连接数据库时返回的连接对象有2个其独有的方法函数: - exec(sqlString): 用于执行SQL语句,使用方式类似于DBExec()函数。 - fd(): fd()函数返回一个句柄(例如:句柄变量为handle),用于其它线程重连(即使Dial创建的对象已经被执行close()函数关闭连接),将句柄传入Dial()函数,例如:Dial(handle)重用连接。 以下是Dial函数连接sqlite3数据库的例子。

|Dial函数的address参数支持的功能|参数说明|
| - | - |
|WebSocket协议数据压缩相关的参数:compress=参数值|compress为压缩方式,compress参数可选gzip_raw、gzip等。如果gzip方式非标准gzip,可以使用扩展的方式:gzip_raw|
|WebSocket协议数据压缩相关的参数:mode=参数值|mode为压缩模式,mode参数可选dual,send,recv三种。dual为双向压缩,发送压缩数据,接收压缩数据。send为发送压缩数据。recv为接收压缩数据,本地解压缩。|
|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 | github.com/go-sql-driver/mysql | mysql://username:yourpassword@tcp(localhost:3306)/yourdatabase?charset=utf8mb4 | -- |
| postgres | github.com/lib/pq | postgres://user=postgres dbname=yourdatabase sslmode=disable password=yourpassword host=localhost port=5432 | -- |
| clickhouse | github.com/ClickHouse/clickhouse-go | clickhouse://tcp://host:9000?username=username&password=yourpassword&database=youdatabase | -- |

需要注意当```address```参数中设置的```payload```内容中有字符```=```或者其它特殊字符时,可能影响```Dial```函数的```address```参数解析,例如以下例子。

backPack交易所websocket私有接口调用范例:
```js
var client = null

function main() {
    // base64编码的秘钥对公钥,即在FMZ上配置的access key
    var base64ApiKey = "xxx"

    var ts = String(new Date().getTime())
    var data = "instruction=subscribe&timestamp=" + ts + "&window=5000"

    // 由于signEd25519最终返回的是base64编码,其中会有字符"="
    var signature = signEd25519(data)
    
    // payload 被JSON编码后可能包含字符"="
    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("连接失败, 程序退出")
        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}}")
}

代码中写成以下调用方式是可以正常工作的:

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

如果直接写在payload中则无法正常工作,例如:

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

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

// 需要先配置、部署完成各个协议的代理服务器
// 为了便于演示,主题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], "连接")
    }
}

详细介绍文档参考:探索FMZ:交易策略实盘间通信协议实践

HttpQuery

发送Http请求。

返回请求的应答数据,如果返回值为JSON字符串,JavaScript语言的策略中可以用JSON.parse()函数解析,C++语言的策略中可以用json::parse()函数解析。 参数options结构中如果debug设置为true,返回值为对象(JSON);如果debug设置为false,返回值为字符串。 string、object

HttpQuery(url) HttpQuery(url, options)

Http请求url。 url true string Http请求相关设置,例如可以是以下结构:

{
    method: "POST",
    body: "a=10&b=20&c=30",
    charset: "UTF-8",
    cookie: "session_id=12345; lang=en",
    profile: "chrome_103",
    debug: false,
    headers: {"TEST-HTTP-QUERY": "123"},
    timeout: 1000
}
  • profile:用来模拟浏览器tls指纹。 支持的设置有以下选项: chrome"chrome_103""chrome_104""chrome_105""chrome_106""chrome_107""chrome_108""chrome_109""chrome_110""chrome_111""chrome_112""chrome_117"、 safari"safari_15_6_1""safari_16_0""safari_ipad_15_6""safari_ios_15_5""safari_ios_15_6""safari_ios_16_0"、 firefox"firefox_102""firefox_104""firefox_105""firefox_106""firefox_108""firefox_110""firefox_117"、 opera"opera_89""opera_90""opera_91"、 zalando"zalando_android_mobile""zalando_ios_mobile"、 nike"nike_ios_mobile""nike_android_mobile"、 cloudscraper:"cloudscraper"、 mms"mms_ios"、 mesh"mesh_ios""mesh_ios_1""mesh_ios_2""mesh_android""mesh_android_1""mesh_android_2"、 confirmed"confirmed_ios""confirmed_android"、 okhttp4"okhttp4_android_7""okhttp4_android_8""okhttp4_android_9""okhttp4_android_10""okhttp4_android_11""okhttp4_android_12""okhttp4_android_13"
  • debug:设置为true时,此次HttpQuery函数调用返回完整的应答报文。设置为false时只返回应答报文Body中的数据。
  • timeout:超时设置,设置1000表示1秒钟超时。
  • charset:支持对请求的应答数据进行转码,例如:GB18030。支持常用编码。

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

options false object

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)
}
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)
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);
}

访问OKX公共行情API接口的例子。

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/")
}
# HttpQuery不支持Python,可以使用Python的urllib2库
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/");
}

HttpQuery函数使用代理设置。


{@fun/Global/HttpQuery_Go HttpQuery_Go}

### HttpQuery_Go

发送Http请求,```HttpQuery```函数的异步版本。

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

HttpQuery_Go(url)
HttpQuery_Go(url, options)

Http请求url。
url
true
string
Http请求相关设置,例如可以是以下结构:

{ method: “POST”, body: “a=10&b=20&c=30”, charset: “UTF-8”, cookie: “session_id=12345; lang=en”, // profile: “”, debug: false, headers: {“TEST-HTTP-QUERY”: “123”}, timeout: 1000 }


- profile:用来模拟浏览器```tls```指纹。
- debug:设置为```true```时,此次```HttpQuery_Go```函数调用返回完整的应答报文。设置为```false```时只返回应答报文```Body```中的数据。
- timeout:超时设置,设置1000表示1秒钟超时。

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

options
false
object

```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)
}
# 不支持
// 不支持

异步访问交易所公共接口获取聚合行情数据。


{@fun/Global/HttpQuery HttpQuery}

### Encode

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

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

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

参数```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```计算。
algo
true
string
用于指定```data```参数的数据格式。 ```inputFormat```参数支持设置为:"raw","hex","base64","string"其中之一。 "raw"表示数据为原始数据,"hex"表示数据为```hex```编码,"base64"表示数据为```base64```编码,"string"表示数据为字符串。
inputFormat
true
string
用于指定输出的数据格式。 ```outputFormat```参数支持设置为:"raw","hex","base64","string"其中之一。 "raw"表示数据为原始数据,"hex"表示数据为```hex```编码,"base64"表示数据为```base64```编码,"string"表示数据为字符串。
outputFormat
true
string
参数```data```为所要处理的数据。
data
true
string
用于指定```key```参数的数据格式。 ```key```参数支持设置为:"raw","hex","base64","string"其中之一。 "raw"表示数据为原始数据,"hex"表示数据为```hex```编码,"base64"表示数据为```base64```编码,"string"表示数据为字符串。
keyFormat
false
string
参数```key```为```HMAC```加密时使用的秘钥。 参数```algo```设置为"sign"或者"signTx"时需要参数```key```。 参数```algo```设置为"raw"时不会使用```key```参数进行```HMAC```加密(因为HMAC加密必须指定算法)。
key
false
string

```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
}
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
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
}

Encode函数调用例子。

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)
}
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)
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);
}

参数algo也支持:”text.encoder.utf8”,”text.decoder.utf8”,”text.encoder.gbk”,”text.decoder.gbk”,对字符串编码、解码。


### UnixNano

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

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

UnixNano()

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

如果需要获取毫秒级时间戳,可以使用如下代码:

{@fun/Global/Unix Unix}

Unix

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

返回秒级别时间戳。 number

Unix()

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

{@fun/Global/UnixNano UnixNano}

GetOS

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

系统信息。 string

GetOS()

function main() {
    Log("GetOS:", GetOS())
}
def main():
    Log("GetOS:", GetOS())
void main() {
    Log("GetOS:", GetOS());
}

例如在Mac OS操作系统下运行的托管者,调用GetOS()函数可能返回:darwin/amd64, 因为苹果电脑有多种硬件架构。darwinMac OS系统的名称。

MD5

计算参数data的MD5哈希值。

MD5哈希值。 string

MD5(data)

需要进行MD5计算的数据。 data true string

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

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

{@fun/Global/Encode Encode}

DBExec

数据库接口函数。

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

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

object

DBExec(sql)

sql语句字符串。 sql true string

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;"))
}
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;"))
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;"));
}

支持内存数据库,对于DBExec函数的参数,如果sql语句是以:开头则在内存数据库中操作,不写文件速度更快。 适合不需要持久化保存的数据库操作,例如:

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)
}
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)
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);
}

创建表。

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))
}
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))
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));
}

表中记录的增删查改操作。

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

{@fun/Global/_G _G}

UUID

创建一个UUID。

32位的UUID。 string

UUID()

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

### EventLoop

监听事件,在有任意```WebSocket```可读数据或者```exchange.Go()```、```HttpQuery_Go()```等并发的任务完成以后返回。

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

{“Seq”:1,“Event”:“Exchange_GetTrades”,“ThreadId”:0,“Index”:3,“Nano”:1682068771309583400}


object

EventLoop()
EventLoop(timeout)

参数```timeout```为超时设置,单位为毫秒。 参数```timeout```如果设置为0则等待有事件发生才返回,如果大于0就是设置事件等待超时,小于0立即返回最近事件。
timeout
false
number

```javascript
function main() {
    var routine_getTicker = exchange.Go("GetTicker")
    var routine_getDepth = exchange.Go("GetDepth")
    var routine_getTrades = exchange.Go("GetTrades")
    
    // Sleep(2000),如果这里使用Sleep语句,会导致之后的EventLoop函数错过之前的事件,因为等待了2秒,并发的函数已经收到了数据,后续才开始EventLoop监听机制,就错过了这些事件
    // 除非在第一行代码开始调用EventLoop(-1),首先初始化EventLoop的监听机制,则不会错过这些事件            

    // Log("GetDepth:", routine_getDepth.wait()) 如果这里提前调用wait函数取出GetDepth函数并发调用的结果,此次GetDepth函数收到请求结果的事件便不会在EventLoop函数返回
    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("第1个并发任务完成的为:", _D(ts1), ret1)
    Log("第2个并发任务完成的为:", _D(ts2), ret2)
    Log("第3个并发任务完成的为:", _D(ts3), ret3)
    
    Log("GetTicker:", routine_getTicker.wait())
    Log("GetDepth:", routine_getDepth.wait())
    Log("GetTrades:", routine_getTrades.wait())
}
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("第1个并发任务完成的为:", _D(ts1), ret1)
    Log("第2个并发任务完成的为:", _D(ts2), ret2)
    Log("第3个并发任务完成的为:", _D(ts3), ret3)
    
    Log("GetTicker:", routine_getTicker.wait())
    Log("GetDepth:", routine_getDepth.wait())
    Log("GetTrades:", routine_getTrades.wait())
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("第1个并发任务完成的为:", _D(ts1), ret1);
    Log("第2个并发任务完成的为:", _D(ts2), ret2);
    Log("第3个并发任务完成的为:", _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);
}

代码中第一次调用EventLoop()函数才会初始化该监听事件的机制,如果在事件回调之后才开始首次EventLoop()调用,会错过之前的事件。 底层系统封装的队列结构会缓存最大500个事件回调,如果程序执行过程中没有及时调用EventLoop()函数取出,会丢失500个缓存之外较晚的事件回调。 EventLoop()函数的调用不会影响系统底层WebSocket的缓存队列,也不影响exchange.Go()等并发函数的缓存, 对于这些缓存依然需要使用各自的方法取出数据。对于在EventLoop()函数返回之前,已经取出的数据,不会在EventLoop()函数中产生返回事件。 EventLoop()函数的主要用途就是通知策略层,系统底层接收到了新的网络数据。以事件驱动整个策略。当EventLoop()函数返回事件时, 只需遍历所有数据来源。例如WebSocket连接、exchange.Go()创建的对象尝试获取数据。 EventLoop()函数仅支持实盘。 在主函数main()中调用时,监听主线程的事件。 在JavaScript语言编写的策略中,threading.Thread()函数创建的线程,在线程的执行函数中也可以调用,监听当前线程的事件。

{@fun/Global/Dial Dial}, {@fun/Trade/exchange.Go exchange.Go}, {@fun/Global/HttpQuery_Go HttpQuery_Go}

__Serve



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

string

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

```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_pem```和```cert_key_pem```参数来加载证书。

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

handler
true
function
作为参数```handler```传入的**回调函数**的参数的实参,参数```arg```可能有多个,例如:
```js
__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

arg false string、number、bool、object、array、function、空值等系统支持的所有类型

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)
    }
}
# 不支持
// 不支持
  • 该函数仅支持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协议,可以使用该方法将编码后的字符串传递给客户端。

{@fun/Global/HttpQuery HttpQuery}, {@fun/Global/HttpQuery_Go HttpQuery_Go}

_G

持久化保存数据,该函数实现了一个可保存的全局字典功能。数据结构为KV表,永久保存在托管者本地数据库文件。

持久化保存的k-v键值对中的键值数据。 string、number、bool、object、array、空值

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

参数k为保存的键值对中的键名,不区分大小写。 k false string、空值 参数v为保存的键值对中的键值,可以是任何可以JSON序列化的数据。 v false string、number、bool、object、array、空值

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()
}
def main():
    _G("num", 1)     
    _G("num", "ok")    
    _G("num", None)
    Log(_G("num"))
    _G(None)
    robotId = _G()
void main() {
    _G("num", 1);
    _G("num", "ok");
    _G("num", NULL);
    Log(_G("num"));
    _G(NULL);
    // 不支持 auto robotId = _G();
}

每个实盘单独一个数据库,策略重启或者托管者停止运行,_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键值对。

{@fun/Global/DBExec DBExec}

_D

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

时间字符串。 string

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

毫秒时间戳或者Date对象。 timestamp false number、object 格式化字符串,JavaScript语言默认格式:yyyy-MM-dd hh:mm:ssPython语言默认格式:%Y-%m-%d %H:%M:%SC++语言默认格式:%Y-%m-%d %H:%M:%S。 fmt false string

function main(){
    var time = _D()
    Log(time)
}
def main():
    strTime = _D()
    Log(strTime)
void main() {
    auto strTime = _D();
    Log(strTime);
}

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

function main() {
    Log(_D(1574993606000))
}
def main():
    # 北京时间的服务器上运行:2019-11-29 10:13:26 ,另一台其它地区的服务器上的托管者运行此代码结果则为:2019-11-29 02:13:26
    Log(_D(1574993606))
void main() {
    Log(_D(1574993606000));
}

时间戳为1574993606000,使用代码转换:

function main() {
    Log(_D(1574993606000, "yyyy--MM--dd hh--mm--ss"))   // 2019--11--29 10--13--26
}
def main():
    # 1574993606为秒级别时间戳
    Log(_D(1574993606, "%Y--%m--%d %H--%M--%S"))        #  2019--11--29 10--13--26
void main() {
    Log(_D(1574993606000, "%Y--%m--%d %H--%M--%S"));    // 2019--11--29 10--13--26
}

使用参数fmt格式化,JavaScriptPythonC++语言的格式化字符串有所不同,具体参看以下例子:

不传任何参数就返回当前时间字符串。 Python策略中使用_D()函数时,需要注意传入的参数为秒级别时间戳(JavaScript、C++策略中为毫秒级别时间戳,1秒等于1000毫秒)。 在实盘时使用_D()函数解析一个时间戳为可读的时间字符串时,需要注意托管者程序所在的操作系统的时区、时间设置。 _D()函数解析一个时间戳为可读时间字符串是根据托管者系统的时间而定的。

{@fun/Global/UnixNano UnixNano}, {@fun/Global/Unix Unix}

_N

格式化一个浮点数。

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

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

需要格式化的浮点数。 num true number 格式化的精度设置,参数precision为整数,参数precision默认为4。 precision false number

function main(){
    var i = 3.1415
    Log(i)
    var ii = _N(i, 2)
    Log(ii)
}
def main():
    i = 3.1415
    Log(i)
    ii = _N(i, 2)
    Log(ii)
void main() {
    auto i = 3.1415;
    Log(i);
    auto ii = _N(i, 2);
    Log(ii);
}

例如_N(3.1415, 2)将删除3.1415小数点两位以后的值,函数返回3.14

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

如果需要将小数点左边的N个位数都变为0,可以这么写:

参数precision可以为正整数、负整数。

{@fun/Trade/exchange.SetPrecision exchange.SetPrecision}

_C

重试函数,用于接口容错。

回调函数执行时的返回值。 除了逻辑假值空值以外系统支持的所有类型。

_C(pfn) _C(pfn, …args)

参数pfn为函数引用,是一个回调函数。 pfn true function 回调函数的参数,参数arg可能有多个。参数arg的类型与个数根据回调函数的参数而定。 arg false string、number、bool、object、array、function、空值等系统支持的所有类型

function main(){
    var ticker = _C(exchange.GetTicker)
    // 调整_C()函数重试时间间隔为2秒
    _CDelay(2000)
    var depth = _C(exchange.GetDepth)
    Log(ticker)
    Log(depth)
}
def main():
    ticker = _C(exchange.GetTicker)
    _CDelay(2000)
    depth = _C(exchange.GetDepth)
    Log(ticker)
    Log(depth)
void main() {
    auto ticker = _C(exchange.GetTicker);
    _CDelay(2000);
    auto depth = _C(exchange.GetDepth);
    Log(ticker);
    Log(depth);
}

对于无参数的函数容错:

function main(){
    var records = _C(exchange.GetRecords, PERIOD_D1)
    Log(records)
}
def main():
    records = _C(exchange.GetRecords, PERIOD_D1)
    Log(records)
void main() {
    auto records = _C(exchange.GetRecords, PERIOD_D1);
    Log(records);
}

对于有参数的函数容错:

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(){
    var ret = _C(test, 1, 5)
    Log(ret)
}
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)
// C++ 不支持这种方式对于自定义函数容错

也可以用于自定义函数的容错处理:

可以但不限于对以下函数做容错处理:

- ```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())```。


### _Cross

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

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

_Cross(arr1, arr2)

元素为```number```类型的数组。
arr1
true
array
元素为```number```类型的数组。
arr2
true
array

```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))
}
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))
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));
}

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


### JSONParse

函数```JSONParse()```用于解析```JSON```字符串。

```JSON```对象。
object

JSONParse(s)

```JSON```字符串。
s
true
string

```javascript
function main() {
    let s1 = '{"num": 8754613216564987646512354656874651651358}'
    Log("JSON.parse:", JSON.parse(s1))    // JSON.parse: {"num":8.754613216564988e+39}
    Log("JSONParse:", JSONParse(s1))      // JSONParse:  {"num":"8754613216564987646512354656874651651358"}
    
    let s2 = '{"num": 123}'
    Log("JSON.parse:", JSON.parse(s2))    // JSON.parse: {"num":123}
    Log("JSONParse:", JSONParse(s2))      // JSONParse:  {"num":123}
}
import json

def main():
    s1 = '{"num": 8754613216564987646512354656874651651358}'
    Log("json.loads:", json.loads(s1))    # json.loads: map[num:8.754613216564987e+39]
    Log("JSONParse:", JSONParse(s1))      # JSONParse:  map[num:8754613216564987646512354656874651651358]
    
    s2 = '{"num": 123}'
    Log("json.loads:", json.loads(s2))    # json.loads: map[num:123]
    Log("JSONParse:", JSONParse(s2))      # JSONParse:  map[num:123]
void main() {
    auto s1 = "{\"num\":8754613216564987646512354656874651651358}";
    Log("json::parse:", json::parse(s1));
    // Log("JSONParse:", JSONParse(s1));   // 不支持该函数
    
    auto s2 = "{\"num\":123}";
    Log("json::parse:", json::parse(s2));
    // Log("JSONParse:", JSONParse(s2));   // 不支持该函数
}

可以正确解析包含有较大数值的JSON字符串,会将较大的数值解析为字符串类型。 回测系统中不支持JSONParse()函数。

Log

Log

输出日志。

Log(…msgs)

参数msg为输出的内容,参数msg可以传多个。 msg false string、number、bool、object、array、空值等系统支持的任意类型

function main() {
    Log("msg1", "msg2", "msg3")
}
def main():
    Log("msg1", "msg2", "msg3")
void main() {
    Log("msg1", "msg2", "msg3");
}

可以传多个msg参数:

function main() {
    Log("发明者量化你好 !@")
    Sleep(1000 * 5)
    // 字符串内加入#ff0000,打印日志显示为红色,并且推送消息
    Log("你好, #ff0000@")
}
def main():
    Log("发明者量化你好 !@")
    Sleep(1000 * 5)
    Log("你好, #ff0000@")
void main() {
    Log("发明者量化你好 !@");
    Sleep(1000 * 5);
    Log("你好, #ff0000@");
}

支持设置输出消息的颜色,如果设置颜色和推送同时使用,需要先设置颜色,最后使用@字符设置推送。

function main() {
    Log("`data:image/png;base64,AAAA`")
}
def main():
    Log("`data:image/png;base64,AAAA`")
void main() {
    Log("`data:image/png;base64,AAAA`");
}
```python
import matplotlib.pyplot as plt 
def main(): 
    plt.plot([3,6,2,4,7,1]) 
    Log(plt)
```javascript
function main() {
    Log("[trans]中文|abc[/trans]")
}
def main():
    Log("[trans]中文|abc[/trans]")
void main() {
    Log("[trans]中文|abc[/trans]");
}

```Log()```函数在实盘或者回测系统的日志区域输出一条日志信息,实盘运行时日志会保存在实盘的数据库中。 ```Log()```函数输出的内容以```@```字符结尾则这条日志会进入消息推送队列。 推送到当前发明者量化交易平台账号[推送设置](https://www.fmz.com/m/account)中配置的邮箱、WebHook地址等。 [调试工具](https://www.fmz.com/m/debug)、回测系统不支持消息推送。 消息推送有频率限制,具体限制规则如下:在一个实盘20秒周期内,只有最后一条推送消息会被保留并进行推送,其它消息将被过滤,不进行推送(通过 Log 函数输出的推送日志会正常打印显示在日志区域)。
关于```WebHook```推送,可以使用```Golang```编写的服务程序:

package main import ( “fmt” “net/http” )

func Handle (w http.ResponseWriter, r *http.Request) { defer func() { fmt.Println(“req:”, *r) }() }

func main () { fmt.Println(“listen http://localhost:9090”) http.HandleFunc(“/data”, Handle) http.ListenAndServe(“:9090”, nil) }


在[推送设置](https://www.fmz.com/m/account)中设置```WebHook```:```http://XXX.XX.XXX.XX:9090/data?data=Hello_FMZ```,
运行写好的```Golang```服务程序后,开始实盘运行策略,以下为```JavaScript```语言编写的策略,策略运行时执行```Log()```函数并推送消息:

```js
function main() {
    Log("msg", "@")
}

listen http://localhost:9090 req: {GET /data?data=Hello_FMZ HTTP/1.1 1 1 map[User-Agent:[Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/xx.x.xxxx.xxx Safari/537.36] Accept-Encoding:[gzip]] {} 0 [] false 1XX.XX.X.XX:9090 map[] map[] map[] XXX.XX.XXX.XX:4xxx2 /data?data=Hello_FMZ 0xc420056300



{@fun/Log/LogReset LogReset}, {@fun/Log/LogVacuum LogVacuum}

### LogProfit

记录盈亏值,打印盈亏数值并根据盈亏数值绘制收益曲线。

LogProfit(profit)
LogProfit(profit, ...args)

参数```profit```为收益数据,该数据由策略中设计算法、计算给出。
profit
true
number
扩展参数,可以输出附带信息到这条收益日志中,```arg```参数可以传多个。
arg
false
string、number、bool、object、array、空值等系统支持的任意类型

```javascript
function main() {
    // 在收益图表上打印30个点
    for(var i = 0; i < 30; i++) {
        LogProfit(i, '&')
        Sleep(500)
    }
}
def main():
    for i in range(30):
        LogProfit(i, '&')
        Sleep(500)
void main() {
    for(int i = 0; i < 30; i++) {
        LogProfit(i, '&');
        Sleep(500);
    }
}

{@fun/Log/LogProfitReset LogProfitReset}

### LogProfitReset

清空所有收益日志、收益图表。

LogProfitReset()
LogProfitReset(remain)

```remain```参数用于指定保留的日志条数(整数值)。
remain
false
number

```javascript
function main() {
    // 在收益图表上打印30个点,然后重置,只保留最后10个点
    for(var i = 0; i < 30; i++) {
        LogProfit(i)
        Sleep(500)
    }
    LogProfitReset(10)
}
def main():
    for i in range(30):
        LogProfit(i)
        Sleep(500)
    LogProfitReset(10)
void main() {
    for(int i = 0; i < 30; i++) {
        LogProfit(i);
        Sleep(500);
    }
    LogProfitReset(10);
}

{@fun/Log/LogProfit LogProfit}

LogStatus

在回测系统或者实盘页面状态栏输出信息。

LogStatus(…msgs)

参数msg为输出的内容,参数msg可以传多个。 msg false string、number、bool、object、array、空值等系统支持的任意类型

function main() {
    LogStatus('这是一个普通的状态提示')
    LogStatus('这是一个红色字体的状态提示#ff0000')
    LogStatus('这是一个多行的状态信息\n我是第二行')
}
def main():
    LogStatus('这是一个普通的状态提示')
    LogStatus('这是一个红色字体的状态提示#ff0000')
    LogStatus('这是一个多行的状态信息\n我是第二行')
void main() {
    LogStatus("这是一个普通的状态提示");
    LogStatus("这是一个红色字体的状态提示#ff0000");
    LogStatus("这是一个多行的状态信息\n我是第二行");
}

支持设置输出内容的颜色:

function main() {
    var table = {type: 'table', title: '持仓信息', cols: ['列1', '列2'], rows: [ ['abc', 'def'], ['ABC', 'support color #ff0000']]}
    // JSON序列化后两边加上`字符,视为一个复杂消息格式(当前支持表格)
    LogStatus('`' + JSON.stringify(table) + '`')                    
    // 表格信息也可以在多行中出现
    LogStatus('第一行消息\n`' + JSON.stringify(table) + '`\n第三行消息')
    // 支持多个表格同时显示,将以TAB显示到一组里
    LogStatus('`' + JSON.stringify([table, table]) + '`')
    
    // 也可以构造一个按钮在表格中,策略用GetCommand接收cmd属性的内容                                
    var table = { 
        type: 'table', 
        title: '持仓操作', 
        cols: ['列1', '列2', 'Action'], 
        rows: [ 
            ['abc', 'def', {'type':'button', 'cmd': 'coverAll', 'name': '平仓'}]
        ]
    }
    LogStatus('`' + JSON.stringify(table) + '`') 
    // 或者构造一单独的按钮
    LogStatus('`' + JSON.stringify({'type':'button', 'cmd': 'coverAll', 'name': '平仓'}) + '`') 
    // 可以自定义按钮风格(bootstrap的按钮属性)
    LogStatus('`' + JSON.stringify({'type':'button', 'class': 'btn btn-xs btn-danger', 'cmd': 'coverAll', 'name': '平仓'}) + '`')
}
import json
def main():
    table = {"type": "table", "title": "持仓信息", "cols": ["列1", "列2"], "rows": [["abc", "def"], ["ABC", "support color #ff0000"]]}
    LogStatus('`' + json.dumps(table) + '`')
    LogStatus('第一行消息\n`' + json.dumps(table) + '`\n第三行消息')
    LogStatus('`' + json.dumps([table, table]) + '`')            

    table = {
        "type" : "table", 
        "title" : "持仓操作", 
        "cols" : ["列1", "列2", "Action"], 
        "rows" : [
            ["abc", "def", {"type": "button", "cmd": "coverAll", "name": "平仓"}]
        ] 
    }
    LogStatus('`' + json.dumps(table) + '`')
    LogStatus('`' + json.dumps({"type": "button", "cmd": "coverAll", "name": "平仓"}) + '`')
    LogStatus('`' + json.dumps({"type": "button", "class": "btn btn-xs btn-danger", "cmd": "coverAll", "name": "平仓"}) + '`')
void main() {
    json table = R"({"type": "table", "title": "持仓信息", "cols": ["列1", "列2"], "rows": [["abc", "def"], ["ABC", "support color #ff0000"]]})"_json;
    LogStatus("`" + table.dump() + "`");
    LogStatus("第一行消息\n`" + table.dump() + "`\n第三行消息");
    json arr = R"([])"_json;
    arr.push_back(table);
    arr.push_back(table);
    LogStatus("`" + arr.dump() + "`");            

    table = R"({
        "type" : "table", 
        "title" : "持仓操作", 
        "cols" : ["列1", "列2", "Action"], 
        "rows" : [
            ["abc", "def", {"type": "button", "cmd": "coverAll", "name": "平仓"}]
        ] 
    })"_json;
    LogStatus("`" + table.dump() + "`");
    LogStatus("`" + R"({"type": "button", "cmd": "coverAll", "name": "平仓"})"_json.dump() + "`");
    LogStatus("`" + R"({"type": "button", "class": "btn btn-xs btn-danger", "cmd": "coverAll", "name": "平仓"})"_json.dump() + "`");
}

状态栏中数据输出示例:

function main() {
    var table = {
        type: "table",
        title: "状态栏按钮样式",
        cols: ["默认", "原始", "成功", "信息", "警告", "危险"], 
        rows: [
            [
                {"type":"button", "class": "btn btn-xs btn-default", "name": "默认"},
                {"type":"button", "class": "btn btn-xs btn-primary", "name": "原始"},
                {"type":"button", "class": "btn btn-xs btn-success", "name": "成功"},
                {"type":"button", "class": "btn btn-xs btn-info", "name": "信息"},
                {"type":"button", "class": "btn btn-xs btn-warning", "name": "告警"},
                {"type":"button", "class": "btn btn-xs btn-danger", "name": "危险"}
            ]
        ]
    }
    LogStatus("`" + JSON.stringify(table) + "`")
}
import json
def main():
    table = {
        "type": "table",
        "title": "状态栏按钮样式",
        "cols": ["默认", "原始", "成功", "信息", "警告", "危险"], 
        "rows": [
            [
                {"type":"button", "class": "btn btn-xs btn-default", "name": "默认"},
                {"type":"button", "class": "btn btn-xs btn-primary", "name": "原始"},
                {"type":"button", "class": "btn btn-xs btn-success", "name": "成功"},
                {"type":"button", "class": "btn btn-xs btn-info", "name": "信息"},
                {"type":"button", "class": "btn btn-xs btn-warning", "name": "告警"},
                {"type":"button", "class": "btn btn-xs btn-danger", "name": "危险"}
            ]
        ]
    }
    LogStatus("`" + json.dumps(table) + "`")
void main() {
    json table = R"({
        "type": "table",
        "title": "状态栏按钮样式",
        "cols": ["默认", "原始", "成功", "信息", "警告", "危险"], 
        "rows": [
            [
                {"type":"button", "class": "btn btn-xs btn-default", "name": "默认"},
                {"type":"button", "class": "btn btn-xs btn-primary", "name": "原始"},
                {"type":"button", "class": "btn btn-xs btn-success", "name": "成功"},
                {"type":"button", "class": "btn btn-xs btn-info", "name": "信息"},
                {"type":"button", "class": "btn btn-xs btn-warning", "name": "告警"},
                {"type":"button", "class": "btn btn-xs btn-danger", "name": "危险"}
            ]
        ]
    })"_json;
    LogStatus("`" + table.dump() + "`");
}

支持状态栏中设计按钮控件(旧版按钮结构):

function main() {
    var table = {
        type: "table",
        title: "状态栏按钮的禁用、描述功能测试",
        cols: ["列1", "列2", "列3"], 
        rows: []
    }
    var button1 = {"type": "button", "name": "按钮1", "cmd": "button1", "description": "这是第一个按钮"}
    var button2 = {"type": "button", "name": "按钮2", "cmd": "button2", "description": "这是第二个按钮,设置为禁用", "disabled": true}
    var button3 = {"type": "button", "name": "按钮3", "cmd": "button3", "description": "这是第三个按钮,设置为启用", "disabled": false}
    table.rows.push([button1, button2, button3])
    LogStatus("`" + JSON.stringify(table) + "`")
}
import json
def main():
    table = {
        "type": "table",
        "title": "状态栏按钮的禁用、描述功能测试",
        "cols": ["列1", "列2", "列3"], 
        "rows": []
    }
    button1 = {"type": "button", "name": "按钮1", "cmd": "button1", "description": "这是第一个按钮"}
    button2 = {"type": "button", "name": "按钮2", "cmd": "button2", "description": "这是第二个按钮,设置为禁用", "disabled": True}
    button3 = {"type": "button", "name": "按钮3", "cmd": "button3", "description": "这是第三个按钮,设置为启用", "disabled": False}
    table["rows"].append([button1, button2, button3])
    LogStatus("`" + json.dumps(table) + "`")
void main() {
    json table = R"({
        "type": "table",
        "title": "状态栏按钮的禁用、描述功能测试",
        "cols": ["列1", "列2", "列3"], 
        "rows": []
    })"_json;
    json button1 = R"({"type": "button", "name": "按钮1", "cmd": "button1", "description": "这是第一个按钮"})"_json;
    json button2 = R"({"type": "button", "name": "按钮2", "cmd": "button2", "description": "这是第二个按钮,设置为禁用", "disabled": true})"_json;
    json button3 = R"({"type": "button", "name": "按钮3", "cmd": "button3", "description": "这是第三个按钮,设置为启用", "disabled": false})"_json;
    json arr = R"([])"_json;
    arr.push_back(button1);
    arr.push_back(button2);
    arr.push_back(button3);
    table["rows"].push_back(arr);
    LogStatus("`" + table.dump() + "`");
}

设置状态栏按钮的禁用、描述功能(旧版按钮结构):

function test1() {
    Log("调用自定义函数")
}            

function main() {
    while (true) {
        var table = {
            type: 'table',
            title: '操作',
            cols: ['列1', '列2', 'Action'],
            rows: [
                ['a', '1', {
                    'type': 'button',                       
                    'cmd': "CoverAll",                      
                    'name': '平仓'                           
                }],
                ['b', '1', {
                    'type': 'button',
                    'cmd': 10,                              
                    'name': '发送数值'
                }],
                ['c', '1', {
                    'type': 'button',
                    'cmd': _D(),                          
                    'name': '调用函数'
                }],
                ['d', '1', {
                    'type': 'button',
                    'cmd': 'test1',       
                    'name': '调用自定义函数'
                }]
            ]
        }
        LogStatus(_D(), "\n", '`' + JSON.stringify(table) + '`')            

        var str_cmd = GetCommand()
        if (str_cmd) {
            Log("接收到的交互数据 str_cmd:", "类型:", typeof(str_cmd), "值:", str_cmd)
            if(str_cmd == "test1") {
                test1()
            }
        }            

        Sleep(500)
    }
}
import json
def test1():
    Log("调用自定义函数")            

def main():
    while True:
        table = {
            "type": "table", 
            "title": "操作", 
            "cols": ["列1", "列2", "Action"],
            "rows": [
                ["a", "1", {
                    "type": "button", 
                    "cmd": "CoverAll",
                    "name": "平仓"
                }],
                ["b", "1", {
                    "type": "button",
                    "cmd": 10,
                    "name": "发送数值" 
                }], 
                ["c", "1", {
                    "type": "button",
                    "cmd": _D(),
                    "name": "调用函数" 
                }],
                ["d", "1", {
                    "type": "button",
                    "cmd": "test1",
                    "name": "调用自定义函数" 
                }]
            ]
        }            

        LogStatus(_D(), "\n", "`" + json.dumps(table) + "`")
        str_cmd = GetCommand()
        if str_cmd:
            Log("接收到的交互数据 str_cmd", "类型:", type(str_cmd), "值:", str_cmd)
            if str_cmd == "test1":
                test1()
        Sleep(500)
void test1() {
    Log("调用自定义函数");
}            

void main() {
    while(true) {
        json table = R"({
            "type": "table", 
            "title": "操作", 
            "cols": ["列1", "列2", "Action"],
            "rows": [
                ["a", "1", {
                    "type": "button", 
                    "cmd": "CoverAll",
                    "name": "平仓"
                }],
                ["b", "1", {
                    "type": "button",
                    "cmd": 10,
                    "name": "发送数值" 
                }], 
                ["c", "1", {
                    "type": "button",
                    "cmd": "",
                    "name": "调用函数" 
                }],
                ["d", "1", {
                    "type": "button",
                    "cmd": "test1",
                    "name": "调用自定义函数" 
                }]
            ]
        })"_json;
        table["rows"][2][2]["cmd"] = _D();
        LogStatus(_D(), "\n", "`" + table.dump() + "`");
        auto str_cmd = GetCommand();
        if(str_cmd != "") {
            Log("接收到的交互数据 str_cmd", "类型:", typeid(str_cmd).name(), "值:", str_cmd);
            if(str_cmd == "test1") {
                test1();
            }
        }
        Sleep(500);
    }
}

结合GetCommand()函数,构造状态栏按钮交互功能(旧版按钮结构):

function main() {
    var tbl = {
        type: "table",
        title: "操作",
        cols: ["列1", "列2"],
        rows: [
            ["开仓操作", {"type": "button", "cmd": "open", "name": "开仓", "input": {"name": "开仓数量", "type": "number", "defValue": 1}}],
            ["平仓操作", {"type": "button", "cmd": "coverAll", "name": "全部平仓"}]
        ] 
    }            

    LogStatus(_D(), "\n", "`" + JSON.stringify(tbl) + "`")
    while (true) {
        var cmd = GetCommand()
        if (cmd) {
            Log("cmd:", cmd)
        }
        Sleep(1000)
    }
}
import json            

def main():
    tbl = {
        "type": "table", 
        "title": "操作", 
        "cols": ["列1", "列2"],
        "rows": [
            ["开仓操作", {"type": "button", "cmd": "open", "name": "开仓", "input": {"name": "开仓数量", "type": "number", "defValue": 1}}],
            ["平仓操作", {"type": "button", "cmd": "coverAll", "name": "全部平仓"}]
        ]
    }            

    LogStatus(_D(), "\n", "`" + json.dumps(tbl) + "`")
    while True:
        cmd = GetCommand()
        if cmd:
            Log("cmd:", cmd)
        Sleep(1000)
void main() {
    json tbl = R"({
        "type": "table", 
        "title": "操作", 
        "cols": ["列1", "列2"],
        "rows": [
            ["开仓操作", {"type": "button", "cmd": "open", "name": "开仓", "input": {"name": "开仓数量", "type": "number", "defValue": 1}}],
            ["平仓操作", {"type": "button", "cmd": "coverAll", "name": "全部平仓"}]
        ]
    })"_json;            

    LogStatus(_D(), "\n", "`" + tbl.dump() + "`");
    while(true) {
        auto cmd = GetCommand();
        if(cmd != "") {
            Log("cmd:", cmd);
        }
        Sleep(1000);
    }
}

在构造状态栏按钮进行交互时也支持输入数据,交互指令最终由GetCommand()函数捕获。 给状态栏中的按钮控件的数据结构中增加input项(旧版按钮结构),例如给{"type": "button", "cmd": "open", "name": "开仓"}增加: "input": {"name": "开仓数量", "type": "number", "defValue": 1}, 就可以使按钮在被点击时弹出一个带输入框控件的弹窗(输入框中默认值为1,即defValue设置的数据), 可以输入一个数据和按钮命令一起发送。例如以下测试代码运行时,在点击「开仓」按钮后,弹出一个带输入框的弹窗, 在输入框中输入111后点击「确定」。GetCommand()函数就会捕获消息:open:111

function main() {
    var tbl = {
        type: "table",
        title: "演示分组按钮控件",
        cols: ["操作"],
        rows: []
    }

    // 创建分组按钮控件结构
    var groupBtn = {
        type: "button",
        cmd: "open",
        name: "开仓",
        group: [
            {"name": "orderType", "description": "下单方式|order type", "type": "selected", "defValue": "市价单|挂单"},
            {"name": "tradePrice@orderType==1", "description": "交易价格|trade price", "type": "number", "defValue": 100},
            {"name": "orderAmount", "description": "委托数量|order amount", "type": "string", "defValue": 100},
            {"name": "boolean", "description": "是/否|boolean", "type": "boolean", "defValue": true}
        ]
    }

    // 测试按钮1
    var testBtn1 = {"type": "button", "name": "按钮1", "cmd": "button1", "description": "这是第一个按钮"}
    var testBtn2 = {"type": "button", "name": "按钮2", "cmd": "button2", "description": "这是第二个按钮", "input": {"name": "开仓数量", "type": "number", "defValue": 1}}

    // 在tbl中添加groupBtn
    tbl.rows.push([groupBtn])
    // 支持状态栏表格的一个单元格内设置多个按钮,即一个单元格内的数据为一个按钮结构数组:[testBtn1, testBtn2]
    tbl.rows.push([[testBtn1, testBtn2]])

    while (true) {
        LogStatus("`" + JSON.stringify(tbl) + "`", "\n", "分组按钮控件除了设置在状态栏表格中,也可以直接设置在状态栏上:", "`" + JSON.stringify(groupBtn) + "`")
        var cmd = GetCommand()
        if (cmd) {
            Log("cmd:", cmd)
        }
        Sleep(5000)
    }
}
import json

def main():
    tbl = {
        "type": "table",
        "title": "演示分组按钮控件",
        "cols": ["操作"],
        "rows": []
    }

    groupBtn = {
        "type": "button",
        "cmd": "open",
        "name": "开仓",
        "group": [
            {"name": "orderType", "description": "下单方式|order type", "type": "selected", "defValue": "市价单|挂单"},
            {"name": "tradePrice@orderType==1", "description": "交易价格|trade price", "type": "number", "defValue": 100},
            {"name": "orderAmount", "description": "委托数量|order amount", "type": "string", "defValue": 100},
            {"name": "boolean", "description": "是/否|boolean", "type": "boolean", "defValue": True}
        ]
    }

    testBtn1 = {"type": "button", "name": "按钮1", "cmd": "button1", "description": "这是第一个按钮"}
    testBtn2 = {"type": "button", "name": "按钮2", "cmd": "button2", "description": "这是第二个按钮", "input": {"name": "开仓数量", "type": "number", "defValue": 1}}

    tbl["rows"].append([groupBtn])
    tbl["rows"].append([[testBtn1, testBtn2]])

    while True:
        LogStatus("`" + json.dumps(tbl) + "`", "\n", "分组按钮控件除了设置在状态栏表格中,也可以直接设置在状态栏上:", "`" + json.dumps(groupBtn) + "`")
        cmd = GetCommand()
        if cmd:
            Log("cmd:", cmd)
        Sleep(5000)
void main() {
    json tbl = R"({
        "type": "table", 
        "title": "演示分组按钮控件", 
        "cols": ["操作"],
        "rows": []
    })"_json;

    json groupBtn = R"({
        "type": "button", 
        "name": "开仓", 
        "cmd": "open", 
        "group": [
            {"name": "orderType", "description": "下单方式|order type", "type": "selected", "defValue": "市价单|挂单"},
            {"name": "tradePrice@orderType==1", "description": "交易价格|trade price", "type": "number", "defValue": 100},
            {"name": "orderAmount", "description": "委托数量|order amount", "type": "string", "defValue": 100},
            {"name": "boolean", "description": "是/否|boolean", "type": "boolean", "defValue": true}
    ]})"_json;

    json testBtn1 = R"({"type": "button", "name": "按钮1", "cmd": "button1", "description": "这是第一个按钮"})"_json;
    json testBtn2 = R"({"type": "button", "name": "按钮2", "cmd": "button2", "description": "这是第二个按钮", "input": {"name": "开仓数量", "type": "number", "defValue": 1}})"_json;
    
    tbl["rows"].push_back({groupBtn});
    tbl["rows"].push_back({{testBtn1, testBtn2}});
    
    while(true) {
        LogStatus("`" + tbl.dump() + "`", "\n", "分组按钮控件除了设置在状态栏表格中,也可以直接设置在状态栏上:", "`" + groupBtn.dump() + "`");
        auto cmd = GetCommand();
        if(cmd != "") {
            Log("cmd:", cmd);
        }
        Sleep(5000);
    }
}

支持分组按钮控件(旧版按钮结构),功能与支持输入数据的状态栏按钮(使用”input”字段设置)一致。交互指令最终由GetCommand()函数捕获。区别在于使用"group"字段设置,当点击按钮触发交互时,页面弹出的对话框中有设置好的一组输入控件,可以一次性输入一组数据。 关于状态栏按钮控件和分组按钮控件结构中"group"字段,需要注意的几点: - group中type属性仅支持以下4种类型,defValue属性为默认值。 “selected”:下拉框控件,在设置下拉框中每个选项时使用|符号分隔。 “number”:数值输入框控件。 “string”:字符串输入框控件。 “boolean”:勾选框控件,勾选为(布尔值)真,不勾选为(布尔值)假。 - 交互输入时的控件支持依赖设置: 例如以下例子中的:"name": "tradePrice@orderType==1"设置,该设置使交易价格tradePrice)输入控件仅当下单方式(orderType)下拉框控件选择为挂单时可用。 - 交互输入时的控件名称支持双语设置 例如以下例子中的:”description”: “下单方式|order type”设置,使用|符号分隔中英文描述内容。 - group中的namedescription与按钮结构中的namedescription虽然字段名一致,但是定义并不相同。 group中的name与input中的name定义也不同。 - 分组按钮控件触发后,发送交互内容的格式为:按钮的cmd字段值、group字段相关数据,例如以下例子测试时Log("cmd:", cmd)语句输出的内容:

- 按钮控件的```type```属性仅支持:```"button"```。
  支持输入数据的按钮控件,即设置了```input```属性的控件,```input```字段的配置信息中的```type```属性支持多种控件类型。
参考以下例子:

```javascript
function main() {
    // 状态栏按钮控件(设置input字段实现)testBtn1按钮触发的页面中的下拉框控件使用options字段设置选项,使用defValue字段设置默认选项。区别于本章其它例子中直接使用defValue设置选项。
    var testBtn1 = {
        type: "button",
        name: "testBtn1",
        cmd: "cmdTestBtn1",
        input: {name: "testBtn1ComboBox", type: "selected", options: ["A", "B"], defValue: 1}
    }

    /* 
      状态栏按钮控件(设置input字段实现)testBtn2按钮触发的页面中的下拉框控件使用options字段设置选项,options字段中的选项不仅支持字符串,
      也支持使用```{text: "描述", value: "值"}```结构。使用defValue字段设置默认选项,默认选项可以是多选(通过数组结构实现多选)。多选需要设置额外的字段multiple为真值(true)。
    */
    var testBtn2 = {
        type: "button", 
        name: "testBtn2",
        cmd: "cmdTestBtn2",
        input: {
            name: "testBtn2MultiComboBox", 
            type: "selected", 
            description: "实现下拉框多选", 
            options: [{text: "选项A", value: "A"}, {text: "选项B", value: "B"}, {text: "选项C", value: "C"}],
            defValue: ["A", "C"],
            multiple: true
        }
    }

    // 状态栏分组按钮控件(设置group字段实现)testBtn3按钮触发的页面中的下拉框控件使用options字段设置选项,也支持直接使用defValue设置选项。
    var testBtn3 = {
        type: "button",                     
        name: "testBtn3",
        cmd: "cmdTestBtn3", 
        group: [
            {name: "comboBox1", label: "labelComboBox1", description: "下拉框1", type: "selected", defValue: 1, options: ["A", "B"]}, 
            {name: "comboBox2", label: "labelComboBox2", description: "下拉框2", type: "selected", defValue: "A|B"}, 
            {name: "comboBox3", label: "labelComboBox3", description: "下拉框3", type: "selected", defValue: [0, 2], multiple: true, options: ["A", "B", "C"]}, 
            {
                name: "comboBox4", 
                label: "labelComboBox4", 
                description: "下拉框4", 
                type: "selected", 
                defValue: ["A", "C"], 
                multiple: true, 
                options: [{text: "选项A", value: "A"}, {text: "选项B", value: "B"}, {text: "选项C", value: "C"}, {text: "选项D", value: "D"}]
            }
        ]
    }
    while (true) {
        LogStatus("`" + JSON.stringify(testBtn1) + "`\n", "`" + JSON.stringify(testBtn2) + "`\n", "`" + JSON.stringify(testBtn3) + "`\n")
        var cmd = GetCommand()
        if (cmd) {
            Log(cmd)
        }
        Sleep(5000)
    }
}
import json

def main():
    testBtn1 = {
        "type": "button",
        "name": "testBtn1",
        "cmd": "cmdTestBtn1",
        "input": {"name": "testBtn1ComboBox", "type": "selected", "options": ["A", "B"], "defValue": 1}
    }

    testBtn2 = {
        "type": "button", 
        "name": "testBtn2",
        "cmd": "cmdTestBtn2",
        "input": {
            "name": "testBtn2MultiComboBox", 
            "type": "selected", 
            "description": "实现下拉框多选", 
            "options": [{"text": "选项A", "value": "A"}, {"text": "选项B", "value": "B"}, {"text": "选项C", "value": "C"}],
            "defValue": ["A", "C"],
            "multiple": True
        }
    }

    testBtn3 = {
        "type": "button",                     
        "name": "testBtn3",
        "cmd": "cmdTestBtn3", 
        "group": [
            {"name": "comboBox1", "label": "labelComboBox1", "description": "下拉框1", "type": "selected", "defValue": 1, "options": ["A", "B"]}, 
            {"name": "comboBox2", "label": "labelComboBox2", "description": "下拉框2", "type": "selected", "defValue": "A|B"}, 
            {"name": "comboBox3", "label": "labelComboBox3", "description": "下拉框3", "type": "selected", "defValue": [0, 2], "multiple": True, "options": ["A", "B", "C"]}, 
            {
                "name": "comboBox4", 
                "label": "labelComboBox4", 
                "description": "下拉框4", 
                "type": "selected", 
                "defValue": ["A", "C"], 
                "multiple": True, 
                "options": [{"text": "选项A", "value": "A"}, {"text": "选项B", "value": "B"}, {"text": "选项C", "value": "C"}, {"text": "选项D", "value": "D"}]
            }
        ]
    }

    while True:
        LogStatus("`" + json.dumps(testBtn1) + "`\n", "`" + json.dumps(testBtn2) + "`\n", "`" + json.dumps(testBtn3) + "`\n")
        cmd = GetCommand()
        if cmd:
            Log(cmd)
        Sleep(5000)
void main() {
    json testBtn1 = R"({
        "type": "button",
        "name": "testBtn1",
        "cmd": "cmdTestBtn1",
        "input": {"name": "testBtn1ComboBox", "type": "selected", "options": ["A", "B"], "defValue": 1}
    })"_json;
    
    json testBtn2 = R"({
        "type": "button", 
        "name": "testBtn2",
        "cmd": "cmdTestBtn2",
        "input": {
            "name": "testBtn2MultiComboBox", 
            "type": "selected", 
            "description": "实现下拉框多选", 
            "options": [{"text": "选项A", "value": "A"}, {"text": "选项B", "value": "B"}, {"text": "选项C", "value": "C"}],
            "defValue": ["A", "C"],
            "multiple": true
        }
    })"_json;
    
    json testBtn3 = R"({
        "type": "button",                     
        "name": "testBtn3",
        "cmd": "cmdTestBtn3", 
        "group": [
            {"name": "comboBox1", "label": "labelComboBox1", "description": "下拉框1", "type": "selected", "defValue": 1, "options": ["A", "B"]}, 
            {"name": "comboBox2", "label": "labelComboBox2", "description": "下拉框2", "type": "selected", "defValue": "A|B"}, 
            {"name": "comboBox3", "label": "labelComboBox3", "description": "下拉框3", "type": "selected", "defValue": [0, 2], "multiple": true, "options": ["A", "B", "C"]}, 
            {
                "name": "comboBox4", 
                "label": "labelComboBox4", 
                "description": "下拉框4", 
                "type": "selected", 
                "defValue": ["A", "C"], 
                "multiple": true, 
                "options": [{"text": "选项A", "value": "A"}, {"text": "选项B", "value": "B"}, {"text": "选项C", "value": "C"}, {"text": "选项D", "value": "D"}]
            }
        ]
    })"_json;
    
    while (true) {
        LogStatus("`" + testBtn1.dump() + "`\n", "`" + testBtn2.dump() + "`\n", "`" + testBtn3.dump() + "`\n");
        auto cmd = GetCommand();
        if (cmd != "") {
            Log(cmd);
        }
        Sleep(5000);
    }
}

状态栏分组按钮控件(设置group字段实现)与状态栏按钮控件(设置input字段实现)被点击触发交互时(旧版按钮结构),页面弹出的对话框中的下拉框控件也支持多选,以下例子演示如何设计包含多选选项的下拉框控件:

var symbols = ["BTC_USDT.swap", "ETH_USDT.swap", "LTC_USDT.swap", "BNB_USDT.swap", "SOL_USDT.swap"]

function createBtn(tmp, group) {
    var btn = JSON.parse(JSON.stringify(tmp))

    _.each(group, function(eleByGroup) {
        btn["group"].unshift(eleByGroup)
    })

    return btn
}

function main() {
    var arrManager = []

    _.each(symbols, function(symbol) {
        arrManager.push({
            "symbol": symbol,
        })
    })

    // Btn
    var tmpBtnOpen = {
        "type": "button",
        "cmd": "open",
        "name": "开仓下单",
        "group": [{
            "type": "selected",
            "name": "tradeType",
            "label": "下单类型",
            "description": "市价单、限价单",
            "default": 0,
            "group": "交易设置",
            "settings": {
                "options": ["市价单", "限价单"],
                "required": true,
            }
        }, {
            "type": "selected",
            "name": "direction",
            "label": "交易方向",
            "description": "买入、卖出",
            "default": "buy",
            "group": "交易设置",
            "settings": {
                "render": "segment",
                "required": true,
                "options": [{"name": "买入", "value": "buy"}, {"name": "卖出", "value": "sell"}],
            }
        }, {
            "type": "number",
            "name": "price",
            "label": "价格",
            "description": "订单的价格",
            "group": "交易设置",
            "filter": "tradeType==1",
            "settings": {
                "required": true,
            }
        }, {
            "type": "number",
            "name": "amount",
            "label": "下单量",
            "description": "订单的下单量",
            "group": "交易设置",
            "settings": {
                "required": true,
            }
        }],
    }

    while (true) {
        var tbl = {"type": "table", "title": "dashboard", "cols": ["symbol", "actionOpen"], "rows": []}

        _.each(arrManager, function(m) {
            var btnOpen = createBtn(tmpBtnOpen, [{"type": "string", "name": "symbol", "label": "交易品种", "default": m["symbol"], "settings": {"required": true}}])
            tbl["rows"].push([m["symbol"], btnOpen])
        })

        var cmd = GetCommand()
        if (cmd) {
            Log("收到交互:", cmd)

            // 解析交互消息: open:{"symbol":"LTC_USDT.swap","tradeType":0,"direction":"buy","amount":111}
            // 根据第一个冒号:之前的指令判断是哪种按钮模板触发的消息
            var arrCmd = cmd.split(":", 2)
            if (arrCmd[0] == "open") {
                var msg = JSON.parse(cmd.slice(5))
                Log("交易品种:", msg["symbol"], ",交易方向:", msg["direction"], ",订单类型:", msg["tradeType"] == 0 ? "市价单" : "限价单", msg["tradeType"] == 0 ? ",订单价格:当前市价" : ",订单价格:" + msg["price"], ",订单数量:", msg["amount"])
            }
        }

        LogStatus(_D(), "\n", "`" + JSON.stringify(tbl) + "`")
        Sleep(1000)
    }
}
import json

symbols = ["BTC_USDT.swap", "ETH_USDT.swap", "LTC_USDT.swap", "BNB_USDT.swap", "SOL_USDT.swap"]

def createBtn(tmp, group):
    btn = json.loads(json.dumps(tmp))
    for eleByGroup in group:
        btn["group"].insert(0, eleByGroup)
    return btn

def main():
    arrManager = []

    for symbol in symbols:
        arrManager.append({"symbol": symbol})

    # Btn
    tmpBtnOpen = {
        "type": "button",
        "cmd": "open",
        "name": "开仓下单",
        "group": [{
            "type": "selected",
            "name": "tradeType",
            "label": "下单类型",
            "description": "市价单、限价单",
            "default": 0,
            "group": "交易设置",
            "settings": {
                "options": ["市价单", "限价单"],
                "required": True,
            }
        }, {
            "type": "selected",
            "name": "direction",
            "label": "交易方向",
            "description": "买入、卖出",
            "default": "buy",
            "group": "交易设置",
            "settings": {
                "render": "segment",
                "required": True,
                "options": [{"name": "买入", "value": "buy"}, {"name": "卖出", "value": "sell"}],
            }
        }, {
            "type": "number",
            "name": "price",
            "label": "价格",
            "description": "订单的价格",
            "group": "交易设置",
            "filter": "tradeType==1",
            "settings": {
                "required": True,
            }
        }, {
            "type": "number",
            "name": "amount",
            "label": "下单量",
            "description": "订单的下单量",
            "group": "交易设置",
            "settings": {
                "required": True,
            }
        }],
    }

    while True:
        tbl = {"type": "table", "title": "dashboard", "cols": ["symbol", "actionOpen"], "rows": []}
        for m in arrManager:
            btnOpen = createBtn(tmpBtnOpen, [{"type": "string", "name": "symbol", "label": "交易品种", "default": m["symbol"], "settings": {"required": True}}])
            tbl["rows"].append([m["symbol"], btnOpen])

        cmd = GetCommand()

        if cmd != "" and cmd != None:
            Log("收到交互:", cmd) 

            # 解析交互消息: open:{"symbol":"LTC_USDT.swap","tradeType":0,"direction":"buy","amount":111}
            # 根据第一个冒号:之前的指令判断是哪种按钮模板触发的消息
            arrCmd = cmd.split(":")
            if arrCmd[0] == "open":
                msg = json.loads(cmd[5:])
                Log("交易品种:", msg["symbol"], ",交易方向:", msg["direction"], ",订单类型:", "市价单" if msg["tradeType"] == 0 else "限价单", ",订单价格:当前市价" if msg["tradeType"] == 0 else ",订单价格:" + str(msg["price"]), ",订单数量:", msg["amount"])
        
        # 输出状态栏信息
        LogStatus(_D(), "\n", "`" + json.dumps(tbl) + "`")
        Sleep(1000)
// 略...

使用当前最新的按钮结构,构造状态栏表格中的按钮,点击按钮触发交互时弹出一个多控件弹窗。 详细内容可以参考:用户指南-状态栏中的交互控件

function main() {
    var table = { 
        type: 'table', 
        title: '持仓操作', 
        cols: ['列1', '列2', 'Action'], 
        rows: [ 
            ['abc', 'def', {'type':'button', 'cmd': 'coverAll', 'name': '平仓'}]
        ]
    } 
    var ticker = exchange.GetTicker()
    // 添加一行数据,第一个和第二个单元格合并,并且输出ticker变量在合并后的单元格内
    table.rows.push([{body : JSON.stringify(ticker), colspan : 2}, "abc"])    
    LogStatus('`' + JSON.stringify(table) + '`')
}
import json
def main():
    table = {
        "type" : "table",
        "title" : "持仓操作",
        "cols" : ["列1", "列2", "Action"],
        "rows" : [
            ["abc", "def", {"type": "button", "cmd": "coverAll", "name": "平仓"}]
        ]
    }
    ticker = exchange.GetTicker()
    table["rows"].append([{"body": json.dumps(ticker), "colspan": 2}, "abc"])
    LogStatus("`" + json.dumps(table) + "`")
void main() {
    json table = R"({
        "type" : "table",
        "title" : "持仓操作",
        "cols" : ["列1", "列2", "Action"],
        "rows" : [
            ["abc", "def", {"type": "button", "cmd": "coverAll", "name": "平仓"}]
        ]
    })"_json;            

    auto ticker = exchange.GetTicker();
    json jsonTicker = R"({"Buy": 0, "Sell": 0, "High": 0, "Low": 0, "Volume": 0, "Last": 0, "Time": 0})"_json;
    jsonTicker["Buy"] = ticker.Buy;
    jsonTicker["Sell"] = ticker.Sell;
    jsonTicker["Last"] = ticker.Last;
    jsonTicker["Volume"] = ticker.Volume;
    jsonTicker["Time"] = ticker.Time;
    jsonTicker["High"] = ticker.High;
    jsonTicker["Low"] = ticker.Low;            

    json arr = R"([{"body": {}, "colspan": 2}, "abc"])"_json;
    arr[0]["body"] = jsonTicker;
    table["rows"].push_back(arr);
    LogStatus("`" + table.dump() + "`");
}

横向合并LogStatus()函数画出的表格内的单元格:

function main() {
    var table = { 
        type: 'table', 
        title: '表格演示', 
        cols: ['列A', '列B', '列C'], 
        rows: [ 
            ['A1', 'B1', {'type':'button', 'cmd': 'coverAll', 'name': 'C1'}]
        ]
    }             

    var ticker = exchange.GetTicker()
    var name = exchange.GetName()            

    table.rows.push([{body : "A2 + B2:" + JSON.stringify(ticker), colspan : 2}, "C2"])
    table.rows.push([{body : "A3 + A4 + A5:" + name, rowspan : 3}, "B3", "C3"])
    // A3被上一行第一个单元格合并
    table.rows.push(["B4", "C4"])
    // A2被上一行第一个单元格合并
    table.rows.push(["B5", "C5"])                                            
    table.rows.push(["A6", "B6", "C6"])
    LogStatus('`' + JSON.stringify(table) + '`')
}
import json
def main():
    table = {
        "type" : "table", 
        "title" : "表格演示", 
        "cols" : ["列A", "列B", "列C"], 
        "rows" : [
            ["A1", "B1", {"type": "button", "cmd": "coverAll", "name": "C1"}]
        ]
    }
    
    ticker = exchange.GetTicker()
    name = exchange.GetName()
    
    table["rows"].append([{"body": "A2 + B2:" + json.dumps(ticker), "colspan": 2}, "C2"])
    table["rows"].append([{"body": "A3 + A4 + A5:" + name, "rowspan": 3}, "B3", "C3"])
    table["rows"].append(["B4", "C4"])
    table["rows"].append(["B5", "C5"])
    table["rows"].append(["A6", "B6", "C6"])
    LogStatus("`" + json.dumps(table) + "`")
void main() {
    json table = R"({
        "type" : "table", 
        "title" : "表格演示", 
        "cols" : ["列A", "列B", "列C"], 
        "rows" : [
            ["A1", "B1", {"type": "button", "cmd": "coverAll", "name": "C1"}]
        ]
    })"_json;
    // 为了测试,代码简短易读,这里使用构造的数据
    json jsonTicker = R"({"High": 0, "Low": 0, "Buy": 0, "Sell": 0, "Last": 0, "Time": 0, "Volume": 0})"_json;
    auto name = exchange.GetName();
    json arr1 = R"([{"body": "", "colspan": 2}, "C2"])"_json;
    arr1[0]["body"] = "A2 + B2:" + jsonTicker.dump();
    json arr2 = R"([{"body": "", "rowspan": 3}, "B3", "C3"])"_json;
    arr2[0]["body"] = "A3 + A4 + A5:" + name;
    table["rows"].push_back(arr1);
    table["rows"].push_back(arr2);
    table["rows"].push_back(R"(["B4", "C4"])"_json);
    table["rows"].push_back(R"(["B5", "C5"])"_json);
    table["rows"].push_back(R"(["A6", "B6", "C6"])"_json);
    LogStatus("`" + table.dump() + "`");
}

纵向合并LogStatus()函数画出的表格内的单元格:

function main() {
    var table1 = {type: 'table', title: 'table1', cols: ['列1', '列2'], rows: [ ['abc', 'def'], ['ABC', 'support color #ff0000']]}
    var table2 = {type: 'table', title: 'table2', cols: ['列1', '列2'], rows: [ ['abc', 'def'], ['ABC', 'support color #ff0000']]}
    LogStatus('`' + JSON.stringify([table1, table2]) + '`')
}
import json
def main():
    table1 = {"type": "table", "title": "table1", "cols": ["列1", "列2"], "rows": [ ["abc", "def"], ["ABC", "support color #ff0000"]]}
    table2 = {"type": "table", "title": "table2", "cols": ["列1", "列2"], "rows": [ ["abc", "def"], ["ABC", "support color #ff0000"]]}
    LogStatus("`" + json.dumps([table1, table2]) + "`")
void main() {
    json table1 = R"({"type": "table", "title": "table1", "cols": ["列1", "列2"], "rows": [ ["abc", "def"], ["ABC", "support color #ff0000"]]})"_json;
    json table2 = R"({"type": "table", "title": "table2", "cols": ["列1", "列2"], "rows": [ ["abc", "def"], ["ABC", "support color #ff0000"]]})"_json;
    json arr = R"([])"_json;
    arr.push_back(table1);
    arr.push_back(table2);
    LogStatus("`" + arr.dump() + "`");
}

状态栏表格分页显示:

function main(){
    var tab1 = {
        type : "table",
        title : "表格1",
        cols : ["1", "2"],
        rows : []
    }
    var tab2 = {
        type : "table",
        title : "表格2",
        cols : ["1", "2", "3"],
        rows : []
    }
    var tab3 = {
        type : "table",
        title : "表格3",
        cols : ["A", "B", "C"],
        rows : []
    }            

    tab1.rows.push(["jack", "lucy"])
    tab2.rows.push(["A", "B", "C"])
    tab3.rows.push(["A", "B", "C"])            

    LogStatus('`' + JSON.stringify(tab1) + '`\n' + 
        '`' + JSON.stringify(tab2) + '`\n' +
        '`' + JSON.stringify(tab3) + '`')
  
    Log("exit")
}
import json
def main():
    tab1 = {
        "type": "table", 
        "title": "表格1", 
        "cols": ["1", "2"], 
        "rows": []
    }
    tab2 = {
        "type": "table", 
        "title": "表格2", 
        "cols": ["1", "2", "3"], 
        "rows": []
    }
    tab3 = {
        "type": "table", 
        "title": "表格3", 
        "cols": ["A", "B", "C"], 
        "rows": []
    }            

    tab1["rows"].append(["jack", "lucy"])
    tab2["rows"].append(["A", "B", "C"])
    tab3["rows"].append(["A", "B", "C"])
    LogStatus("`" + json.dumps(tab1) + "`\n" + 
        "`" + json.dumps(tab2) + "`\n" + 
        "`" + json.dumps(tab3) + "`")
void main() {
    json tab1 = R"({
        "type": "table", 
        "title": "表格1", 
        "cols": ["1", "2"], 
        "rows": []
    })"_json;
    json tab2 = R"({
        "type": "table", 
        "title": "表格2", 
        "cols": ["1", "2", "3"], 
        "rows": []
    })"_json;
    json tab3 = R"({
        "type": "table", 
        "title": "表格3", 
        "cols": ["A", "B", "C"], 
        "rows": []
    })"_json;
    tab1["rows"].push_back(R"(["jack", "lucy"])"_json);
    tab2["rows"].push_back(R"(["A", "B", "C"])"_json);
    tab3["rows"].push_back(R"(["A", "B", "C"])"_json);
    LogStatus("`" + tab1.dump() + "`\n" + 
        "`" + tab2.dump() + "`\n" +
        "`" + tab3.dump() + "`");
}

除了可以分页显示表格,也可以多个表格自上而下排列显示:

function main() {
    var tbl = {
        type : "table",
        title : "test scroll",
        scroll : "auto",
        cols : ["col 0", "col 1", "col 2", "col 3", "col 4", "col 5", "col 6", "col 7", "col 8", "col 9", "col 10", 
            "col 11", "col 12", "col 13", "col 14", "col 15", "col 16", "col 17", "col 18", "col 19", "col 20"],
        rows : []
    }

    for (var i = 1 ; i < 100 ; i++) {
        tbl.rows.push([i, "1," + i, "2," + i, "3," + i, "4," + i, "5," + i, "6," + i, "7," + i, "8," + i, "9," + i, "10," + i, 
            "11," + i, "12," + i, "13," + i, "14," + i, "15," + i, "16," + i, "17," + i, "18," + i, "19," + i, "20," + i])
    }
    
    LogStatus("`" + JSON.stringify(tbl) + "`")
}
import json

def main():
    tbl = {
        "type" : "table",
        "title" : "test scroll",
        "scroll" : "auto",
        "cols" : ["col 0", "col 1", "col 2", "col 3", "col 4", "col 5", "col 6", "col 7", "col 8", "col 9", "col 10", 
            "col 11", "col 12", "col 13", "col 14", "col 15", "col 16", "col 17", "col 18", "col 19", "col 20"],
        "rows" : []
    }

    for index in range(1, 100):
        i = str(index)
        tbl["rows"].append([i, "1," + i, "2," + i, "3," + i, "4," + i, "5," + i, "6," + i, "7," + i, "8," + i, "9," + i, "10," + i, 
            "11," + i, "12," + i, "13," + i, "14," + i, "15," + i, "16," + i, "17," + i, "18," + i, "19," + i, "20," + i])
    
    LogStatus("`" + json.dumps(tbl) + "`")
void main() {
    json table = R"({
        "type" : "table",
        "title" : "test scroll",
        "scroll" : "auto",
        "cols" : ["col 0", "col 1", "col 2", "col 3", "col 4", "col 5", "col 6", "col 7", "col 8", "col 9", "col 10", 
            "col 11", "col 12", "col 13", "col 14", "col 15", "col 16", "col 17", "col 18", "col 19", "col 20"],
        "rows" : []
    })"_json;

    for (int index = 1; index < 100; ++index) {
        std::string i = std::to_string(index);
        table["rows"].push_back({i, "1," + i, "2," + i, "3," + i, "4," + i, "5," + i, "6," + i, "7," + i, "8," + i, "9," + i, "10," + i,
            "11," + i, "12," + i, "13," + i, "14," + i, "15," + i, "16," + i, "17," + i, "18," + i, "19," + i, "20," + i});
    }

    LogStatus("`" + table.dump() + "`");
}

支持设置状态栏表格横向、纵向滚动模式。设置scroll属性为"auto",当状态栏表格纵向的行数超过20行时内容进行滚动显示, 当横向的列数超出页面显示范围时进行横向滚动显示,使用scroll属性可以缓解实盘时状态栏中大量写入数据的卡顿问题。参考以下测试例子:

实盘运行时LogStatus()函数输出的信息不保存到实盘数据库,只更新当前实盘的状态栏内容。

```LogStatus()```函数支持直接传入```Python```的```matplotlib.pyplot```对象,只要对象包含```savefig```方法就可以作为参数传入```LogStatus()```函数,例如:

```python
import matplotlib.pyplot as plt 
def main():
    plt.plot([3,6,2,4,7,1])
    LogStatus(plt)             

策略实盘运行时,在实盘页面如果翻看历史记录,状态栏会进入休眠状态,停止更新。只有日志在第一页的时候状态栏数据才会刷新。 支持在状态栏输出base64编码后的图片,也支持在状态栏显示的表格中输出base64编码后的图片。 由于编码后的图片的字符串数据一般很长,所以不再展示范例代码。

{@fun/Global/GetCommand GetCommand}

EnableLog

打开或者关闭订单信息的日志记录。

EnableLog(enable)

enable
true
bool

```javascript
function main() {
    EnableLog(false)
}
def main():
    EnableLog(False)
void main() {
    EnableLog(false);
}

{@fun/Trade/exchange.Buy exchange.Buy}, {@fun/Trade/exchange.Sell exchange.Sell}, {@fun/Trade/exchange.CancelOrder exchange.CancelOrder}

Chart

自定义图表画图函数。

图表对象。 object

Chart(options)

options
true
object、object数组

```javascript
function main() {
    var cfgA = {
        extension: {
            layout: 'single', // 不参于分组,单独显示, 默认为分组 'group'
            height: 300, // 指定高度
        },
        title: {
            text: '盘口图表'
        },
        xAxis: {
            type: 'datetime'
        },
        series: [{
            name: '买一',
            data: [],
        }, {
            name: '卖一',
            data: [],
        }]
    }
    var cfgB = {
        title: {
            text: '差价图'
        },
        xAxis: {
            type: 'datetime'
        },
        series: [{
            name: '差价',
            type: 'column',
            data: [],
        }]
    }            

    var cfgC = {
        __isStock: false,
        title: {
            text: '饼图'
        },
        series: [{
            type: 'pie',
            name: 'one',
            data: [
                ["A", 25],
                ["B", 25],
                ["C", 25],
                ["D", 25],
            ]  // 指定初始数据后不需要用add函数更新, 直接更改图表配置就可以更新序列.
        }]
    };
    var cfgD = {
        extension: {
            layout: 'single',
            col: 8, // 指定宽度占的单元值, 总值 为12
            height: '300px',
        },
        title: {
            text: '盘口图表'
        },
        xAxis: {
            type: 'datetime'
        },
        series: [{
            name: '买一',
            data: [],
        }, {
            name: '卖一',
            data: [],
        }]
    }
    var cfgE = {
        __isStock: false,
        extension: {
            layout: 'single',
            col: 4,
            height: '300px',
        },
        title: {
            text: '饼图2'
        },
        series: [{
            type: 'pie',
            name: 'one',
            data: [
                ["A", 25],
                ["B", 25],
                ["C", 25],
                ["D", 25],
            ]
        }]
    };            

    var chart = Chart([cfgA, cfgB, cfgC, cfgD, cfgE]);
    chart.reset()
        // 为饼图清加一个数点,add只能更新通过add方式添加的数据点, 内置的数据点无法后期更新
    chart.add(3, {
        name: "ZZ",
        y: Math.random() * 100
    });
    while (true) {
        Sleep(1000)
        var ticker = exchange.GetTicker()
        if (!ticker) {
            continue;
        }
        var diff = ticker.Sell - ticker.Buy
        cfgA.subtitle = {
            text: '买一 ' + ticker.Buy + ', 卖一 ' + ticker.Sell,
        };
        cfgB.subtitle = {
            text: '价差 ' + diff,
        };            

        chart.add([0, [new Date().getTime(), ticker.Buy]]);
        chart.add([1, [new Date().getTime(), ticker.Sell]]);
        // 相当于更新第二个图表的第一个数据序列
        chart.add([2, [new Date().getTime(), diff]]);
        chart.add(4, [new Date().getTime(), ticker.Buy]);
        chart.add(5, [new Date().getTime(), ticker.Buy]);
        cfgC.series[0].data[0][1] = Math.random() * 100;
        cfgE.series[0].data[0][1] = Math.random() * 100;
        // update实际上等于重置了图表的配置
        chart.update([cfgA, cfgB, cfgC, cfgD, cfgE]);
    }
}            
import random
import time
def main():
    cfgA = {
        "extension" : {
            "layout" : "single", 
            "height" : 300,
            "col" : 8
        }, 
        "title" : {
            "text" : "盘口图表"
        },
        "xAxis" : {
            "type" : "datetime" 
        }, 
        "series" : [{
            "name" : "买一",
            "data" : []
        }, {
            "name" : "卖一", 
            "data" : []
        }]
    }                

    cfgB = {
        "title" : {
            "text" : "差价图"
        }, 
        "xAxis" : {
            "type" : "datetime",
        }, 
        "series" : [{
            "name" : "差价", 
            "type" : "column", 
            "data" : []
        }]
    }                

    cfgC = {
        "__isStock" : False,
        "title" : {
            "text" : "饼图"
        }, 
        "series" : [{
            "type" : "pie", 
            "name" : "one", 
            "data" : [
                ["A", 25],
                ["B", 25],
                ["C", 25],
                ["D", 25],
            ]
        }]
    }                

    cfgD = {
        "extension" : {
            "layout" : "single",
            "col" : 8,
            "height" : "300px"
        }, 
        "title" : {
            "text" : "盘口图表"
        }, 
        "series" : [{
            "name" : "买一", 
            "data" : []
        }, {
            "name" : "卖一",
            "data" : []
        }]
    }                

    cfgE = {
        "__isStock" : False, 
        "extension" : {
            "layout" : "single", 
            "col" : 4,
            "height" : "300px"
        }, 
        "title" : {
            "text" : "饼图2"
        },
        "series" : [{
            "type" : "pie",
            "name" : "one", 
            "data" : [
                ["A", 25], 
                ["B", 25], 
                ["C", 25], 
                ["D", 25]
            ]
        }]
    }
    
    chart = Chart([cfgA, cfgB, cfgC, cfgD, cfgE])
    chart.reset()
    chart.add(3, {
        "name" : "ZZ",
        "y" : random.random() * 100
    })
    
    while True:
        Sleep(1000)
        ticker = exchange.GetTicker()
        if not ticker :
            continue
        diff = ticker["Sell"] - ticker["Buy"]
        cfgA["subtitle"] = {
            "text" : "买一" + str(ticker["Buy"]) + "卖一" + str(ticker["Sell"])
        }
        cfgB["subtitle"] = {
            "text" : "价差 " + str(diff)
        }
        
        chart.add(0, [time.time() * 1000, ticker["Buy"]])
        chart.add(1, [time.time() * 1000, ticker["Sell"]])
        chart.add(2, [time.time() * 1000, diff])
        chart.add(4, [time.time() * 1000, ticker["Buy"]])
        chart.add(5, [time.time() * 1000, ticker["Buy"]])
        cfgC["series"][0]["data"][0][1] = random.random() * 100
        cfgE["series"][0]["data"][0][1] = random.random() * 100
void main() {
    json cfgA = R"({
        "extension" : {
            "layout" : "single", 
            "height" : 300,
            "col" : 8
        }, 
        "title" : {
            "text" : "盘口图表"
        },
        "xAxis" : {
            "type" : "datetime" 
        }, 
        "series" : [{
            "name" : "买一",
            "data" : []
        }, {
            "name" : "卖一", 
            "data" : []
        }]
    })"_json;                

    json cfgB = R"({
        "title" : {
            "text" : "差价图"
        }, 
        "xAxis" : {
            "type" : "datetime"
        }, 
        "series" : [{
            "name" : "差价", 
            "type" : "column", 
            "data" : []
        }]
    })"_json;    
    
    json cfgC = R"({
        "__isStock" : false,
        "title" : {
            "text" : "饼图"
        }, 
        "series" : [{
            "type" : "pie", 
            "name" : "one", 
            "data" : [
                ["A", 25],
                ["B", 25],
                ["C", 25],
                ["D", 25]
            ]
        }]
    })"_json;    
    
    json cfgD = R"({
        "extension" : {
            "layout" : "single",
            "col" : 8,
            "height" : "300px"
        }, 
        "title" : {
            "text" : "盘口图表"
        }, 
        "series" : [{
            "name" : "买一", 
            "data" : []
        }, {
            "name" : "卖一",
            "data" : []
        }]
    })"_json;    
    
    json cfgE = R"({
        "__isStock" : false, 
        "extension" : {
            "layout" : "single", 
            "col" : 4,
            "height" : "300px"
        }, 
        "title" : {
            "text" : "饼图2"
        },
        "series" : [{
            "type" : "pie",
            "name" : "one", 
            "data" : [
                ["A", 25], 
                ["B", 25], 
                ["C", 25], 
                ["D", 25]
            ]
        }]
    })"_json;            

    auto chart = Chart({cfgA, cfgB, cfgC, cfgD, cfgE});
    chart.reset();
    json zz = R"({
        "name" : "ZZ", 
        "y" : 0
    })"_json;
    zz["y"] = rand() % 100;
    chart.add(3, zz);
    
    while(true) {
        Sleep(1000);
        auto ticker = exchange.GetTicker();
        if(!ticker.Valid) {
            continue;
        }
        auto diff = ticker.Sell - ticker.Buy;
        json cfgASubTitle = R"({"text" : ""})"_json;
        cfgASubTitle["text"] = format("买一 %f , 卖一 %f", ticker.Buy, ticker.Sell);
        cfgA["subtitle"] = cfgASubTitle;
        
        json cfgBSubTitle = R"({"text" : ""})"_json;
        cfgBSubTitle["text"] = format("价差 %f", diff);
        cfgB["subtitle"] = cfgBSubTitle;            

        chart.add(0, {Unix() * 1000, ticker.Buy});
        chart.add(1, {Unix() * 1000, ticker.Sell});
        chart.add(2, {Unix() * 1000, diff});
        chart.add(4, {Unix() * 1000, ticker.Buy});
        chart.add(5, {Unix() * 1000, ticker.Buy});
        cfgC["series"][0]["data"][0][1] = rand() % 100;
        cfgE["series"][0]["data"][0][1] = rand() % 100;
        chart.update({cfgA, cfgB, cfgC, cfgD, cfgE});
    }
}

多图表画图配置: - extension.layout属性 如果设置此属性,值为”single”,则图表不会叠加(不会以分页标签方式显示),会单独显示(平铺显示)。 - extension.height属性 此属性用于设置图表的高度,值可以为数值类型,或以”300px”方式设置。 - extension.col属性 此属性用于设置图表的宽度,页面宽度一共划分为12个单元,设置8即该图表占用8个单元宽度。

// 这个chart在JavaScript语言中是对象,在使用Chart函数之前我们需要声明一个配置图表的对象变量chart
var chart = {                                           
    // 该字段标记图表是否为一般图表,有兴趣的可以改成false运行看看
    __isStock: true,                                    
    // 缩放工具
    tooltip: {xDateFormat: '%Y-%m-%d %H:%M:%S, %A'},    
    // 标题
    title : { text : '差价分析图'},                       
    // 选择范围
    rangeSelector: {                                    
        buttons:  [{type: 'hour',count: 1, text: '1h'}, {type: 'hour',count: 3, text: '3h'}, {type: 'hour', count: 8, text: '8h'}, {type: 'all',text: 'All'}],
        selected: 0,
        inputEnabled: false
    },
    // 坐标轴横轴即:x轴,当前设置的类型是:时间
    xAxis: { type: 'datetime'},                         
    // 坐标轴纵轴即:y轴,默认数值随数据大小调整
    yAxis : {                                           
        // 标题
        title: {text: '差价'},                           
        // 是否启用右边纵轴
        opposite: false                                 
    },
    // 数据系列,该属性保存的是各个数据系列(线,K线图,标签等...)
    series : [                                          
        // 索引为0,data数组内存放的是该索引系列的数据
        {name : "line1", id : "线1,buy1Price", data : []},                          
        // 索引为1,设置了dashStyle:'shortdash'即:设置虚线
        {name : "line2", id : "线2,lastPrice", dashStyle : 'shortdash', data : []}  
    ]
}
function main(){
    // 调用Chart函数,初始化图表
    var ObjChart = Chart(chart)         
    // 清空
    ObjChart.reset()                      
    while(true){
        // 获取本次轮询的时间戳,即一个毫秒的时间戳。用来确定写入到图表的X轴的位置
        var nowTime = new Date().getTime()
        // 获取行情数据
        var ticker = _C(exchange.GetTicker)
        // 从行情数据的返回值取得买一价
        var buy1Price = ticker.Buy    
        // 取得最后成交价,为了2条线不重合在一起,我们加1
        var lastPrice = ticker.Last + 1
        // 用时间戳作为X值,买一价作为Y值传入索引0的数据序列
        ObjChart.add(0, [nowTime, buy1Price])
        // 同上
        ObjChart.add(1, [nowTime, lastPrice])
        Sleep(2000)
    }
}
import time
chart = {
    "__isStock" : True,
    "tooltip" : {"xDateFormat" : "%Y-%m-%d %H:%M:%S, %A"},  
    "title" : {"text" : "差价分析图"}, 
    "rangeSelector" : {
        "buttons" : [{"type": "count", "count": 1, "text": "1h"}, {"type": "hour", "count": 3, "text": "3h"}, {"type": "hour", "count": 8, "text": "8h"}, {"type": "all", "text": "All"}], 
        "selected": 0,
        "inputEnabled": False 
    }, 
    "xAxis": {"type": "datetime"}, 
    "yAxis": {
        "title": {"text": "差价"},
        "opposite": False
    },
    "series": [{
        "name": "line1", "id": "线1,buy1Price", "data": []
    }, {
        "name": "line2", "id": "线2,lastPrice", "dashStyle": "shortdash", "data": []
    }]
}
def main():
    ObjChart = Chart(chart)
    ObjChart.reset()
    while True:
        nowTime = time.time() * 1000
        ticker = exchange.GetTicker()
        buy1Price = ticker["Buy"]
        lastPrice = ticker["Last"] + 1
        ObjChart.add(0, [nowTime, buy1Price])
        ObjChart.add(1, [nowTime, lastPrice])
        Sleep(2000)
void main() {
    // C++编写策略时,尽量不要声明非基础类型的全局变量,所以图表配置对象声明在main函数内
    json chart = R"({
        "__isStock" : true,
        "tooltip" : {"xDateFormat" : "%Y-%m-%d %H:%M:%S, %A"},  
        "title" : {"text" : "差价分析图"}, 
        "rangeSelector" : {
            "buttons" : [{"type": "count", "count": 1, "text": "1h"}, {"type": "hour", "count": 3, "text": "3h"}, {"type": "hour", "count": 8, "text": "8h"}, {"type": "all", "text": "All"}], 
            "selected": 0,
            "inputEnabled": false 
        }, 
        "xAxis": {"type": "datetime"}, 
        "yAxis": {
            "title": {"text": "差价"},
            "opposite": false
        },
        "series": [{
            "name": "line1", "id": "线1,buy1Price", "data": []
        }, {
            "name": "line2", "id": "线2,lastPrice", "dashStyle": "shortdash", "data": []
        }]
    })"_json;
    auto ObjChart = Chart(chart);
    ObjChart.reset();
    while(true) {
        auto nowTime = Unix() * 1000;
        auto ticker = exchange.GetTicker();
        auto buy1Price = ticker.Buy;
        auto lastPrice = ticker.Last + 1.0;
        ObjChart.add(0, {nowTime, buy1Price});
        ObjChart.add(1, {nowTime, lastPrice});
        Sleep(2000);
    }
}

简单的画图例子:

// 用于初始化图表的对象
var chart = {                                   
    // 图表标题
    title: {text: "line数值触发 plotLines 值"},   
    // Y轴相关设置
    yAxis: {                                    
        // 垂直于Y轴的水平线,用作触发线,是一个结构数组,可以设置多条触发线
        plotLines: [{                           
            // 触发线的值,设置多少这条线就在相应的数值位置显示
            value: 0,                           
            // 设置触发线的颜色
            color: 'red',                       
            // 宽度
            width: 2,                           
            // 显示的标签
            label: {                            
                // 标签文本
                text: '触发值',                  
                // 标签位置居中
                align: 'center'                 
            }
        }]
    },
    // X轴相关设置,这里设置类型是时间轴
    xAxis: {type: "datetime"},                  
    series: [
        {name: "sin", type: "spline", data: []},
        // 这个是比较重要的数据系列,可以设置多个数据系列,根据数组索引控制
        {name: "cos", type: "spline", data: []}
    ]  
}
function main(){
    // 圆周率
    var pi = 3.1415926535897
    // 用于记录时间戳的变量
    var time = 0                   
    // 角度
    var angle = 0                        
    // 坐标y值,用于接收正弦值、余弦值
    var y = 0          
    // 调用API接口用chart对象初始化图表
    var objChart = Chart(chart)        
    // 初始,清空图表
    objChart.reset()
    // 设置触发线的值为1
    chart.yAxis.plotLines[0].value = 1
    // 循环
    while(true){                          
        // 获取当前时刻的时间戳
        time = new Date().getTime() 
        // 每500ms角度angle增加5度,计算正弦值
        y = Math.sin(angle * 2 * pi / 360)
        // 把计算出来的y值写入图表相应索引的数据系列,add函数的第一个参数为指定的数据系列索引
        objChart.add(0, [time, y])
        // 计算余弦值
        y = Math.cos(angle * 2 * pi / 360)
        objChart.add(1, [time, y])
        // 增加5度
        angle += 5
        // 暂停5秒,以免画图太频繁,数据增长过快
        Sleep(5000)     
    }
}
import math
import time
chart = {
    "title": {"text": "line数值触发 plotLines 值"}, 
    "yAxis": {
        "plotLines": [{
            "value": 0,
            "color": "red",
            "width": 2,
            "label": {
                "text": "触发值", 
                "align": "center"
            }
        }]
    },
    "xAxis": {"type": "datetime"},
    "series": [{"name": "sin", "type": "spline", "data": []},
               {"name": "cos", "type": "spline", "data": []}]
}
def main():
    pi = 3.1415926535897
    ts = 0
    angle = 0
    y = 0
    objChart = Chart(chart)
    objChart.reset()
    chart["yAxis"]["plotLines"][0]["value"] = 1
    while True:
        ts = time.time() * 1000
        y = math.sin(angle * 2 * pi / 360)
        objChart.add(0, [ts, y])
        y = math.cos(angle * 2 * pi / 360)
        objChart.add(1, [ts, y])
        angle += 5
        Sleep(5000)
void main() {
    json chart = R"({
        "title": {"text": "line数值触发 plotLines 值"}, 
        "yAxis": {
            "plotLines": [{
                "value": 0,
                "color": "red",
                "width": 2,
                "label": {
                    "text": "触发值", 
                    "align": "center"
                }
            }]
        },
        "xAxis": {"type": "datetime"},
        "series": [{"name": "sin", "type": "spline", "data": []},
                   {"name": "cos", "type": "spline", "data": []}]     
    })"_json;            

    auto pi = 3.1415926535897;
    auto ts = 0;
    auto angle = 0.0;
    auto y = 0.0;
    auto objChart = Chart(chart);
    objChart.reset();
    chart["yAxis"]["plotLines"][0]["value"] = 1;
    while(true) {
        ts = Unix() * 1000;
        y = sin(angle * 2 * pi / 360);
        objChart.add(0, {ts, y});
        y = cos(angle * 2 * pi / 360);
        objChart.add(1, {ts, y});
        angle += 5;
        Sleep(5000);
    }
}

三角函数曲线画图例子:

/*backtest
start: 2020-03-11 00:00:00
end: 2020-04-09 23:59:00
period: 1d
exchanges: [{"eid":"Bitfinex","currency":"BTC_USD"}]
*/            

var chartCfg = {
    subtitle: {
        text: "subtitle",
    },
    yAxis: [{
        height: "40%",
        lineWidth: 2,
        title: {
            text: 'PnL',
        },
        tickPixelInterval: 20,
        minorGridLineWidth: 1,
        minorTickWidth: 0,
        opposite: true,
        labels: {
            align: "right",
            x: -3,
        }
    }, {
        title: {
            text: 'Profit',
        },
        top: "42%",
        height: "18%",
        offset: 0,
        lineWidth: 2
    }, {
        title: {
            text: 'Vol',
        },
        top: '62%',
        height: '18%',
        offset: 0,
        lineWidth: 2
    }, {
        title: {
            text: 'Asset',
        },
        top: '82%',
        height: '18%',
        offset: 0,
        lineWidth: 2
    }],
    series: [{
        name: 'PnL',
        data: [],
        id: 'primary',
        tooltip: {
            xDateFormat: '%Y-%m-%d %H:%M:%S'
        },
        yAxis: 0
    }, {
        type: 'column',
        lineWidth: 2,
        name: 'Profit',
        data: [],
        yAxis: 1,
    }, {
        type: 'column',
        name: 'Trade',
        data: [],
        yAxis: 2
    }, {
        type: 'area',
        step: true,
        lineWidth: 0,
        name: 'Long',
        data: [],
        yAxis: 2
    }, {
        type: 'area',
        step: true,
        lineWidth: 0,
        name: 'Short',
        data: [],
        yAxis: 2
    }, {
        type: 'line',
        step: true,
        color: '#5b4b00',
        name: 'Asset',
        data: [],
        yAxis: 3
    }, {
        type: 'pie',
        innerSize: '70%',
        name: 'Random',
        data: [],
        center: ['3%', '6%'],
        size: '15%',
        dataLabels: {
            enabled: false
        },
        startAngle: -90,
        endAngle: 90,
    }],
};            

function main() {
    let c = Chart(chartCfg);
    let preTicker = null;
    while (true) {
        let t = exchange.GetTicker();
        
        c.add(0, [t.Time, t.Last]); // PnL
        c.add(1, [t.Time, preTicker ? t.Last - preTicker.Last : 0]); // profit
        let r = Math.random();
        var pos = parseInt(t.Time/86400);
        c.add(2, [t.Time, pos/2]); // Vol
        c.add(3, [t.Time, r > 0.8 ? pos : null]); // Long
        c.add(4, [t.Time, r < 0.8 ? -pos : null]); // Short
        c.add(5, [t.Time, Math.random() * 100]); // Asset
        // update pie
        chartCfg.series[chartCfg.series.length-1].data = [
            ["A", Math.random()*100],
            ["B", Math.random()*100],
         ];
        c.update(chartCfg)
        preTicker = t;
    }
}
'''backtest
start: 2020-03-11 00:00:00
end: 2020-04-09 23:59:00
period: 1d
exchanges: [{"eid":"Bitfinex","currency":"BTC_USD"}]
'''            

import random            

chartCfg = {
    "subtitle": {
        "text": "subtitle"
    },
    "yAxis": [{
        "height": "40%",
        "lineWidth": 2,
        "title": {
            "text": 'PnL'
        },
        "tickPixelInterval": 20,
        "minorGridLineWidth": 1,
        "minorTickWidth": 0,
        "opposite": True,
        "labels": {
            "align": "right",
            "x": -3
        }
    }, {
        "title": {
            "text": 'Profit'
        },
        "top": "42%",
        "height": "18%",
        "offset": 0,
        "lineWidth": 2
    }, {
        "title": {
            "text": 'Vol'
        },
        "top": '62%',
        "height": '18%',
        "offset": 0,
        "lineWidth": 2
    }, {
        "title": {
            "text": 'Asset'
        },
        "top": '82%',
        "height": '18%',
        "offset": 0,
        "lineWidth": 2
    }],
    "series": [{
        "name": 'PnL',
        "data": [],
        "id": 'primary',
        "tooltip": {
            "xDateFormat": '%Y-%m-%d %H:%M:%S'
        },
        "yAxis": 0
    }, {
        "type": 'column',
        "lineWidth": 2,
        "name": 'Profit',
        "data": [],
        "yAxis": 1
    }, {
        "type": 'column',
        "name": 'Trade',
        "data": [],
        "yAxis": 2
    }, {
        "type": 'area',
        "step": True,
        "lineWidth": 0,
        "name": 'Long',
        "data": [],
        "yAxis": 2
    }, {
        "type": 'area',
        "step": True,
        "lineWidth": 0,
        "name": 'Short',
        "data": [],
        "yAxis": 2
    }, {
        "type": 'line',
        "step": True,
        "color": '#5b4b00',
        "name": 'Asset',
        "data": [],
        "yAxis": 3
    }, {
        "type": 'pie',
        "innerSize": '70%',
        "name": 'Random',
        "data": [],
        "center": ['3%', '6%'],
        "size": '15%',
        "dataLabels": {
            "enabled": False
        },
        "startAngle": -90,
        "endAngle": 90
    }]
}            

def main():
    c = Chart(chartCfg)
    preTicker = None
    while True:
        t = exchange.GetTicker()
        c.add(0, [t["Time"], t["Last"]])
        profit = t["Last"] - preTicker["Last"] if preTicker else 0
        c.add(1, [t["Time"], profit])
        r = random.random()
        pos = t["Time"] / 86400
        c.add(2, [t["Time"], pos / 2])
        long = pos if r > 0.8 else None
        c.add(3, [t["Time"], long])
        short = -pos if r < 0.8 else None
        c.add(4, [t["Time"], short])
        c.add(5, [t["Time"], random.random() * 100])            

        # update pie
        chartCfg["series"][len(chartCfg["series"]) - 1]["data"] = [
            ["A", random.random() * 100], 
            ["B", random.random() * 100]
        ]
        c.update(chartCfg)
        preTicker = t
/*backtest
start: 2020-03-11 00:00:00
end: 2020-04-09 23:59:00
period: 1d
exchanges: [{"eid":"Bitfinex","currency":"BTC_USD"}]
*/            

void main() {
    json chartCfg = R"({
        "subtitle": {
            "text": "subtitle"
        },
        "yAxis": [{
            "height": "40%",
            "lineWidth": 2,
            "title": {
                "text": "PnL"
            },
            "tickPixelInterval": 20,
            "minorGridLineWidth": 1,
            "minorTickWidth": 0,
            "opposite": true,
            "labels": {
                "align": "right",
                "x": -3
            }
        }, {
            "title": {
                "text": "Profit"
            },
            "top": "42%",
            "height": "18%",
            "offset": 0,
            "lineWidth": 2
        }, {
            "title": {
                "text": "Vol"
            },
            "top": "62%",
            "height": "18%",
            "offset": 0,
            "lineWidth": 2
        }, {
            "title": {
                "text": "Asset"
            },
            "top": "82%",
            "height": "18%",
            "offset": 0,
            "lineWidth": 2
        }],
        "series": [{
            "name": "PnL",
            "data": [],
            "id": "primary",
            "tooltip": {
                "xDateFormat": "%Y-%m-%d %H:%M:%S"
            },
            "yAxis": 0
        }, {
            "type": "column",
            "lineWidth": 2,
            "name": "Profit",
            "data": [],
            "yAxis": 1
        }, {
            "type": "column",
            "name": "Trade",
            "data": [],
            "yAxis": 2
        }, {
            "type": "area",
            "step": true,
            "lineWidth": 0,
            "name": "Long",
            "data": [],
            "yAxis": 2
        }, {
            "type": "area",
            "step": true,
            "lineWidth": 0,
            "name": "Short",
            "data": [],
            "yAxis": 2
        }, {
            "type": "line",
            "step": true,
            "color": "#5b4b00",
            "name": "Asset",
            "data": [],
            "yAxis": 3
        }, {
            "type": "pie",
            "innerSize": "70%",
            "name": "Random",
            "data": [],
            "center": ["3%", "6%"],
            "size": "15%",
            "dataLabels": {
                "enabled": false
            },
            "startAngle": -90,
            "endAngle": 90
        }]
    })"_json;
    
    Chart c = Chart(chartCfg);
    Ticker preTicker;
    while(true) {
        auto t = exchange.GetTicker();
        c.add(0, {t.Time, t.Last});
        auto profit = preTicker.Valid ? t.Last - preTicker.Last : 0;
        c.add(1, {t.Time, profit});    
        auto r = rand() % 100;
        auto pos = t.Time / 86400.0;
        c.add(2, {t.Time, pos / 2.0});
        auto longPos = r > 0.8 ? pos : NULL;
        c.add(3, {t.Time, longPos});
        auto shortPos = r < 0.8 ? -pos : NULL;
        c.add(4, {t.Time, shortPos});
        c.add(5, {t.Time, rand() % 100});
        
        // update pie 
        json pie = R"([["A", 0], ["B", 0]])"_json;
        pie[0][1] = rand() % 100;
        pie[1][1] = rand() % 100;
        chartCfg["series"][chartCfg["series"].size() - 1]["data"] = pie;
        
        c.update(chartCfg);
        preTicker = t;
    }
}            

使用混合图表的复杂例子:

// update pie
chartCfg.series[chartCfg.series.length-1].data = [
    ["A", Math.random()*100],
    ["B", Math.random()*100],
];
c.update(chartCfg)
# update pie
chartCfg["series"][len(chartCfg["series"]) - 1]["data"] = [
    ["A", random.random() * 100], 
    ["B", random.random() * 100]
]
c.update(chartCfg)
// update pie 
json pie = R"([["A", 0], ["B", 0]])"_json;
pie[0][1] = rand() % 100;
pie[1][1] = rand() % 100;
chartCfg["series"][chartCfg["series"].size() - 1]["data"] = pie;
c.update(chartCfg);

图表中pie类型的图是没有时间轴的图表,在更新数据时需要直接更新图表配置。 例如以上范例中的代码,更新数据后使用c.update(chartCfg)更新图表,如下所示:

- 1、```update()```方法:
  ```update()```方法可以更新图表配置信息,该方法的参数为Chart图表配置对象(JSON)。
- 2、```del()```方法:
  ```del()```方法可以根据传入的series参数,删除指定索引的数据系列。
- 3、```add()```方法:
  ```add()```方法可以向图表中写入数据,参数依次为:
  - ```series```:用于设置数据系列索引,是整数。
  - ```data```:用于设置写入的具体数据,是一个数组。
  - ```index```(可选):用于设置数据索引,是整数。指定修改数据的具体索引位置,支持使用负数表示,设置为```-1```指数据集的最后一个数据。
    例如画线时,修改线的最后一个点上的数据:```chart.add(0, [1574993606000, 13.5], -1)```,即更改图表```series[0].data```的倒数第一个点的数据。
    不设置```index```参数表示向当前数据系列(series)最后添加数据。

- 4、```reset()```方法:
  ```reset()```方法用于清空图表数据,```reset()```方法可以带一个参数```remain```用于指定保留数据的条数。不传参数```remain```表示清除全部数据。


{@fun/Log/KLineChart KLineChart}

### KLineChart

该函数用于使用类似```Pine```语言的画图方式进行策略运行时的自定义画图。

图表对象。 ```KLineChart()```函数返回的图表对象有多个方法,其中需要注意```begin()```和```close()```, 在K线数据上遍历执行画图操作,画图操作中必须以```begin()```函数调用作为起始,以```close()```函数调用作为结束。
object

KLineChart(options)

```options```参数为图表配置。
options
true
object、object数组

```javascript
function main() {
    // 调用KLineChart函数创建图表控制对象c
    let c = KLineChart({
        overlay: true
    })            

    // 使用现货交易所对象测试,获取K线数据。如果使用期货交易所对象测试,需要先设置合约
    let bars = exchange.GetRecords()
    if (!bars) {
        return
    }            
    
    // 在K线数据上遍历执行画图操作,画图操作中必须以```c.begin(bar)```函数调用作为起始,以```c.close()```函数调用作为结束。
    bars.forEach(function(bar, index) {
        c.begin(bar)
        c.barcolor(bar.Close > bar.Open ? 'rgba(255, 0, 0, 0.2)' : 'rgba(0, 0, 0, 0.2)')
        if (bar.Close > bar.Open) {
            c.bgcolor('rgba(0, 255, 0, 0.5)')
        }
        let h = c.plot(bar.High, 'high')
        let l = c.plot(bar.Low, 'low')            

        c.fill(h, l, {
            color: bar.Close > bar.Open ? 'rgba(255, 0, 0, 0.2)' : 'rgba(255, 0, 0, 0.2)'
        })
        c.hline(bar.High)
        c.plotarrow(bar.Close - bar.Open)
        c.plotshape(bar.Low, {
            style: 'diamond'
        })
        c.plotchar(bar.Close, {
            char: 'X'
        })
        c.plotcandle(bar.Open*0.9, bar.High*0.9, bar.Low*0.9, bar.Close*0.9)
        if (bar.Close > bar.Open) {
            // long/short/closelong/closeshort
            c.signal("long", bar.High, 1.5)
        } else if (bar.Close < bar.Open) {
            c.signal("closelong", bar.Low, 1.5)
        }
        c.close()
    })
}
def main():
    # 调用KLineChart函数创建图表控制对象c
    c = KLineChart({
        "overlay": True
    })            

    # 使用现货交易所对象测试,获取K线数据。如果使用期货交易所对象测试,需要先设置合约
    bars = exchange.GetRecords()
    if not bars:
        return            

    for bar in bars:
        c.begin(bar)
        c.barcolor('rgba(255, 0, 0, 0.2)' if bar.Close > bar.Open else 'rgba(0, 0, 0, 0.2)')
        if bar.Close > bar.Open:
            c.bgcolor('rgba(0, 255, 0, 0.5)')            

        h = c.plot(bar.High, 'high')
        l = c.plot(bar.Low, 'low')            

        c.fill(h, l, 'rgba(255, 0, 0, 0.2)' if bar.Close > bar.Open else 'rgba(255, 0, 0, 0.2)')
        c.hline(bar.High)
        c.plotarrow(bar.Close - bar.Open)        
        c.plotshape(bar.Low, style = 'diamond')
        c.plotchar(bar.Close, char = 'X')
        c.plotcandle(bar.Open*0.9, bar.High*0.9, bar.Low*0.9, bar.Close*0.9)
        if bar.Close > bar.Open:
            # long/short/closelong/closeshort
            c.signal("long", bar.High, 1.5)
        elif bar.Close < bar.Open:
            c.signal("closelong", bar.Low, 1.5)            

        c.close()
// 暂不支持

如果在策略自定义画图区域画图必须有图表控制对象,使用KLineChart()函数创建该对象。 KLineChart()函数的参数为一个图表配置结构,在参考代码中使用的图表结构很简单:{overlay: true}。 这个图表配置结构仅仅设置了画图内容在图表主图上输出,如果overlay设置为假值,例如:false,则图表上的内容都输出在副图上, 如果需要指定某个画图函数在主图上画出也可以在具体函数调用中指定参数overlay为真值,例如:true

c.barcolor(bar.Close > bar.Open ? 'rgba(255, 0, 0, 0.2)' : 'rgba(0, 0, 0, 0.2)')   // 使用本例中参考代码中的例子说明,不再赘述
c.barcolor('rgba(255, 0, 0, 0.2)' if bar.Close > bar.Open else 'rgba(0, 0, 0, 0.2)')
//  暂不支持

画图操作中支持的Pine语言的画图接口函数有:

> barcolor(color, offset, editable, show_last, title, display)
> display参数可选:"none", "all"

```javascript
c.bgcolor('rgba(0, 255, 0, 0.5)')
c.bgcolor('rgba(0, 255, 0, 0.5)')
// 暂不支持
> bgcolor(color, offset, editable, show_last, title, display, overlay)
> display参数可选:"none", "all"

```javascript
c.plot(bar.High, 'high')            
c.plot(bar.Open < bar.Close ? NaN : bar.Close, "Close", {style: "linebr"})  // 支持画不连续的数据线
h = c.plot(bar.High, 'high')
h = c.plot(None if bar.Open < bar.Close else bar.Close, "Close", style = "linebr")  # 支持画不连续的数据线
// 暂不支持
> plot(series, title, color, linewidth, style, trackprice, histbase, offset, join, editable, show_last, display)
> style参数可选:"stepline_diamond", "stepline", "cross", "areabr", "area", "circles", "columns", "histogram", "linebr", "line"
> display参数可选:"none", "all"

```javascript
let h = c.plot(bar.High, 'high')
let l = c.plot(bar.Low, 'low')

c.fill(h, l, {color: bar.Close > bar.Open ? 'rgba(255, 0, 0, 0.2)' : 'rgba(255, 0, 0, 0.2)'})
h = c.plot(bar.High, 'high')
l = c.plot(bar.Low, 'low')

c.fill(h, l, color = 'rgba(255, 0, 0, 0.2)' if bar.Close > bar.Open else 'rgba(255, 0, 0, 0.2)')
// 暂不支持
> fill(hline1, hline2, color, title, editable, fillgaps, display)
> display参数可选:"none", "all"

由于```JavaScript```语言不能根据函数形参名称指定传入参数,为了解决这个问题可以使用一个```{key: value}```结构指定传入某个形参名称的参数,
例如参考代码中使用```{color: bar.Close > bar.Open ? 'rgba(255, 0, 0, 0.2)' : 'rgba(255, 0, 0, 0.2)'}```指定```fill```函数的```color```参数。
如果需要连续指定多个形参名称的参数,可以使用```{key1: value1, key2: value2, key3: value3}```。
例如本例子中增加指定一个```title```参数:```{color: bar.Close > bar.Open ? 'rgba(255, 0, 0, 0.2)' : 'rgba(255, 0, 0, 0.2)', title: 'fill'}```。
对于颜色值可以使用```'rgba(255, 0, 0, 0.2)'```方式设置,也可以使用```'#FF0000'```方式设置。

```javascript
c.hline(bar.High)
c.hline(bar.High)
// 暂不支持
> hline(price, title, color, linestyle, linewidth, editable, display)
> linestyle参数可选:"dashed", "dotted", "solid"
> display参数可选:"none", "all"

```javascript
c.plotarrow(bar.Close - bar.Open)
c.plotarrow(bar.Close - bar.Open)
// 暂不支持
> plotarrow(series, title, colorup, colordown, offset, minheight, maxheight, editable, show_last, display)
> display参数可选:"none", "all"

```javascript
c.plotshape(bar.Low, {style: 'diamond'})
c.plotshape(bar.Low, style = 'diamond')
// 暂不支持
> plotshape(series, title, style, location, color, offset, text, textcolor, editable, size, show_last, display)
> style参数可选:"diamond", "square", "label_down", "label_up", "arrow_down", "arrow_up", "circle", "flag", "triangle_down", "triangle_up", "cross", "xcross"
> location参数可选:"abovebar", "belowbar", "top", "bottom", "absolute"
> size参数可选:"10px", "14px", "20px", "40px", "80px",对比Pine语言中的size.tiny、size.small、size.normal、size.large、size.huge
> size.auto即size.small。
> display参数可选:"none", "all"

```javascript
c.plotchar(bar.Close, {char: 'X'})
c.plotchar(bar.Close, char = 'X')
// 暂不支持
> plotchar(series, title, char, location, color, offset, text, textcolor, editable, size, show_last, display)
> location参数可选:"abovebar", "belowbar", "top", "bottom", "absolute"
> size参数可选:"10px", "14px", "20px", "40px", "80px",对比Pine语言中的size.tiny、size.small、size.normal、size.large、size.huge
> size.auto即size.small。
> display参数可选:"none", "all"

```javascript
c.plotcandle(bar.Open*0.9, bar.High*0.9, bar.Low*0.9, bar.Close*0.9)
c.plotcandle(bar.Open*0.9, bar.High*0.9, bar.Low*0.9, bar.Close*0.9)
// 暂不支持
> plotcandle(open, high, low, close, title, color, wickcolor, editable, show_last, bordercolor, display)
> display参数可选:"none", "all"

```javascript
c.signal("long", bar.High, 1.5)
c.signal("long", bar.High, 1.5)
// 暂不支持
> signal(direction, price, qty, id)
传入的参数"long"表示交易方向,可选"long"、"closelong"、"short"、"closeshort"。传入的参数```bar.High```为标记信号的Y轴位置。
传入的参数1.5表示信号的交易数量。可以传入第四个参数用来替换默认画出的文本内容,画出的信号标记默认文本为交易方向,例如:"closelong"。

```javascript
c.reset()
c.reset()
// 暂不支持
> reset(remain)
```reset()```方法可以带一个参数```remain```用于指定保留数据的条数。不传参数```remain```表示清除全部数据。


策略自定义画图只能使用```KLineChart()```函数的方式或者```Chart()```函数的方式中的一种。 ```KLineChart()```函数调用时用到的一些颜色、样式等设置,参看[使用KLineChart函数画图的专题文章](https://www.fmz.com/bbs-topic/9482)

{@fun/Log/Chart Chart}

### LogReset

清除日志。

LogReset(remain)

```remain```参数用于设置保留的最近日志条数。
remain
false
number

```javascript
function main() {
    // 保留最近10条日志,清除其余日志
    LogReset(10)     
}
def main():
    LogReset(10)
void main() {
    LogReset(10);
}

策略实盘每次启动的启动日志算一条,所以如果不传入参数并且策略起始时没有日志输出,就会完全不显示日志,等待托管者日志回传(并非异常情况)。

{@fun/Log Log}, {@fun/Log/LogVacuum LogVacuum}

LogVacuum

用于在调用LogReset()函数清除日志后,回收SQLite删除数据时占用的储存空间。

LogVacuum()

function main() {
    LogReset()
    LogVacuum()
}
def main():
    LogReset()
    LogVacuum()
void main() {
    LogReset()
    LogVacuum()
}

原因是SQLite删除数据时不回收占用的空间,需要执行VACUUM清理表,释放空间。 该函数调用时会发生文件移动操作,延迟较大,建议在合适的时间间隔调用。

{@fun/Log/LogReset LogReset}

console.log

用于在实盘页面中的「调试信息」栏中输出调试信息。举例实盘Id为123456console.log函数在实盘页面输出调试信息的同时在实盘所属托管者目录下/logs/storage/123456/创建一个扩展名为.log的日志文件并写入调试信息,文件名前缀为stdout_

console.log(…msgs)

参数msg为输出的内容,参数msg可以传多个。 msg false string、number、bool、object、array、空值等系统支持的任意类型

function main() {
    console.log("test console.log")
}
# 不支持
// 不支持
  • JavaScript语言支持该函数。
  • 仅实盘支持该函数,「调试工具」和「回测系统」均不支持。
  • 输出对象时会被转换为字符串[object Object],所以尽量输出可读的信息。

{@fun/Log/console.error console.error}

console.error

用于在实盘页面中的「调试信息」栏中错误输出。举例实盘Id为123456console.error函数在实盘页面错误输出的同时在实盘所属托管者目录下/logs/storage/123456/创建一个扩展名为.log的日志文件并写入错误输出,文件名前缀为stderr_

console.error(…msgs)

参数msg为输出的内容,参数msg可以传多个。 msg false string、number、bool、object、array、空值等系统支持的任意类型

function main() {
    console.error("test console.error")
}
# 不支持
// 不支持
  • JavaScript语言支持该函数。
  • 仅实盘支持该函数,「调试工具」和「回测系统」均不支持。
  • 输出对象时会被转换为字符串[object Object],所以尽量输出可读的信息。

{@fun/Log/console.log console.log}

Market

exchange.GetTicker

获取当前设置的交易对、合约代码对应的现货或者合约的{@struct/Ticker Ticker}结构,即行情数据。 GetTicker()函数是交易所对象{@var/EXCHANGE exchange}的成员函数,exchange对象的成员函数(方法)的用途只和exchange相关,文档之后不再赘述。

{@struct/Ticker Ticker}、空值

exchange.GetTicker()
exchange.GetTicker(symbol)

参数```symbol```用于指定请求的{@struct/Ticker Ticker}数据对应的具体交易对、合约代码。不传该参数时默认请求当前设置的交易对、合约代码的行情数据。
当调用```exchange.GetTicker(symbol)```函数时,```exchange```为现货交易所对象,如果需要请求获取计价币种为USDT,交易币种为BTC的行情数据。参数```symbol```为:```"BTC_USDT"```,格式为FMZ平台定义的交易对格式。
当调用```exchange.GetTicker(symbol)```函数时,```exchange```为期货交易所对象,如果需要请求获取的是BTC的U本位永续合约的行情数据。参数```symbol```为:```"BTC_USDT.swap"```,格式为FMZ平台定义的**交易对**与**合约代码**组合,再以字符"."间隔。
当调用```exchange.GetTicker(symbol)```函数时,```exchange```为期货交易所对象,如果需要请求获取的是BTC的U本位期权合约的行情数据。参数```symbol```为:```"BTC_USDT.BTC-240108-40000-C"```(以币安期权BTC-240108-40000-C为例),格式为FMZ平台定义的**交易对**与交易所定义的具体期权合约代码组合,再以字符"."间隔。

symbol
false
string

```javascript
function main(){
    // 如果是期货交易所对象,先设置合约代码,例如设置为永续合约
    // exchange.SetContractType("swap")

    var ticker = exchange.GetTicker()
    /*
        可能由于网络原因,访问不到交易所接口(即使托管者程序所在设备能打开交易所网站,但是API接口也可能访问不通)
        此时ticker为null,当访问ticker.High时,会导致错误,所以在测试该代码时,确保可以访问到交易所接口
    */
    Log("Symbol:", ticker.Symbol, "High:", ticker.High, "Low:", ticker.Low, "Sell:", ticker.Sell, "Buy:", ticker.Buy, "Last:", ticker.Last, "Open:", ticker.Open, "Volume:", ticker.Volume)
}
def main():
    ticker = exchange.GetTicker()
    Log("Symbol:", ticker["Symbol"], "High:", ticker["High"], "Low:", ticker["Low"], "Sell:", ticker["Sell"], "Buy:", ticker["Buy"], "Last:", ticker["Last"], "Open:", ticker["Open"], "Volume:", ticker["Volume"])
void main() {
    auto ticker = exchange.GetTicker();
    Log("Symbol:", ticker.Symbol, "High:", ticker.High, "Low:", ticker.Low, "Sell:", ticker.Sell, "Buy:", ticker.Buy, "Last:", ticker.Last, "Open:", ticker.Open, "Volume:", ticker.Volume);
}

对于期货交易所对象(即exchangeexchanges[0]),在调用行情函数前需要先使用exchange.SetContractType()函数设置合约代码,文档之后不再赘述。

function main() {
    var ticker = exchange.GetTicker("BTC_USDT")
    Log(ticker)
}
def main():
    ticker = exchange.GetTicker("BTC_USDT")
    Log(ticker)
void main() {
    auto ticker = exchange.GetTicker("BTC_USDT");
    Log(ticker);
}

使用symbol参数请求具体品种(现货品种)的行情数据。

回测系统中exchange.GetTicker()函数返回的Ticker数据, 其中HighLow为模拟值,取自当时盘口的卖一、买一。 实盘中exchange.GetTicker()函数返回的Ticker数据, 其中HighLow的值是根据封装的交易所Tick接口返回的数据来确定的,这些数据包括一定周期内(通常为24小时周期)的最高价和最低价。 不支持exchange.GetTicker()函数的交易所:

函数名 不支持的现货交易所 不支持的期货交易所
GetTicker Futures_Aevo

{@fun/Market/exchange.GetDepth exchange.GetDepth}, {@fun/Market/exchange.GetTrades exchange.GetTrades}, {@fun/Market/exchange.GetRecords exchange.GetRecords}, {@fun/Market/exchange.GetTickers exchange.GetTickers}

exchange.GetDepth

获取当前设置的交易对、合约代码对应的现货或者合约的{@struct/Depth Depth}结构,即订单薄数据。

{@struct/Depth Depth}、空值

exchange.GetDepth()
exchange.GetDepth(symbol)

参数```symbol```用于指定请求的{@struct/Depth Depth}数据对应的具体交易对、合约代码。不传该参数时默认请求当前设置的交易对、合约代码的订单薄数据。 当调用```exchange.GetDepth(symbol)```函数时,```exchange```为现货交易所对象,如果需要请求获取计价币种为USDT,交易币种为BTC的订单薄数据。参数```symbol```为:```"BTC_USDT"```,格式为FMZ平台定义的交易对格式。 当调用```exchange.GetDepth(symbol)```函数时,```exchange```为期货交易所对象,如果需要请求获取的是BTC的U本位永续合约的订单薄数据。参数```symbol```为:```"BTC_USDT.swap"```,格式为FMZ平台定义的**交易对**与**合约代码**组合,再以字符"."间隔。 当调用```exchange.GetDepth(symbol)```函数时,```exchange```为期货交易所对象,如果需要请求获取的是BTC的U本位期权合约的订单薄数据。参数```symbol```为:```"BTC_USDT.BTC-240108-40000-C"```(以币安期权BTC-240108-40000-C为例),格式为FMZ平台定义的**交易对**与交易所定义的具体期权合约代码组合,再以字符"."间隔。
symbol
false
string

```javascript
function main(){
    var depth = exchange.GetDepth()
    /*
        可能由于网络原因,访问不到交易所接口(即使托管者程序所在设备能打开交易所网站,但是API接口也可能访问不通)
        此时depth为null,当访问depth.Asks[1].Price时,会导致错误,所以在测试该代码时,确保可以访问到交易所接口
    */
    var price = depth.Asks[1].Price
    Log("卖二价为:", price)
}
def main():
    depth = exchange.GetDepth()
    price = depth["Asks"][1]["Price"]
    Log("卖二价为:", price)
void main() {
    auto depth = exchange.GetDepth();
    auto price = depth.Asks[1].Price;
    Log("卖二价为:", price);
}

测试exchange.GetDepth()函数:

function main() {
    // BTC的U本位永续合约
    var depth = exchange.GetDepth("BTC_USDT.swap")
    Log(depth)
}
def main():
    depth = exchange.GetDepth("BTC_USDT.swap")
    Log(depth)
void main() {
    auto depth = exchange.GetDepth("BTC_USDT.swap");
    Log(depth);
}

当配置的exchange对象为期货交易所对象时,使用symbol参数请求具体品种(期货品种)的订单薄数据。

回测系统中,使用模拟级 Tick回测时exchange.GetDepth()函数返回的数据各档位均为模拟值。 回测系统中,使用实盘级 Tick回测时exchange.GetDepth()函数返回的数据为秒级别深度快照。

{@fun/Market/exchange.GetTicker exchange.GetTicker}, {@fun/Market/exchange.GetTrades exchange.GetTrades}, {@fun/Market/exchange.GetRecords exchange.GetRecords}

exchange.GetTrades

获取当前设置的交易对、合约代码对应的现货或者合约的{@struct/Trade Trade}结构数组,即市场的成交数据。

{@struct/Trade Trade}数组、空值

exchange.GetTrades()
exchange.GetTrades(symbol)

参数```symbol```用于指定请求的{@struct/Trade Trade}数组数据对应的具体交易对、合约代码。不传该参数时默认请求当前设置的交易对、合约代码的最近成交记录数据。 当调用```exchange.GetTrades(symbol)```函数时,```exchange```为现货交易所对象,如果需要请求获取计价币种为USDT,交易币种为BTC的订单薄数据。参数```symbol```为:```"BTC_USDT"```,格式为FMZ平台定义的交易对格式。 当调用```exchange.GetTrades(symbol)```函数时,```exchange```为期货交易所对象,如果需要请求获取的是BTC的U本位永续合约的订单薄数据。参数```symbol```为:```"BTC_USDT.swap"```,格式为FMZ平台定义的**交易对**与**合约代码**组合,再以字符"."间隔。 当调用```exchange.GetTrades(symbol)```函数时,```exchange```为期货交易所对象,如果需要请求获取的是BTC的U本位期权合约的订单薄数据。参数```symbol```为:```"BTC_USDT.BTC-240108-40000-C"```(以币安期权BTC-240108-40000-C为例),格式为FMZ平台定义的**交易对**与交易所定义的具体期权合约代码组合,再以字符"."间隔。
symbol
false
string

```javascript
function main(){
    var trades = exchange.GetTrades()
    /*
        可能由于网络原因,访问不到交易所接口(即使托管者程序所在设备能打开交易所网站,但是API接口也可能访问不通)
        此时trades为null,当访问trades[0].Id时,会导致错误,所以在测试该代码时,确保可以访问到交易所接口
    */
    Log("id:", trades[0].Id, "time:", trades[0].Time, "Price:", trades[0].Price, "Amount:", trades[0].Amount, "type:", trades[0].Type)
}
def main():
    trades = exchange.GetTrades()
    Log("id:", trades[0]["Id"], "time:", trades[0]["Time"], "Price:", trades[0]["Price"], "Amount:", trades[0]["Amount"], "type:", trades[0]["Type"])
void main() {
    auto trades = exchange.GetTrades();
    Log("id:", trades[0].Id, "time:", trades[0].Time, "Price:", trades[0].Price, "Amount:", trades[0].Amount, "type:", trades[0].Type);
}

测试exchange.GetTrades()函数:

function main() {
    // BTC的U本位永续合约
    var trades = exchange.GetTrades("BTC_USDT.swap")
    Log(trades)
}
def main():
    trades = exchange.GetTrades("BTC_USDT.swap")
    Log(trades)
void main() {
    auto trades = exchange.GetTrades("BTC_USDT.swap");
    Log(trades);
}

当配置的exchange对象为期货交易所对象时,使用symbol参数请求具体品种(期货品种)的市场成交记录数据。

回测系统中,使用**模拟级 Tick**回测时```exchange.GetTrades()```函数返回空数组。 回测系统中,使用**实盘级 Tick**回测时```exchange.GetTrades()```函数返回的数据为订单流快照数据,即{@struct/Trade Trade}结构数组。
不支持```exchange.GetTrades()```函数的交易所:
| 函数名 | 不支持的现货交易所 | 不支持的期货交易所 |
| - | - | - |
| GetTrades | -- | Futures_BitMart / Futures_Bibox |


{@fun/Market/exchange.GetTicker exchange.GetTicker}, {@fun/Market/exchange.GetDepth exchange.GetDepth}, {@fun/Market/exchange.GetRecords exchange.GetRecords}

### exchange.GetRecords

获取当前设置的交易对、合约代码对应的现货或者合约的{@struct/Record Record}结构数组,即K线数据。

```exchange.GetRecords()```函数请求数据成功时返回{@struct/Record Record}结构数组,请求数据失败时返回空值。
{@struct/Record Record}数组、空值

exchange.GetRecords()
exchange.GetRecords(symbol)
exchange.GetRecords(symbol, period)
exchange.GetRecords(symbol, period, limit)
exchange.GetRecords(period)
exchange.GetRecords(period, limit)

参数```symbol```用于指定请求的{@struct/Record Record}数组数据对应的具体交易对、合约代码。不传该参数时默认请求当前设置的交易对、合约代码的K线数据。 当调用```exchange.GetRecords(symbol)```函数时,```exchange```为现货交易所对象,如果需要请求获取计价币种为USDT,交易币种为BTC的数据。参数```symbol```为:```"BTC_USDT"```,格式为FMZ平台定义的交易对格式。 当调用```exchange.GetRecords(symbol)```函数时,```exchange```为期货交易所对象,如果需要请求获取的是BTC的U本位永续合约的订单薄数据。参数```symbol```为:```"BTC_USDT.swap"```,格式为FMZ平台定义的**交易对**与**合约代码**组合,再以字符"."间隔。 当调用```exchange.GetRecords(symbol)```函数时,```exchange```为期货交易所对象,如果需要请求获取的是BTC的U本位期权合约的订单薄数据。参数```symbol```为:```"BTC_USDT.BTC-240108-40000-C"```(以币安期权BTC-240108-40000-C为例),格式为FMZ平台定义的**交易对**与交易所定义的具体期权合约代码组合,再以字符"."间隔。
symbol
false
string
参数```period```指定请求的K线数据的周期,例如:{@var/PERIOD/PERIOD_M1 PERIOD_M1},{@var/PERIOD/PERIOD_M5 PERIOD_M5},{@var/PERIOD/PERIOD_M15 PERIOD_M15}等;参数```period```的值除了可以传定义的标准周期,还可以传入整数数值,单位为秒。 不传该参数时默认请求的K线数据的周期为当前策略实盘/回测配置的默认K线周期。
period
false
number
参数```limit```用于指定请求的K线数据的长度,不传该参数时默认请求长度为交易所K线接口的单次最大请求K线柱数量;该参数可能会引起分页查询交易所K线数据,分页查询时该函数调用耗时会增加。
limit
false
number

```javascript
function main() {
    // 打印K线周期为120秒(2分钟)的K线数据
    Log(exchange.GetRecords(60 * 2))         
    // 打印K线周期为5分钟的K线数据
    Log(exchange.GetRecords(PERIOD_M5))      
}
def main():
    Log(exchange.GetRecords(60 * 2))
    Log(exchange.GetRecords(PERIOD_M5))
void main() {
    Log(exchange.GetRecords(60 * 2)[0]);
    Log(exchange.GetRecords(PERIOD_M5)[0]);
}

获取自定义周期的K线数据。

function main() {
    var records = exchange.GetRecords(PERIOD_H1)
    /*
        可能由于网络原因,访问不到交易所接口(即使托管者程序所在设备能打开交易所网站,但是API接口也可能访问不通)
        此时records为null,当访问records[0].Time时,会导致错误,所以在测试该代码时,确保可以访问到交易所接口
    */
    Log("第一根k线数据为,Time:", records[0].Time, "Open:", records[0].Open, "High:", records[0].High)
    Log("第二根k线数据为,Time:", records[1].Time ,"Close:", records[1].Close)
    Log("当前K线(最新)", records[records.length-1], "上一根K线", records[records.length-2])
}
def main():
    records = exchange.GetRecords(PERIOD_H1)
    Log("第一根k线数据为,Time:", records[0]["Time"], "Open:", records[0]["Open"], "High:", records[0]["High"])
    Log("第二根k线数据为,Time:", records[1]["Time"], "Close:", records[1]["Close"])
    Log("当前K线(最新)", records[-1], "上一根K线", records[-2])
void main() {
    auto records = exchange.GetRecords(PERIOD_H1);
    Log("第一根k线数据为,Time:", records[0].Time, "Open:", records[0].Open, "High:", records[0].High);
    Log("第二根k线数据为,Time:", records[1].Time, "Close:", records[1].Close);
    Log("当前K线(最新)", records[records.size() - 1], "上一根K线", records[records.size() - 2]);
}

输出K线柱数据:

function main() {
    var records = exchange.GetRecords("BTC_USDT.swap", 60, 100)
    Log(records)
}
def main():
    records = exchange.GetRecords("BTC_USDT.swap", 60, 100)
    Log(records)
void main() {
    auto records = exchange.GetRecords("BTC_USDT.swap", 60, 100);
    Log(records);
}

当配置的exchange对象为期货交易所对象时,使用symbolperiodlimit参数请求具体品种(期货品种)的K线数据。

默认K线周期在回测、实盘页面可以设置,如果在调用exchange.GetRecords()函数时指定了参数,获取的就是该参数周期对应的K线数据。 如果函数调用时没有指定参数,则按照回测、实盘参数上设置的K线周期返回对应的K线数据。 返回值为Record结构数组,返回的K线数据会随时间累积,累积K线柱数量的上限受到exchange.SetMaxBarLen()函数设置的影响, 没有设置时默认上限为5000个K线柱。当K线数据到达K线柱累积上限,之后会更新加入一根K线柱的同时删除一根最早时间的K线柱(如队列进出)。 部分交易所没有提供K线接口,则托管者实时收集市场成交记录数据(Trade结构数组)生成K线。 如果交易所的K线接口支持分页查询,当调用exchange.SetMaxBarLen()函数设置一个比较大的K线长度时,会进行多次API请求。 初始调用exchange.GetRecords()函数时,获取的K线柱数量在回测和实盘时有所不同: - 回测系统中会预先获取回测时间范围起始时刻前一定数量的K线柱(默认为5000个,回测系统的设置、数据量会影响最终返回的数量),作为初始K线数据。 - 实盘时具体获取的K线柱数量基于交易所K线接口可获取的最大数据量而定。

回测系统中模拟级别回测由于需要设置底层K线周期(回测系统模拟级别回测时,根据设置的底层K线周期使用对应的K线数据生成Tick数据), 需要注意在策略中获取的K线数据的周期不能小于底层K线周期。因为在模拟级别回测中,各个周期的K线数据在回测系统中都是通过底层K线周期对应的K线数据合成的。
```C++```语言中如果需要自己构造K线数据有以下代码范例:

#include void main() { Records r; r.Valid = true; for (auto i = 0; i < 10; i++) { Record ele; ele.Time = i * 100000; ele.High = i * 10000; ele.Low = i * 1000; ele.Close = i * 100; ele.Open = i * 10; ele.Volume = i * 1; r.push_back(ele); } // 输出显示:Records[10] Log®;
auto ma = TA.MA(r,10);
// 输出显示:[nan,nan,nan,nan,nan,nan,nan,nan,nan,450] Log(ma);
}


不支持```exchange.GetRecords()```函数的交易所:
| 函数名 | 不支持的现货交易所 | 不支持的期货交易所 |
| - | - | - |
| GetRecords | Zaif / Coincheck / BitFlyer | Futures_Aevo |


{@fun/Market/exchange.GetTicker exchange.GetTicker}, {@fun/Market/exchange.GetDepth exchange.GetDepth}, {@fun/Market/exchange.GetTrades exchange.GetTrades}, {@fun/Market/exchange.SetMaxBarLen exchange.SetMaxBarLen}

### exchange.GetPeriod

获取回测、实盘运行策略时在发明者量化交易平台网站页面上设置的K线周期,即调用```exchange.GetRecords()```函数不传参数时使用的默认K线周期。

K线周期秒数,整数数值,单位为秒。
number

exchange.GetPeriod()

```javascript
function main() {
    // 例如回测、实盘时发明者量化交易平台网站页面上设置的K线周期为1小时
    var period = exchange.GetPeriod()
    Log("K线周期:", period / (60 * 60), "小时")
}
def main():
    period = exchange.GetPeriod()
    Log("K线周期:", period / (60 * 60), "小时")
void main() {
    auto period = exchange.GetPeriod();
    Log("K线周期:", period / (60 * 60.0), "小时");
}

{@fun/Market/exchange.GetRecords exchange.GetRecords}

exchange.SetMaxBarLen

设置K线最大长度。

exchange.SetMaxBarLen(n)

参数n用于指定最大K线长度。 n true number

function main() {
    exchange.SetMaxBarLen(50)
    var records = exchange.GetRecords()
    Log(records.length, records)
}
def main():
    exchange.SetMaxBarLen(50)
    r = exchange.GetRecords()
    Log(len(r), r)
void main() {
    exchange.SetMaxBarLen(50);
    auto r = exchange.GetRecords();
    Log(r.size(), r[0]);
}
- 影响第一次调用时获取K线的线柱(Bar)数量。
- 影响K线线柱(Bar)上限数量。


{@fun/Market/exchange.GetRecords exchange.GetRecords}

### exchange.GetRawJSON

获取当前交易所对象({@var/EXCHANGE exchange}、{@var/EXCHANGE/exchanges exchanges})最近一次```rest```请求返回的原始内容。

```rest```请求的应答数据。
string

exchange.GetRawJSON()

```javascript
function main(){
    exchange.GetAccount(); 
    var obj = JSON.parse(exchange.GetRawJSON());
    Log(obj);
}
import json
def main():
    exchange.GetAccount()
    obj = json.loads(exchange.GetRawJSON())
    Log(obj)
void main() {
    auto obj = exchange.GetAccount();
    // C++ 不支持GetRawJSON函数
    Log(obj);
}

{@var/EXCHANGE exchange}

### exchange.GetRate

获取交易所对象当前设置的汇率。

交易所对象当前的汇率值。
number

exchange.GetRate()

```javascript
function main(){
    Log(exchange.GetTicker())
    // 设置汇率转换
    exchange.SetRate(7)
    Log(exchange.GetTicker())
    Log("当前汇率:", exchange.GetRate())
}
def main():
    Log(exchange.GetTicker())
    exchange.SetRate(7)
    Log(exchange.GetTicker())
    Log("当前汇率:", exchange.GetRate())
void main() {
    Log(exchange.GetTicker());
    exchange.SetRate(7);
    Log(exchange.GetTicker());
    Log("当前汇率:", exchange.GetRate());
}

如果没有调用exchange.SetRate()设置过转换汇率,exchange.GetRate()函数返回的默认汇率值为1, 即当前显示的计价货币(quoteCurrency)相关数据没有发生过汇率转换。 如果使用exchange.SetRate()设置过一个汇率值,例如exchange.SetRate(7), 那么通过exchange这个交易所对象获取的行情、深度、下单价格等所有价格信息,都会被乘以设置的汇率7来进行转换。 如果exchange对应的是以美元为计价货币的交易所,调用exchange.SetRate(7)后,实盘所有价格都会被乘7转换成接近CNY的价格。 此时使用exchange.GetRate()获取的汇率值就是7

{@fun/Trade/exchange.SetRate exchange.SetRate}

exchange.SetData


参数```value```JSON编码后的字符串长度。
number

exchange.SetData(key, value)

数据集合名称。
key
true
string
```exchange.SetData()```函数所要加载的数据,数据结构为数组。数据结构与```exchange.GetData()```函数请求外部数据时所要求的数据格式相同,即:```"schema": ["time", "data"]```。
value
true
array

```javascript
/*backtest
start: 2020-01-21 00:00:00
end: 2020-02-12 00:00:00
period: 1d
basePeriod: 1d
exchanges: [{"eid":"Bitfinex","currency":"BTC_USD"}]
*/
function main() {
    var data = [
        [1579536000000, "abc"],
        [1579622400000, 123],
        [1579708800000, {"price": 123}],
        [1579795200000, ["abc", 123, {"price": 123}]]
    ]
    exchange.SetData("test", data)
    while(true) {
        Log(exchange.GetData("test"))
        Sleep(1000)
    }
}
'''backtest
start: 2020-01-21 00:00:00
end: 2020-02-12 00:00:00
period: 1d
basePeriod: 1d
exchanges: [{"eid":"Bitfinex","currency":"BTC_USD"}]
'''              

def main():
    data = [
        [1579536000000, "abc"],
        [1579622400000, 123],
        [1579708800000, {"price": 123}],
        [1579795200000, ["abc", 123, {"price": 123}]]
    ]
    exchange.SetData("test", data)
    while True:
        Log(exchange.GetData("test"))
        Sleep(1000)
/*backtest
start: 2020-01-21 00:00:00
end: 2020-02-12 00:00:00
period: 1d
basePeriod: 1d
exchanges: [{"eid":"Bitfinex","currency":"BTC_USD"}]
*/              

void main() {
    json data = R"([
        [1579536000000, "abc"],
        [1579622400000, 123],
        [1579708800000, {"price": 123}],
        [1579795200000, ["abc", 123, {"price": 123}]]
    ])"_json;
    
    exchange.SetData("test", data);
    while(true) {
        Log(exchange.GetData("test"));
        Sleep(1000);
    }
}

要求参数value的数据格式如同以下例子中的data变量, 可以看到时间戳1579622400000对应的时间为2020-01-22 00:00:00,当策略程序运行在这个时间之后, 在下一条数据时间戳1579708800000即时间2020-01-23 00:00:00之前,调用exchange.GetData()函数获取数据。 获取的都是[1579622400000, 123]该条数据的内容,随着程序继续运行,时间变化,以此类推获取逐条数据。 以下例子中,当运行时(回测或者实盘),当前时刻到达或者超过1579795200000这个时间戳时,调用exchange.GetData()函数,返回值为:{"Time":1579795200000,"Data":["abc",123,{"price":123}]}"Time":1579795200000对应数据[1579795200000, ["abc", 123, {"price": 123}]]中的1579795200000"Data":["abc",123,{"price":123}]对应数据[1579795200000, ["abc", 123, {"price": 123}]]中的["abc", 123, {"price": 123}]

加载的数据可以是任何经济指标、行业数据、相关指数等,用于策略量化考核所有可量化的信息。

{@fun/Market/exchange.GetData exchange.GetData}

exchange.GetData


数据集合中的记录。
object

exchange.GetData(key)
exchange.GetData(key, timeout)

数据集合名称。
key
true
string
用于设置缓存超时,单位为毫秒。实盘时默认为一分钟缓存超时。
timeout
false
number

```javascript
/*backtest
start: 2020-01-21 00:00:00
end: 2020-02-12 00:00:00
period: 1d
basePeriod: 1d
exchanges: [{"eid":"Bitfinex","currency":"BTC_USD"}]
*/
function main() {
    exchange.SetData("test", [[1579536000000, _D(1579536000000)], [1579622400000, _D(1579622400000)], [1579708800000, _D(1579708800000)]])
    while(true) {
        Log(exchange.GetData("test"))
        Sleep(1000 * 60 * 60 * 24)
    }
}
'''backtest
start: 2020-01-21 00:00:00
end: 2020-02-12 00:00:00
period: 1d
basePeriod: 1d
exchanges: [{"eid":"Bitfinex","currency":"BTC_USD"}]
'''  
def main():
    exchange.SetData("test", [[1579536000000, _D(1579536000000/1000)], [1579622400000, _D(1579622400000/1000)], [1579708800000, _D(1579708800000/1000)]])
    while True:
        Log(exchange.GetData("test"))
        Sleep(1000 * 60 * 60 * 24)
/*backtest
start: 2020-01-21 00:00:00
end: 2020-02-12 00:00:00
period: 1d
basePeriod: 1d
exchanges: [{"eid":"Bitfinex","currency":"BTC_USD"}]
*/    
void main() {
    json arr = R"([[1579536000000, ""], [1579622400000, ""], [1579708800000, ""]])"_json;
    arr[0][1] = _D(1579536000000);
    arr[1][1] = _D(1579622400000);
    arr[2][1] = _D(1579708800000);
    exchange.SetData("test", arr);
    while(true) {
        Log(exchange.GetData("test"));
        Sleep(1000 * 60 * 60 * 24);
    }
}

获取直接写入的数据的调用方式。

/*backtest
start: 2020-01-21 00:00:00
end: 2020-02-12 00:00:00
period: 1d
basePeriod: 1d
exchanges: [{"eid":"Bitfinex","currency":"BTC_USD"}]
*/
function main() {
    while(true) {
        Log(exchange.GetData("http://xxx.xx.x.xx:9090/data"))
        Sleep(1000)
    }
}
'''backtest
start: 2020-01-21 00:00:00
end: 2020-02-12 00:00:00
period: 1d
basePeriod: 1d
exchanges: [{"eid":"Bitfinex","currency":"BTC_USD"}]
'''              

def main():
    while True:
        Log(exchange.GetData("http://xxx.xx.x.xx:9090/data"))
        Sleep(1000)
/*backtest
start: 2020-01-21 00:00:00
end: 2020-02-12 00:00:00
period: 1d
basePeriod: 1d
exchanges: [{"eid":"Bitfinex","currency":"BTC_USD"}]
*/              

void main() {
    while(true) {
        Log(exchange.GetData("http://xxx.xx.x.xx:9090/data"));
        Sleep(1000);
    }
}

支持通过外部链接请求数据,请求到的数据格式:

{
    "schema":["time","data"],
    "data":[
        [1579536000000, "abc"],
        [1579622400000, 123],
        [1579708800000, {"price": 123}],
        [1579795200000, ["abc", 123, {"price": 123}]]
    ]
}

其中schema为加载数据的主体中的每一条记录的数据格式,该格式固定为["time","data"]对应data属性中的逐条数据的格式。

测试用的服务程序,使用Go语言编写:

```golang
package main
import (
    "fmt"
    "net/http"
    "encoding/json"
)                

func Handle (w http.ResponseWriter, r *http.Request) {
    defer func() {
        fmt.Println("req:", *r)
        ret := map[string]interface{}{
            "schema": []string{"time","data"},
            "data": []interface{}{
                []interface{}{1579536000000, "abc"},
                []interface{}{1579622400000, 123},
                []interface{}{1579708800000, map[string]interface{}{"price":123}},
                []interface{}{1579795200000, []interface{}{"abc", 123, map[string]interface{}{"price":123}}},
            },
        }
        b, _ := json.Marshal(ret)
        w.Write(b)
    }()
}                

func main () {
    fmt.Println("listen http://localhost:9090")
    http.HandleFunc("/data", Handle)
    http.ListenAndServe(":9090", nil)
}

程序在接收到请求后的应答数据:

{
    "schema":["time","data"],
    "data":[
        [1579536000000, "abc"],
        [1579622400000, 123],
        [1579708800000, {"price": 123}],
        [1579795200000, ["abc", 123, {"price": 123}]]
    ]
}

测试策略代码:

function main() {
    Log(exchange.GetData("http://xxx.xx.x.xx:9090/data"))
    Log(exchange.GetData("https://www.fmz.com/upload/asset/32bf73a69fc12d36e76.json"))
}
def main():
    Log(exchange.GetData("http://xxx.xx.x.xx:9090/data"))
    Log(exchange.GetData("https://www.fmz.com/upload/asset/32bf73a69fc12d36e76.json"))
void main() {
    Log(exchange.GetData("http://xxx.xx.x.xx:9090/data"));
    Log(exchange.GetData("https://www.fmz.com/upload/asset/32bf73a69fc12d36e76.json"));
}

获取外部链接的数据的调用方式。

function main() {
    Log(exchange.GetData("https://www.datadata.com/api/v1/query/xxx/data"))   // 链接中xxx部分为查询的数据的编码,此处xxx为举例
}
def main():
    Log(exchange.GetData("https://www.datadata.com/api/v1/query/xxx/data"))
void main() {
    Log(exchange.GetData("https://www.datadata.com/api/v1/query/xxx/data"));
}

请求datadata平台上创建的查询数据,要求应答的数据格式为(必须有time、data字段在schema里描述):

{
    "data": [],
    "schema": ["time", "data"]
}

其中”data”字段为需要的数据内容,”data”字段中的数据需要与”schema”中约定的一致。当调用exchange.GetData()函数时,返回一个JSON对象,例如:{"Time":1579795200000, "Data":"..."}

回测时一次性获取数据,实盘时缓存一分钟的数据。 回测系统中,当使用访问接口请求数据的方式时,回测系统会自动给请求增加from(时间戳秒),to(时间戳秒), period(底层K线周期,时间戳毫秒)等参数,用于确定要获取数据的时间范围。

{@fun/Market/exchange.SetData exchange.SetData}

exchange.GetMarkets


包含{@struct/Market Market}结构体的字典。
object

exchange.GetMarkets()

```javascript
function main() {
    var markets = exchange.GetMarkets()
    var currency = exchange.GetCurrency()

    // 获取当前合约代码也可以用exchange.GetContractType()函数
    var ct = "swap"

    var key = currency + "." + ct
    Log(key, ":", markets[key])
}
def main():
    markets = exchange.GetMarkets()
    currency = exchange.GetCurrency()
    ct = "swap"

    key = currency + "." + ct
    Log(key, ":", markets[key])
void main() {
    auto markets = exchange.GetMarkets();
    auto currency = exchange.GetCurrency();

    auto ct = "swap";
    auto key = currency + "." + ct;
    Log(key, ":", markets[key]);
}

期货交易所对象的调用例子:

/*backtest
start: 2023-05-10 00:00:00
end: 2023-05-20 00:00:00
period: 1m
basePeriod: 1m
exchanges: [{"eid":"Futures_Binance","currency":"BTC_USDT"}]
*/

function main() {
    var arrSymbol = ["SOL_USDT.swap", "BTC_USDT.quarter", "ETH_USDT.swap", "ETH_USDT.quarter"]

    var tbl1 = {
        type: "table",
        title: "markets1",
        cols: ["key", "Symbol", "BaseAsset", "QuoteAsset", "TickSize", "AmountSize", "PricePrecision", "AmountPrecision", "MinQty", "MaxQty", "MinNotional", "MaxNotional", "CtVal"],
        rows: []
    }

    var markets1 = exchange.GetMarkets()
    for (var key in markets1) {
        var market = markets1[key]
        tbl1.rows.push([key, market.Symbol, market.BaseAsset, market.QuoteAsset, market.TickSize, market.AmountSize, market.PricePrecision, market.AmountPrecision, market.MinQty, market.MaxQty, market.MinNotional, market.MaxNotional, market.CtVal])
    }

    for (var symbol of arrSymbol) {
        exchange.GetTicker(symbol)
    }

    var tbl2 = {
        type: "table",
        title: "markets2",
        cols: ["key", "Symbol", "BaseAsset", "QuoteAsset", "TickSize", "AmountSize", "PricePrecision", "AmountPrecision", "MinQty", "MaxQty", "MinNotional", "MaxNotional", "CtVal"],
        rows: []
    }

    var markets2 = exchange.GetMarkets()
    for (var key in markets2) {
        var market = markets2[key]
        tbl2.rows.push([key, market.Symbol, market.BaseAsset, market.QuoteAsset, market.TickSize, market.AmountSize, market.PricePrecision, market.AmountPrecision, market.MinQty, market.MaxQty, market.MinNotional, market.MaxNotional, market.CtVal])
    }

    LogStatus("`" + JSON.stringify([tbl1, tbl2]) + "`")
}
'''backtest
start: 2023-05-10 00:00:00
end: 2023-05-20 00:00:00
period: 1m
basePeriod: 1m
exchanges: [{"eid":"Futures_Binance","currency":"BTC_USDT"}]
'''

import json

def main():
    arrSymbol = ["SOL_USDT.swap", "BTC_USDT.quarter", "ETH_USDT.swap", "ETH_USDT.quarter"]

    tbl1 = {
        "type": "table",
        "title": "markets1",
        "cols": ["key", "Symbol", "BaseAsset", "QuoteAsset", "TickSize", "AmountSize", "PricePrecision", "AmountPrecision", "MinQty", "MaxQty", "MinNotional", "MaxNotional", "CtVal"],
        "rows": []
    }

    markets1 = exchange.GetMarkets()
    for key in markets1:
        market = markets1[key]
        tbl1["rows"].append([key, market["Symbol"], market["BaseAsset"], market["QuoteAsset"], market["TickSize"], market["AmountSize"], market["PricePrecision"], market["AmountPrecision"], market["MinQty"], market["MaxQty"], market["MinNotional"], market["MaxNotional"], market["CtVal"]])

    for symbol in arrSymbol:
        exchange.GetTicker(symbol)

    tbl2 = {
        "type": "table",
        "title": "markets2",
        "cols": ["key", "Symbol", "BaseAsset", "QuoteAsset", "TickSize", "AmountSize", "PricePrecision", "AmountPrecision", "MinQty", "MaxQty", "MinNotional", "MaxNotional", "CtVal"],
        "rows": []
    }

    markets2 = exchange.GetMarkets()
    for key in markets2:
        market = markets2[key]
        tbl2["rows"].append([key, market["Symbol"], market["BaseAsset"], market["QuoteAsset"], market["TickSize"], market["AmountSize"], market["PricePrecision"], market["AmountPrecision"], market["MinQty"], market["MaxQty"], market["MinNotional"], market["MaxNotional"], market["CtVal"]])

    LogStatus("`" + json.dumps([tbl1, tbl2]) + "`")
/*backtest
start: 2023-05-10 00:00:00
end: 2023-05-20 00:00:00
period: 1m
basePeriod: 1m
exchanges: [{"eid":"Futures_Binance","currency":"BTC_USDT"}]
*/

void main() {
    auto arrSymbol = {"SOL_USDT.swap", "BTC_USDT.quarter", "ETH_USDT.swap", "ETH_USDT.quarter"};

    json tbl1 = R"({
        "type": "table",
        "title": "markets1",
        "cols": ["key", "Symbol", "BaseAsset", "QuoteAsset", "TickSize", "AmountSize", "PricePrecision", "AmountPrecision", "MinQty", "MaxQty", "MinNotional", "MaxNotional", "CtVal"],
        "rows": []
    })"_json;

    auto markets1 = exchange.GetMarkets();
    for (auto& [key, market] : markets1.items()) {
        json arrJson = {key, market["Symbol"], market["BaseAsset"], market["QuoteAsset"], market["TickSize"], market["AmountSize"], market["PricePrecision"], market["AmountPrecision"], market["MinQty"], market["MaxQty"], market["MinNotional"], market["MaxNotional"], market["CtVal"]};
        tbl1["rows"].push_back(arrJson);
    }

    for (const auto& symbol : arrSymbol) {
        exchange.GetTicker(symbol);
    }

    json tbl2 = R"({
        "type": "table",
        "title": "markets2",
        "cols": ["key", "Symbol", "BaseAsset", "QuoteAsset", "TickSize", "AmountSize", "PricePrecision", "AmountPrecision", "MinQty", "MaxQty", "MinNotional", "MaxNotional", "CtVal"],
        "rows": []
    })"_json;

    auto markets2 = exchange.GetMarkets();
    for (auto& [key, market] : markets2.items()) {
        json arrJson = {key, market["Symbol"], market["BaseAsset"], market["QuoteAsset"], market["TickSize"], market["AmountSize"], market["PricePrecision"], market["AmountPrecision"], market["MinQty"], market["MaxQty"], market["MinNotional"], market["MaxNotional"], market["CtVal"]};
        tbl2["rows"].push_back(arrJson);
    }

    json tbls = R"([])"_json;
    tbls.push_back(tbl1);
    tbls.push_back(tbl2);
    LogStatus("`" + tbls.dump() + "`");
}

使用期货交易所对象,在回测系统中调用exchange.GetMarkets()函数。调用任何行情函数之前,GetMarkets只返回当前默认交易对的market数据,调用行情函数之后会返回所有请求过的品种的market数据。可以参考以下测试例子:


```json
{
    "BTC_USDT" : {...},  // 键值为Market结构
    "LTC_USDT" : {...},  
    ...
}

对于期货合约交易所来说,因为一个品种可能有多个合约,例如:BTC_USDT交易对,有永续合约、季度合约等。exchange.GetMarkets()函数返回一个字典,键名为交易对与合约代码的组合,例如:

{
    "BTC_USDT.swap" : {...},     // 键值为Market结构
    "BTC_USDT.quarter" : {...}, 
    "LTC_USDT.swap" : {...},
    ...
}
  • exchange.GetMarkets()函数支持实盘、回测系统。
  • exchange.GetMarkets()函数仅返回交易所上线交易的品种市场信息。
  • exchange.GetMarkets()不支持期权合约。

不支持exchange.GetMarkets()函数的交易所:

函数名 不支持的现货交易所 不支持的期货交易所
GetMarkets Coincheck / Bithumb / BitFlyer

{@struct/Market Market}

exchange.GetTickers


```exchange.GetTickers()```函数请求数据成功时返回{@struct/Ticker Ticker}结构数组,请求数据失败时返回空值。
{@struct/Ticker Ticker}数组、空值

exchange.GetTickers()

```javascript
function main() {
    var tickers = exchange.GetTickers()
    if (tickers && tickers.length > 0) {
        Log("交易所中可交易品种个数:", tickers.length)
    }
}
def main():
    tickers = exchange.GetTickers()
    if tickers and len(tickers) > 0:
        Log("交易所中可交易品种个数:", len(tickers))
void main() {
    auto tickers = exchange.GetTickers();
    if (tickers.Valid && tickers.size() > 0) {
        Log("交易所中可交易品种个数:", tickers.size());
    }
}

调用exchange.GetTickers()函数,获取聚合行情数据。

/*backtest
start: 2024-05-21 00:00:00
end: 2024-09-05 00:00:00
period: 5m
basePeriod: 1m
exchanges: [{"eid":"Binance","currency":"BTC_USDT"}]
*/

function main() {
    var arrSymbol = ["ADA_USDT", "LTC_USDT", "ETH_USDT", "SOL_USDT"]
    
    // 请求其它交易对行情数据之前,调用GetTickers
    var tickers1 = exchange.GetTickers()
    var tbl1 = {type: "table", title: "tickers1", cols: ["Symbol", "High", "Open", "Low", "Last", "Buy", "Sell", "Time", "Volume"], rows: []}
    for (var ticker of tickers1) {
        tbl1.rows.push([ticker.Symbol, ticker.High, ticker.Open, ticker.Low, ticker.Last, ticker.Buy, ticker.Sell, ticker.Time, ticker.Volume])
    }
    
    // 请求其它交易对行情数据
    for (var symbol of arrSymbol) {
        exchange.GetTicker(symbol)
    }

    // 再次调用GetTickers
    var tickers2 = exchange.GetTickers()
    var tbl2 = {type: "table", title: "tickers2", cols: ["Symbol", "High", "Open", "Low", "Last", "Buy", "Sell", "Time", "Volume"], rows: []}
    for (var ticker of tickers2) {
        tbl2.rows.push([ticker.Symbol, ticker.High, ticker.Open, ticker.Low, ticker.Last, ticker.Buy, ticker.Sell, ticker.Time, ticker.Volume])
    }

    LogStatus("`" + JSON.stringify([tbl1, tbl2]) +  "`")
}
'''backtest
start: 2024-05-21 00:00:00
end: 2024-09-05 00:00:00
period: 5m
basePeriod: 1m
exchanges: [{"eid":"Binance","currency":"BTC_USDT"}]
'''

import json

def main():
    arrSymbol = ["ADA_USDT", "LTC_USDT", "ETH_USDT", "SOL_USDT"]
        
    tickers1 = exchange.GetTickers()
    tbl1 = {"type": "table", "title": "tickers1", "cols": ["Symbol", "High", "Open", "Low", "Last", "Buy", "Sell", "Time", "Volume"], "rows": []}
    for ticker in tickers1:
        tbl1["rows"].append([ticker["Symbol"], ticker["High"], ticker["Open"], ticker["Low"], ticker["Last"], ticker["Buy"], ticker["Sell"], ticker["Time"], ticker["Volume"]])
    
    for symbol in arrSymbol:
        exchange.GetTicker(symbol)
    
    tickers2 = exchange.GetTickers()
    tbl2 = {"type": "table", "title": "tickers2", "cols": ["Symbol", "High", "Open", "Low", "Last", "Buy", "Sell", "Time", "Volume"], "rows": []}
    for ticker in tickers2:
        tbl2["rows"].append([ticker["Symbol"], ticker["High"], ticker["Open"], ticker["Low"], ticker["Last"], ticker["Buy"], ticker["Sell"], ticker["Time"], ticker["Volume"]])
    
    LogStatus("`" + json.dumps([tbl1, tbl2]) +  "`")
/*backtest
start: 2024-05-21 00:00:00
end: 2024-09-05 00:00:00
period: 5m
basePeriod: 1m
exchanges: [{"eid":"Binance","currency":"BTC_USDT"}]
*/

json tickerToJson(const Ticker& ticker) {
    json arrJson;

    arrJson.push_back(ticker.Symbol);
    arrJson.push_back(ticker.High);
    arrJson.push_back(ticker.Open);
    arrJson.push_back(ticker.Low);
    arrJson.push_back(ticker.Last);
    arrJson.push_back(ticker.Buy);
    arrJson.push_back(ticker.Sell);
    arrJson.push_back(ticker.Time);
    arrJson.push_back(ticker.Volume);

    return arrJson;
}

void main() {
    std::string arrSymbol[] = {"ADA_USDT", "LTC_USDT", "ETH_USDT", "SOL_USDT"};
    
    auto tickers1 = exchange.GetTickers();
    json tbl1 = R"({
        "type": "table", 
        "cols": ["Symbol", "High", "Open", "Low", "Last", "Buy", "Sell", "Time", "Volume"],
        "rows": []
    })"_json;
    tbl1["title"] = "tickers1";
    
    for (const auto& ticker : tickers1) {
        json arrJson = tickerToJson(ticker);
        tbl1["rows"].push_back(arrJson);
    }
    
    for (const std::string& symbol : arrSymbol) {
        exchange.GetTicker(symbol);
    }
    
    auto tickers2 = exchange.GetTickers();
    json tbl2 = R"({
        "type": "table", 
        "cols": ["Symbol", "High", "Open", "Low", "Last", "Buy", "Sell", "Time", "Volume"],
        "rows": []
    })"_json;
    tbl2["title"] = "tickers2";
    
    for (const auto& ticker : tickers2) {
        json arrJson = tickerToJson(ticker);
        tbl2["rows"].push_back(arrJson);
    }
    
    json tbls = R"([])"_json;
    tbls.push_back(tbl1);
    tbls.push_back(tbl2);
    LogStatus("`" + tbls.dump() + "`");
}

使用现货交易所对象,回测系统中调用exchange.GetTickers()函数。调用任何行情函数之前,GetTickers只返回当前默认交易对的ticker数据,调用行情函数之后会返回所有请求过的品种的ticker数据。可以参考以下测试例子:

  • 该函数请求交易所聚合行情接口,调用之前无需设置交易对、合约代码。仅返回交易所上线交易品种的行情数据。
  • 回测系统支持该函数。
  • 未提供聚合行情接口的交易所对象,不支持该函数。
  • 该函数不支持期权合约。

不支持exchange.GetTickers()函数的交易所:

函数名 不支持的现货交易所 不支持的期货交易所
GetTickers Zaif / WOO / Gemini / Coincheck / BitFlyer / Bibox Futures_WOO / Futures_dYdX / Futures_Deribit / Futures_Bibox / Futures_Aevo

{@struct/Ticker Ticker}, {@fun/Market/exchange.GetTicker exchange.GetTicker}

Trade

exchange.Buy


下单成功返回订单Id,下单失败返回空值。
FMZ平台的订单{@struct/Order Order}结构的属性```Id```由交易所品种代码和交易所原始订单Id组成,以英文逗号间隔。例如OKX交易所的现货交易对```ETH_USDT```订单的属性```Id```格式为:```ETH-USDT,1547130415509278720```。
调用```exchange.Buy()```函数下单时,返回值订单```Id```与订单{@struct/Order Order}结构的```Id```属性一致。

string、空值

exchange.Buy(price, amount)
exchange.Buy(price, amount, ...args)

```price```参数用于设置订单价格。
price
true
number
```amount```参数用于设置订单量。
amount
true
number
扩展参数,可以输出附带信息到这条下单日志中,```arg```参数可以传多个。
arg
false
string、number、bool、object、array、空值等系统支持的任意类型

```javascript
function main() {
    var id = exchange.Buy(100, 1);
    Log("id:", id);
}
def main():
    id = exchange.Buy(100, 1)
    Log("id:", id)
void main() {
    auto id = exchange.Buy(100, 1);
    Log("id:", id);
}
```javascript
// 以下为错误调用
function main() {
    exchange.SetContractType("quarter")
  
    // 设置做空方向
    exchange.SetDirection("sell")     
    // 下买单,会报错,做空只能卖出
    var id = exchange.Buy(50, 1)

    // 设置做多方向
    exchange.SetDirection("buy")      
    // 下卖单,会报错,做多只能买入
    var id2 = exchange.Sell(60, 1)    
  
    // 设置平多方向
    exchange.SetDirection("closebuy")    
    // 下买单,会报错,平多只能卖出
    var id3 = exchange.Buy(-1, 1)        
  
    // 设置平空方向
    exchange.SetDirection("closesell")   
    // 下卖单,会报错,平空只能买入
    var id4 = exchange.Sell(-1, 1)       
}
# 以下为错误调用
def main():
    exchange.SetContractType("quarter")
    exchange.SetDirection("sell")
    id = exchange.Buy(50, 1)
    exchange.SetDirection("buy")
    id2 = exchange.Sell(60, 1)
    exchange.SetDirection("closebuy")
    id3 = exchange.Buy(-1, 1)
    exchange.SetDirection("closesell")
    id4 = exchange.Sell(-1, 1)
// 以下为错误调用
void main() {
    exchange.SetContractType("quarter");
    exchange.SetDirection("sell");
    auto id = exchange.Buy(50, 1);
    exchange.SetDirection("buy");
    auto id2 = exchange.Sell(60, 1);
    exchange.SetDirection("closebuy");
    auto id3 = exchange.Buy(-1, 1);
    exchange.SetDirection("closesell");
    auto id4 = exchange.Sell(-1, 1);
}

加密货币期货合约下单时必须注意交易方向是否设置正确,如果交易方向和交易函数不匹配会报错:

direction is sell, invalid order type Buy
direction is buy, invalid order type Sell
direction is closebuy, invalid order type Buy
direction is closesell, invalid order type Sell
// 例如交易对:ETH_BTC ,市价单买入
function main() {
    // 下市价单买入,买入0.1个BTC(计价币)金额的ETH币
    exchange.Buy(-1, 0.1)    
}
def main():
    exchange.Buy(-1, 0.1)
void main() {
    exchange.Buy(-1, 0.1);
}

现货市价单。

期货合约下单时必须注意交易方向是否设置正确,如果交易方向和交易函数不匹配会报错。 加密货币期货合约交易所的下单量如无特殊说明则为合约张数。 参数price设置为-1用于下市价单,需要交易所的下单接口支持市价单。 加密货币现货的市价单方式下单,下买单时,下单量参数amount是以计价币为单位的金额数量。 加密货币期货合约的市价单方式下单,下单量参数amount的单位为合约张数。实盘时,有少数加密货币交易所不支持市价单接口。 个别现货交易所的市价单买单的下单量为交易币数,具体查看「用户指南」中的交易所特殊说明。 如使用较旧版本的托管者,exchange.Buy()函数的返回值订单Id可能与当前文档中描述的返回值订单Id有差别。

{@fun/Trade/exchange.Sell exchange.Sell}, {@fun/Futures/exchange.SetContractType exchange.SetContractType}, {@fun/Futures/exchange.SetDirection exchange.SetDirection}

exchange.Sell


下单成功返回订单Id,下单失败返回空值。 FMZ平台的订单{@struct/Order Order}结构的属性```Id```由交易所品种代码和交易所原始订单Id组成,以英文逗号间隔。例如OKX交易所的现货交易对```ETH_USDT```订单的属性```Id```格式为:```ETH-USDT,1547130415509278720```。 调用```exchange.Sell()```函数下单时,返回值订单```Id```与订单{@struct/Order Order}结构的```Id```属性一致。
string、空值

exchange.Sell(price, amount)
exchange.Sell(price, amount, ...args)

```price```参数用于设置订单价格。
price
true
number
```amount```参数用于设置订单量。
amount
true
number
扩展参数,可以输出附带信息到这条下单日志中,```arg```参数可以传多个。
arg
false
string、number、bool、object、array、空值等系统支持的任意类型

```javascript
function main(){
    var id = exchange.Sell(100, 1)
    Log("id:", id)
}
def main():
    id = exchange.Sell(100, 1)
    Log("id:", id)
void main() {
    auto id = exchange.Sell(100, 1);
    Log("id:", id);
}
```javascript
// 以下为错误调用
function main() {
    exchange.SetContractType("quarter")
  
    // 设置做空方向
    exchange.SetDirection("sell")     
    // 下买单,会报错,做空只能卖出
    var id = exchange.Buy(50, 1)                  

    // 设置做多方向
    exchange.SetDirection("buy")      
    // 下卖单,会报错,做多只能买入
    var id2 = exchange.Sell(60, 1)    
  
    // 设置平多方向
    exchange.SetDirection("closebuy")    
    // 下买单,会报错,平多只能卖出
    var id3 = exchange.Buy(-1, 1)        
  
    // 设置平空方向
    exchange.SetDirection("closesell")   
    // 下卖单,会报错,平空只能买入
    var id4 = exchange.Sell(-1, 1)       
}
# 以下为错误调用
def main():
    exchange.SetContractType("quarter")
    exchange.SetDirection("sell")
    id = exchange.Buy(50, 1)
    exchange.SetDirection("buy")
    id2 = exchange.Sell(60, 1)
    exchange.SetDirection("closebuy")
    id3 = exchange.Buy(-1, 1)
    exchange.SetDirection("closesell")
    id4 = exchange.Sell(-1, 1)
// 以下为错误调用
void main() {
    exchange.SetContractType("quarter");
    exchange.SetDirection("sell");
    auto id = exchange.Buy(50, 1);
    exchange.SetDirection("buy");
    auto id2 = exchange.Sell(60, 1);
    exchange.SetDirection("closebuy");
    auto id3 = exchange.Buy(-1, 1);
    exchange.SetDirection("closesell");
    auto id4 = exchange.Sell(-1, 1);
}

加密货币期货合约下单时必须注意交易方向是否设置正确,如果交易方向和交易函数不匹配会报错:

direction is sell, invalid order type Buy
direction is buy, invalid order type Sell
direction is closebuy, invalid order type Buy
direction is closesell, invalid order type Sell
// 例如交易对:ETH_BTC,市价单卖出
function main() {
    // 注意:下市价单卖出,卖出0.2个ETH
    exchange.Sell(-1, 0.2)   
}
def main():
    exchange.Sell(-1, 0.2)
void main() {
    exchange.Sell(-1, 0.2);
}

现货市价单。

期货合约下单时必须注意交易方向是否设置正确,如果交易方向和交易函数不匹配会报错。 加密货币期货合约交易所的下单量如无特殊说明则为合约张数。 参数price设置为-1用于下市价单,需要交易所的下单接口支持市价单。 加密货币现货的市价单方式下单,下卖单时,下单量参数amount是以交易币为单位的数量。 加密货币期货合约的市价单方式下单,下单量参数amount的单位为合约张数。实盘时,有少数加密货币交易所不支持市价单接口。 如使用较旧版本的托管者,exchange.Sell()函数的返回值订单Id可能与当前文档中描述的返回值订单Id有差别。

{@fun/Trade/exchange.Buy exchange.Buy}, {@fun/Futures/exchange.SetContractType exchange.SetContractType}, {@fun/Futures/exchange.SetDirection exchange.SetDirection}

exchange.CreateOrder


下单成功返回订单Id,下单失败返回空值。 FMZ平台的订单{@struct/Order Order}结构的属性```Id```由交易所品种代码和交易所原始订单Id组成,以英文逗号间隔。例如OKX交易所的现货交易对```ETH_USDT```订单的属性```Id```格式为:```ETH-USDT,1547130415509278720```。 调用```exchange.CreateOrder(symbol, side, price, amount)```函数下单时,返回值订单```Id```与订单{@struct/Order Order}结构的```Id```属性一致。
string、空值

exchange.CreateOrder(symbol, side, price, amount)
exchange.CreateOrder(symbol, side, price, amount, ...args)

参数```symbol```用于指定订单的具体交易对、合约代码。 当调用```exchange.CreateOrder(symbol, side, price, amount)```函数下单时,```exchange```为现货交易所对象,如果订单计价币种为USDT,交易币种为BTC。则参数```symbol```为:```"BTC_USDT"```,格式为FMZ平台定义的交易对格式。 当调用```exchange.CreateOrder(symbol, side, price, amount)```函数下单时,```exchange```为期货交易所对象,如果订单为BTC的U本位永续合约订单。则参数```symbol```为:```"BTC_USDT.swap"```,格式为FMZ平台定义的**交易对**与**合约代码**组合,再以字符"."间隔。 当调用```exchange.CreateOrder(symbol, side, price, amount)```函数下单时,```exchange```为期货交易所对象,如果订单为BTC的U本位期权合约订单。则参数```symbol```为:```"BTC_USDT.BTC-240108-40000-C"```(以币安期权BTC-240108-40000-C为例),格式为FMZ平台定义的**交易对**与交易所定义的具体期权合约代码组合,再以字符"."间隔。
symbol
true
string
参数```side```用于指定订单的交易方向。
对于现货交易所对象,```side```参数的可选值为:```buy```、```sell```。```buy```表示买入,```sell```表示卖出。
对于期货交易所对象,```side```参数的可选值为:```buy```、```closebuy```、```sell```、```closesell```。```buy```表示开多仓、```closebuy```表示平多仓、```sell```表示开空仓、```closesell```表示平空仓。

side
true
string
参数```price```用于设置订单的价格。价格为-1时表示订单为市价单。
price
true
number
参数```amount```用于设置订单的下单量。需要注意当订单为**现货市价单买单**时,下单量为买入金额;个别现货交易所的市价单买单的下单量为交易币数,具体查看「用户指南」中的**交易所特殊说明**。
对于期货交易所对象,使用```CreateOrder()```/```Buy()```/```Sell()```函数下单时如无特殊说明,下单量参数```amount```均为合约张数。

amount
true
number
扩展参数,可以输出附带信息到这条下单日志中,```arg```参数可以传多个。
arg
false
string、number、bool、object、array、空值等系统支持的任意类型

```javascript
function main() {
    var id = exchange.CreateOrder("BTC_USDT", "buy", 60000, 0.01)           // 现货交易所对象下单币币交易BTC_USDT交易对
    // var id = exchange.CreateOrder("BTC_USDT.swap", "buy", 60000, 0.01)   // 期货交易所对象下单BTC的U本位永续合约
    Log("订单Id:", id)
}
def main():
    id = exchange.CreateOrder("BTC_USDT", "buy", 60000, 0.01)          # 现货交易所对象下单币币交易BTC_USDT交易对
    # id = exchange.CreateOrder("BTC_USDT.swap", "buy", 60000, 0.01)   # 期货交易所对象下单BTC的U本位永续合约
    Log("订单Id:", id)
void main() {
    auto id = exchange.CreateOrder("BTC_USDT", "buy", 60000, 0.01);           // 现货交易所对象下单币币交易BTC_USDT交易对
    // auto id = exchange.CreateOrder("BTC_USDT.swap", "buy", 60000, 0.01);   // 期货交易所对象下单BTC的U本位永续合约
    Log("订单Id:", id);
}

现货交易所对象、期货交易所对象调用exchange.CreateOrder()函数下单。

{@fun/Trade/exchange.Buy exchange.Buy}, {@fun/Trade/exchange.Sell exchange.Sell}

exchange.CancelOrder

FMZ平台的订单{@struct/Order Order}结构的属性```Id```由交易所品种代码和交易所原始订单Id组成,以英文逗号间隔。例如OKX交易所的现货交易对```ETH_USDT```订单的属性```Id```格式为:```ETH-USDT,1547130415509278720```。
调用```exchange.CancelOrder()```函数撤销订单时传入的参数```orderId```与订单{@struct/Order Order}结构的```Id```属性一致。


```exchange.CancelOrder()```函数返回真值,例如```true```表示取消订单请求发送成功, 返回假值,例如```false```表示取消订单请求发送失败。返回值只是代表发送请求成功或失败,判断交易所是否取消订单, 可以调用```exchange.GetOrders()```判断。
bool

exchange.CancelOrder(orderId)
exchange.CancelOrder(orderId, ...args)

```orderId```参数用于指定所要取消的订单。
orderId
true
string
扩展参数,可以输出附带信息到这条撤单日志中,```arg```参数可以传多个。
arg
false
string、number、bool、object、array、空值等系统支持的任意类型

```javascript
function main(){
    var id = exchange.Sell(99999, 1)
    exchange.CancelOrder(id)
}
def main():
    id = exchange.Sell(99999, 1)
    exchange.CancelOrder(id)
void main() {
    auto id = exchange.Sell(99999, 1);
    exchange.CancelOrder(id);
}

撤销订单。

function main() {
    if (exchange.GetName().includes("Futures_")) {
        Log("设置合约为:永续合约,设置交易方向为:开多仓。")
        exchange.SetContractType("swap")
        exchange.SetDirection("buy")
    }
    
    var ticker = exchange.GetTicker()
    exchange.Buy(ticker.Last * 0.5, 0.1)
    
    var orders = exchange.GetOrders()
    for (var i = 0 ; i < orders.length ; i++) {
        exchange.CancelOrder(orders[i].Id, "撤销的订单:", orders[i])
        Sleep(500)
    }
}
def main():
    if exchange.GetName().find("Futures_") != -1:
        Log("设置合约为:永续合约,设置交易方向为:开多仓。")
        exchange.SetContractType("swap")
        exchange.SetDirection("buy")
    
    ticker = exchange.GetTicker()
    exchange.Buy(ticker["Last"] * 0.5, 0.1)            

    orders = exchange.GetOrders()
    for i in range(len(orders)):
        exchange.CancelOrder(orders[i]["Id"], "撤销的订单:", orders[i])
        Sleep(500)
void main() {
    if (exchange.GetName().find("Futures_") != std::string::npos) {
        Log("设置合约为:永续合约,设置交易方向为:开多仓。");
        exchange.SetContractType("swap");
        exchange.SetDirection("buy");
    }            

    auto ticker = exchange.GetTicker();
    exchange.Buy(ticker.Last * 0.5, 0.1);            

    auto orders = exchange.GetOrders();
    for (int i = 0 ; i < orders.size() ; i++) {
        exchange.CancelOrder(orders[i].Id, "撤销的订单:", orders[i]);
        Sleep(500);
    }
}

FMZ的API函数中可以产生日志输出的函数例如:Log()exchange.Buy()exchange.CancelOrder()等都可以在必要参数后跟一些附带输出参数。 例如:exchange.CancelOrder(orders[i].Id, orders[i]),这样就是在取消Id为orders[i].Id的这个订单时附带输出这个订单的信息, 即orders[i]这个{@struct/Order Order}结构。

如使用较旧版本的托管者,exchange.CancelOrder()函数的参数orderId可能与当前文档中描述的orderId有差别。

{@fun/Trade/exchange.Buy exchange.Buy}, {@fun/Trade/exchange.Sell exchange.Sell}, {@fun/Trade/exchange.GetOrders exchange.GetOrders}

exchange.GetOrder


根据订单号查询订单详情,查询成功返回{@struct/Order Order}结构,查询失败返回空值。
{@struct/Order Order}、空值

exchange.GetOrder(orderId)

```orderId```参数用于指定所要查询的订单。
FMZ平台的订单{@struct/Order Order}结构的属性```Id```由交易所品种代码和交易所原始订单Id组成,以英文逗号间隔。例如OKX交易所的现货交易对```ETH_USDT```订单的属性```Id```格式为:```ETH-USDT,1547130415509278720```。
调用```exchange.GetOrder()```函数查询订单时传入的参数```orderId```与订单{@struct/Order Order}结构的```Id```属性一致。

orderId
true
string

```javascript
function main(){
    var id = exchange.Sell(1000, 1)
    // 参数id为订单号码,需填入你想要查询的订单的号码
    var order = exchange.GetOrder(id)      
    Log("Id:", order.Id, "Price:", order.Price, "Amount:", order.Amount, "DealAmount:",
        order.DealAmount, "Status:", order.Status, "Type:", order.Type)
}
def main():
    id = exchange.Sell(1000, 1)
    order = exchange.GetOrder(id)
    Log("Id:", order["Id"], "Price:", order["Price"], "Amount:", order["Amount"], "DealAmount:", 
        order["DealAmount"], "Status:", order["Status"], "Type:", order["Type"])
void main() {
    auto id = exchange.Sell(1000, 1);
    auto order = exchange.GetOrder(id);
    Log("Id:", order.Id, "Price:", order.Price, "Amount:", order.Amount, "DealAmount:", 
        order.DealAmount, "Status:", order.Status, "Type:", order.Type);
}

部分交易所不支持exchange.GetOrder()函数。 返回值{@struct/Order Order}结构中AvgPrice属性为成交均价,有些交易所不支持该字段,不支持则设置为0。 如使用较旧版本的托管者,exchange.GetOrder()函数的参数orderId可能与当前文档中描述的orderId有差别。 不支持exchange.GetOrder()函数的交易所:

函数名 不支持的现货交易所 不支持的期货交易所
GetOrder Zaif / Coincheck / Bitstamp

{@struct/Order Order}, {@fun/Trade/exchange.GetOrders exchange.GetOrders}, {@fun/Trade/exchange.GetHistoryOrders exchange.GetHistoryOrders}

exchange.GetOrders


```exchange.GetOrders()```函数请求数据成功时返回{@struct/Order Order}结构数组,请求数据失败时返回空值。
{@struct/Order Order}数组、空值

exchange.GetOrders()
exchange.GetOrders(symbol)

参数```symbol```用于设置所要查询的**交易品种**或者**交易品种的范围**。
对于现货交易所对象,不传```symbol```参数时,请求所有现货品种的未完成订单数据。
对于期货交易所对象,不传```symbol```参数时,默认以当前交易对、合约代码所在维度范围请求所有品种的未完成订单数据。

symbol
false
string

```javascript
/*backtest
start: 2024-05-21 00:00:00
end: 2024-09-05 00:00:00
period: 5m
basePeriod: 1m
exchanges: [{"eid":"Binance","currency":"BTC_USDT"}]
*/

function main() {
    var arrSymbol = ["ETH_USDT", "BTC_USDT", "LTC_USDT", "SOL_USDT"]

    for (var symbol of arrSymbol) {
        var t = exchange.GetTicker(symbol)
        exchange.CreateOrder(symbol, "buy", t.Last / 2, 0.01)
    }

    var spotOrders = exchange.GetOrders()

    var tbls = []
    for (var orders of [spotOrders]) {
        var tbl = {type: "table", title: "test GetOrders", cols: ["Symbol", "Id", "Price", "Amount", "DealAmount", "AvgPrice", "Status", "Type", "Offset", "ContractType"], rows: []}
        for (var order of orders) {
            tbl.rows.push([order.Symbol, order.Id, order.Price, order.Amount, order.DealAmount, order.AvgPrice, order.Status, order.Type, order.Offset, order.ContractType])
        }
        tbls.push(tbl)
    }

    LogStatus("`" + JSON.stringify(tbls) +  "`")

    // 打印输出一次信息后返回,防止后续回测时订单成交,影响数据观察
    return
}
'''backtest
start: 2024-05-21 00:00:00
end: 2024-09-05 00:00:00
period: 5m
basePeriod: 1m
exchanges: [{"eid":"Binance","currency":"BTC_USDT"}]
'''

import json

def main():
    arrSymbol = ["ETH_USDT", "BTC_USDT", "LTC_USDT", "SOL_USDT"]

    for symbol in arrSymbol:
        t = exchange.GetTicker(symbol)
        exchange.CreateOrder(symbol, "buy", t["Last"] / 2, 0.01)

    spotOrders = exchange.GetOrders()

    tbls = []
    for orders in [spotOrders]:
        tbl = {"type": "table", "title": "test GetOrders", "cols": ["Symbol", "Id", "Price", "Amount", "DealAmount", "AvgPrice", "Status", "Type", "Offset", "ContractType"], "rows": []}
        for order in orders:
            tbl["rows"].append([order.Symbol, order.Id, order.Price, order.Amount, order.DealAmount, order.AvgPrice, order.Status, order.Type, order.Offset, order.ContractType])
        tbls.append(tbl)

    LogStatus("`" + json.dumps(tbls) +  "`")

    return
/*backtest
start: 2024-05-21 00:00:00
end: 2024-09-05 00:00:00
period: 5m
basePeriod: 1m
exchanges: [{"eid":"Binance","currency":"BTC_USDT"}]
*/

void main() {
    auto arrSymbol = {"ETH_USDT", "BTC_USDT", "LTC_USDT", "SOL_USDT"};
    
    for (const auto& symbol : arrSymbol) {
        auto t = exchange.GetTicker(symbol);
        exchange.CreateOrder(symbol, "buy", t.Last / 2, 0.01);
    }

    auto spotOrders = exchange.GetOrders();

    json tbls = R"([])"_json;
    std::vector<std::vector<Order>> arr = {spotOrders};
    for (const auto& orders : arr) {
        json tbl = R"({
            "type": "table", 
            "title": "test GetOrders", 
            "cols": ["Symbol", "Id", "Price", "Amount", "DealAmount", "AvgPrice", "Status", "Type", "Offset", "ContractType"],
            "rows": []
        })"_json;

        for (const auto& order : orders) {
            json arrJson = R"([])"_json;

            arrJson.push_back("Symbol");
            arrJson.push_back("Id");
            arrJson.push_back(order.Price);
            arrJson.push_back(order.Amount);
            arrJson.push_back(order.DealAmount);
            arrJson.push_back(order.AvgPrice);
            arrJson.push_back(order.Status);
            arrJson.push_back(order.Type);
            arrJson.push_back(order.Offset);
            arrJson.push_back(order.ContractType);

            tbl["rows"].push_back(arrJson);
        }

        tbls.push_back(tbl);
    }
    
    LogStatus(_D(), "\n", "`" + tbls.dump() + "`");

    return;
}

使用现货交易所对象,对多个不同交易对,以当前价格的一半作为下单价下买单,然后查询未完成订单信息。

/*backtest
start: 2024-05-21 00:00:00
end: 2024-09-05 00:00:00
period: 5m
basePeriod: 1m
exchanges: [{"eid":"Futures_Binance","currency":"BTC_USDT"}]
*/

function main() {
    var arrSymbol = ["BTC_USDT.swap", "BTC_USDT.quarter", "ETH_USDT.swap", "ETH_USDT.quarter"]

    for (var symbol of arrSymbol) {
        var t = exchange.GetTicker(symbol)
        exchange.CreateOrder(symbol, "buy", t.Last / 2, 1)
        exchange.CreateOrder(symbol, "sell", t.Last * 2, 1)
    }

    var defaultOrders = exchange.GetOrders()
    var swapOrders = exchange.GetOrders("USDT.swap")
    var futuresOrders = exchange.GetOrders("USDT.futures")
    var btcUsdtSwapOrders = exchange.GetOrders("BTC_USDT.swap")

    var tbls = []
    var arr = [defaultOrders, swapOrders, futuresOrders, btcUsdtSwapOrders]
    var tblDesc = ["defaultOrders", "swapOrders", "futuresOrders", "btcUsdtSwapOrders"]
    for (var index in arr) {
        var orders = arr[index]
        var tbl = {type: "table", title: tblDesc[index], cols: ["Symbol", "Id", "Price", "Amount", "DealAmount", "AvgPrice", "Status", "Type", "Offset", "ContractType"], rows: []}
        for (var order of orders) {
            tbl.rows.push([order.Symbol, order.Id, order.Price, order.Amount, order.DealAmount, order.AvgPrice, order.Status, order.Type, order.Offset, order.ContractType])
        }
        tbls.push(tbl)
    }

    LogStatus("`" + JSON.stringify(tbls) +  "`")

    // 打印输出一次信息后返回,防止后续回测时订单成交,影响数据观察
    return
}
'''backtest
start: 2024-05-21 00:00:00
end: 2024-09-05 00:00:00
period: 5m
basePeriod: 1m
exchanges: [{"eid":"Futures_Binance","currency":"BTC_USDT"}]
'''

import json

def main():
    arrSymbol = ["BTC_USDT.swap", "BTC_USDT.quarter", "ETH_USDT.swap", "ETH_USDT.quarter"]

    for symbol in arrSymbol:
        t = exchange.GetTicker(symbol)
        exchange.CreateOrder(symbol, "buy", t["Last"] / 2, 1)
        exchange.CreateOrder(symbol, "sell", t["Last"] * 2, 1)

    defaultOrders = exchange.GetOrders()
    swapOrders = exchange.GetOrders("USDT.swap")
    futuresOrders = exchange.GetOrders("USDT.futures")
    btcUsdtSwapOrders = exchange.GetOrders("BTC_USDT.swap")

    tbls = []
    arr = [defaultOrders, swapOrders, futuresOrders, btcUsdtSwapOrders]
    tblDesc = ["defaultOrders", "swapOrders", "futuresOrders", "btcUsdtSwapOrders"]
    for index in range(len(arr)):
        orders = arr[index]
        tbl = {"type": "table", "title": tblDesc[index], "cols": ["Symbol", "Id", "Price", "Amount", "DealAmount", "AvgPrice", "Status", "Type", "Offset", "ContractType"], "rows": []}
        for order in orders:
            tbl["rows"].append([order["Symbol"], order["Id"], order["Price"], order["Amount"], order["DealAmount"], order["AvgPrice"], order["Status"], order["Type"], order["Offset"], order["ContractType"]])
        tbls.append(tbl)

    LogStatus("`" + json.dumps(tbls) +  "`")

    return
/*backtest
start: 2024-05-21 00:00:00
end: 2024-09-05 00:00:00
period: 5m
basePeriod: 1m
exchanges: [{"eid":"Futures_Binance","currency":"BTC_USDT"}]
*/

void main() {
    auto arrSymbol = {"BTC_USDT.swap", "BTC_USDT.quarter", "ETH_USDT.swap", "ETH_USDT.quarter"};
    
    for (const auto& symbol : arrSymbol) {
        auto t = exchange.GetTicker(symbol);
        exchange.CreateOrder(symbol, "buy", t.Last / 2, 1);
        exchange.CreateOrder(symbol, "sell", t.Last * 2, 1);
    }
    
    auto defaultOrders = exchange.GetOrders();
    auto swapOrders = exchange.GetOrders("USDT.swap");
    auto futuresOrders = exchange.GetOrders("USDT.futures");
    auto btcUsdtSwapOrders = exchange.GetOrders("BTC_USDT.swap");
    
    json tbls = R"([])"_json;
    std::vector<std::vector<Order>> arr = {defaultOrders, swapOrders, futuresOrders, btcUsdtSwapOrders};
    std::string tblDesc[] = {"defaultOrders", "swapOrders", "futuresOrders", "btcUsdtSwapOrders"};
    for (int index = 0; index < arr.size(); index++) {
        auto orders = arr[index];
        json tbl = R"({
            "type": "table", 
            "cols": ["Symbol", "Id", "Price", "Amount", "DealAmount", "AvgPrice", "Status", "Type", "Offset", "ContractType"],
            "rows": []
        })"_json;
        tbl["title"] = tblDesc[index];
    
        for (const auto& order : orders) {
            json arrJson = R"([])"_json;

            arrJson.push_back(order.Symbol);
            arrJson.push_back(to_string(order.Id));    // Order订单结构中的Id属性类型为TId,使用FMZ平台内置的一个C++函数to_string编码
            arrJson.push_back(order.Price);
            arrJson.push_back(order.Amount);
            arrJson.push_back(order.DealAmount);
            arrJson.push_back(order.AvgPrice);
            arrJson.push_back(order.Status);
            arrJson.push_back(order.Type);
            arrJson.push_back(order.Offset);
            arrJson.push_back(order.ContractType);
    
            tbl["rows"].push_back(arrJson);
        }
    
        tbls.push_back(tbl);
    }
    
    LogStatus(_D(), "\n", "`" + tbls.dump() + "`");
    
    return;
}

使用期货交易所对象,对多个不同交易对、合约代码的品种下单。下单价格远离盘口对手价,保持订单处于未成交状态,按多种方式查询订单。

function main() {
    var orders = exchange.GetOrders("BTC_USDT")           // 现货品种举例
    // var orders = exchange.GetOrders("BTC_USDT.swap")   // 期货品种举例
    Log("orders:", orders)
}
def main():
    orders = exchange.GetOrders("BTC_USDT")          # 现货品种举例
    # orders = exchange.GetOrders("BTC_USDT.swap")   # 期货品种举例
    Log("orders:", orders)
void main() {
    auto orders = exchange.GetOrders("BTC_USDT");           // 现货品种举例
    // auto orders = exchange.GetOrders("BTC_USDT.swap");   // 期货品种举例
    Log("orders:", orders);
}

调用exchange.GetOrders()函数时传入Symbol参数指定请求具体交易对、合约代码的订单数据。

GetOrders函数中,symbol参数的使用场景归纳:

交易所对象分类 symbol参数 查询范围 备注
现货 不传symbol参数 查询所有现货交易对 所有调用场景,如果交易所接口不支持则报错返回空值,不再赘述
现货 指定交易品种,symbol参数为:”BTC_USDT” 查询指定的BTC_USDT交易对 对于现货交易所对象,参数symbol格式为:”BTC_USDT”
期货 不传symbol参数 查询当前交易对、合约代码维度范围的所有交易品种 假如当前交易对为BTC_USDT,合约代码为swap,即查询所有的USDT本位永续合约。等价于调用GetOrders("USDT.swap")
期货 指定交易品种,symbol参数为:”BTC_USDT.swap” 查询指定的BTC的USDT本位永续合约 对于期货交易所对象,参数symbol格式为:FMZ平台定义的交易对合约代码组合,以字符"."间隔。
期货 指定交易品种范围,symbol参数为:”USDT.swap” 查询所有USDT本位永续合约 -
支持期权的期货交易所 不传symbol参数 查询当前交易对维度范围的所有期权合约 假如当前交易对为BTC_USDT,合约设置为期权合约,例如币安期权合约:BTC-240108-40000-C
支持期权的期货交易所 指定具体交易品种 查询指定的期权合约 例如对于币安期货交易所,symbol参数:BTC_USDT.BTC-240108-40000-C
支持期权的期货交易所 指定交易品种范围,symbol参数为:”USDT.option” 查询所有USDT本位期权合约 -

GetOrders函数中,期货交易所对象查询维度范围归纳:

symbol参数 请求范围定义 备注
USDT.swap USDT本位永续合约范围。 对于交易所API接口不支持的维度,调用时会报错返回空值。
USDT.futures USDT本位交割合约范围。 -
USD.swap 币本位永续合约范围。 -
USD.futures 币本位交割合约范围。 -
USDT.option USDT本位期权合约范围。 -
USD.option 币本位期权合约范围。 -
USDT.futures_combo 差价组合合约范围。 Futures_Deribit交易所
USD.futures_ff 混合保证金交割合约范围。 Futures_Kraken交易所
USD.swap_pf 混合保证金永续合约范围。 Futures_Kraken交易所

当交易所对象exchange代表的账户在查询范围内指定的交易品种没有挂单时(处于未成交状态的活动订单),调用该函数返回空数组,即:[]。 以下交易所查询当前未完成订单的接口必须传入品种参数,使用这些交易所调用GetOrders函数,没有传入symbol参数时只请求当前品种的未完成订单,并非所有品种的未完成订单(因为交易所接口不支持)。 Zaif, MEXC, LBank, Korbit, Coinw, BitMart, Bithumb, BitFlyer, BigONE.

不支持exchange.GetOrders()函数的交易所:

函数名 不支持的现货交易所 不支持的期货交易所
GetOrders Futures_Bibox

{@struct/Order Order}, {@fun/Trade/exchange.GetOrder exchange.GetOrder}, {@fun/Trade/exchange.GetHistoryOrders exchange.GetHistoryOrders}

exchange.GetHistoryOrders


```exchange.GetHistoryOrders()```函数请求数据成功时返回{@struct/Order Order}结构数组,请求数据失败时返回空值。
{@struct/Order Order}数组、空值

exchange.GetHistoryOrders()
exchange.GetHistoryOrders(symbol)
exchange.GetHistoryOrders(symbol, since)
exchange.GetHistoryOrders(symbol, since, limit)
exchange.GetHistoryOrders(since)
exchange.GetHistoryOrders(since, limit)

```symbol```参数用来指定交易品种。以```BTC_USDT```交易对为例,```exchange```为现货交易所对象时,```symbol```参数格式为:```BTC_USDT```;如果是期货交易所对象,以永续合约为例,```symbol```参数格式为:```BTC_USDT.swap```。
如果查询的是期权合约的订单数据,参数```symbol```设置为```"BTC_USDT.BTC-240108-40000-C"```(以币安期权BTC-240108-40000-C为例),格式为FMZ平台定义的**交易对**与交易所定义的具体期权合约代码组合,再以字符"."间隔。
不传该参数时默认请求当前设置的交易对、合约代码的订单数据。

symbol
false
string
```since```参数用来指定查询的起始时间戳,单位为毫秒。
since
false
number
```limit```参数用来指定查询的订单数量。
limit
false
number

```javascript
function main() {
    var historyOrders = exchange.GetHistoryOrders()
    Log(historyOrders)
}
def main():
    historyOrders = exchange.GetHistoryOrders()
    Log(historyOrders)
void main() {
    auto historyOrders = exchange.GetHistoryOrders();
    Log(historyOrders);
}
  • 不指定symbolsincelimit参数时,默认查询当前交易对、合约的历史订单。查询距离当前时间最近的一定范围内的历史订单,查询范围根据交易所接口单次查询范围而定。
  • 指定symbol参数时,查询设置的交易品种的历史订单。
  • 指定since参数时,以since时间戳为开始时间向当前时间方向查询。
  • 指定limit参数时,查询足够条数后返回。
  • 该函数仅支持提供历史订单查询接口的交易所。

不支持exchange.GetHistoryOrders()函数的交易所:

函数名 不支持的现货交易所 不支持的期货交易所
GetHistoryOrders Zaif / Upbit / Coincheck / Bitstamp / Bithumb / BitFlyer / BigONE Futures_Bibox / Futures_ApolloX

{@struct/Order Order}, {@fun/Trade/exchange.GetOrder exchange.GetOrder}, {@fun/Trade/exchange.GetOrders exchange.GetOrders}

exchange.SetPrecision


exchange.SetPrecision(pricePrecision, amountPrecision)

```pricePrecision```参数用来控制价格数据的精度。
pricePrecision
true
number
```amountPrecision```参数用来控制下单量数据的精度。
amountPrecision
true
number

```javascript
function main(){
    // 设置价格小数位精度为2位,品种下单量小数位精度为3位
    exchange.SetPrecision(2, 3)
}
def main():
    exchange.SetPrecision(2, 3)
void main() {
    exchange.SetPrecision(2, 3);
}

回测系统不支持该函数,回测系统的数值精度会自动处理。

{@fun/Trade/exchange.Buy exchange.Buy}, {@fun/Trade/exchange.Sell exchange.Sell}

exchange.SetRate

设置交易所对象当前的汇率。

exchange.SetRate(rate)

rate
true
number

```javascript
function main(){
    Log(exchange.GetTicker())
    // 设置汇率转换
    exchange.SetRate(7)
    Log(exchange.GetTicker())
    // 设置为1,不转换
    exchange.SetRate(1)
}
def main():
    Log(exchange.GetTicker())
    exchange.SetRate(7)
    Log(exchange.GetTicker())
    exchange.SetRate(1)
void main() {
    Log(exchange.GetTicker());
    exchange.SetRate(7);
    Log(exchange.GetTicker());
    exchange.SetRate(1);
}

如果使用exchange.SetRate()函数设置过一个汇率值,例如设置为7。 那么当前exchange这个交易所对象代表的交易所的行情、深度、下单价格等所有价格信息,都会被乘以设置的汇率7,进行转换。 例如exchange是以美元为计价货币的交易所。执行exchange.SetRate(7)之后,实盘所有价格都会被乘7转换成接近CNY计价的价格。

{@fun/Market/exchange.GetRate exchange.GetRate}

exchange.IO


```exchange.IO()```函数调用交易所对象相关的其它接口,调用成功时返回请求的应答数据,调用失败时返回空值。
string、number、bool、object、array、空值等系统支持的任意类型

exchange.IO(k, ...args)

```k```参数用于设置调用类型,可选值为```"api"```、```"currency"```、```"base"```、```"trade_margin"```、```"trade_normal"```、```"public_base"```、```"mbase"```、```selfTradePreventionMode```、```simulate```、```cross```、```dual```、```unified```等。
k
true
string
扩展参数,根据具体调用场景传参,```arg```参数可以传多个。 由于```exchange.IO()```函数的多态机制,不同的参数设置对应不同的功能。 ```exchange.IO()```函数的参数个数、类型都是不确定的。
arg
true
string、number、bool、object、array、空值等系统支持的任意类型

```javascript
function main() {
    var arrOrders = [
        {"instId":"BTC-USDT-SWAP","tdMode":"cross","side":"buy","ordType":"limit","px":"16000","sz":"1","posSide":"long"},
        {"instId":"BTC-USDT-SWAP","tdMode":"cross","side":"buy","ordType":"limit","px":"16000","sz":"2","posSide":"long"}
    ]
    
    // 调用 exchange.IO 直接访问交易所批量下单接口
    var ret = exchange.IO("api", "POST", "/api/v5/trade/batch-orders", "", JSON.stringify(arrOrders))
    Log(ret)
}
import json
def main():
    arrOrders = [
        {"instId":"BTC-USDT-SWAP","tdMode":"cross","side":"buy","ordType":"limit","px":"16000","sz":"1","posSide":"long"}, 
        {"instId":"BTC-USDT-SWAP","tdMode":"cross","side":"buy","ordType":"limit","px":"16000","sz":"2","posSide":"long"}
    ]
    ret = exchange.IO("api", "POST", "/api/v5/trade/batch-orders", "", json.dumps(arrOrders))
    Log(ret)
void main() {
    json arrOrders = R"([
        {"instId":"BTC-USDT-SWAP","tdMode":"cross","side":"buy","ordType":"limit","px":"16000","sz":"1","posSide":"long"},
        {"instId":"BTC-USDT-SWAP","tdMode":"cross","side":"buy","ordType":"limit","px":"16000","sz":"2","posSide":"long"}
    ])"_json;
    auto ret = exchange.IO("api", "POST", "/api/v5/trade/batch-orders", "", arrOrders.dump());
    Log(ret);
}

使用exchange.IO()函数的exchange.IO("api", httpMethod, resource, params, raw)调用形式, 需要首先了解该交易所的API接口,查阅相关文档。这样就可以扩展FMZ平台没有添加的功能。 提交POST请求不必担心参数加密、签名、验证等过程。FMZ在底层已经处理,只要填入相应参数即可。 可以参考OKX交易所期货合约的批量下单范例,使用参数raw传订单参数:

var amount = 1
var price = 10
var basecurrency = "ltc"
function main () {
    // 注意 amount.toString() 和 price.toString() 左边右边都有一个 ' 字符
    var message = "symbol=" + basecurrency + "&amount='" + amount.toString() + "'&price='" + price.toString() + "'&side=buy" + "&type=limit"
    var id = exchange.IO("api", "POST", "/v1/order/new", message)
}
amount = 1
price = 10
basecurrency = "ltc"
def main():
    message = "symbol=" + basecurrency + "&amount='" + str(amount) + "'&price='" + str(price) + "'&side=buy" + "&type=limit"
    id = exchange.IO("api", "POST", "/v1/order/new", message)
void main() {
    auto amount = 1.0;
    auto price = 10.0;
    auto basecurrency = "ltc";
    string message = format("symbol=%s&amount=\"%.1f\"&price=\"%.1f\"&side=buy&type=limit", basecurrency, amount, price);
    auto id = exchange.IO("api", "POST", "/v1/order/new", message);
}

如果params参数(即Http请求参数)中键值是字符串,需要用单引号(即符号’)写在参数值左右,把参数值包裹起来。

function main() {
    var ret = exchange.IO("api", "GET", "https://www.okx.com/api/v5/account/max-withdrawal", "ccy=BTC")
    Log(ret)
}
def main():
    ret = exchange.IO("api", "GET", "https://www.okx.com/api/v5/account/max-withdrawal", "ccy=BTC")
    Log(ret)
void main() {
    auto ret = exchange.IO("api", "GET", "https://www.okx.com/api/v5/account/max-withdrawal", "ccy=BTC");
    Log(ret);
}

支持传入完整的url参数,这样可以省略切换基地址的操作(调用exchange.SetBase()函数)。

function main(){
    var ret = exchange.IO("api", "GET", "/api/v5/trade/orders-pending", "instType=SPOT")
    Log(ret)
}
def main():
    ret = exchange.IO("api", "GET", "/api/v5/trade/orders-pending", "instType=SPOT")
    Log(ret)
void main() {
    auto ret = exchange.IO("api", "GET", "/api/v5/trade/orders-pending", "instType=SPOT");
    Log(ret);
}

不使用参数raw的调用范例:

function main() {
    // 例如开始实盘上设置交易所对象目前交易对为BTC_USDT,打印目前交易对行情
    Log(exchange.GetTicker())
    // 切换交易对为LTC_BTC      
    exchange.IO("currency", "LTC_BTC")
    Log(exchange.GetTicker())
}
def main():
    Log(exchange.GetTicker())
    exchange.IO("currency", "LTC_BTC")
    Log(exchange.GetTicker())
void main() {
    Log(exchange.GetTicker());
    exchange.IO("currency", "LTC_BTC");
    Log(exchange.GetTicker());
}

切换当前交易所的交易对,这样就会通过代码切换实盘创建时或者回测时配置的交易对。

function main () {
    // exchanges[0]就是实盘创建时,第一个添加的交易所对象 
    exchanges[0].IO("base", "https://api.huobi.pro")
}
def main():
    exchanges[0].IO("base", "https://api.huobi.pro")
void main() {
    exchanges[0].IO("base", "https://api.huobi.pro");
}

例如交易所对象封装时默认的基地址为https://api.huobipro.com,需要切换至https://api.huobi.pro时,使用以下代码切换:

function main() {
    exchange.SetBase("https://api.bitfinex.com")
    exchange.IO("mbase", "https://api-pub.bitfinex.com")
}
def main():
    exchange.SetBase("https://api.bitfinex.com")
    exchange.IO("mbase", "https://api-pub.bitfinex.com")
void main() {
    exchange.SetBase("https://api.bitfinex.com");
    exchange.IO("mbase", "https://api-pub.bitfinex.com");
}

对于行情接口、交易接口基地址不同的交易所,例如Bitfinex期货有两个地址,一个是行情接口地址,一个是交易接口地址。 Bitfinex期货切换私有接口基地址使用exchange.SetBase("xxx")。 Bitfinex期货切换公共接口基地址使用exchange.IO("mbase", "xxx")

一、用于加密货币中心化交易所其它未统一封装的API接口调用,参数k设置为"api"

exchange.IO("api", httpMethod, resource, params, raw)
  • httpMethod :该参数为字符串类型,填入请求类型POSTGET等。
  • resource :该参数为字符串类型,填入请求路径;支持使用完整的请求路径,详见参考例子。
  • params :该参数为字符串类型,填入请求参数,使用URL编码。
  • raw :该参数为原始字符串参数,可以不传。
仅实盘支持调用```exchange.IO("api", httpMethod, resource, params, raw)```函数。

**二、用于切换交易对,参数```k```设置为```"currency"```:**

```javascript
exchange.IO("currency", currency)
  • currency :该参数为字符串类型,格式统一为大写,使用下划线分隔baseCurrencyquoteCurrency,例如:BTC_USDT

1、回测系统现已支持切换交易对(仅限数字货币现货交易所对象),回测时需要注意只能切换为相同计价币的交易对,例如当前交易对为ETH_BTC只能切换为LTC_BTC,不能切换为LTC_USDT。 2、对于加密货币期货合约交易所对象切换了交易对,需要再次设置合约代码以确定要交易的是哪个合约。 3、使用{@fun/Account/exchange.SetCurrency exchange.SetCurrency}函数切换交易对的功能与使用exchange.IO("currency", currency)切换交易对的功能完全相同。

三、用于切换加密货币现货交易所对象杠杆账户模式: - 参数k设置为"trade_margin",切换为现货杠杠账户模式。下单、获取账户资产将访问交易所现货杠杆接口。 如果交易所现货杠杆区分全仓、逐仓则使用:exchange.IO("trade_super_margin")切换为杠杆账户全仓、exchange.IO("trade_margin")切换为杠杆账户逐仓。 - 参数k设置为"trade_normal",切换回普通现货账户模式。

支持切换杠杆账户模式的现货交易所:

交易所 特殊备注
OKX 杠杆账户模式的交易对和普通的有所不同,有些交易对可能没有。使用exchange.IO("trade_super_margin")切换为杠杆账户全仓,exchange.IO("trade_margin")切换为逐仓。使用trade_normal切换为普通币币模式。使用exchange.IO("tdMode", "cross")直接指定杠杆模式。
火币 杠杆账户模式的交易对和普通的有所不同,有些交易对可能没有。火币杠杆账户有全仓和逐仓之分,使用trade_margin切换为杠杆账户逐仓,使用trade_super_margin切换为杠杆账户全仓。使用trade_normal切换为普通币币模式。
币安(Binance) 杠杆账户模式分为逐仓、全仓,使用trade_margin切换为逐仓,使用trade_super_margin切换为全仓,使用trade_normal切换为普通币币模式。
GateIO 杠杆账户模式分为逐仓、全仓,使用trade_margin切换为逐仓,使用trade_super_margin切换为全仓,使用trade_normal切换为普通币币模式。
AscendEx 使用exchange.IO("trade_margin")切换为杠杠账户模式,使用exchange.IO("trade_normal")切换回普通账户模式。
WOO 使用exchange.IO("trade_margin")切换为杠杆账户模式,使用exchange.IO("trade_normal")切换回普通账户模式。
CoinEx 使用exchange.IO("trade_margin")切换为杠杆账户模式,使用exchange.IO("trade_normal")切换回普通账户模式。

四、其它切换功能: 在用户指南中可以查看exchange.IO()函数的其它切换功能

{@fun/NetSettings/exchange.SetBase exchange.SetBase}, {@fun/Account/exchange.SetCurrency exchange.SetCurrency}, {@var EXCHANGE_OP_IO_CONTROL}

exchange.Log


exchange.Log(orderType, price, amount)
exchange.Log(orderType, price, amount, ...args)

```orderType```参数用于设置输出的日志类型,可选值为{@var/LOG_TYPE/LOG_TYPE_BUY LOG_TYPE_BUY},{@var/LOG_TYPE/LOG_TYPE_SELL LOG_TYPE_SELL},{@var/LOG_TYPE/LOG_TYPE_CANCEL LOG_TYPE_CANCEL}。
orderType
true
number
```price```参数用于设置输出的日志中显示的价格。
price
true
number
```amount```参数用于设置输出的日志中显示的下单量。
amount
true
number
扩展参数,可以输出附带信息到这条日志中,```arg```参数可以传多个。
arg
false
string、number、bool、object、array、空值等系统支持的任意类型

```javascript
var id = 123
function main() {
    // 下单类型买入,价格999,数量 0.1
    exchange.Log(LOG_TYPE_BUY, 999, 0.1)      
    // 取消订单
    exchange.Log(LOG_TYPE_CANCEL, id)         
}
id = 123
def main():
    exchange.Log(LOG_TYPE_BUY, 999, 0.1)
    exchange.Log(LOG_TYPE_CANCEL, id)
void main() {
    auto id = 123;
    exchange.Log(LOG_TYPE_BUY, 999, 0.1);
    exchange.Log(LOG_TYPE_CANCEL, id);
}

使用exchange.Log(orderType, price, amount)可以进行实盘跟单测试、模拟下单、可以辅助记录下单。 最常见的一个使用场景为:使用{@fun/Trade/exchange.IO exchange.IO}函数访问交易所的创建条件订单的接口,但是使用exchange.IO()函数并不会在实盘日志记录中输出交易日志信息。 这时就可以使用exchange.Log()函数补充输出日志,以便记录下单信息,对于撤单操作亦是如此。

orderType参数为LOG_TYPE_CANCEL时,price参数为撤单的订单Id,用于直接使用exchange.IO()函数撤单时打印撤单日志。 exchange.Log()函数是{@var/EXCHANGE exchange}交易所对象的成员函数,区别于全局函数{@fun/Log Log}。

{@fun/Log Log}, {@var/EXCHANGE exchange}, {@var/LOG_TYPE/LOG_TYPE_BUY LOG_TYPE_BUY}, {@var/LOG_TYPE/LOG_TYPE_SELL LOG_TYPE_SELL}, {@var/LOG_TYPE/LOG_TYPE_CANCEL LOG_TYPE_CANCEL}

exchange.Encode


```exchange.Encode()```函数返回计算出来的哈希值编码。
string

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

参数```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```计算。
algo
true
string
用于指定```data```参数的数据格式。```inputFormat```参数支持设置为:"raw","hex","base64","string"其中之一。 "raw"表示数据为原始数据,"hex"表示数据为```hex```编码,"base64"表示数据为```base64```编码,"string"表示数据为字符串。
inputFormat
true
string
用于指定输出的数据格式。 ```outputFormat```参数支持设置为:"raw","hex","base64","string"其中之一。 "raw"表示数据为原始数据,"hex"表示数据为```hex```编码,"base64"表示数据为```base64```编码,"string"表示数据为字符串。
outputFormat
true
string
参数```data```为所要处理的数据。
data
true
string
用于指定```key```参数的数据格式。 ```key```参数支持设置为:"raw","hex","base64","string"其中之一。 "raw"表示数据为原始数据,"hex"表示数据为```hex```编码,"base64"表示数据为```base64```编码,"string"表示数据为字符串。
keyFormat
false
string
```key```参数用于指定签名计算时使用的密钥,可以使用明文字符串。 也可以使用```"{{accesskey}}"```、```"{{secretkey}}"```代指{@var/EXCHANGE exchange}交易所对象中配置的```accessKey```和```secretKey```。
key
false
string

```javascript
function main() {
    var APIKEY = "your Access Key(Bitmex API ID)"
    var expires = parseInt(Date.now() / 1000) + 10
    var signature = exchange.Encode("sha256", "string", "hex", "GET/realtime" + expires, "hex", "{{secretkey}}")
    var client = Dial("wss://www.bitmex.com/realtime", 60)
    var auth = JSON.stringify({args: [APIKEY, expires, signature], op: "authKeyExpires"})
    var pos = 0
    client.write(auth)
    client.write('{"op": "subscribe", "args": "position"}')
    while (true) {
        bitmexData = client.read()
        if(bitmexData.table == 'position' && pos != parseInt(bitmexData.data[0].currentQty)){
            Log('position change', pos, parseInt(bitmexData.data[0].currentQty), '@')
            pos = parseInt(bitmexData.data[0].currentQty)
        }
    }
}
import time
def main():
    APIKEY = "your Access Key(Bitmex API ID)"
    expires = int(time.time() + 10)                
    signature = exchange.Encode("sha256", "string", "hex", "GET/realtime" + expires, "hex", "{{secretkey}}")
    client = Dial("wss://www.bitmex.com/realtime", 60)
    auth = json.dumps({"args": [APIKEY, expires, signature], "op": "authKeyExpires"})
    pos = 0
    client.write(auth)
    client.write('{"op": "subscribe", "args": "position"}')
    while True:
        bitmexData = json.loads(client.read())
        if "table" in bitmexData and bitmexData["table"] == "position" and len(bitmexData["data"]) != 0 and pos != bitmexData["data"][0]["currentQty"]:   
            Log("position change", pos, bitmexData["data"][0]["currentQty"], "@")
            pos = bitmexData["data"][0]["currentQty"]
void main() {
    auto APIKEY = "your Access Key(Bitmex API ID)";
    auto expires = Unix() + 10;
    auto signature = exchange.Encode("sha256", "string", "hex", format("GET/realtime%d", expires), "hex", "{{secretkey}}");
    
    auto client = Dial("wss://www.bitmex.com/realtime", 60);
    json auth = R"({"args": [], "op": "authKeyExpires"})"_json;            

    auth["args"].push_back(APIKEY);
    auth["args"].push_back(expires);
    auth["args"].push_back(signature);
    auto pos = 0;
    client.write(auth.dump());
    client.write("{\"op\": \"subscribe\", \"args\": \"position\"}");
    while(true) {
        auto bitmexData = json::parse(client.read());
        if(bitmexData["table"] == "position" && bitmexData["data"][0].find("currentQty") != bitmexData["data"][0].end() && pos != bitmexData["data"][0]["currentQty"]) {
            Log("测试");
            Log("position change", pos, bitmexData["data"][0]["currentQty"], "@");
            pos = bitmexData["data"][0]["currentQty"];
        }
    }
}

BitMEX仓位变化推送(wss协议)例子:

仅实盘支持调用exchange.Encode()函数。 "{{accesskey}}""{{secretkey}}"的引用方式仅在exchange.Encode()函数使用时有效。

{@var/EXCHANGE exchange}, {@fun/Global/Encode Encode}

exchange.Go

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


object

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

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

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

arg
false
string、number、bool、object、array、function、空值等系统支持的所有类型

```javascript
function main(){
    // 以下四种操作是并发多线程异步执行, 不会耗时, 立即返回的
    var a = exchange.Go("GetTicker")
    var b = exchange.Go("GetDepth") 
    var c = exchange.Go("Buy", 1000, 0.1)
    var d = exchange.Go("GetRecords", PERIOD_H1)
           
    // 调用wait方法等待返回异步获取ticker结果 
    var ticker = a.wait()            
    // 返回深度, 如果获取失败也是有可能返回null的 
    var depth = b.wait()             
    // 返回订单号, 限定1秒超时, 超时返回undefined, 此对象可以继续调用wait等待如果上次wait超时 
    var orderId = c.wait(1000)
    if(typeof(orderId) == "undefined") {
        // 超时,重新获取
        orderId = c.wait()
    }
    var records = d.wait()
}
def main():
    a = exchange.Go("GetTicker")
    b = exchange.Go("GetDepth")
    c = exchange.Go("Buy", 1000, 0.1)
    d = exchange.Go("GetRecords", PERIOD_H1)            

    ticker, ok = a.wait()
    depth, ok = b.wait()
    orderId, ok = c.wait(1000)
    if ok == False:
        orderId, ok = c.wait()
    records, ok = d.wait()
void main() {
    auto a = exchange.Go("GetTicker");
    auto b = exchange.Go("GetDepth");
    auto c = exchange.Go("Buy", 1000, 0.1);
    auto d = exchange.Go("GetRecords", PERIOD_H1);            

    Ticker ticker;
    Depth depth;
    Records records;
    TId orderId;
    a.wait(ticker);
    b.wait(depth);
    if(!c.wait(orderId, 300)) {
        c.wait(orderId);
    }
    d.wait(records);
}

```javascript
function main() {
    var d = exchange.Go("GetRecords", PERIOD_H1)
    // 等待K线结果
    var records = d.wait()
    // 这里wait了一个已经wait过且结束的异步操作,会返回null,并记录出错信息
    var ret = d.wait()
}
def main():
    d = exchange.Go("GetRecords", PERIOD_H1)
    records, ok = d.wait()
    ret, ok = d.wait()
void main() {
    auto d = exchange.Go("GetRecords", PERIOD_H1);
    Records records;
    d.wait(records);
    Records ret;
    d.wait(ret);
}

对已经释放的并发对象,调用其wait()方法会报错:

function main() {
    while(true) {
        var beginTS = new Date().getTime()
        var arrRoutine = []
        var arrTicker = []
        var arrName = []
        for(var i = 0; i < exchanges.length; i++) {
            arrRoutine.push(exchanges[i].Go("GetTicker"))
            arrName.push(exchanges[i].GetName())
        }            

        for(var i = 0; i < arrRoutine.length; i++) {
            arrTicker.push(arrRoutine[i].wait())
        }
        var endTS = new Date().getTime()            

        var tbl = {
            type: "table", 
            title: "行情", 
            cols: ["索引", "名称", "最新成交价"], 
            rows: []
        }
        
        for(var i = 0; i < arrTicker.length; i++) {
            tbl.rows.push([i, arrName[i], arrTicker[i].Last])
        }            

        LogStatus(_D(), "并发获取多个交易所行情总耗时:", endTS - beginTS, "毫秒", "\n", "`" + JSON.stringify(tbl) + "`")
        Sleep(500)
    }
}
import time 
import json
def main():
    while True:
        beginTS = time.time()
        arrRoutine = []
        arrTicker = []
        arrName = []
        for i in range(len(exchanges)):
            arrRoutine.append(exchanges[i].Go("GetTicker"))
            arrName.append(exchanges[i].GetName())            

        for i in range(len(exchanges)):
            ticker, ok = arrRoutine[i].wait()
            arrTicker.append(ticker)            

        endTS = time.time()
        tbl = {
            "type": "table", 
            "title": "行情", 
            "cols": ["索引", "名称", "最新成交价"], 
            "rows": [] 
        }            

        for i in range(len(arrTicker)):
            tbl["rows"].append([i, arrName[i], arrTicker[i]["Last"]])            

        LogStatus(_D(), "并发获取多个交易所行情总耗时:", endTS - beginTS, "秒", "\n", "`" + json.dumps(tbl) + "`")
        Sleep(500)
void main() {
    while(true) {
        int length = exchanges.size();
        auto beginTS = UnixNano() / 1000000;
        Ticker arrTicker[length] = {};
        string arrName[length] = {};
        
        // 注意,添加几个交易所对象,这里要执行几次exchanges[n].Go 函数,这个例子是需要添加四个交易所对象,具体可以修改
        auto r0 = exchanges[0].Go("GetTicker");
        auto r1 = exchanges[1].Go("GetTicker");
        auto r2 = exchanges[2].Go("GetTicker");
        auto r3 = exchanges[3].Go("GetTicker");
        GoObj *arrRoutine[length] = {&r0, &r1, &r2, &r3};
        
        for(int i = 0; i < length; i++) {
            arrName[i] = exchanges[i].GetName();
        }            

        for(int i = 0; i < length; i++) {
            Ticker ticker;
            arrRoutine[i]->wait(ticker);
            arrTicker[i] = ticker;
        }        
        auto endTS = UnixNano() / 1000000;            

        json tbl = R"({
            "type": "table", 
            "title": "行情", 
            "cols": ["索引", "名称", "最新成交价"], 
            "rows": [] 
        })"_json;            

        for(int i = 0; i < length; i++) {
            json arr = R"(["", "", ""])"_json;
            arr[0] = format("%d", i);
            arr[1] = arrName[i];
            arr[2] = format("%f", arrTicker[i].Last);
            tbl["rows"].push_back(arr);
        }            

        LogStatus(_D(), "并发获取多个交易所行情总耗时:", format("%d", endTS - beginTS), "毫秒", "\n", "`" + tbl.dump() + "`");
        Sleep(500);
    }
}

并发获取多个交易所行情:

function main() {
    /*  
        使用OKX期货下单接口测试
        POST /api/v5/trade/order        
    */
    
    var beginTS = new Date().getTime()
    var param = {"instId":"BTC-USDT-SWAP","tdMode":"cross","side":"buy","ordType":"limit","px":"16000","sz":"1","posSide":"long"}
    var ret1 = exchange.Go("IO", "api", "POST", "/api/v5/trade/order", "", JSON.stringify(param))
    var ret2 = exchange.Go("IO", "api", "POST", "/api/v5/trade/order", "", JSON.stringify(param))
    var ret3 = exchange.Go("IO", "api", "POST", "/api/v5/trade/order", "", JSON.stringify(param))
    
    var id1 = ret1.wait()
    var id2 = ret2.wait()
    var id3 = ret3.wait()
    var endTS = new Date().getTime()                

    Log("id1:", id1)
    Log("id2:", id2)
    Log("id3:", id3)
    Log("并发下单耗时:", endTS - beginTS, "毫秒")
}
import time
import json
def main():
    beginTS = time.time()
    param = {"instId":"BTC-USDT-SWAP","tdMode":"cross","side":"buy","ordType":"limit","px":"16000","sz":"1","posSide":"long"}
    ret1 = exchange.Go("IO", "api", "POST", "/api/v5/trade/order", "", json.dumps(param))
    ret2 = exchange.Go("IO", "api", "POST", "/api/v5/trade/order", "", json.dumps(param))
    ret3 = exchange.Go("IO", "api", "POST", "/api/v5/trade/order", "", json.dumps(param))            

    id1, ok1 = ret1.wait()
    id2, ok2 = ret2.wait()
    id3, ok3 = ret3.wait()
    endTS = time.time()            

    Log("id1:", id1)
    Log("id2:", id2)
    Log("id3:", id3)
    Log("并发下单耗时:", endTS - beginTS, "秒")
void main() {
    auto beginTS = UnixNano() / 1000000;
    json param = R"({"instId":"BTC-USDT-SWAP","tdMode":"cross","side":"buy","ordType":"limit","px":"16000","sz":"1","posSide":"long"})"_json;
    auto ret1 = exchange.Go("IO", "api", "POST", "/api/v5/trade/order", "", param.dump());
    auto ret2 = exchange.Go("IO", "api", "POST", "/api/v5/trade/order", "", param.dump());
    auto ret3 = exchange.Go("IO", "api", "POST", "/api/v5/trade/order", "", param.dump());            

    json id1 = R"({})"_json;
    json id2 = R"({})"_json;
    json id3 = R"({})"_json;            

    ret1.wait(id1);
    ret2.wait(id2);
    ret3.wait(id3);
    auto endTS = UnixNano() / 1000000;            

    Log("id1:", id1);
    Log("id2:", id2);
    Log("id3:", id3);
    Log("并发下单耗时:", endTS - beginTS, "毫秒");
}

exchange.IO("api", ...)函数并发调用:

function main() {
    var counter = 0
    var arr = []                 // 用于测试持续引用并发的相关变量
    var symbols = ["BTC_USDT", "ETH_USDT", "SOL_USDT", "LTC_USDT", "EOS_USDT"]
    while (true) {
        var arrRoutine = []
        for (var symbol of symbols) {
            var r = exchange.Go("GetTicker", symbol)
            arrRoutine.push(r)   // 记录并发对象用于调用 r.wait() 函数获取结果,每一轮循环都清空
            // arr.push(r)       // 如果使用这句代码,运行时持续引用并发的对象,无法自动释放,超过2000个并发时,会报错:```InternalError: too many routine wait, max is 2000```。
            counter++
        }
        
        // 遍历 arrRoutine 调用 r.wait()
        
        LogStatus(_D(), "routine number:", counter)
        Sleep(50)
    }
}

针对自动释放机制的测试

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

当并发的多线程任务执行完毕时,相关变量没有被继续引用,系统底层会自动处理资源回收。

```wait()```方法支持超时参数:
1、不设置超时参数,即```wait()```,或者设置超时参数0,即```wait(0)```。```wait()```函数会阻塞等待,直到并发的线程运行完毕,返回并发线程执行的结果。
2、设置超时参数-1,即```wait(-1)```。```wait()```函数会立即返回,不同编程语言有不同的返回值,具体可以参考本小节的调用例子。
3、设置具体超时参数,即```wait(300)```,```wait()```函数会等待最长300毫秒后返回。

虽然系统底层有自动回收机制,但是如果持续引用相关变量,并发的线程并不会释放。并发的线程数量超过2000个会报错:```"too many routine wait, max is 2000"```。

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

Python语言与JavaScript语言中的区别,Python语言中并发对象的```wait()```函数返回两个参数,第一个是异步的api调用返回的结果,第二个表示是异步调用是否完成。
```python
def main():
    d = exchange.Go("GetRecords", PERIOD_D1)
    # ok是一定返回True的, 除非策略被停止
    ret, ok = d.wait()          
    # 如果等待超时, 或者wait了一个已经结束的实例,ok返回False
    ret, ok = d.wait(100)

{@fun/Global/Mail_Go Mail_Go}, {@fun/Global/HttpQuery_Go HttpQuery_Go}, {@fun/Global/EventLoop EventLoop}

Account

exchange.GetAccount


查询账户资产信息,查询成功返回{@struct/Account Account}结构,查询失败返回空值。
{@struct/Account Account}、空值

exchange.GetAccount()

```javascript
function main(){
    // 切换交易对
    exchange.IO("currency", "BTC_USDT")     
    // 以OKX期货为例,设置合约为当周合约,当前交易对为BTC_USDT,所以当前合约为BTC的U本位当周合约
    exchange.SetContractType("this_week")   
    // 获取当前账户资产数据
    var account = exchange.GetAccount()
    // USDT作为保证金的可用余额
    Log(account.Balance)
    // USDT作为保证金的冻结金额
    Log(account.FrozenBalance)
    // 当前资产权益
    Log(account.Equity)
    // 当前资产作为保证金的所有持仓的未实现盈亏
    Log(account.UPnL)
}
def main():
    exchange.IO("currency", "BTC_USDT")
    exchange.SetContractType("this_week")    
    account = exchange.GetAccount()
    Log(account["Balance"])
    Log(account["FrozenBalance"])
    Log(account["Equity"])
    Log(account["UPnL"])
void main() {
    exchange.IO("currency", "BTC_USDT");
    exchange.SetContractType("this_week");    
    auto account = exchange.GetAccount();
    Log(account.Balance);
    Log(account.FrozenBalance);
    Log(account.Equity);
    Log(account.UPnL);
}

设置交易对、合约代码,获取当前账户信息。

如果交易所对象设置为加密货币期货合约交易所, 并且切换为以USDT作为保证金的合约时(如何切换参看{@fun/Account/exchange.SetCurrency exchange.SetCurrency}、{@fun/Futures/exchange.SetContractType exchange.SetContractType}函数), 资产是USDT作为保证金,是记录在{@struct/Account Account}结构的BalanceFrozenBalance属性中。 如果交易所对象设置为加密货币期货合约交易所, 并且切换为币本位合约时,资产是以币作为保证金,是记录在{@struct/Account Account}结构的StocksFrozenStocks属性中。 使用币安期货统一账户时,调用exchange.GetAccount()函数请求账户信息时,封装的数据为所有资产折算为USD的金额。显示在{@struct/Account Account}结构的Balance字段。 如果需要计算其它资产的折算金额,可以使用USD折算金额除以(所要折算的资产的)指数价格再除以(所要折算的资产的)质押率即可算出。

{@struct/Account Account}, {@fun/Account/exchange.SetCurrency exchange.SetCurrency}, {@fun/Futures/exchange.SetContractType exchange.SetContractType}

exchange.GetAssets


```exchange.GetAssets()```函数请求数据成功时返回{@struct/Asset Asset}结构数组,请求数据失败时返回空值。
{@struct/Asset Asset}数组、空值

exchange.GetAssets()

```javascript
function main() {
    // exchange.SetCurrency("BTC_USDT")  // 可以设置交易对
    // exchange.SetContractType("swap")  // 可以设置合约
    var assets = exchange.GetAssets()
    Log(assets)
}
def main():
    # exchange.SetCurrency("BTC_USDT")  # 可以设置交易对
    # exchange.SetContractType("swap")  # 可以设置合约
    assets = exchange.GetAssets()
    Log(assets)
void main() {
    // exchange.SetCurrency("BTC_USDT");  // 可以设置交易对
    // exchange.SetContractType("swap");  // 可以设置合约
    auto assets = exchange.GetAssets();
    Log(assets);
}

获取交易所账户资产信息,exchange.GetAssets()返回一个元素为Asset结构的数组。

期货交易所对象的GetAssets()函数返回当前交易对(币本位、USDT本位、USDC本位等)下的保证金资产。

{@struct/Asset Asset}

exchange.GetName


```exchange.GetName()```函数返回FMZ量化交易平台定义的交易所名称。
string

exchange.GetName()

```javascript
function main() {
    Log("判断交易所对象exchange为币安现货,判断结果为:", exchange.GetName() == "Binance")
}
def main():
    Log("判断交易所对象exchange为币安现货,判断结果为:", exchange.GetName() == "Binance")
void main() {
    Log("判断交易所对象exchange为币安现货,判断结果为:", exchange.GetName() == "Binance");
}

{@fun/Account/exchange.GetLabel exchange.GetLabel}

### exchange.GetLabel

```exchange.GetLabel()```函数用于获取配置交易所对象时设置的自定义标签。

```exchange.GetLabel()```函数返回配置交易所对象时设置的自定义标签。
string

exchange.GetLabel()

```javascript
function main() {
    Log("exchange label:", exchange.GetLabel())
}
def main():
    Log("exchange label:", exchange.GetLabel())
void main() {
    Log("exchange label:", exchange.GetLabel());
}

通过设置的标签来识别策略代码中的exchange或者exchanges[1]exchanges[2]等交易所对象。

{@var/EXCHANGE exchange}

exchange.GetCurrency


```exchange.GetCurrency()```函数返回当前{@var/EXCHANGE exchange}交易所对象设置的交易对。
string

exchange.GetCurrency()

```javascript
function main() {
    Log("exchange 当前交易对为:", exchange.GetCurrency())
}
def main():
    Log("exchange 当前交易对为:", exchange.GetCurrency())
void main() {
    Log("exchange 当前交易对为:", exchange.GetCurrency());
}

交易对格式统一为大写,使用下划线分隔baseCurrencyquoteCurrency,例如:BTC_USDT

{@fun/Account/exchange.SetCurrency exchange.SetCurrency}

exchange.SetCurrency


exchange.SetCurrency(currency)

```currency```参数用于设置切换的交易对,交易对格式统一为大写,使用下划线分隔```baseCurrency```与```quoteCurrency```,例如:```BTC_USDT```。
currency
true
string

```javascript
function main() {
    var ticker = exchange.GetTicker() 
    Log(ticker)
    Log(exchange.GetAccount())    
    // 切换交易对,注意切换后行情数据,账户信息的变化
    exchange.SetCurrency("LTC_USDT")
    Log("切换为LTC_USDT")
    ticker = exchange.GetTicker()
    Log(ticker)
    Log(exchange.GetAccount())
}
def main():
    ticker = exchange.GetTicker()
    Log(ticker)
    Log(exchange.GetAccount())
    exchange.SetCurrency("LTC_USDT")
    Log("切换为LTC_USDT")
    ticker = exchange.GetTicker()
    Log(ticker)
    Log(exchange.GetAccount())
void main() {
    auto ticker = exchange.GetTicker();
    Log(ticker);
    Log(exchange.GetAccount());
    exchange.SetCurrency("LTC_USDT");
    Log("切换为LTC_USDT");
    ticker = exchange.GetTicker();
    Log(ticker);
    Log(exchange.GetAccount());
}

1、兼容exchange.IO("currency", "BTC_USDT")切换方式,参考{@fun excahnge.IO}。 2、支持回测系统中切换交易对,回测系统中切换交易对时计价币名称不能改变。例如:BTC_USDT可以切换为LTC_USDT,不能切换为LTC_BTC。 3、切换为非回测页面初始设置的交易对后交易币的数量为0。例如:回测时回测页面上初始设置的交易对为BTC_USDTBTC数量为3个,USDT数量为10000。此时立即切换为LTC_USDT,切换后交易币数量为0,即账户中LTC数量为0,切换的交易对共享USDT数量,数量为10000。

{@fun/Account/exchange.GetCurrency exchange.GetCurrency}

exchange.GetQuoteCurrency


```exchange.GetQuoteCurrency()```函数返回当前交易对的计价币名称。
string

exchange.GetQuoteCurrency()

```javascript
function main() {
    exchange.SetCurrency("BTC_USDT")
    Log("BTC_USDT的计价币名称:", exchange.GetQuoteCurrency())
    // exchange.SetCurrency("ETH_BTC")
    // Log("ETH_BTC的计价币名称:", exchange.GetQuoteCurrency())
}
def main():
    exchange.SetCurrency("BTC_USDT")
    Log("BTC_USDT的计价币名称:", exchange.GetQuoteCurrency())
    # exchange.SetCurrency("ETH_BTC")
    # Log("ETH_BTC的计价币名称:", exchange.GetQuoteCurrency())
void main() {
    exchange.SetCurrency("BTC_USDT");
    Log("BTC_USDT的计价币名称:", exchange.GetQuoteCurrency());
    // exchange.SetCurrency("ETH_BTC")
    // Log("ETH_BTC的计价币名称:", exchange.GetQuoteCurrency())
}

例如:{@var/EXCHANGE exchange}交易所对象当前的交易对为BTC_USDTexchange.GetQuoteCurrency()函数就返回USDT。 如果当前的交易对为ETH_BTCexchange.GetQuoteCurrency()函数就返回BTC

{@fun/Account/exchange.GetCurrency exchange.GetCurrency}, {@fun/Account/exchange.SetCurrency exchange.SetCurrency}

Futures

exchange.GetPositions


```exchange.GetPositions()```函数请求数据成功时返回{@struct/Position Position}结构数组,请求数据失败时返回空值。
{@struct/Position Position}数组、空值

exchange.GetPositions()
exchange.GetPositions(symbol)

参数```symbol```用于设置所要查询的**交易品种**或者**交易品种的范围**。
不传```symbol```参数时,默认以当前交易对、合约代码所在维度范围请求所有品种的持仓数据。

symbol
false
string

```javascript
/*backtest
start: 2024-05-21 00:00:00
end: 2024-09-05 00:00:00
period: 5m
basePeriod: 1m
exchanges: [{"eid":"Futures_Binance","currency":"BTC_USDT"}]
*/

function main() {
    var arrSymbol = ["BTC_USDT.swap", "BTC_USDT.quarter", "ETH_USDT.swap", "ETH_USDT.quarter"]

    for (var symbol of arrSymbol) {
        exchange.CreateOrder(symbol, "buy", -1, 1)
        exchange.CreateOrder(symbol, "sell", -1, 1)
    }

    var defaultPositions = exchange.GetPositions()
    var swapPositions = exchange.GetPositions("USDT.swap")
    var futuresPositions = exchange.GetPositions("USDT.futures")
    var btcUsdtSwapPositions = exchange.GetPositions("BTC_USDT.swap")

    var tbls = []
    var arr = [defaultPositions, swapPositions, futuresPositions, btcUsdtSwapPositions]
    var tblDesc = ["defaultPositions", "swapPositions", "futuresPositions", "btcUsdtSwapPositions"]
    for (var index in arr) {
        var positions = arr[index]
        var tbl = {type: "table", title: tblDesc[index], cols: ["Symbol", "MarginLevel", "Amount", "FrozenAmount", "Price", "Profit", "Type", "ContractType", "Margin"], rows: [] }
        for (var pos of positions) {
            tbl.rows.push([pos.Symbol, pos.MarginLevel, pos.Amount, pos.FrozenAmount, pos.Price, pos.Profit, pos.Type, pos.ContractType, pos.Margin])
        }
        tbls.push(tbl)
    }

    LogStatus("`" + JSON.stringify(tbls) + "`")

    // 打印输出一次信息后返回,防止后续回测时订单成交,影响数据观察
    return
}
'''backtest
start: 2024-05-21 00:00:00
end: 2024-09-05 00:00:00
period: 5m
basePeriod: 1m
exchanges: [{"eid":"Futures_Binance","currency":"BTC_USDT"}]
'''

import json

def main():
    arrSymbol = ["BTC_USDT.swap", "BTC_USDT.quarter", "ETH_USDT.swap", "ETH_USDT.quarter"]

    for symbol in arrSymbol:
        exchange.CreateOrder(symbol, "buy", -1, 1)
        exchange.CreateOrder(symbol, "sell", -1, 1)

    defaultPositions = exchange.GetPositions()
    swapPositions = exchange.GetPositions("USDT.swap")
    futuresPositions = exchange.GetPositions("USDT.futures")
    btcUsdtSwapPositions = exchange.GetPositions("BTC_USDT.swap")

    tbls = []
    arr = [defaultPositions, swapPositions, futuresPositions, btcUsdtSwapPositions]
    tblDesc = ["defaultPositions", "swapPositions", "futuresPositions", "btcUsdtSwapPositions"]
    for index in range(len(arr)):
        positions = arr[index]
        tbl = {"type": "table", "title": tblDesc[index], "cols": ["Symbol", "MarginLevel", "Amount", "FrozenAmount", "Price", "Profit", "Type", "ContractType", "Margin"], "rows": []}
        for pos in positions:
            tbl["rows"].append([pos["Symbol"], pos["MarginLevel"], pos["Amount"], pos["FrozenAmount"], pos["Price"], pos["Profit"], pos["Type"], pos["ContractType"], pos["Margin"]])

        tbls.append(tbl)

    LogStatus("`" + json.dumps(tbls) + "`")

    return
/*backtest
start: 2024-05-21 00:00:00
end: 2024-09-05 00:00:00
period: 5m
basePeriod: 1m
exchanges: [{"eid":"Futures_Binance","currency":"BTC_USDT"}]
*/

void main() {
    auto arrSymbol = {"BTC_USDT.swap", "BTC_USDT.quarter", "ETH_USDT.swap", "ETH_USDT.quarter"};
    
    for (const auto& symbol : arrSymbol) {
        exchange.CreateOrder(symbol, "buy", -1, 1);
        exchange.CreateOrder(symbol, "sell", -1, 1);
    }
    
    auto defaultPositions = exchange.GetPositions();
    auto swapPositions = exchange.GetPositions("USDT.swap");
    auto futuresPositions = exchange.GetPositions("USDT.futures");
    auto btcUsdtSwapPositions = exchange.GetPositions("BTC_USDT.swap");
    
    json tbls = R"([])"_json;
    std::vector<std::vector<Position>> arr = {defaultPositions, swapPositions, futuresPositions, btcUsdtSwapPositions};
    std::string tblDesc[] = {"defaultPositions", "swapPositions", "futuresPositions", "btcUsdtSwapPositions"};
    for (int index = 0; index < arr.size(); index++) {
        auto positions = arr[index];
        json tbl = R"({
            "type": "table", 
            "cols": ["Symbol", "MarginLevel", "Amount", "FrozenAmount", "Price", "Profit", "Type", "ContractType", "Margin"],
            "rows": []
        })"_json;
        tbl["title"] = tblDesc[index];
    
        for (const auto& pos : positions) {
            json arrJson = R"([])"_json;
    
            arrJson.push_back(pos.Symbol);
            arrJson.push_back(pos.MarginLevel);
            arrJson.push_back(pos.Amount);
            arrJson.push_back(pos.FrozenAmount);
            arrJson.push_back(pos.Price);
            arrJson.push_back(pos.Profit);
            arrJson.push_back(pos.Type);
            arrJson.push_back(pos.ContractType);
            arrJson.push_back(pos.Margin);
    
            tbl["rows"].push_back(arrJson);
        }
    
        tbls.push_back(tbl);
    }
    
    LogStatus(_D(), "\n", "`" + tbls.dump() + "`");
    
    return;
}

使用期货交易所对象,对多个不同交易对、合约代码的品种下市价单。按多种方式查询持仓。

加密货币期货合约与加密货币现货不同,现货只有逻辑上的持仓概念。在FMZ量化交易平台的系统中加密货币期货合约具体品种是由交易对合约代码共同标识的。 可以参看{@fun/Account/exchange.SetCurrency exchange.SetCurrency}、{@fun/Futures/exchange.SetContractType exchange.SetContractType}函数。 在GetPositions函数中,symbol参数的使用场景归纳:

交易所对象分类 symbol参数 查询范围 备注
期货 不传symbol参数 查询当前交易对、合约代码维度范围的所有交易品种 假如当前交易对为BTC_USDT,合约代码为swap,即查询所有的USDT本位永续合约。等价于调用GetPositions("USDT.swap")
期货 指定交易品种,symbol参数为:”BTC_USDT.swap” 查询指定的BTC的USDT本位永续合约 对于期货交易所对象,参数symbol格式为:FMZ平台定义的交易对合约代码组合,以字符"."间隔。
期货 指定交易品种范围,symbol参数为:”USDT.swap” 查询所有USDT本位永续合约 -
支持期权的期货交易所 不传symbol参数 查询当前交易对维度范围的所有期权合约 假如当前交易对为BTC_USDT,合约设置为期权合约,例如币安期权合约:BTC-240108-40000-C
支持期权的期货交易所 指定具体交易品种 查询指定的期权合约 例如对于币安期货交易所,symbol参数:BTC_USDT.BTC-240108-40000-C
支持期权的期货交易所 指定交易品种范围,symbol参数为:”USDT.option” 查询所有USDT本位期权合约 -

GetPositions函数中,期货交易所对象查询维度范围归纳:

symbol参数 请求范围定义 备注
USDT.swap USDT本位永续合约范围。 对于交易所API接口不支持的维度,调用时会报错返回空值。
USDT.futures USDT本位交割合约范围。 -
USD.swap 币本位永续合约范围。 -
USD.futures 币本位交割合约范围。 -
USDT.option USDT本位期权合约范围。 -
USD.option 币本位期权合约范围。 -
USDT.futures_combo 差价组合合约范围。 Futures_Deribit交易所
USD.futures_ff 混合保证金交割合约范围。 Futures_Kraken交易所
USD.swap_pf 混合保证金永续合约范围。 Futures_Kraken交易所

兼容exchange.GetPosition()调用,GetPositionGetPositions使用完全一致。

当交易所对象exchange代表的账户在查询范围内指定的交易品种没有持仓时exchange.GetPositions()函数返回空数组,例如:[]

{@struct/Position Position}, {@fun/Account/exchange.SetCurrency exchange.SetCurrency}, {@fun/Futures/exchange.SetContractType exchange.SetContractType}

exchange.SetMarginLevel


exchange.SetMarginLevel(symbol, marginLevel)
exchange.SetMarginLevel(marginLevel)

```symbol```参数用于指定需要调整杠杆值的交易对、合约。```SetMarginLevel()```函数的```symbol```参数的格式与```GetTicker()```函数的```symbol```参数的格式一致。
symbol
false
string
```marginLevel```参数用于设置杠杆值,交易所的杠杆值通常是整数,也支持一些交易所的浮点数杠杆值设置。
marginLevel
true
number

```javascript
function main() {
    exchange.SetMarginLevel(10)
    // 设置BTC的USDT本位永续合约的杠杆为15
    exchange.SetMarginLevel("BTC_USDT.swap", 15)
}
def main():
    exchange.SetMarginLevel(10)
    exchange.SetMarginLevel("BTC_USDT.swap", 15)
void main() {
    exchange.SetMarginLevel(10);
    exchange.SetMarginLevel("BTC_USDT.swap", 15);
}
对于加密货币期货合约来说,由于加密货币期货合约交易所的杠杆机制并不统一。 有些交易所期货合约杠杆值是下单接口中的一个参数,这时调用```exchange.SetMarginLevel()```函数并不产生网络请求,仅设置FMZ系统底层中的杠杆变量(用于下单接口传参)。 有些交易所期货合约杠杆值是交易所的一项设置,是需要通过在交易所网站页面设置或者使用API接口设置。 此时调用```exchange.SetMarginLevel()```函数就会产生网络请求,并且有可能设置杠杆失败。 原因可能有很多,例如:当前有持仓、挂单,导致这个交易对、合约无法再设置新的杠杆值。
不支持```exchange.SetMarginLevel()```函数的交易所:
| 函数名 | 不支持的现货交易所 | 不支持的期货交易所 |
| - | - | - |
| SetMarginLevel | -- | Futures_dYdX / Futures_Deribit |


{@var/EXCHANGE exchange}

### exchange.SetDirection

```exchange.SetDirection()```函数用于设置{@fun/Trade/exchange.Buy exchange.Buy}函数、{@fun/Trade/exchange.Sell exchange.Sell}函数进行期货合约下单时的订单方向。

exchange.SetDirection(direction)

```direction```参数用于设置期货合约下单时的方向,可选值为:```"buy"```、```"closesell"```、```"sell"```、```"closebuy"```。
direction
true
string

```javascript
function main(){
    // 举例设置为OKX期货当周合约
    exchange.SetContractType("this_week")    
    // 设置杠杆为5倍
    exchange.SetMarginLevel(5)
    // 设置下单类型为做多
    exchange.SetDirection("buy")
    // 以10000的价格,合约数量为2张下单
    exchange.Buy(10000, 2)              
    exchange.SetMarginLevel(5)
    exchange.SetDirection("closebuy")
    exchange.Sell(1000, 2)
}
def main():
    exchange.SetContractType("this_week")
    exchange.SetMarginLevel(5)
    exchange.SetDirection("buy")
    exchange.Buy(10000, 2)
    exchange.SetMarginLevel(5)
    exchange.SetDirection("closebuy")
    exchange.Sell(1000, 2)
void main() {
    exchange.SetContractType("this_week");
    exchange.SetMarginLevel(5);
    exchange.SetDirection("buy");
    exchange.Buy(10000, 2);
    exchange.SetMarginLevel(5);
    exchange.SetDirection("closebuy");
    exchange.Sell(1000, 2);
}

|下单函数|SetDirection函数的参数设置的方向|备注|
|-|-|-|
|exchange.Buy|"buy"|买入开多仓|
|exchange.Buy|"closesell"|买入平空仓|
|exchange.Sell|"sell"|卖出开空仓|
|exchange.Sell|"closebuy"|卖出平多仓|


{@fun/Trade/exchange.Buy exchange.Buy}, {@fun/Trade/exchange.Sell exchange.Sell}

### exchange.SetContractType

```exchange.SetContractType()```函数用于设置{@var/EXCHANGE exchange}交易所对象当前的合约代码。

```exchange.SetContractType()```函数返回一个结构,其中包含当前合约代码对应的交易所合约代码。 例如币安期货合约交易所,当前合约代码为```quarter```,该函数的返回值结构为:```{"InstrumentID":"BTCUSD_230630","instrument":"BTCUSD_230630"}```。
object

exchange.SetContractType(symbol)

```symbol```参数用于设置合约代码,可选值为:```"this_week"```、```"next_week"```、```"quarter"```、```"next_quarter"```、```"swap"```等。
加密货币期货合约中**交割合约**代码如无特殊说明一般有:

- ```this_week```:当周合约。
- ```next_week```:次周合约。
- ```quarter```:季度合约。
- ```next_quarter```:次季度合约。
加密货币期货合约中**永续合约**代码如无特殊说明一般有:
- ```swap```:永续合约。

symbol
true
string

```javascript
function main() {
    // 设置为当周合约
    exchange.SetContractType("this_week") 
}
def main():
    exchange.SetContractType("this_week")
void main() {
    exchange.SetContractType("this_week");
}

设置当前合约为当周合约:

function main() {
    // 默认交易对为BTC_USD,设置合约为当周,合约为币本位合约
    exchange.SetContractType("this_week")
    Log("ticker:", exchange.GetTicker())
    
    // 切换交易对,然后设置合约,切换成USDT作为保证金的合约,区别于币本位合约
    exchange.IO("currency", "BTC_USDT")   
    exchange.SetContractType("swap")
    Log("ticker:", exchange.GetTicker())
}
def main():
    exchange.SetContractType("this_week")
    Log("ticker:", exchange.GetTicker())
    exchange.IO("currency", "BTC_USDT")
    exchange.SetContractType("swap")
    Log("ticker:", exchange.GetTicker())
void main() {
    exchange.SetContractType("this_week");
    Log("ticker:", exchange.GetTicker());
    exchange.IO("currency", "BTC_USDT");
    exchange.SetContractType("swap");
    Log("ticker:", exchange.GetTicker());
}

设置USDT作为保证金的合约时,需要在代码中切换交易对(也可以在添加交易所对象时直接设置交易对):

function main(){
    // 设置合约为当周
    var ret = exchange.SetContractType("this_week")     
    // 返回当周合约的信息
    Log(ret)
}
def main():
    ret = exchange.SetContractType("this_week")
    Log(ret)
void main() {
    auto ret = exchange.SetContractType("this_week");
    Log(ret);
}

打印exchange.SetContractType()函数的返回值:

在加密货币期货合约策略中,以切换为BTC_USDT交易对为例: 当使用exchange.SetCurrency("BTC_USDT")或者exchange.IO("currency", "BTC_USDT")函数切换交易对时, 在切换之后需要使用exchange.SetContractType()函数重新设置合约才可以在新交易对下确定当前需要操作的合约。 系统根据交易对来确定是币本位合约或者USDT本位合约。 例如:交易对设置为BTC_USDT时,使用exchange.SetContractType("swap")函数设置合约代码为swap, 此时就设置为BTCUSDT本位的永续合约。如果交易对为BTC_USD,使用exchange.SetContractType("swap")函数设置合约代码为swap, 此时就设置为BTC币本位的永续合约。 详细介绍支持的加密货币期货合约交易所,每个交易所的合约命名如下: - Futures_OKCoin(OKX) 设置为永续合约:exchange.SetContractType("swap") 设置为当周合约:exchange.SetContractType("this_week") 设置为次周合约:exchange.SetContractType("next_week") 设置为月度合约:exchange.SetContractType("month") 设置为次月合约:exchange.SetContractType("next_month") 设置为季度合约:exchange.SetContractType("quarter") 设置为次季合约:exchange.SetContractType("next_quarter")

OKX有盘前交易合约:合约交割日期为固定时间,交易所定义的合约代码举例为:HMSTR-USDT-250207,在发明者平台设置交易对为HMSTR_USDT,然后使用exchange.SetContractType("HMSTR-USDT-250207")设置该合约。 对于支持symbol参数的函数,例如:exchange.GetTicker()exchange.CreateOrder()等。可以指定symbol参数为:HMSTR_USDT.HMSTR-USDT-250207来获取这个合约的行情数据或者下单等操作。 - Futures_HuobiDM(火币期货) 设置为当周合约:exchange.SetContractType("this_week")。 设置为次周合约:exchange.SetContractType("next_week")。 设置为季度合约:exchange.SetContractType("quarter")。 设置为次季合约:exchange.SetContractType("next_quarter")。 设置为永续合约:exchange.SetContractType("swap")。 支持USDT作为保证金的合约,以BTC合约为例:使用exchange.IO("currency", "BTC_USDT")即可切换为使用USDT作为保证金的合约, 或者在配置实盘参数、添加交易所对象时直接设置当前交易对为BTC_USDT。切换交易对后需要重新调用exchange.SetContractType()函数设置合约。 - Futures_BitMEX(BitMEX) 设置为永续合约:exchange.SetContractType("swap")。 Futures_BitMEX交易所交割合约为月度合约,合约代码如下(一月到十二月):

  "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"

设置交割合约:exchange.SetContractType("December")。举例交易对设置为XBT_USDT时,调用exchange.SetContractType("December")函数设置BTC的USDT本位十二月交割的合约(对应的实际合约代码为XBTUSDTZ23)。

Futures_BitMEX合约信息汇总 |Futures_BitMEX定义的合约代码|在FMZ对应的交易对|在FMZ对应的合约代码|备注| | - | - | - | - | | DOGEUSD | DOGE_USD | swap | 美元计价,XBT结算。XBT即BTC。 | | DOGEUSDT | DOGE_USDT | swap | USDT计价,USDT结算。 | | XBTETH | XBT_ETH | swap | ETH计价,XBT结算。 | | XBTEUR | XBT_EUR | swap | 欧元计价(EUR),XBT结算。 | | USDTUSDC | USDT_USDC | swap | USDC计价,XBT结算。 | | ETHUSD_ETH | ETH_USD_ETH | swap | 美元计价,ETH结算。 | | XBTH24 | XBT_USD | March | 到期日:24年3月,月份代码是:H ;美元计价,XBT结算。 | | ETHUSDZ23 | ETH_USD | December | 到期日:23年12月,月份代码是:Z ;美元计价,XBT结算。 | | XBTUSDTZ23 | XBT_USDT | December | 到期日:23年12月,月份代码是:Z ;USDT计价,USDT结算。 | | ADAZ23 | ADA_XBT | December | 到期日:23年12月,月份代码是:Z ;XBT计价,XBT结算。 | | P_XBTETFX23 | USDT_XXX | P_XBTETFX23 | 到期日:23年11月;计价为百分比,USDT结算。 | - Futures_GateIO 设置为当周合约:exchange.SetContractType("this_week")。 设置为次周合约:exchange.SetContractType("next_week")。 设置为季度合约:exchange.SetContractType("quarter")。 设置为次季合约:exchange.SetContractType("next_quarter")。 设置为永续合约:exchange.SetContractType("swap")。 支持USDT作为保证金的合约,以BTC合约为例使用exchange.IO("currency", "BTC_USDT")即可切换为使用USDT作为保证金的合约, 或者在配置实盘参数、添加交易所对象时直接设置当前交易对为BTC_USDT。切换交易对后需要重新调用exchange.SetContractType()函数设置合约。 - Futures_Deribit 设置为永续合约:exchange.SetContractType("swap")。 支持Deribit的USDC合约。 交割合约有:"this_week", "next_week", "month", "quarter", "next_quarter", "third_quarter", "fourth_quarter"。 差价合约(future_combo):"this_week,swap", "next_week,swap", "next_quarter,this_week", "third_quarter,this_week", "month,next_week"有很多种组合。 对于期权合约需要传入交易所定义的具体期权合约代码,详情参看Deribit官网。 - Futures_KuCoin 币本位合约,例如交易对设置为BTC_USD,再设置合约代码,即为币本位合约: 设置为永续合约:exchange.SetContractType("swap")。 设置为当季合约:exchange.SetContractType("quarter")。 设置为次季合约:exchange.SetContractType("next_quarter")

USDT作为保证金的合约: 例如交易对设置为BTC_USDT,再设置合约代码,即为USDT作为保证金的合约。 设置为永续合约:exchange.SetContractType("swap")。 - Futures_Binance 币安期货交易所默认为当前交易对的永续合约,合约代码:swap。 设置为永续合约:exchange.SetContractType("swap"),币安的永续合约有使用USDT作为保证金的合约,举例BTCUSDT本位永续合约,交易对设置为BTC_USDT。币安也支持使用币作为保证金的永续合约,举例BTC的币本位永续合约,交易对设置为BTC_USD。 设置为季度合约:exchange.SetContractType("quarter"),交割合约有币本位合约(即使用币作为保证金),举例BTC的季度合约,交易对设置为:BTC_USD再设置合约exchange.SetContractType("quarter"),就设置为BTC的币本位季度合约。 设置为次季合约:exchange.SetContractType("next_quarter"),举例BTC的币本位次季度合约,交易对设置为:BTC_USD,再设置合约exchange.SetContractType("next_quarter")。 币安支持部分USDT作为保证金的交割合约,以BTC举例交易对设置为BTC_USDT,再设置合约代码即可。

支持币安期权合约: 期权合约代码格式以交易所定义的期权合约代码为准:BTC-241227-15000-CXRP-240112-0.5-CBTC-241227-15000-P。以币安期权合约代码BTC-241227-15000-P为例:BTC为期权币种代码,241227为行权日期,15000为行权价格,P表示看跌期权,C表示看涨期权。 期权类型具体是欧式期权/美式期权具体可以查阅交易所期权合约相关资料。 交易所可能会限制期权卖方,需要单独申请资格。币安期权需要申请卖方资格。 - Futures_Bibox Bibox永续合约的合约代码:swap。 设置为永续合约:exchange.SetContractType("swap")。 - Futures_Bybit 默认为当前交易对的永续合约,合约代码:swap。 当周合约代码:this_week。 次周合约代码:next_week。 第三周合约代码:third_week。 月度合约代码:month。 次月合约代码:next_month。 季度合约代码:quarter。 次季度合约代码:next_quarter。 第三季度合约代码:third_quarter。 - Futures_Kraken 默认为当前交易对的永续合约,合约代码:swap

  ```month```:当月合约。
  ```quarter```:季度合约。
  ```next_quarter```:次季合约。
  ```swap_pf```:混合保证金永续合约。 
  ```quarter_ff```:混合保证金季度合约。 
  ```month_ff```:混合保证金当月合约。 
  ```next_quarter_ff```:混合保证金次季度合约。
- Futures_Bitfinex
  默认为当前交易对的永续合约,合约代码:```swap```。
- Futures_Bitget
  默认为当前交易对的永续合约,合约代码:```swap```。
  交易对设置为```BTC_USD```为币本位合约,交易对设置为```BTC_USDT```为```USDT```结算的合约。模拟合约可以设置交易对为:```SBTC_USD```、```BTC_SUSDT```。
- Futures_dYdX (v4)
  dYdX永续合约的合约代码:```swap```。
  设置为永续合约:```exchange.SetContractType("swap")```,dYdX仅有```USD.swap```品种维度,使用的保证金为USDC。
- Futures_MEXC
  MEXC(抹茶)永续合约的合约代码:```swap```。
  设置为永续合约:```exchange.SetContractType("swap")```。交易对设置为```BTC_USD```为币本位合约,交易对设置为```BTC_USDT```为```USDT```结算的合约。
- Futures_Crypto
  crypto.com交易所的账户中的代币可以折算为USD计价的额度,用于合约交易的保证金。
  设置为永续合约:```exchange.SetContractType("swap")```。举例交易对设置为```BTC_USD```时,调用```exchange.SetContractType("swap")```函数设置BTC的永续合约。
  crypto.com交易所交割合约为月度合约,合约代码如下(一月到十二月):
  ```code
  "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"

设置交割合约:exchange.SetContractType("October")。举例交易对设置为BTC_USD时,调用exchange.SetContractType("October")函数设置BTC的十月交割合约。 当前时刻对应的合约代码为:BTCUSD-231027。 - Futures_WOO Futures_WOO交易所支持USDT本位合约,永续合约代码为swap。举例交易对设置为BTC_USDT时,调用exchange.SetContractType("swap")函数设置当前合约为BTC的USDT本位永续合约。

{@fun/Futures/exchange.GetContractType exchange.GetContractType}, {@fun/Account/exchange.SetCurrency exchange.SetCurrency}

exchange.GetContractType


```exchange.GetContractType()```函数返回FMZ平台定义的合约代码,例如:```this_week```、```swap```等。
string

exchange.GetContractType()

```javascript
function main () {
    Log(exchange.SetContractType("this_week")) 
    Log(exchange.GetContractType())
}
def main():
    Log(exchange.SetContractType("this_week"))
    Log(exchange.GetContractType())
void main() {
    Log(exchange.SetContractType("this_week"));
    Log(exchange.GetContractType());
}

{@fun/Futures/exchange.SetContractType exchange.SetContractType}

exchange.GetFundings


```exchange.GetFundings()```函数请求数据成功时返回{@struct/Funding Funding}结构数组,请求数据失败时返回空值。
{@struct/Funding Funding}数组、空值

exchange.GetFundings()
exchange.GetFundings(symbol)

参数```symbol```用于设置所要查询的**交易品种**或者**交易品种的范围**。 不传```symbol```参数时,默认以当前交易对、合约代码所在维度范围请求所有品种的当期资金费率数据。

symbol
false
string

```javascript
/*backtest
start: 2024-10-01 00:00:00
end: 2024-10-23 00:05:00
period: 1m
basePeriod: 1m
exchanges: [{"eid":"Futures_Binance","currency":"SOL_USDC"}]
*/

function main() {
    // LPT_USDT.swap 4小时周期
    var symbols = ["SOL_USDT.swap", "ETH_USDT.swap", "LTC_USDT.swap", "SOL_USDC.swap", "ETH_USDC.swap", "BTC_USD.swap", "BTC_USDT.quarter", "LPT_USDT.swap"]
    for (var symbol of symbols) {
        exchange.GetTicker(symbol)
    }
    
    var arr = []
    var arrParams = ["no param", "LTC_USDT.swap", "USDT.swap", "USD.swap", "USDC.swap", "USDT.futures", "BTC_USDT.quarter"]
    for (p of arrParams) {
        if (p == "no param") {
            arr.push(exchange.GetFundings())
        } else {
            arr.push(exchange.GetFundings(p))
        }
    }
    
    var tbls = []
    var index = 0
    for (var fundings of arr) {
        var tbl = {
            "type": "table",
            "title": arrParams[index],
            "cols": ["Symbol", "Interval", "Time", "Rate"],
            "rows": [],
        }
    
        for (var f of fundings) {
            tbl["rows"].push([f.Symbol, f.Interval / 3600000, _D(f.Time), f.Rate * 100 + " %"])
        }
        tbls.push(tbl)
        index++
    }
    
    LogStatus(_D(), "\n 已经请求过的行情品种:", symbols, "\n`" + JSON.stringify(tbls) + "`")
}
'''backtest
start: 2024-10-01 00:00:00
end: 2024-10-23 00:05:00
period: 1m
basePeriod: 1m
exchanges: [{"eid":"Futures_Binance","currency":"SOL_USDC"}]
'''
    
import json
    
def main():
    # LPT_USDT.swap 4小时周期
    symbols = ["SOL_USDT.swap", "ETH_USDT.swap", "LTC_USDT.swap", "SOL_USDC.swap", "ETH_USDC.swap", "BTC_USD.swap", "BTC_USDT.quarter", "LPT_USDT.swap"]
    for symbol in symbols:
        exchange.GetTicker(symbol)
    
    arr = []
    arrParams = ["no param", "LTC_USDT.swap", "USDT.swap", "USD.swap", "USDC.swap", "USDT.futures", "BTC_USDT.quarter"]
    for p in arrParams:
        if p == "no param":
            arr.append(exchange.GetFundings())
        else:
            arr.append(exchange.GetFundings(p))
    
    tbls = []
    index = 0
    for fundings in arr:
        tbl = {
            "type": "table",
            "title": arrParams[index],
            "cols": ["Symbol", "Interval", "Time", "Rate"],
            "rows": [],
        }
    
        for f in fundings:
            tbl["rows"].append([f["Symbol"], f["Interval"] / 3600000, _D(f["Time"]), str(f["Rate"] * 100) + " %"])
    
        tbls.append(tbl)
        index += 1
    
    LogStatus(_D(), "\n 已经请求过的行情品种:", symbols, "\n`" + json.dumps(tbls) + "`")
/*backtest
start: 2024-10-01 00:00:00
end: 2024-10-23 00:05:00
period: 1m
basePeriod: 1m
exchanges: [{"eid":"Futures_Binance","currency":"SOL_USDC"}]
*/
    
void main() {
    // LPT_USDT.swap 4小时周期
    json arrSymbol = R"([])"_json;
    std::string symbols[] = {"SOL_USDT.swap", "ETH_USDT.swap", "LTC_USDT.swap", "SOL_USDC.swap", "ETH_USDC.swap", "BTC_USD.swap", "BTC_USDT.quarter", "LPT_USDT.swap"};
    for (const std::string& symbol : symbols) {
        exchange.GetTicker(symbol);
        arrSymbol.push_back(symbol);
    }
    
    std::vector<std::vector<Funding>> arr = {};
    std::string arrParams[] = {"no param", "LTC_USDT.swap", "USDT.swap", "USD.swap", "USDC.swap", "USDT.futures", "BTC_USDT.quarter"};
    for (const std::string& p : arrParams) {
        if (p == "no param") {
            arr.push_back(exchange.GetFundings());
        } else {
            arr.push_back(exchange.GetFundings(p));
        }
    }
    
    json tbls = R"([])"_json;
    int index = 0;
    for (int i = 0; i < arr.size(); i++) {
        auto fundings = arr[i];
    
        json tbl = R"({
            "type": "table", 
            "cols": ["Symbol", "Interval", "Time", "Rate"],
            "rows": []
        })"_json;
        tbl["title"] = arrParams[index];
    
        for (int j = 0; j < fundings.size(); j++) {
            auto f = fundings[j];
            // json arrJson = {f.Symbol, f.Interval / 3600000, _D(f.Time), string(f.Rate * 100) + " %"};
            json arrJson = {f.Symbol, f.Interval / 3600000, _D(f.Time), f.Rate};
            tbl["rows"].push_back(arrJson);
        }
        tbls.push_back(tbl);
        index++;
    }
    
    LogStatus(_D(), "\n 已经请求过的行情品种:", arrSymbol.dump(), "\n`" + tbls.dump() + "`");
}

使用期货交易所对象,在回测系统中调用exchange.GetFundings()函数。调用任何行情函数之前,GetFundings只返回当前默认交易对的Funding数据,调用行情函数之后会返回所有请求过的品种的Funding数据。可以参考以下测试例子:

对于不支持批量查询资金费率数据的期货交易所,如果指定symbol参数为查询范围,例如:USDT.swap或者不传symbol参数时接口会报错。 使用这类期货交易所对象调用GetFundings()函数必须指定symbol参数为具体某个永续合约品种,才能查询到该品种的当期资金费率数据。

不支持批量获取资金费率数据的交易所:Futures_Bitget、Futures_OKX、Futures_MEXC、Futures_Deribit、Futures_Crypto。需要传入```symbol```参数具体品种代码,例如:```ETH_USDT.swap```。

不支持```exchange.GetFundings()```函数的交易所:
| 函数名 | 不支持的现货交易所 | 不支持的期货交易所 |
| - | - | - |
| GetFundings | -- | Futures_DigiFinex |


{@struct/Funding Funding}

### NetSettings

### exchange.SetBase

```exchange.SetBase()```函数用于设置{@var/EXCHANGE exchange}交易所对象中配置的交易所API接口基地址。

exchange.SetBase(s)

```s```参数用于指定交易所API接口基地址。
s
true
string

```javascript
function main() {
    // 使用默认基地址
    Log(exchange.GetTicker())
    // 切换为https://aws.okx.com
    exchange.SetBase("https://aws.okx.com")
    Log(exchange.GetTicker())
}
def main():
    Log(exchange.GetTicker())
    exchange.SetBase("https://aws.okx.com")
    Log(exchange.GetTicker())
void main() {
    Log(exchange.GetTicker());
    exchange.SetBase("https://aws.okx.com");
    Log(exchange.GetTicker());
}

回测系统中不支持切换交易所API基地址,因为回测系统是一个沙盒模拟环境,并不会真正访问交易所的API接口。

{@fun/Trade/exchange.IO exchange.IO}

exchange.GetBase


当前交易所API接口基地址。
string

exchange.GetBase()

```javascript
function main() {
    Log(exchange.GetBase())
}
def main():
    Log(exchange.GetBase())
void main() {
    Log(exchange.GetBase());
}

{@fun/NetSettings/exchange.SetBase exchange.SetBase}

exchange.SetProxy


exchange.SetProxy(proxy)

```proxy```参数用于指定代理配置。
proxy
true
string

```javascript
function main() {
    exchange.SetProxy("socks5://192.168.1.10:8080")
    // 如果访问不到交易所行情接口,设置一个可用的ss5代理,就可以访问到行情接口了
    Log(exchange.GetTicker())
}
def main():
    exchange.SetProxy("socks5://192.168.1.10:8080")
    Log(exchange.GetTicker())
void main() {
    exchange.SetProxy("socks5://192.168.1.10:8080");
    Log(exchange.GetTicker());
}

配置{@var/EXCHANGE exchange}交易所对象socks5代理:

function main(){
    exchange.SetProxy("ip://10.0.3.15")
    // 发出的请求IP地址为10.0.3.15
    exchange.GetTicker()
}
def main():
    exchange.SetProxy("ip://10.0.3.15")
    exchange.GetTicker()
void main() {
    exchange.SetProxy("ip://10.0.3.15");
    exchange.GetTicker();
}

除了全局指定{@var/EXCHANGE exchange}交易所对象发出请求的IP地址,也支持基于{@var/EXCHANGE exchange}指定ip地址:

如果代理设置失败,在调用exchange.SetProxy()函数时会返回空值。 exchange.SetProxy()函数设置代理的功能仅限rest协议。 每个{@var/EXCHANGE exchange}交易所对象可以设置一个代理,设置代理后访问{@var/EXCHANGE exchange}交易所对象绑定的交易所接口都会通过代理访问。 支持设置socks5代理,以第一个添加的交易所对象{@var/EXCHANGE exchange}即:exchanges[0]为例: - 设置代理,无用户名,无密码:exchange.SetProxy("socks5://127.0.0.1:8889")。 - 设置代理,输入用户名和密码:exchange.SetProxy("socks5://username:password@127.0.0.1:8889")username为用户名,password为密码。 - 切换为正常模式,不使用代理:exchange.SetProxy("")

支持设置{@var/EXCHANGE exchange}交易所对象发出请求的IP地址,全局指定

{@var/EXCHANGE exchange}

exchange.SetTimeout


exchange.SetTimeout(timeout)

```timeout```参数用于指定超时设置的毫秒数。
timeout
true
number

```javascript
function main() {
    exchange.SetTimeout(3000)
    Log(exchange.GetTicker())
}
def main():
    exchange.SetTimeout(3000)
    Log(exchange.GetTicker())
void main() {
    exchange.SetTimeout(3000);
    Log(exchange.GetTicker());
}

参数timeout为毫秒数值,1000毫秒等于1秒。 仅限rest协议,用于设置rest请求时的超时时间,只用设置一次即可生效。 例如:exchange.SetTimeout(3000),设置exchange交易所对象的rest请求超时时间为3秒, 调用exchange.GetTicker()等具有网络请求的函数超过3秒未收到应答则超时,发生超时的函数调用会返回空值。


{@var/EXCHANGE exchange}

### Threads

发明者量化交易平台从系统底层真正支持```JavaScript```语言策略的多线程功能,实现了以下对象:

| 对象 | 说明 | 备注 |
| - | - | - |
| threading | 多线程全局对象 | 成员函数:```Thread```、```getThread```、```mainThread```等。 |
| Thread | 线程对象 | 成员函数:```peekMessage```、```postMessage```、```join```等。 |
| ThreadLock | 线程锁对象 | 成员函数:```acquire```、```release```。可作为线程执行函数的参数传入线程环境。 |
| ThreadEvent | 事件对象 | 成员函数:```set```、```clear```、```wait```、```isSet```。可作为线程执行函数的参数传入线程环境。 |
| ThreadCondition | 条件对象 | 成员函数:```notify```、```notifyAll```、```wait```、```acquire```、```release```。可作为线程执行函数的参数传入线程环境。 |
| ThreadDict | 字典对象 | 成员函数:```get```、```set```。可作为线程执行函数的参数传入线程环境。 |


### threading

```threading```对象作为全局多线程管理工具,提供了创建并发线程、线程锁、条件对象等功能;本章节介绍```threading```对象的成员函数;仅```JavaScript```语言策略支持该对象。


### Thread

```Thread()```函数用于创建并发线程。


```Thread()```函数返回一个```Thread```对象,用于管理创建出的并发线程、线程通信等。

```Thread```对象


Thread(func, ...args)
Thread(...items)

参数```func```是用于并发执行的函数(通过引用传递),支持传入匿名函数。```func```可接受多个参数,这些参数将在并发执行时通过```...args```传入。因此,```func```的参数列表需要与```...args```一致。

func
true
function
参数```arg```是在回调执行时传递给```func```(即并发线程执行函数)的实际参数;参数```arg```可能有多个,```func```的参数列表需要与```...args```一致。

arg
false
string、number、bool、object、array、function、空值等系统支持的所有类型
参数```item```是一个数组,包含待并发执行的函数引用及其参数,调用```Thread```函数时的参数```item```可以传入多组。

item
true
array

```javascript
function test1(a, b, c) {
    Log("test1:", a, b, c)
}

function main() {
    var t1 = threading.Thread(test1, 1, 2, 3)
    var t2 = threading.Thread(function (msg) {
        Log("msg:", msg)
    }, "Hello thread2")

    t1.join()
    t2.join()
}

同时创建一个自定义函数和一个匿名函数的并发线程。

function test1(msg) {
    Log("msg:", msg)
    test2("Hello test2")
}

function main() {
    var t1 = threading.Thread(
        [function(a, b, c) {Log(a, b, c)}, 1, 2, 3], 
        [test1, "Hello test1"], 
        [`function test2(msg) {Log("msg:", msg)}`])

    t1.join()
}

使用Thread(...items)形式来创建并发线程,顺序执行多个函数。

function testFunc1(p) {
    Log("testFunc1 p:", p)
}

function main() {
    threading.Thread(function(pfn) {
        var threadName = threading.currentThread().name()
        var threadId = threading.currentThread().id()
        pfn(`in thread threadName: ${threadName}, threadId: ${threadId}`)
    }, testFunc1).join()
}

支持向并发执行函数的参数传入函数。

function ml(input) {
    const net = new brain.NeuralNetwork()
    net.train([
        { input: [0, 0], output: [0] },
        { input: [0, 1], output: [1] },
        { input: [1, 0], output: [1] },
        { input: [1, 1], output: [0] },
    ])
    return net.run(input)
}

function main() {
    var ret = threading.Thread([ml, [1, 0]], [HttpQuery("https://unpkg.com/brain.js")]).join()

    // ret: {"id":1,"terminated":false,"elapsed":337636000,"ret":{"0":0.9339330196380615}}
    Log(ret)
}

支持传入函数字符串,可以动态导入外部库进行并发计算。

传入Thread()函数用于并发执行的线程函数func运行在隔离环境中,因此无法直接引用线程外部的变量,引用时会编译失败。同时,线程内不支持引用其它闭包函数。线程内部可调用平台提供的所有API,但不能调用用户自定义的其他函数。

当线程执行完毕且没有被持续引用时,系统底层会自动回收线程相关的资源,不需要显式调用join()函数来释放资源。如果有持续引用导致无法释放资源,并发数量超过2000个会报错:InternalError: too many routine wait, max is 2000

支持回测系统、实盘环境;所有并发线程相关的函数,在回测系统中仅作为代码兼容支持,实际不会真正并发线程执行,本章不再赘述。

{@fun/Threads/threading/getThread getThread}, {@fun/Threads/threading/mainThread mainThread}, {@fun/Threads/threading/currentThread currentThread}, {@fun/Threads/threading/Lock Lock}, {@fun/Threads/threading/Condition Condition}, {@fun/Threads/threading/Event Event}, {@fun/Threads/threading/Dict Dict}, {@fun/Threads/threading/pending pending}, {@fun/Threads/threading/eventLoop eventLoop}

getThread



```getThread()```函数返回通过参数指定threadId的```Thread```对象

```Thread```对象


getThread(threadId)

参数```threadId```为线程对象Id,通过指定参数获取对应的线程对象。

threadId
true
number

```javascript
function main() {
    var t1 = threading.Thread(function () {
        // Thread 对象有方法:id(),用于获取线程的Id,可以查看文档对应Thread对象的章节
        var id = threading.currentThread().id()
        var thread1 = threading.getThread(id)
        
        Log("id:", id, ", thread1.id():", thread1.id())
        Log(`id == thread1.id():`, id == thread1.id())
    })
    t1.join()
}

通过threadId获取指定的线程对象。

支持回测系统、实盘环境。

如果期望获取的线程已经执行完毕、释放,此时无法通过threading.getThread(threadId)获取该线程的线程对象。

{@fun/Threads/threading/Thread Thread}, {@fun/Threads/threading/mainThread mainThread}, {@fun/Threads/threading/currentThread currentThread}, {@fun/Threads/threading/Lock Lock}, {@fun/Threads/threading/Condition Condition}, {@fun/Threads/threading/Event Event}, {@fun/Threads/threading/Dict Dict}, {@fun/Threads/threading/pending pending}, {@fun/Threads/threading/eventLoop eventLoop}

mainThread



```mainThread()```函数返回主线程的线程对象。

```Thread```对象


mainThread()

```javascript
function main() {
    Log("主线程的threadId:", threading.mainThread().id())
}

获取主线程的Thread对象,输出主线程的threadId

function test() {
    Log("test函数中输出主线程Id:", threading.mainThread().id())
}

function main() {
    var t1 = threading.Thread(test)
    t1.join()
}

在并发的线程中也可以获取主线程的线程对象。

支持回测系统、实盘环境。

{@fun/Threads/threading/getThread getThread}, {@fun/Threads/threading/Thread Thread}, {@fun/Threads/threading/currentThread currentThread}, {@fun/Threads/threading/Lock Lock}, {@fun/Threads/threading/Condition Condition}, {@fun/Threads/threading/Event Event}, {@fun/Threads/threading/Dict Dict}, {@fun/Threads/threading/pending pending}, {@fun/Threads/threading/eventLoop eventLoop}

currentThread



```currentThread()```函数返回当前线程的线程对象。

```Thread```对象


currentThread()

```javascript
function test() {
    Log("当前线程的Id:", threading.currentThread().id())
}

function main() {
    var t1 = threading.Thread(test)
    t1.join()
}

获取当前线程的Thread对象,输出当前线程的threadId

支持回测系统、实盘环境。

{@fun/Threads/threading/Thread Thread}, {@fun/Threads/threading/mainThread mainThread}, {@fun/Threads/threading/Thread Thread}, {@fun/Threads/threading/Lock Lock}, {@fun/Threads/threading/Condition Condition}, {@fun/Threads/threading/Event Event}, {@fun/Threads/threading/Dict Dict}, {@fun/Threads/threading/pending pending}, {@fun/Threads/threading/eventLoop eventLoop}

Lock



```Lock()```函数返回一个线程锁对象。

```ThreadLock```对象


Lock()

```javascript
function consumer(productionQuantity, dict, lock) {
    for (var i = 0; i < productionQuantity; i++) {
        lock.acquire()
        var count = dict.get("count")        
        Log("consumer:", count)
        Sleep(1000)
        lock.release()
    }
}

function producer(productionQuantity, dict, lock) {
    for (var i = 0; i < productionQuantity; i++) {
        lock.acquire()
        dict.set("count", i)
        Log("producer:", i)
        Sleep(1000)
        lock.release()
    }
}

function main() {
    var dict = threading.Dict()
    dict.set("count", -1)
    var lock = threading.Lock()
    var productionQuantity = 10
    var producerThread = threading.Thread(producer, productionQuantity, dict, lock)
    var consumerThread = threading.Thread(consumer, productionQuantity, dict, lock)

    consumerThread.join()
    producerThread.join()
}

两个并发线程访问公共资源。

支持回测系统、实盘环境。

{@fun/Threads/threading/getThread getThread}, {@fun/Threads/threading/mainThread mainThread}, {@fun/Threads/threading/currentThread currentThread}, {@fun/Threads/threading/Thread Thread}, {@fun/Threads/threading/Condition Condition}, {@fun/Threads/threading/Event Event}, {@fun/Threads/threading/Dict Dict}, {@fun/Threads/threading/pending pending}, {@fun/Threads/threading/eventLoop eventLoop}

Condition



```Condition()```函数返回一个```ThreadCondition```对象。

```ThreadCondition```对象


Condition()

```javascript
function consumer(productionQuantity, dict, condition) {
    for (var i = 0; i < productionQuantity; i++) {
        condition.acquire()
        while (dict.get("array").length == 0) {
            condition.wait()
        }
        var arr = dict.get("array")
        var count = arr.shift()
        dict.set("array", arr)
        Log("consumer:", count, ", array:", arr)
        condition.release()
        Sleep(1000)
    }
}

function producer(productionQuantity, dict, condition) {
    for (var i = 0; i < productionQuantity; i++) {
        condition.acquire()
        var arr = dict.get("array")
        arr.push(i)
        dict.set("array", arr)
        Log("producer:", i, ", array:", arr)
        condition.notify()
        condition.release()
        Sleep(1000)
    }
}

function main() {
    var dict = threading.Dict()
    dict.set("array", [])
    var condition = threading.Condition()
    var productionQuantity = 10
    var producerThread = threading.Thread(producer, productionQuantity, dict, condition)
    var consumerThread = threading.Thread(consumer, productionQuantity, dict, condition)
    consumerThread.join()
    producerThread.join()
}

两个并发线程访问公共资源。

回测系统没有实现该功能,仅仅是定义。

{@fun/Threads/threading/getThread getThread}, {@fun/Threads/threading/mainThread mainThread}, {@fun/Threads/threading/currentThread currentThread}, {@fun/Threads/threading/Lock Lock}, {@fun/Threads/threading/Thread Thread}, {@fun/Threads/threading/Event Event}, {@fun/Threads/threading/Dict Dict}, {@fun/Threads/threading/pending pending}, {@fun/Threads/threading/eventLoop eventLoop}

Event



```Event()```函数返回一个```ThreadEvent```对象。

```ThreadEvent```对象


Event()

```javascript
function consumer(productionQuantity, dict, pEvent, cEvent) {
    for (var i = 0; i < productionQuantity; i++) {
        while (dict.get("array").length == 0) {
            pEvent.wait()
        }
        if (pEvent.isSet()) {
            pEvent.clear()
        }

        var arr = dict.get("array")
        var count = arr.shift()
        dict.set("array", arr)
        Log("consumer:", count, ", array:", arr)
        cEvent.set()
        Sleep(1000)
    }
}

function producer(productionQuantity, dict, pEvent, cEvent) {
    for (var i = 0; i < productionQuantity; i++) {
        while (dict.get("array").length != 0) {
            cEvent.wait()
        }
        if (cEvent.isSet()) {
            cEvent.clear()
        }

        var arr = dict.get("array")
        arr.push(i)
        dict.set("array", arr)
        Log("producer:", i, ", array:", arr)        
        pEvent.set()       
        Sleep(1000)
    }
}

function main() {    
    var dict = threading.Dict()
    dict.set("array", [])
    var pEvent = threading.Event()
    var cEvent = threading.Event()
    var productionQuantity = 10
    var producerThread = threading.Thread(producer, productionQuantity, dict, pEvent, cEvent)
    var consumerThread = threading.Thread(consumer, productionQuantity, dict, pEvent, cEvent)

    consumerThread.join()
    producerThread.join()
}

两个并发线程访问公共资源。

支持回测系统、实盘环境。

{@fun/Threads/threading/getThread getThread}, {@fun/Threads/threading/mainThread mainThread}, {@fun/Threads/threading/currentThread currentThread}, {@fun/Threads/threading/Lock Lock}, {@fun/Threads/threading/Condition Condition}, {@fun/Threads/threading/Thread Thread}, {@fun/Threads/threading/Dict Dict}, {@fun/Threads/threading/pending pending}, {@fun/Threads/threading/eventLoop eventLoop}

Dict



```Dict()```函数返回一个```ThreadDict```对象。

```ThreadDict```对象


Dict()

```javascript
function threadFun1(obj) {
    obj["age"] = 100
    while (true) {
        Log("threadFun1 obj:", obj)
        Sleep(5000)
    }
}

function threadFun2(obj) {
    while (true) {
        Log("threadFun2 obj:", obj)
        Sleep(5000)
    }
}

function main() {
    var obj = {"age": 10}
    var t1 = threading.Thread(threadFun1, obj)
    var t2 = threading.Thread(threadFun2, obj)
    t1.join()
    t2.join()    
}

给并发的线程执行函数传入普通的对象,测试修改对象的键值后是否引起其它线程中的对象键值变动。

function threadFun1(threadDict) {
    threadDict.set("age", 100)
    while (true) {
        Log(`threadFun1 threadDict.get("age"):`, threadDict.get("age"))
        Sleep(5000)
    }
}

function threadFun2(threadDict) {
    while (true) {
        Log(`threadFun2 threadDict.get("age"):`, threadDict.get("age"))
        Sleep(5000)
    }
}

function main() {
    var threadDict = threading.Dict()
    threadDict.set("age", 10)
    var t1 = threading.Thread(threadFun1, threadDict)
    var t2 = threading.Thread(threadFun2, threadDict)

    t1.join()
    t2.join()    
}

给并发的线程执行函数传入Dict()函数创建的ThreadDict对象,测试修改对象的键值后是否引起其它线程中的对象键值变动。

线程并发函数传入普通对象时为深拷贝传递,在并发线程中修改键值,并不会影响到其它线程中的字典。

支持回测系统、实盘环境。

{@fun/Threads/threading/getThread getThread}, {@fun/Threads/threading/mainThread mainThread}, {@fun/Threads/threading/currentThread currentThread}, {@fun/Threads/threading/Lock Lock}, {@fun/Threads/threading/Condition Condition}, {@fun/Threads/threading/Event Event}, {@fun/Threads/threading/Thread Thread}, {@fun/Threads/threading/pending pending}, {@fun/Threads/threading/eventLoop eventLoop}

pending



```pending()```函数返回当前策略程序正在运行的并发线程数。

number

pending()

```javascript
function threadFun1() {
    Log("threadFun1")
    Sleep(3000)
}

function threadFun2() {
    for (var i = 0; i < 3; i++) {
        LogStatus(_D(), "print from threadFun2")
        Sleep(3000)
    }
}

function main() {
    Log(`begin -- threading.pending():`, threading.pending())

    var t1 = threading.Thread(threadFun1)
    var t2 = threading.Thread(threadFun2)
    Log(`after threading.Thread -- threading.pending():`, threading.pending())

    t1.join()
    t2.join()
    Log(`after thread.join -- threading.pending():`, threading.pending())
}

创建两个并发运行的线程,在不同时间节点调用pending()函数。

策略main()函数开始运行时直接调用pending()函数会返回1,因为策略main()函数所在的主线程也是一个pending中的线程。

支持回测系统、实盘环境。

{@fun/Threads/threading/getThread getThread}, {@fun/Threads/threading/mainThread mainThread}, {@fun/Threads/threading/currentThread currentThread}, {@fun/Threads/threading/Lock Lock}, {@fun/Threads/threading/Condition Condition}, {@fun/Threads/threading/Event Event}, {@fun/Threads/threading/Dict Dict}, {@fun/Threads/threading/Thread Thread}, {@fun/Threads/threading/eventLoop eventLoop}

Thread



### peekMessage

```peekMessage()```函数用于从线程获取消息。


```peekMessage()```函数返回当前线程对象关联的线程收到的消息。

string、number、bool、object、array、空值等系统支持的所有类型


peekMessage()
peekMessage(timeout)

参数```timeout```为超时设置,会按照该参数设置的毫秒数阻塞等待,返回数据;没有数据并且超时则返回空值。如果```timeout```设置为0或者不传```timeout```参数,则表示一直阻塞等待,直到接收到通道中的数据。如果```timeout```设置为-1,则表示不阻塞并且立即返回数据,没有数据时返回空值。

timeout
false
number

```javascript
function main() {
    var t1 = threading.Thread(function() {
        for (var i = 0; i < 10; i++) {
            Log("thread1 postMessage():", i)
            threading.mainThread().postMessage(i)
            Sleep(500)
        }        
    })

    while (true) {
        var msg = threading.currentThread().peekMessage()
        Log("main peekMessage():", msg)
        if (msg == 9) {
            break
        }
        Sleep(1000)
    }

    t1.join()
}

并发线程中向主线程发送消息。

在编写程序时需要注意线程死锁问题。

{@fun/Threads/Thread/postMessage postMessage}, {@fun/Threads/Thread/join join}, {@fun/Threads/Thread/terminate terminate}, {@fun/Threads/Thread/getData getData}, {@fun/Threads/Thread/setData setData}, {@fun/Threads/Thread/id id}, {@fun/Threads/Thread/name name}, {@fun/Threads/Thread/eventLoop eventLoop}

postMessage



postMessage(msg)

参数```msg```为所要发送的消息。

msg
true
string、number、bool、object、array、function、空值等系统支持的任意类型

```javascript
function main() {
    var t1 = threading.Thread(function() {
        for (var i = 0; i < 10; i++) {
            Log("thread1 postMessage():", i)
            threading.mainThread().postMessage(i)
            Sleep(500)
        }        
    })
    for (var i = 0; i < 10; i++) {
        var event = threading.mainThread().eventLoop()
        Log("main event:", event)
        Sleep(500)
    }
    t1.join()
}

在并发的线程中发送消息,使用eventLoop()接收消息通知。

function main() {
    threading.mainThread().postMessage(function(msg) {
        Log("func from mainThread, msg:", msg)
    })
    
    threading.Thread(function() {
        var func = threading.mainThread().peekMessage()
        func("in " + threading.currentThread().name())
    }).join()
}

支持发送一个函数。

当一个线程的执行函数中调用postMessage()函数发出信号、数据时,也会产生消息事件。 可以用eventLoop()函数收到消息通知。

{@fun/Threads/Thread/peekMessage peekMessage}, {@fun/Threads/Thread/join join}, {@fun/Threads/Thread/terminate terminate}, {@fun/Threads/Thread/getData getData}, {@fun/Threads/Thread/setData setData}, {@fun/Threads/Thread/id id}, {@fun/Threads/Thread/name name}, {@fun/Threads/Thread/eventLoop eventLoop}

join



[```ThreadRet```对象](https://www.fmz.com/syntax-guide/struct/otherstruct/Thread.join-return)包含执行结果的相关数据,包含的属性如下:

- id: 线程Id。
- terminated: 线程是否被强制结束。
- elapsed: 线程的运行时间(纳秒)。
- ret: 线程函数的返回值。

```ThreadRet```对象


join()
join(timeout)

```timeout```参数用于设置等待线程结束的超时时间,单位为毫秒。```timeout```参数设置为0或者不设置```timeout```参数时```join()```函数会阻塞,等待到线程执行结束。```timeout```参数设置为-1时,```join()```函数会立即返回。

timeout
false
number

```javascript
function main() {
    var t1 = threading.Thread(function() {
        Log("Hello thread1")
        Sleep(5000)
    })

    var ret = t1.join(1000)
    Log("ret:", ret)   // ret: undefined

    ret = t1.join()
    Log("ret:", ret)   // ret: {"id":1,"terminated":false,"elapsed":5003252000}
}

测试join()函数超时,输出返回值。



{@fun/Threads/Thread/peekMessage peekMessage}, {@fun/Threads/Thread/postMessage postMessage}, {@fun/Threads/Thread/terminate terminate}, {@fun/Threads/Thread/getData getData}, {@fun/Threads/Thread/setData setData}, {@fun/Threads/Thread/id id}, {@fun/Threads/Thread/name name}, {@fun/Threads/Thread/eventLoop eventLoop}

### terminate

```terminate()```函数用于强制结束线程,释放创建线程使用的硬件资源。


terminate()

```javascript
function main() {
    var t1 = threading.Thread(function() {
        for (var i = 0; i < 10; i++) {
            Log("thread1 i:", i)
            Sleep(1000)
        }
    })

    Sleep(3000)
    t1.terminate()
    Log("after t1.terminate()")

    while (true) {
        LogStatus(_D())
        Sleep(1000)
    }
}

强制终止一个线程的执行,在强制终止一个线程之后,日志中不再有这个线程输出的内容。

对于terminate()函数强制结束的线程,无法再使用join()函数等待结束。

{@fun/Threads/Thread/peekMessage peekMessage}, {@fun/Threads/Thread/postMessage postMessage}, {@fun/Threads/Thread/join join}, {@fun/Threads/Thread/getData getData}, {@fun/Threads/Thread/setData setData}, {@fun/Threads/Thread/id id}, {@fun/Threads/Thread/name name}, {@fun/Threads/Thread/eventLoop eventLoop}

getData



```getData()```函数返回当前线程环境中储存的键-值对中```key```参数对应的键值。

string、number、bool、object、array、空值等系统支持的所有类型


getData()
getData(key)

```key```参数为储存的键-值对的键名。

key
true
string

```javascript
function main() {
    var t1 = threading.Thread(function() {
        for (var i = 0; i < 5; i++) {
            threading.currentThread().setData("count", i)
            Log(`setData("count"):`, i)
            Sleep(1000)
        }
    })
    for (var i = 0; i < 5; i++) {
        var count = threading.getThread(t1.id()).getData("count")
        Log(`getData("count"):`, count)
        Sleep(1000)
    }
    t1.join()
}

在并发线程的环境中记录键名为count的值,然后在主线程中读取count的键值。

{@fun/Threads/Thread/peekMessage peekMessage}, {@fun/Threads/Thread/postMessage postMessage}, {@fun/Threads/Thread/join join}, {@fun/Threads/Thread/terminate terminate}, {@fun/Threads/Thread/setData setData}, {@fun/Threads/Thread/id id}, {@fun/Threads/Thread/name name}, {@fun/Threads/Thread/eventLoop eventLoop}

setData



setData(key, value)

```key```参数用于指定储存的键-值对的键名。

key
true
string
```value```参数用于指定储存的键-值对的键值。

value
true
string、number、bool、object、array、function、空值等系统支持的任意类型

```javascript
function main() {
    var t1 = threading.Thread(function() {
        threading.currentThread().setData("data", 100)
    })
    Sleep(1000)
    Log(`t1.getData("data"):`, t1.getData("data"))
    t1.join()
}

并发的线程中设置键值对,主线程中读取这个键值对。

function main() {
    threading.mainThread().setData("func2", function(p) {
        Log("func2 p:", p)
    })
    
    var t1 = threading.Thread(function() {
        threading.currentThread().setData("func1", function(p) {
            Log("func1 p:", p)
        })
    
        var func2 = threading.mainThread().getData("func2")
        func2("test2")
    })
    
    Sleep(1000)
    var func1 = t1.getData("func1")
    func1("test1")
    t1.join()
}

支持键值传入函数。

数据在线程没有被执行join()函数(等待退出成功)并且没有被执行terminate()函数(强制终止线程)的情况下有效。参数value的值必须是可序列化的变量。

{@fun/Threads/Thread/peekMessage peekMessage}, {@fun/Threads/Thread/postMessage postMessage}, {@fun/Threads/Thread/join join}, {@fun/Threads/Thread/terminate terminate}, {@fun/Threads/Thread/getData getData}, {@fun/Threads/Thread/id id}, {@fun/Threads/Thread/name name}, {@fun/Threads/Thread/eventLoop eventLoop}

id



```id()```函数的返回值为```threadId```。

number


id()

```javascript
function main() {
    var t1 = threading.Thread(function() {
        threading.currentThread().setData("data", 100)
    })
    Log(`t1.id():`, t1.id())
    t1.join()
}

创建一个并发运行的线程,在主线程输出这个并发线程的threadId

{@fun/Threads/Thread/peekMessage peekMessage}, {@fun/Threads/Thread/postMessage postMessage}, {@fun/Threads/Thread/join join}, {@fun/Threads/Thread/terminate terminate}, {@fun/Threads/Thread/getData getData}, {@fun/Threads/Thread/setData setData}, {@fun/Threads/Thread/name name}, {@fun/Threads/Thread/eventLoop eventLoop}

name



```name()```函数返回值为并发的线程名称。

string


name()

```javascript
function main() {
    var t1 = threading.Thread(function() {
        threading.currentThread().setData("data", 100)
    })
    Log(`t1.name():`, t1.name())  // t1.name(): Thread-1
    t1.join()
}

创建一个并发运行的线程,在主线程输出这个并发线程的名称。

{@fun/Threads/Thread/peekMessage peekMessage}, {@fun/Threads/Thread/postMessage postMessage}, {@fun/Threads/Thread/join join}, {@fun/Threads/Thread/terminate terminate}, {@fun/Threads/Thread/getData getData}, {@fun/Threads/Thread/setData setData}, {@fun/Threads/Thread/id id}, {@fun/Threads/Thread/eventLoop eventLoop}

eventLoop



```eventLoop()```函数返回当前线程收到的事件信息,查看[事件信息结构](https://www.fmz.com/syntax-guide/struct/otherstruct/eventloop-return)。

object、空值


eventLoop()
eventLoop(timeout)

参数```timeout```为超时设置,单位为毫秒。参数```timeout```如果设置为0则等待有事件发生才返回,如果大于0就是设置事件等待超时,小于0立即返回最近事件。

timeout
false
number

```javascript
function main() {
    var t1 = threading.Thread(function() {
        while (true) {
            var eventMsg = threading.currentThread().eventLoop()     // 阻塞等待
            // 2024-11-14 10:14:18 thread1 eventMsg: {"Seq":1,"Event":"thread","ThreadId":0,"Index":1,"Queue":0,"Nano":1731550458699947000}
            Log(_D(), "thread1 eventMsg:", eventMsg)
        }
    })

    var t2 = threading.Thread(function() {
        while (true) {
            var eventMsg = threading.currentThread().eventLoop(-1)   // 立即返回
            Log(_D(), "thread2 eventMsg:", eventMsg)
            Sleep(5000)
        }
    })

    var t3 = threading.Thread(function() {
        while (true) {
            var eventMsg = threading.currentThread().eventLoop(3000) // 设置3秒超时
            Log(_D(), "thread3 eventMsg:", eventMsg)
        }
    })

    t1.postMessage("Hello ", t1.name())
    t2.postMessage("Hello ", t2.name())
    t3.postMessage("Hello ", t3.name())
    t1.join()
    t2.join()
    t3.join()
}

并发执行3个线程,输出接收到的事件信息,超时或者立即返回时输出的是空值。



{@fun/Threads/Thread/peekMessage peekMessage}, {@fun/Threads/Thread/postMessage postMessage}, {@fun/Threads/Thread/join join}, {@fun/Threads/Thread/terminate terminate}, {@fun/Threads/Thread/getData getData}, {@fun/Threads/Thread/setData setData}, {@fun/Threads/Thread/id id}, {@fun/Threads/Thread/name name}

### ThreadLock

线程锁对象,用于多线程同步处理。


### acquire

```acquire()```函数用于请求一个线程锁(加锁)。


acquire()

范例可以参考```threading.Lock()```章节的内容。


```acquire()```函数用于请求一个线程锁。当一个线程调用某个线程锁对象的```acquire()```函数时,它会尝试获取锁,如果锁当前没有被其它线程占用,调用线程就会成功获得锁并继续执行。如果锁已经被其它线程持有,调用```acquire()```的线程会被阻塞,直到锁被释放。


{@fun/Threads/threading/Lock Lock}, {@fun/Threads/ThreadLock/release release}

### release

```release()```函数用于释放一个线程锁(解锁)。


release()

```javascript
function consumer(productionQuantity, dict, pLock, cLock) {
    for (var i = 0; i < productionQuantity; i++) {
        pLock.acquire()
        cLock.acquire()
        var arr = dict.get("array")
        var count = arr.shift()
        dict.set("array", arr)
        Log("consumer:", count, ", array:", arr)
        cLock.release()
        Sleep(1000)
        pLock.release()
    }
}

function producer(productionQuantity, dict, pLock, cLock) {
    for (var i = 0; i < productionQuantity; i++) {
        cLock.acquire()   // cLock.acquire() 放在 pLock.acquire() 后不会产生死锁
        pLock.acquire()   
        var arr = dict.get("array")
        arr.push(i)
        dict.set("array", arr)
        Log("producer:", i, ", array:", arr)
        pLock.release()
        Sleep(1000)
        cLock.release()
    }
}

function main() {
    var dict = threading.Dict()
    dict.set("array", [])
    var pLock = threading.Lock()
    var cLock = threading.Lock()
    var productionQuantity = 10
    var producerThread = threading.Thread(producer, productionQuantity, dict, pLock, cLock)
    var consumerThread = threading.Thread(consumer, productionQuantity, dict, pLock, cLock)

    consumerThread.join()
    producerThread.join()
}

测试死锁场景

需要注意,线程锁使用不当可能导致死锁。

{@fun/Threads/threading/Lock Lock}, {@fun/Threads/ThreadLock/acquire acquire}

ThreadEvent

事件对象,用于多线程事件通知、信号。

set



set()

可以参考```threading.Event()```章节范例。


如果已经```set()```设置过,不能重复设置,需要清空之后重新设置信号。


{@fun/Threads/ThreadEvent/clear clear}, {@fun/Threads/ThreadEvent/wait wait}, {@fun/Threads/ThreadEvent/isSet isSet}

### clear

```clear()```函数用于清理信号。


clear()

可以参考```threading.Event()```章节范例。


{@fun/Threads/ThreadEvent/set set}, {@fun/Threads/ThreadEvent/wait wait}, {@fun/Threads/ThreadEvent/isSet isSet}

### wait

```wait()```函数用于设置事件(信号)等待,在事件(信号)被设置之前会阻塞;支持设置超时参数。


```wait()```函数返回是否超时,如果超时返回真值。

bool


wait()
wait(timeout)

参数```timeout```用于设置等待超时,单位毫秒。

timeout
false
number

```javascript
function main() {
    var event = threading.Event()
    var t1 = threading.Thread(function(event) {
        var ret = event.wait(100)
        Log(`event.wait(100):`, ret)
        ret = event.wait()
        Log(`event.wait():`, ret)
    }, event)

    Sleep(1000)
    event.set()
    t1.join()
}

测试wait()函数的返回值。

{@fun/Threads/ThreadEvent/set set}, {@fun/Threads/ThreadEvent/clear clear}, {@fun/Threads/ThreadEvent/isSet isSet}

isSet



```isSet()```函数返回是否已经设置了事件(信号);如果当前已经设置过事件(信号)则返回真值。

bool


isSet()

可以参考```threading.Event()```章节范例。


{@fun/Threads/ThreadEvent/set set}, {@fun/Threads/ThreadEvent/clear clear}, {@fun/Threads/ThreadEvent/wait wait}

### ThreadCondition

条件对象,用于多线程同步。


### notify

```notify()```函数用于唤醒一个正在等待的线程(如果有的话)。只有调用了```wait()```方法的线程才会被唤醒。


notify()

```javascript
function consumer(dict, condition) {
    while (true) {
        condition.acquire()
        while (dict.get("array").length == 0) {
            Log(threading.currentThread().name(), "wait()...", ", array:", dict.get("array"))
            condition.wait()
        }
        var arr = dict.get("array")
        var num = arr.shift()
        Log(threading.currentThread().name(), ", num:", num, ", array:", arr, "#FF0000")
        dict.set("array", arr)
        Sleep(1000)
        condition.release()
    }
}

function main() {
    var condition = threading.Condition()
    var dict = threading.Dict()
    dict.set("array", [])
    var t1 = threading.Thread(consumer, dict, condition)
    var t2 = threading.Thread(consumer, dict, condition)
    var t3 = threading.Thread(consumer, dict, condition)
    Sleep(1000)
    var i = 0
    while (true) {
        condition.acquire()
        var msg = ""
        var arr = dict.get("array")
        var randomNum = Math.floor(Math.random() * 5) + 1
        if (arr.length >= 3) {
            condition.notifyAll()
            msg = "notifyAll"
        } else {
            arr.push(i)
            dict.set("array", arr)
            if (randomNum > 3 && arr.length > 0) {
                condition.notify()
                msg = "notify"
            } else {
                msg = "pass"
            }
            i++
        }

        Log(_D(), "randomNum:", randomNum, ", array:", arr, ", msg:", msg)
        condition.release()
        Sleep(1000)
    }
}

使用notify()函数唤醒等待中的线程。


```notify()```函数唤醒一个线程时,这个线程会重新获取线程锁。


{@fun/Threads/ThreadCondition/notifyAll notifyAll}, {@fun/Threads/ThreadCondition/wait wait},  {@fun/Threads/ThreadCondition/acquire acquire}, {@fun/Threads/ThreadCondition/release release}

### notifyAll

```notifyAll()```函数会唤醒所有正在等待的线程。


notifyAll()

范例可以参考```ThreadCondition.notify()```章节的内容。


```notifyAll()```函数逐个唤醒所有等待中的线程,被唤醒的线程重新获取线程锁。


{@fun/Threads/ThreadCondition/notify notify}, {@fun/Threads/ThreadCondition/wait wait},  {@fun/Threads/ThreadCondition/acquire acquire}, {@fun/Threads/ThreadCondition/release release}

### wait

```wait()```函数用于在某些设计的条件下让线程等待。


wait()

范例可以参考```ThreadCondition.notify()```章节的内容。


```wait()```函数会释放线程锁,当被唤醒时重新获取线程锁。


{@fun/Threads/ThreadCondition/notify notify}, {@fun/Threads/ThreadCondition/notifyAll notifyAll}, {@fun/Threads/ThreadCondition/acquire acquire}, {@fun/Threads/ThreadCondition/release release}

### acquire

```acquire()```函数用于请求一个线程锁(加锁)。


acquire()

范例可以参考```ThreadCondition.notify()```章节的内容。


在使用```wait()```之前需要请求当前条件对象的线程锁(加锁)。


{@fun/Threads/ThreadCondition/notify notify}, {@fun/Threads/ThreadCondition/notifyAll notifyAll}, {@fun/Threads/ThreadCondition/wait wait},  {@fun/Threads/ThreadCondition/release release}

### release

```release()```函数用于释放一个线程锁(解锁)。


release()

范例可以参考```ThreadCondition.notify()```章节的内容。


在使用```wait()```之后需要释放当前条件对象的线程锁(解锁)。


{@fun/Threads/ThreadCondition/notify notify}, {@fun/Threads/ThreadCondition/notifyAll notifyAll}, {@fun/Threads/ThreadCondition/wait wait},  {@fun/Threads/ThreadCondition/acquire acquire}

### ThreadDict

字典对象,用于数据共享。


### get

```get()```函数用于获取字典对象中记录的键值。


```get()```函数返回通过参数```key```指定的键值。

string、number、bool、object、array、空值等系统支持的所有类型


get(key)

参数```key```用于指定要获取的键对应的键名。

key
true
string

```javascript
function main() {
    var event = threading.Event()
    var dict = threading.Dict()
    dict.set("data", 100)
    
    var t1 = threading.Thread(function(dict, event) {
        Log(`thread1, dict.get("data"):`, dict.get("data"))
        
        event.set()
        event.clear()
        
        event.wait()
        Log(`after main change data, thread1 dict.get("data"):`, dict.get("data"))
    
        dict.set("data", 0)
    }, dict, event)
    
    event.wait()
    
    dict.set("data", 99)
    
    event.set()
    event.clear()
    
    t1.join()
    Log(`main thread, dict.get("data"):`, dict.get("data"))
}

使用事件对象通知线程读取、修改数据。

{@fun/Threads/ThreadDict/set set}

set



set(key, value)

参数```key```用于设置需要修改的键名。

key
true
string
参数```value```用于设置需要修改的键值。

value
true
string、number、bool、object、array、function、空值等系统支持的所有类型

```javascript
function main() {
    var dict1 = threading.Dict()
    dict1.set("func1", function(p) {
        Log("func1 p:", p)
    })
    
    threading.Thread(function(dict1) {
        var func1 = dict1.get("func1")
        func1("test")
    }, dict1).join()
}

支持键值传入函数。

{@fun/Threads/ThreadDict/get get}

Web3

exchange.IO(“abi”, …)

在发明者量化交易平台主要通过exchange.IO()函数实现区块链相关的各种功能、调用。 以下文档把exchange.IO()函数根据其功能分别描述。 exchange.IO("abi", ...)函数的调用方式用于注册ABI。

exchange.IO(k, address, abiContent)

k
true
string
```address```参数用于指定智能合约的地址。
address
true
string
```abiContent```参数用于指定智能合约的```ABI```。
abiContent
true
string

```javascript
function main() {
    // register Uniswap SwapRouter02 abi
    var routerAddress = "0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45"
    var abi = `[{"inputs":[{"components":[{"internalType":"bytes","name":"path","type":"bytes"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"amountInMaximum","type":"uint256"}],"internalType":"struct IV3SwapRouter.ExactOutputParams","name":"params","type":"tuple"}],"name":"exactOutput","outputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"}],"stateMutability":"payable","type":"function"}]`
    
    // abi只使用了局部的exactOutput方法的内容,完整的abi可以在网上搜索
    exchange.IO("abi", routerAddress, abi)
}

调用的智能合约方法如果是标准ERC20方法,则不需要注册。 获取合约的ABI内容可以通过下面URL获取,只取result字段,例如:

https://api.etherscan.io/api?module=contract&action=getabi&address=0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45

exchange.IO(“api”, “eth”, …)


```exchange.IO("api", "eth", ...)```函数返回调用的RPC方法的返回值。
string、number、bool、object、array、空值等系统支持的所有类型

exchange.IO(k, blockChain, rpcMethod)
exchange.IO(k, blockChain, rpcMethod, ...args)

```k```参数用于设置```exchange.IO()```函数的功能,设置为```"api"```表示该函数用于扩展调用请求。
k
true
string
```blockChain```参数用于设置```exchange.IO()```函数的功能,设置为```"eth"```表示该函数用于以太坊网络的RPC方法调用。
blockChain
true
string
```rpcMethod```参数用于设置```exchange.IO()```函数调用的RPC方法。
rpcMethod
true
string
```arg```参数用于指定所要调用的RPC方法的参数。 ```arg```参数可能有多个,```arg```参数的类型与个数根据```rpcMethod```参数指定的RPC方法而定。
arg
false
string、number、bool、object、array、function、空值等系统支持的所有类型

```javascript
function main() {
    // "owner" 需要替换为具体钱包地址
    // "latest"字符串位置的参数标签:'latest'、'earliest'或'pending',参考https://eth.wiki/json-rpc/API#the-default-block-parameter
    // 返回值 ethBalance 为十六进制字符串:0x9b19ce56113070
    var ethBalance = exchange.IO("api", "eth", "eth_getBalance", "owner", "latest")              

    // ETH的精度单位为1e18
    var ethDecimal = 18              

    // 由于JavaScript语言精度原因,需要使用系统底层封装的函数BigInt、BigDecimal处理
    // 将ethBalance转换为可读数量,0x9b19ce56113070转换为0.043656995388076145
    Log(Number((BigDecimal(BigInt(ethBalance))/BigDecimal(Math.pow(10, ethDecimal))).toString()))
}

查询钱包中ETH的余额:

function mian() {
    // ETH的精度单位为1e18
    var ethDecimal = 18  

    // 转账数量,可读的数量例如:0.01个ETH
    var sendAmount = 0.01  

    // 由于JavaScript语言精度原因,需要使用系统底层封装的函数BigInt、BigDecimal处理,并且将可读数量转换为链上处理的数据
    var toAmount = (BigDecimal(sendAmount)*BigDecimal(Math.pow(10, ethDecimal))).toFixed(0)
    
    // "toAddress"为转账时接收方的ETH钱包地址,需要具体填写,toAmount为转账数量
    exchange.IO("api", "eth", "send", "toAddress", toAmount)
}

ETH转账,可以根据具体需求设置{gasPrice: 11, gasLimit: 111, nonce: 111}参数,该参数设置在exchange.IO()函数的最后一个参数上。 可以省略其中的nonce使用系统默认的值,或者不设置gasLimit/gasPrice/nonce,全部使用系统默认值。

function toAmount(s, decimals) {
    return Number((BigDecimal(BigInt(s))/BigDecimal(Math.pow(10, decimals))).toString())
}

function main() {
    var gasPrice = exchange.IO("api", "eth", "eth_gasPrice")
    Log("gasPrice:", toAmount(gasPrice, 0))   // 5000000000 , in wei (5 gwei)
}

查询gasPrice

function toAmount(s, decimals) {
    // toAmount函数可以把hex编码的数值转换为十进制数值
    return Number((BigDecimal(BigInt(s))/BigDecimal(Math.pow(10, decimals))).toString())
}                

function main() {
    // 编码approve(授权)方法的调用
    var data = exchange.IO("encode", "0x111111111117dC0aa78b770fA6A738034120C302", "approve", "0xe592427a0aece92de3edee1f18e0157c05861564", "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")
    Log("data:", data)
    var gasPrice = exchange.IO("api", "eth", "eth_gasPrice")
    Log("gasPrice:", toAmount(gasPrice, 0))
    var obj = {
        "from" : "0x0xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",   // walletAddress
        "to"  : "0x111111111117dC0aa78b770fA6A738034120C302",
        "gasPrice" : gasPrice,
        "value" : "0x0",
        "data" : "0x" + data,
    }
    
    var gasLimit = exchange.IO("api", "eth", "eth_estimateGas", obj)
    Log("gasLimit:", toAmount(gasLimit, 0))
    Log("gas fee", toAmount(gasLimit, 0) * toAmount(gasPrice, 0) / 1e18)
}

查询eth_estimateGas


{@fun BigDecimal}, {@fun BigInt}

### exchange.IO("encode", ...)

```exchange.IO("encode", ...)```函数的调用方式用于数据编码。

```exchange.IO("encode", ...)```函数返回编码后的数据。
string

exchange.IO(k, dataFormat, ...args)
exchange.IO(k, address, dataFormat)
exchange.IO(k, address, dataFormat, ...args)

```k```参数用于设置```exchange.IO()```函数的功能,设置为```"encode"```表示该函数用于数据编码。
k
true
string
```address```参数用于设置智能合约的地址。 在调用```exchange.IO("encode", ...)```函数时,如果传入```address```参数表示编码(encode)智能合约上的方法调用。 在调用```exchange.IO("encode", ...)```函数时,如果未传入```address```参数,则该函数用于编码指定的类型顺序,功能等同```Solidity```中的```abi.encode```。
address
false
string
```dataFormat```参数用于指定编码数据的方法、类型、顺序。
dataFormat
true
string
```arg```参数用于指定与```dataFormat```参数匹配的具体数据值。 ```arg```参数可能有多个,```arg```参数的类型与个数根据```dataFormat```参数设置而定。
arg
false
string、number、tuple、array等系统支持的所有类型

```javascript
function main() {
    // ContractV3SwapRouterV2 主网地址 : 0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45
    // 调用unwrapWETH9方法需要先注册ABI,此处省略注册
    // "owner"代表钱包地址,需要具体填写,1代表解包装数量,把一个WETH解包装为ETH
    var data = exchange.IO("encode", "0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45", "unwrapWETH9(uint256,address)", 1, "owner")
    Log(data)
}

编码unwrapWETH9方法的调用为例:

function main() {
    var x = 10 
    var address = "0x02a5fBb259d20A3Ad2Fdf9CCADeF86F6C1c1Ccc9"
    var str = "Hello World"
    var array = [1, 2, 3]
    var ret = exchange.IO("encode", "uint256,address,string,uint256[]", x, address, str, array)   // uint 即 uint256 , FMZ上需要指定类型长度
    Log("ret:", ret)
    /*
    000000000000000000000000000000000000000000000000000000000000000a    // x
    00000000000000000000000002a5fbb259d20a3ad2fdf9ccadef86f6c1c1ccc9    // address
    0000000000000000000000000000000000000000000000000000000000000080    // str 的偏移
    00000000000000000000000000000000000000000000000000000000000000c0    // array 的偏移
    000000000000000000000000000000000000000000000000000000000000000b    // str 的长度
    48656c6c6f20576f726c64000000000000000000000000000000000000000000    // str 数据
    0000000000000000000000000000000000000000000000000000000000000003    // array 的长度
    0000000000000000000000000000000000000000000000000000000000000001    // array 第一个数据
    0000000000000000000000000000000000000000000000000000000000000002    // array 第二个数据
    0000000000000000000000000000000000000000000000000000000000000003    // array 第三个数据
    */
}

等同Solidityabi.encode的编码范例:

function main() {
    var types = "tuple(a uint256,b uint8,c address),bytes"
    var ret = exchange.IO("encode", types, {
        a: 30,
        b: 20,
        c: "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"
    }, "0011")
    Log("encode: ", ret)
}

支持对元组(tuple)或者包含元组的类型顺序编码, 这个类型顺序由tuplebytes组成,所以在调用exchange.IO()进行encode时需要继续传入两个参数:

  • 1、对应tuple类型的变量:
  {
      a: 30,
      b: 20,
      c: "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"
  }

传入的参数也必须和tuple的结构、类型保持一致,如同types参数中定义的形式:tuple(a uint256,b uint8,c address)。 - 2、对应bytes类型的变量:

  "0011"
function main() {
    var path = ["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", "0xdac17f958d2ee523a2206206994597c13d831ec7"]   // ETH address, USDT address
    var ret = exchange.IO("encode", "address[]", path)
    Log("encode: ", ret)
}

支持对数组或者包含数组的类型顺序编码:

编码智能合约上的方法调用时,需要先注册对应的ABI。

### exchange.IO("encodePacked", ...)

```exchange.IO("encodePacked", ...)```函数的调用方式用于```encodePacked```编码。

```exchange.IO("encodePacked", ...)```函数返回```encodePacked```编码后的数据。
string

exchange.IO(k, dataFormat, ...args)

```k```参数用于设置```exchange.IO()```函数的功能,设置为```"encodePacked"```表示该函数用于数据```encodePacked```编码。
k
true
string
```dataFormat```参数用于指定```encodePacked```编码数据的类型、顺序。
dataFormat
true
string
```arg```参数用于指定与```dataFormat```参数匹配的具体数据值。 ```arg```参数可能有多个,```arg```参数的类型与个数根据```dataFormat```参数设置而定。
arg
true
string、number、tuple、array等系统支持的所有类型

```javascript
function main() {
    var fee = exchange.IO("encodePacked", "uint24", 3000)
    var tokenInAddress = "0x111111111117dC0aa78b770fA6A738034120C302"
    var tokenOutAddress = "0x6b175474e89094c44da98b954eedeac495271d0f"
    var path = tokenInAddress.slice(2).toLowerCase()
    path += fee + tokenOutAddress.slice(2).toLowerCase()
    Log("path:", path)
}

使用Uniswap V3时需要传入兑换路径之类的参数,就需要使用encodePacked编码操作:

exchange.IO(“decode”, …)


```exchange.IO("decode", ...)```函数返回解码后的数据。 当```dataFormat```参数指定的数据只有一个时返回一个字符串。 当```dataFormat```参数指定的数据有多个时返回一个数组。
array、string

exchange.IO(k, dataFormat, data)

```k```参数用于设置```exchange.IO()```函数的功能,设置为```"decode"```表示该函数用于数据解码。
k
true
string
```dataFormat```参数用于指定解码数据的类型、顺序。
dataFormat
true
string
```data```参数用于设置所要解码的数据。
data
true
string

```javascript
function main() {
    var types = "tuple(a uint256,b uint8,c address),bytes"
    var ret = exchange.IO("encode", types, {
        a: 30,
        b: 20,
        c: "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"
    }, "0011")
    Log("encode: ", ret)            

    var rawData = exchange.IO("decode", types, ret)
    Log("decode:", rawData)
}
```javascript
function main() {
    // register SwapRouter02 abi
    var walletAddress = "0x398a93ca23CBdd2642a07445bCD2b8435e0a373f"
    var routerAddress = "0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45"
    var abi = `[{"inputs":[{"components":[{"internalType":"bytes","name":"path","type":"bytes"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"amountInMaximum","type":"uint256"}],"internalType":"struct IV3SwapRouter.ExactOutputParams","name":"params","type":"tuple"}],"name":"exactOutput","outputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"}],"stateMutability":"payable","type":"function"}]`
    exchange.IO("abi", routerAddress, abi)   // abi只使用了局部的exactOutput方法的内容,完整的abi可以在网上搜索              

    // encode path
    var fee = exchange.IO("encodePacked", "uint24", 3000)
    var tokenInAddress = "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"
    var tokenOutAddress = "0xdac17f958d2ee523a2206206994597c13d831ec7"
    var path = tokenInAddress.slice(2).toLowerCase()
    path += fee + tokenOutAddress.slice(2).toLowerCase()
    Log("path:", path)              

    var dataTuple = {
        "path" : path, 
        "recipient" : walletAddress, 
        "amountOut" : 1000, 
        "amountInMaximum" : 1, 
    }
    // encode SwapRouter02 exactOutput 
    var rawData = exchange.IO("encode", routerAddress, "exactOutput", dataTuple)
    Log("method hash:", rawData.slice(0, 8))   // 09b81346
    Log("params hash:", rawData.slice(8))              

    // decode exactOutput params
    var decodeRaw = exchange.IO("decode", "tuple(path bytes,recipient address,amountOut uint256,amountInMaximum uint256)", rawData.slice(8))
    Log("decodeRaw:", decodeRaw)
}

以下例子首先在path参数处理时进行了encodePacked操作,因为之后需要编码的exactOutput方法调用需要path作为参数。 然后encode路由合约的exactOutput方法,该方法只有一个参数,参数类型是tuple类型。 exactOutput这个方法名编码后即:0x09b81346,使用exchange.IO("decode", ...)方法解码得出decodeRaw,与变量dataTuple一致。

对于数据的处理,exchange.IO()函数不仅支持编码(encode),也支持解码(decode)。

exchange.IO(“key”, …)


exchange.IO(k, key)

```k```参数用于设置```exchange.IO()```函数的功能,设置为```"key"```表示该函数用于切换私钥。
k
true
string
```key```参数用于设置私钥。
key
true
string

```javascript
function main() {
    exchange.IO("key", "Private Key")   // "Private Key"代表私钥字符串,需要具体填写
}

### exchange.IO("api", ...)

```exchange.IO("api", ...)```函数的调用方式用于调用智能合约的方法。

```exchange.IO("api", ...)```函数返回所调用的智能合约方法的返回值。
string、number、bool、object、array、空值等系统支持的所有类型

exchange.IO(k, address, method)
exchange.IO(k, address, method, ...args)
exchange.IO(k, address, method, value, ...args)

```k```参数用于设置```exchange.IO()```函数的功能,设置为```"api"```表示该函数用于扩展调用请求。
k
true
string
```address```参数用于指定智能合约的地址。
address
true
string
```method```参数用于指定所要调用的智能合约的方法。
method
true
string
```value```参数用于设置发送的ETH数量。 所要执行的智能合约方法的```stateMutability```属性是```payable```,则需要传```value```参数。 ```"stateMutability":"payable"```属性可以从ABI中查看,```exchange.IO()```函数会根据已经注册的ABI中的```stateMutability```属性判断所需要的参数, 如果```stateMutability```属性是```nonpayable```则不需要传```value```参数。
value
false
number、string
```arg```参数用于指定所要调用智能合约的方法的参数。 ```arg```参数可能有多个,```arg```参数的类型与个数根据所要调用的智能合约的方法而定。
arg
false
string、number、bool等系统支持的所有类型

```javascript
function main(){
    var tokenAddress = "0x111111111117dC0aa78b770fA6A738034120C302"    // 代币的合约地址,例子中的代币为1INCH
    Log(exchange.IO("api", tokenAddress, "decimals"))                  // 查询,打印1INCH代币的精度指数为18
}
```javascript
function main(){
    // 代币的合约地址,例子中的代币为1INCH
    var tokenAddress = "0x111111111117dC0aa78b770fA6A738034120C302"                          

    // 例如查询得出1000000000000000000,除以该token的精度单位1e18,得出当前交易所对象绑定的钱包给spender地址授权了1个1INCH数量
    Log(exchange.IO("api", tokenAddress, "allowance", "owner", "spender"))   
}
```owner```:钱包地址,例子中以字符串"owner"代替,实际使用需要具体填写地址。 ```spender```:被授权的合约地址,例子中以字符串"spender"代替,实际使用需要具体填写地址,例如可以是```Uniswap V3 router v1```地址。
```javascript
function main(){
    // 代币的合约地址,例子中的代币为1INCH
    var tokenAddress = "0x111111111117dC0aa78b770fA6A738034120C302"                 

    // 授权量的十六进制字符串: 0xde0b6b3a7640000 , 对应的十进制字符串: 1e18 , 1e18除以该token的精度单位,即1个代币数量 , 所以这里指授权一个代币
    Log(exchange.IO("api", tokenAddress, "approve", "spender", "0xde0b6b3a7640000"))  
}
```spender```:被授权的合约地址,例子中以字符串"spender"代替,实际使用需要具体填写地址,例如可以是```Uniswap V3 router v1```地址。 ```0xde0b6b3a7640000```:授权数量,这里使用的是十六进制字符串表示,对应的十进制数值为1e18,除以例子中的token精度单位(即1e18), 得出授权了1个token。 ```exchange.IO()```函数的第三个参数传入方法名```approve```,也可以写methodId的形式,例如:"0x571ac8b0"。 也可以写完整标准方法名,例如:"approve(address,uint256)"。
```javascript
function main() {
    var ContractV3SwapRouterV2 = "0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45"
    var tokenInName = "ETH"
    var amountIn = 0.01
    var options = {gasPrice: 5000000000, gasLimit: 21000, nonce: 100}   // 此处为举例,具体要根据实际场景设置
    var data = ""                                                       // 编码后的数据,此处为空字符串,具体要根据实际场景设置
    var tx = exchange.IO("api", ContractV3SwapRouterV2, "multicall(uint256,bytes[])", (tokenInName == 'ETH' ? amountIn : 0), (new Date().getTime() / 1000) + 3600, data, options || {})
}
```multicall```方法可能有多种传参方式,具体可以查询包含该方法的ABI,调用该方法之前需要先注册ABI。返回值:txid。  

具体的```multicall```方法调用例子,可以参考平台公开的[「Uniswap V3 交易类库」模板](https://www.fmz.com/strategy/397260)  

这里使用伪代码来描述一些细节:

exchange.IO(“api”, ContractV3SwapRouterV2, “multicall(uint256,bytes[])”, value, deadline, data)



```ContractV3SwapRouterV2```:Uniswap V3的router v2地址。
```value```:转账的ETH数量,如果兑换操作的tokenIn代币不是ETH,则设置为0。
```deadline```:```deadline```是```multicall```方法的参数,可以设置为(new Date().getTime() / 1000) + 3600,表示一小时内有效。
```data```:```data```是```multicall```方法的参数,需要执行的打包操作数据。  

与```exchange.IO("api", "eth", "send", "toAddress", toAmount)```类似,在调用```multicall```方法时也可以指定方法调用的```gasLimit/gasPrice/nonce```设置,
同样使用伪代码来描述:

exchange.IO(“api”, ContractV3SwapRouterV2, “multicall(uint256,bytes[])”, value, deadline, data, {gasPrice: 123456, gasLimit: 21000})


可以根据具体需求设置```{gasPrice: 11, gasLimit: 111, nonce: 111}```参数,该参数设置在```exchange.IO()```函数的最后一个参数上。
可以省略其中的```nonce```使用系统默认的值,或者不设置```gasLimit/gasPrice/nonce```,全部使用系统默认值。


### exchange.IO("address")

```exchange.IO("address")```函数的调用方式用于获取{@var/EXCHANGE exchange}交易所对象配置的钱包的地址。

```exchange.IO("address")```函数返回配置的钱包地址。
string

exchange.IO(k)

```k```参数用于设置```exchange.IO()```函数的功能,设置为```"address"```表示该函数用于获取配置的钱包地址。
k
true
string

```javascript
function main() {
    Log(exchange.IO("address"))         // 打印exchange交易所对象上配置的私钥的钱包地址
}

exchange.IO(“base”, …)


exchange.IO(k, address)

```k```参数用于设置```exchange.IO()```函数的功能,设置为```"base"```表示该函数用于切换RPC节点。
k
true
string
```address```参数用于设置RPC节点地址。
address
true
string

```javascript
function main() {
    var chainRpc = "https://bsc-dataseed.binance.org"
    e.IO("base", chainRpc)    // 切换到BSC链
}

TA

TA.MACD


```TA.MACD()```函数的返回值为二维数组,结构为:```[DIF, DEA, MACD]```。
array

TA.MACD(inReal)
TA.MACD(inReal, optInFastPeriod, optInSlowPeriod, optInSignalPeriod)

```inReal```参数用于指定K线数据。
inReal
true
{@struct/Record Record}结构数组、数值数组
```optInFastPeriod```参数用于设置快周期。
optInFastPeriod
false
number
```optInSlowPeriod```参数用于设置慢周期。
optInSlowPeriod
false
number
```optInSignalPeriod```参数用于设置信号周期。
optInSignalPeriod
false
number

```javascript
function main(){
    // 可以填入不同k线周期,比如PERIOD_M1,PERIOD_M30,PERIOD_H1......
    var records = exchange.GetRecords(PERIOD_M15)
    var macd = TA.MACD(records, 12, 26, 9)
    // 观看日志可得知返回三个数组,分别对应DIF,DEA,MACD
    Log("DIF:", macd[0], "DEA:", macd[1], "MACD:", macd[2])
}
def main():
    r = exchange.GetRecords(PERIOD_M15)
    macd = TA.MACD(r, 12, 26, 9)
    Log("DIF:", macd[0], "DEA:", macd[1], "MACD:", macd[2])
void main() {
    auto r = exchange.GetRecords(PERIOD_M15);
    auto macd = TA.MACD(r, 12, 26, 9);
    Log("DIF:", macd[0], "DEA:", macd[1], "MACD:", macd[2]);
}

发明者量化的TA指标库,优化了常用指标算法。 支持JavaScriptPythonC++语言策略的调用,开源TA库代码


{@fun/TA/TA.KDJ TA.KDJ}, {@fun/TA/TA.RSI TA.RSI}, {@fun/TA/TA.ATR TA.ATR}, {@fun/TA/TA.OBV TA.OBV},  {@fun/TA/TA.MA TA.MA}, {@fun/TA/TA.EMA TA.EMA}, {@fun/TA/TA.BOLL TA.BOLL}, {@fun/TA/TA.Alligator TA.Alligator}, {@fun/TA/TA.CMF TA.CMF}, {@fun/TA/TA.Highest TA.Highest}, {@fun/TA/TA.Lowest TA.Lowest}

### TA.KDJ

```TA.KDJ()```函数用于计算**随机指标**。

```TA.KDJ()```函数的返回值为二维数组,结构为:```[K, D, J]```。
array

TA.KDJ(inReal)
TA.KDJ(inReal, period, kPeriod, dPeriod)

```inReal```参数用于指定K线数据。
inReal
true
{@struct/Record Record}结构数组、数值数组
```period```参数用于设置周期1。
period
false
number
```kPeriod```参数用于设置周期2。
kPeriod
false
number
```dPeriod```参数用于设置周期3。
dPeriod
false
number

```javascript
function main(){
    var records = exchange.GetRecords(PERIOD_M15)
    var kdj = TA.KDJ(records, 9, 3, 3)
    Log("k:", kdj[0], "d:", kdj[1], "j:", kdj[2])
}
def main():
    r = exchange.GetRecords(PERIOD_M15)
    kdj = TA.KDJ(r, 9, 3, 3)
    Log("k:", kdj[0], "d:", kdj[1], "j:", kdj[2])
void main() {
    auto r = exchange.GetRecords();
    auto kdj = TA.KDJ(r, 9, 3, 3);
    Log("k:", kdj[0], "d:", kdj[1], "j:", kdj[2]);
}

{@fun/TA/TA.MACD TA.MACD}, {@fun/TA/TA.RSI TA.RSI}, {@fun/TA/TA.ATR TA.ATR}, {@fun/TA/TA.OBV TA.OBV},  {@fun/TA/TA.MA TA.MA}, {@fun/TA/TA.EMA TA.EMA}, {@fun/TA/TA.BOLL TA.BOLL}, {@fun/TA/TA.Alligator TA.Alligator}, {@fun/TA/TA.CMF TA.CMF}, {@fun/TA/TA.Highest TA.Highest}, {@fun/TA/TA.Lowest TA.Lowest}

### TA.RSI

```TA.RSI()```函数用于计算**强弱指标**。

```TA.RSI()```函数的返回值为:一维数组。
array

TA.RSI(inReal)
TA.RSI(inReal, optInTimePeriod)

```inReal```参数用于指定K线数据。
inReal
true
{@struct/Record Record}结构数组、数值数组
```optInTimePeriod```参数用于设置周期。
optInTimePeriod
false
number

```javascript
function main(){
    var records = exchange.GetRecords(PERIOD_M30)
    var rsi = TA.RSI(records, 14)
    Log(rsi)
}
def main():
    r = exchange.GetRecords(PERIOD_M30)
    rsi = TA.RSI(r, 14)
    Log(rsi)
void main() {
    auto r = exchange.GetRecords(PERIOD_M30);
    auto rsi = TA.RSI(r, 14);
    Log(rsi); 
}

{@fun/TA/TA.MACD TA.MACD}, {@fun/TA/TA.KDJ TA.KDJ}, {@fun/TA/TA.ATR TA.ATR}, {@fun/TA/TA.OBV TA.OBV},  {@fun/TA/TA.MA TA.MA}, {@fun/TA/TA.EMA TA.EMA}, {@fun/TA/TA.BOLL TA.BOLL}, {@fun/TA/TA.Alligator TA.Alligator}, {@fun/TA/TA.CMF TA.CMF}, {@fun/TA/TA.Highest TA.Highest}, {@fun/TA/TA.Lowest TA.Lowest}

### TA.ATR

```TA.ATR()```函数用于计算**平均真实波幅指标**。

```TA.ATR()```函数的返回值为:一维数组。
array

TA.ATR(inPriceHLC)
TA.ATR(inPriceHLC, optInTimePeriod)

```inPriceHLC```参数用于指定K线数据。
inPriceHLC
true
{@struct/Record Record}结构数组
```optInTimePeriod```参数用于设置周期。
optInTimePeriod
false
number

```javascript
function main(){
    var records = exchange.GetRecords(PERIOD_M30)
    var atr = TA.ATR(records, 14)
    Log(atr)
}
def main():
    r = exchange.GetRecords(PERIOD_M30)
    atr = TA.ATR(r, 14)
    Log(atr)
void main() {
    auto r = exchange.GetRecords(PERIOD_M30);
    auto atr = TA.ATR(r, 14);
    Log(atr);
}

{@fun/TA/TA.MACD TA.MACD}, {@fun/TA/TA.KDJ TA.KDJ}, {@fun/TA/TA.RSI TA.RSI}, {@fun/TA/TA.OBV TA.OBV},  {@fun/TA/TA.MA TA.MA}, {@fun/TA/TA.EMA TA.EMA}, {@fun/TA/TA.BOLL TA.BOLL}, {@fun/TA/TA.Alligator TA.Alligator}, {@fun/TA/TA.CMF TA.CMF}, {@fun/TA/TA.Highest TA.Highest}, {@fun/TA/TA.Lowest TA.Lowest}

### TA.OBV

```TA.OBV()```函数用于计算**能量潮指标**。

```TA.OBV()```函数的返回值为:一维数组。
array

TA.OBV(inReal)
TA.OBV(inReal, inPriceV)

```inReal```参数用于指定K线数据。
inReal
true
{@struct/Record Record}结构数组、数值数组
```inPriceV```参数用于指定成交量数据。
inPriceV
false
{@struct/Record Record}结构数组

```javascript
function main(){
    var records = exchange.GetRecords(PERIOD_M30)
    var obv = TA.OBV(records)
    Log(obv)
}
def main():
    r = exchange.GetRecords(PERIOD_M30)
    obv = TA.OBV(r)
    Log(obv)
void main() {
    auto r = exchange.GetRecords(PERIOD_M30);
    auto obv = TA.OBV(r);
    Log(obv);
}

{@fun/TA/TA.MACD TA.MACD}, {@fun/TA/TA.KDJ TA.KDJ}, {@fun/TA/TA.RSI TA.RSI}, {@fun/TA/TA.ATR TA.ATR}, {@fun/TA/TA.MA TA.MA}, {@fun/TA/TA.EMA TA.EMA}, {@fun/TA/TA.BOLL TA.BOLL}, {@fun/TA/TA.Alligator TA.Alligator}, {@fun/TA/TA.CMF TA.CMF}, {@fun/TA/TA.Highest TA.Highest}, {@fun/TA/TA.Lowest TA.Lowest}

TA.MA


```TA.MA()```函数的返回值为:一维数组。
array

TA.MA(inReal)
TA.MA(inReal, optInTimePeriod)

```inReal```参数用于指定K线数据。
inReal
true
{@struct/Record Record}结构数组、数值数组
```optInTimePeriod```参数用于设置周期。
optInTimePeriod
false
number

```javascript
function main(){
    var records = exchange.GetRecords(PERIOD_M30)
    var ma = TA.MA(records, 14)
    Log(ma)
}
def main():
    r = exchange.GetRecords(PERIOD_M30)
    ma = TA.MA(r, 14)
    Log(ma)
void main() {
    auto r = exchange.GetRecords(PERIOD_M30);
    auto ma = TA.MA(r, 14);
    Log(ma);
}

{@fun/TA/TA.MACD TA.MACD}, {@fun/TA/TA.KDJ TA.KDJ}, {@fun/TA/TA.RSI TA.RSI}, {@fun/TA/TA.ATR TA.ATR}, {@fun/TA/TA.OBV TA.OBV},  {@fun/TA/TA.EMA TA.EMA}, {@fun/TA/TA.BOLL TA.BOLL}, {@fun/TA/TA.Alligator TA.Alligator}, {@fun/TA/TA.CMF TA.CMF}, {@fun/TA/TA.Highest TA.Highest}, {@fun/TA/TA.Lowest TA.Lowest}

### TA.EMA

```TA.EMA()```函数用于计算**指数平均数指标**。

```TA.EMA()```函数的返回值为:一维数组。
array

TA.EMA(inReal)
TA.EMA(inReal, optInTimePeriod)

```inReal```参数用于指定K线数据。
inReal
true
{@struct/Record Record}结构数组、数值数组
```optInTimePeriod```参数用于设置周期。
optInTimePeriod
false
number

```javascript
function main(){
    var records = exchange.GetRecords()
    // 判断K线bar数量是否满足指标计算周期
    if (records && records.length > 9) {
        var ema = TA.EMA(records, 9)          
        Log(ema)
    }
}
def main():
    r = exchange.GetRecords()
    if r and len(r) > 9:
        ema = TA.EMA(r, 9)
        Log(ema)
void main() {
    auto r = exchange.GetRecords();
    if(r.Valid && r.size() > 9) {
        auto ema = TA.EMA(r, 9);
        Log(ema);
    }
}

{@fun/TA/TA.MACD TA.MACD}, {@fun/TA/TA.KDJ TA.KDJ}, {@fun/TA/TA.RSI TA.RSI}, {@fun/TA/TA.ATR TA.ATR}, {@fun/TA/TA.OBV TA.OBV},  {@fun/TA/TA.MA TA.MA}, {@fun/TA/TA.BOLL TA.BOLL}, {@fun/TA/TA.Alligator TA.Alligator}, {@fun/TA/TA.CMF TA.CMF}, {@fun/TA/TA.Highest TA.Highest}, {@fun/TA/TA.Lowest TA.Lowest}

### TA.BOLL

```TA.BOLL()```函数用于计算**布林带指标**。

```TA.BOLL()```函数的返回值为二维数组,结构为:```[upLine, midLine, downLine]```。
array

TA.BOLL(inReal)
TA.BOLL(inReal, period, multiplier)

```inReal```参数用于指定K线数据。
inReal
true
{@struct/Record Record}结构数组、数值数组
```period```参数用于设置周期。
period
false
number
```multiplier```参数用于设置乘数。
multiplier
false
number

```javascript
function main() {
    var records = exchange.GetRecords()
    if(records && records.length > 20) {
        var boll = TA.BOLL(records, 20, 2)
        var upLine = boll[0]
        var midLine = boll[1]
        var downLine = boll[2]
        Log(upLine)
        Log(midLine)
        Log(downLine)
    }
}
def main():
    r = exchange.GetRecords()
    if r and len(r) > 20:
        boll = TA.BOLL(r, 20, 2)
        upLine = boll[0]
        midLine = boll[1]
        downLine = boll[2]
        Log(upLine)
        Log(midLine)
        Log(downLine)
void main() {
    auto r = exchange.GetRecords();
    if(r.Valid && r.size() > 20) {
        auto boll = TA.BOLL(r, 20, 2);
        auto upLine = boll[0];
        auto midLine = boll[1];
        auto downLine = boll[2];
        Log(upLine);
        Log(midLine);
        Log(downLine);
    }
}

{@fun/TA/TA.MACD TA.MACD}, {@fun/TA/TA.KDJ TA.KDJ}, {@fun/TA/TA.RSI TA.RSI}, {@fun/TA/TA.ATR TA.ATR}, {@fun/TA/TA.OBV TA.OBV},  {@fun/TA/TA.MA TA.MA}, {@fun/TA/TA.EMA TA.EMA}, {@fun/TA/TA.Alligator TA.Alligator}, {@fun/TA/TA.CMF TA.CMF}, {@fun/TA/TA.Highest TA.Highest}, {@fun/TA/TA.Lowest TA.Lowest}

### TA.Alligator

```TA.Alligator()```函数用于计算**鳄鱼线指标**。

```TA.Alligator()```函数的返回值为二维数组,结构为:```[jawLine, teethLine, lipsLine]```。
array

TA.Alligator(inReal)
TA.Alligator(inReal, jawLength, teethLength, lipsLength)

```inReal```参数用于指定K线数据。
inReal
true
{@struct/Record Record}结构数组、数值数组
```jawLength```参数用于设置下颚周期。
jawLength
false
number
```teethLength```参数用于设置牙齿周期。
teethLength
false
number
```lipsLength```参数用于设置上唇周期。
lipsLength
false
number

```javascript
function main(){
    var records = exchange.GetRecords()
    var alligator = TA.Alligator(records)
    Log("jawLine:", alligator[0])
    Log("teethLine:", alligator[1])
    Log("lipsLine:", alligator[2])
}
def main():
    records = exchange.GetRecords()
    alligator = TA.Alligator(records)
    Log("jawLine:", alligator[0])
    Log("teethLine:", alligator[1])
    Log("lipsLine:", alligator[2])
void main() {
    auto records = exchange.GetRecords();
    auto alligator = TA.Alligator(records);
    Log("jawLine:", alligator[0]);
    Log("teethLine:", alligator[1]);
    Log("lipsLine:", alligator[2]);
}

{@fun/TA/TA.MACD TA.MACD}, {@fun/TA/TA.KDJ TA.KDJ}, {@fun/TA/TA.RSI TA.RSI}, {@fun/TA/TA.ATR TA.ATR}, {@fun/TA/TA.OBV TA.OBV},  {@fun/TA/TA.MA TA.MA}, {@fun/TA/TA.EMA TA.EMA}, {@fun/TA/TA.BOLL TA.BOLL}, {@fun/TA/TA.CMF TA.CMF}, {@fun/TA/TA.Highest TA.Highest}, {@fun/TA/TA.Lowest TA.Lowest}

### TA.CMF

```TA.CMF()```函数用于计算**蔡金货币流量指标**。

```TA.CMF()```函数的返回值为:一维数组。
array

TA.CMF(inReal)
TA.CMF(inReal, inPriceV)

```inReal```参数用于指定K线数据。
inReal
true
{@struct/Record Record}结构数组、数值数组
```inPriceV```参数用于指定成交量数据。
inPriceV
false
{@struct/Record Record}结构数组

```javascript
function main() {
    var records = exchange.GetRecords()
    var cmf = TA.CMF(records)
    Log(cmf)
}
def main():
    records = exchange.GetRecords()
    cmf = TA.CMF(records)
    Log(cmf)
void main() {
    auto records = exchange.GetRecords();
    auto cmf = TA.CMF(records);
    Log(cmf);
}

{@fun/TA/TA.MACD TA.MACD}, {@fun/TA/TA.KDJ TA.KDJ}, {@fun/TA/TA.RSI TA.RSI}, {@fun/TA/TA.ATR TA.ATR}, {@fun/TA/TA.OBV TA.OBV}, {@fun/TA/TA.MA TA.MA}, {@fun/TA/TA.EMA TA.EMA}, {@fun/TA/TA.BOLL TA.BOLL}, {@fun/TA/TA.Alligator TA.Alligator}, {@fun/TA/TA.Highest TA.Highest}, {@fun/TA/TA.Lowest TA.Lowest}

TA.Highest


```TA.Highest()```函数返回最近一定周期内的某个属性的最大值,不包含当前Bar。
number

TA.Highest(inReal)
TA.Highest(inReal, period, attr)

```inReal```参数用于指定K线数据。
inReal
true
{@struct/Record Record}结构数组、数值数组
```period```参数用于设置周期。
period
false
number
```attr```参数用于设置属性,可选:```Open```、```Close```、```Low```、```High```、```Volume```、```OpenInterest```。
attr
false
string

```javascript
function main() {
    var records = exchange.GetRecords()
    var highestForOpen = TA.Highest(records, 10, "Open")
    Log(highestForOpen)
}
def main():
    records = exchange.GetRecords()
    highestForOpen = TA.Highest(records, 10, "Open")
    Log(highestForOpen)
void main() {
    auto records = exchange.GetRecords();
    auto highestForOpen = TA.Highest(records.Open(), 10);
    Log(highestForOpen);
}

例如调用TA.Highest(records, 30, "High")函数,如果周期参数period设置为0, 指计算inReal参数传入的K线数据的所有Bar;如果属性参数attr不指定,则视为inReal参数传入的K线数据为普通数组。

{@fun/TA/TA.MACD TA.MACD}, {@fun/TA/TA.KDJ TA.KDJ}, {@fun/TA/TA.RSI TA.RSI}, {@fun/TA/TA.ATR TA.ATR}, {@fun/TA/TA.OBV TA.OBV}, {@fun/TA/TA.MA TA.MA}, {@fun/TA/TA.EMA TA.EMA}, {@fun/TA/TA.BOLL TA.BOLL}, {@fun/TA/TA.Alligator TA.Alligator}, {@fun/TA/TA.CMF TA.CMF}, {@fun/TA/TA.Lowest TA.Lowest}

TA.Lowest


```TA.Lowest()```函数返回最近一定周期内的某个属性的最小值,不包含当前Bar。
number

TA.Lowest(inReal)
TA.Lowest(inReal, period, attr)

```inReal```参数用于指定K线数据。
inReal
true
{@struct/Record Record}结构数组、数值数组
```period```参数用于设置周期。
period
false
number
```attr```参数用于设置属性,可选:```Open```、```Close```、```Low```、```High```、```Volume```、```OpenInterest```。
attr
false
string

```javascript
function main() {
    var records = exchange.GetRecords()
    var lowestForOpen = TA.Lowest(records, 10, "Open")
    Log(lowestForOpen)
}
def main():
    records = exchange.GetRecords()
    lowestForOpen = TA.Lowest(records, 10, "Open")
    Log(lowestForOpen)
void main() {
    auto records = exchange.GetRecords();
    auto lowestForOpen = TA.Lowest(records.Open(), 10);
    Log(lowestForOpen);
}

例如调用TA.Lowest(records, 30, "Low")函数,如果周期参数period设置为0, 指计算inReal参数传入的K线数据的所有Bar;如果属性参数attr不指定,则视为inReal参数传入的K线数据为普通数组。

并且第一个参数传入的不是```auto r = exchange.GetRecords()```函数调用时获取的K线数据```r```。
需要调用```r```的方法,传入具体属性数据。例如传入```r.Close()```收盘价数据。
```Close```、```High```、```Low```、```Open```、```Volume```如同```r.Close()```调用方式。

```C++```语言策略的测试范例:

void main() { Records r; r.Valid = true; for (auto i = 0; i < 10; i++) { Record ele; ele.Time = i * 100000; ele.High = i * 10000; ele.Low = i * 1000; ele.Close = i * 100; ele.Open = i * 10; ele.Volume = i * 1; r.push_back(ele); }

for(int j = 0; j < r.size(); j++){
    Log(r[j]);
}            

// 注意:第一个参数传入的不是r,需要调用r.Close()
auto highest = TA.Highest(r.Close(), 8);   
Log(highest);                     

}



{@fun/TA/TA.MACD TA.MACD}, {@fun/TA/TA.KDJ TA.KDJ}, {@fun/TA/TA.RSI TA.RSI}, {@fun/TA/TA.ATR TA.ATR}, {@fun/TA/TA.OBV TA.OBV},  {@fun/TA/TA.MA TA.MA}, {@fun/TA/TA.EMA TA.EMA}, {@fun/TA/TA.BOLL TA.BOLL}, {@fun/TA/TA.Alligator TA.Alligator}, {@fun/TA/TA.CMF TA.CMF}, {@fun/TA/TA.Highest TA.Highest}

### TA.SMA

```TA.SMA()```函数用于计算**简单移动平均指标**。

```TA.SMA()```函数的返回值为:一维数组。
array

TA.SMA(inReal)
TA.SMA(inReal, optInTimePeriod)

```inReal```参数用于指定K线数据。
inReal
true
{@struct/Record Record}结构数组、数值数组
```optInTimePeriod```参数用于设置周期。
optInTimePeriod
false
number

```javascript
function main(){
    var records = exchange.GetRecords(PERIOD_M30)
    var sma = TA.SMA(records, 14)
    Log(sma)
}
def main():
    r = exchange.GetRecords(PERIOD_M30)
    sma = TA.SMA(r, 14)
    Log(sma)
void main() {
    auto r = exchange.GetRecords(PERIOD_M30);
    auto sma = TA.SMA(r, 14);
    Log(sma);
}

{@fun/TA/TA.MACD TA.MACD}, {@fun/TA/TA.KDJ TA.KDJ}, {@fun/TA/TA.RSI TA.RSI}, {@fun/TA/TA.ATR TA.ATR}, {@fun/TA/TA.OBV TA.OBV},  {@fun/TA/TA.MA TA.MA}, {@fun/TA/TA.EMA TA.EMA}, {@fun/TA/TA.BOLL TA.BOLL}, {@fun/TA/TA.Alligator TA.Alligator}, {@fun/TA/TA.CMF TA.CMF}, {@fun/TA/TA.Highest TA.Highest}, {@fun/TA/TA.Lowest TA.Lowest}

### Talib

### talib.CDL2CROWS

```talib.CDL2CROWS()```函数用于计算**Two Crows (K线图--两只乌鸦)**。

```talib.CDL2CROWS()```函数的返回值为:一维数组。
array

talib.CDL2CROWS(inPriceOHLC)

```inPriceOHLC```参数用于指定K线数据。
inPriceOHLC
true
{@struct/Record Record}结构数组

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.CDL2CROWS(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.CDL2CROWS(records.Open, records.High, records.Low, records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.CDL2CROWS(records);
    Log(ret);
}
对于```Python```语言中的调用来说,传参有所不同,需要根据以上描述中的:```Records[Open,High,Low,Close]```传参。

举例把一个变量```records```(即参数```inPriceOHLC```,类型为{@struct/Record Record}结构数组)拆分成:
```Open```列表:在Python中写为```records.Open```。
```High```列表:在Python中写为```records.High```。
```Low```列表:在Python中写为```records.Low```。
```Close```列表:在Python中写为```records.Close```。

Python策略代码中调用:

talib.CDL2CROWS(records.Open, records.High, records.Low, records.Close)


其它```talib```指标以此类推,不再赘述。


### talib.CDL3BLACKCROWS

```talib.CDL3BLACKCROWS()```函数用于计算**Three Black Crows (K线图--3只黑乌鸦)**。

```talib.CDL3BLACKCROWS()```函数的返回值为:一维数组。
array

talib.CDL3BLACKCROWS(inPriceOHLC)

```inPriceOHLC```参数用于指定K线数据。
inPriceOHLC
true
{@struct/Record Record}结构数组

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.CDL3BLACKCROWS(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.CDL3BLACKCROWS(records.Open, records.High, records.Low, records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.CDL3BLACKCROWS(records);
    Log(ret);
}

### talib.CDL3INSIDE

```talib.CDL3INSIDE()```函数用于计算**Three Inside Up/Down (K线图:3内上下震荡)**。

```talib.CDL3INSIDE()```函数的返回值为:一维数组。
array

talib.CDL3INSIDE(inPriceOHLC)

```inPriceOHLC```参数用于指定K线数据。
inPriceOHLC
true
{@struct/Record Record}结构数组

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.CDL3INSIDE(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.CDL3INSIDE(records.Open, records.High, records.Low, records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.CDL3INSIDE(records);
    Log(ret);
}

### talib.CDL3LINESTRIKE

```talib.CDL3LINESTRIKE()```函数用于计算**Three-Line Strike (K线图:3线震荡)**。

```talib.CDL3LINESTRIKE()```函数的返回值为:一维数组。
array

talib.CDL3LINESTRIKE(inPriceOHLC)

```inPriceOHLC```参数用于指定K线数据。
inPriceOHLC
true
{@struct/Record Record}结构数组

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.CDL3LINESTRIKE(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.CDL3LINESTRIKE(records.Open, records.High, records.Low, records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.CDL3LINESTRIKE(records);
    Log(ret);
}

### talib.CDL3OUTSIDE

```talib.CDL3OUTSIDE()```函数用于计算**Three Outside Up/Down (K线图:3外下震荡)**。

```talib.CDL3OUTSIDE()```函数的返回值为:一维数组。
array

talib.CDL3OUTSIDE(inPriceOHLC)

```inPriceOHLC```参数用于指定K线数据。
inPriceOHLC
true
{@struct/Record Record}结构数组

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.CDL3OUTSIDE(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.CDL3OUTSIDE(records.Open, records.High, records.Low, records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.CDL3OUTSIDE(records);
    Log(ret);
}

### talib.CDL3STARSINSOUTH

```talib.CDL3STARSINSOUTH()```函数用于计算**Three Stars In The South (K线图:南方三星)**。

```talib.CDL3STARSINSOUTH()```函数的返回值为:一维数组。
array

talib.CDL3STARSINSOUTH(inPriceOHLC)

```inPriceOHLC```参数用于指定K线数据。
inPriceOHLC
true
{@struct/Record Record}结构数组

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.CDL3STARSINSOUTH(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.CDL3STARSINSOUTH(records.Open, records.High, records.Low, records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.CDL3STARSINSOUTH(records);
    Log(ret);
}

### talib.CDL3WHITESOLDIERS

```talib.CDL3WHITESOLDIERS()```函数用于计算**Three Advancing White Soldiers (K线图:三白兵)**。

```talib.CDL3WHITESOLDIERS()```函数的返回值为:一维数组。
array

talib.CDL3WHITESOLDIERS(inPriceOHLC)

```inPriceOHLC```参数用于指定K线数据。
inPriceOHLC
true
{@struct/Record Record}结构数组

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.CDL3WHITESOLDIERS(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.CDL3WHITESOLDIERS(records.Open, records.High, records.Low, records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.CDL3WHITESOLDIERS(records);
    Log(ret);
}

### talib.CDLABANDONEDBABY

```talib.CDLABANDONEDBABY()```函数用于计算**Abandoned Baby (K线图:弃婴)**。

```talib.CDLABANDONEDBABY()```函数的返回值为:一维数组。
array

talib.CDLABANDONEDBABY(inPriceOHLC)
talib.CDLABANDONEDBABY(inPriceOHLC, optInPenetration)

```inPriceOHLC```参数用于指定K线数据。
inPriceOHLC
true
{@struct/Record Record}结构数组
```optInPenetration```参数用于设置Penetration,默认值为0.3。
optInPenetration
false
number

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.CDLABANDONEDBABY(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.CDLABANDONEDBABY(records.Open, records.High, records.Low, records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.CDLABANDONEDBABY(records);
    Log(ret);
}

### talib.CDLADVANCEBLOCK

```talib.CDLADVANCEBLOCK()```函数用于计算**Advance Block (K线图:推进)**。

```talib.CDLADVANCEBLOCK()```函数的返回值为:一维数组。
array

talib.CDLADVANCEBLOCK(inPriceOHLC)

```inPriceOHLC```参数用于指定K线数据。
inPriceOHLC
true
{@struct/Record Record}结构数组

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.CDLADVANCEBLOCK(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.CDLADVANCEBLOCK(records.Open, records.High, records.Low, records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.CDLADVANCEBLOCK(records);
    Log(ret);
}

### talib.CDLBELTHOLD

```talib.CDLBELTHOLD()```函数用于计算**Belt-hold (K线图:带住)**。

```talib.CDLBELTHOLD()```函数的返回值为:一维数组。
array

talib.CDLBELTHOLD(inPriceOHLC)

```inPriceOHLC```参数用于指定K线数据。
inPriceOHLC
true
{@struct/Record Record}结构数组

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.CDLBELTHOLD(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.CDLBELTHOLD(records.Open, records.High, records.Low, records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.CDLBELTHOLD(records);
    Log(ret);
}

### talib.CDLBREAKAWAY

```talib.CDLBREAKAWAY()```函数用于计算**Breakaway (K线图:分离)**。

```talib.CDLBREAKAWAY()```函数的返回值为:一维数组。
array

talib.CDLBREAKAWAY(inPriceOHLC)

```inPriceOHLC```参数用于指定K线数据。
inPriceOHLC
true
{@struct/Record Record}结构数组

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.CDLBREAKAWAY(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.CDLBREAKAWAY(records.Open, records.High, records.Low, records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.CDLBREAKAWAY(records);
    Log(ret);
}

### talib.CDLCLOSINGMARUBOZU

```talib.CDLCLOSINGMARUBOZU()```函数用于计算**Closing Marubozu (K线图:收盘光头光脚)**。

```talib.CDLCLOSINGMARUBOZU()```函数的返回值为:一维数组。
array

talib.CDLCLOSINGMARUBOZU(inPriceOHLC)

```inPriceOHLC```参数用于指定K线数据。
inPriceOHLC
true
{@struct/Record Record}结构数组

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.CDLCLOSINGMARUBOZU(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.CDLCLOSINGMARUBOZU(records.Open, records.High, records.Low, records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.CDLCLOSINGMARUBOZU(records);
    Log(ret);
}

### talib.CDLCONCEALBABYSWALL

```talib.CDLCONCEALBABYSWALL()```函数用于计算**Concealing Baby Swallow (K线图:藏婴吞没形态)**。

```talib.CDLCONCEALBABYSWALL()```函数的返回值为:一维数组。
array

talib.CDLCONCEALBABYSWALL(inPriceOHLC)

```inPriceOHLC```参数用于指定K线数据。
inPriceOHLC
true
{@struct/Record Record}结构数组

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.CDLCONCEALBABYSWALL(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.CDLCONCEALBABYSWALL(records.Open, records.High, records.Low, records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.CDLCONCEALBABYSWALL(records);
    Log(ret);
}

### talib.CDLCOUNTERATTACK

```talib.CDLCOUNTERATTACK()```函数用于计算**Counterattack (K线图:反击)**。

```talib.CDLCOUNTERATTACK()```函数的返回值为:一维数组。
array

talib.CDLCOUNTERATTACK(inPriceOHLC)

```inPriceOHLC```参数用于指定K线数据。
inPriceOHLC
true
{@struct/Record Record}结构数组

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.CDLCOUNTERATTACK(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.CDLCOUNTERATTACK(records.Open, records.High, records.Low, records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.CDLCOUNTERATTACK(records);
    Log(ret);
}

### talib.CDLDARKCLOUDCOVER

```talib.CDLDARKCLOUDCOVER()```函数用于计算**Dark Cloud Cover (K线图:乌云盖)**。

```talib.CDLDARKCLOUDCOVER()```函数的返回值为:一维数组。
array

talib.CDLDARKCLOUDCOVER(inPriceOHLC)
talib.CDLDARKCLOUDCOVER(inPriceOHLC, optInPenetration)

```inPriceOHLC```参数用于指定K线数据。
inPriceOHLC
true
{@struct/Record Record}结构数组
```optInPenetration```参数用于设置Penetration,默认值为0.5。
optInPenetration
false
number

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.CDLDARKCLOUDCOVER(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.CDLDARKCLOUDCOVER(records.Open, records.High, records.Low, records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.CDLDARKCLOUDCOVER(records);
    Log(ret);
}

### talib.CDLDOJI

```talib.CDLDOJI()```函数用于计算**Doji (K线图:十字星 )**。

```talib.CDLDOJI()```函数的返回值为:一维数组。
array

talib.CDLDOJI(inPriceOHLC)

```inPriceOHLC```参数用于指定K线数据。
inPriceOHLC
true
{@struct/Record Record}结构数组

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.CDLDOJI(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.CDLDOJI(records.Open, records.High, records.Low, records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.CDLDOJI(records);
    Log(ret);
}

### talib.CDLDOJISTAR

```talib.CDLDOJISTAR()```函数用于计算**Doji Star (K线图:十字星)**。

```talib.CDLDOJISTAR()```函数的返回值为:一维数组。
array

talib.CDLDOJISTAR(inPriceOHLC)

```inPriceOHLC```参数用于指定K线数据。
inPriceOHLC
true
{@struct/Record Record}结构数组

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.CDLDOJISTAR(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.CDLDOJISTAR(records.Open, records.High, records.Low, records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.CDLDOJISTAR(records);
    Log(ret);
}

### talib.CDLDRAGONFLYDOJI

```talib.CDLDRAGONFLYDOJI()```函数用于计算**Dragonfly Doji (K线图:蜻蜓十字星)**。

```talib.CDLDRAGONFLYDOJI()```函数的返回值为:一维数组。
array

talib.CDLDRAGONFLYDOJI(inPriceOHLC)

```inPriceOHLC```参数用于指定K线数据。
inPriceOHLC
true
{@struct/Record Record}结构数组

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.CDLDRAGONFLYDOJI(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.CDLDRAGONFLYDOJI(records.Open, records.High, records.Low, records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.CDLDRAGONFLYDOJI(records);
    Log(ret);
}

### talib.CDLENGULFING

```talib.CDLENGULFING()```函数用于计算**Engulfing Pattern (K线图:吞没)**。

```talib.CDLENGULFING()```函数的返回值为:一维数组。
array

talib.CDLENGULFING(inPriceOHLC)

```inPriceOHLC```参数用于指定K线数据。
inPriceOHLC
true
{@struct/Record Record}结构数组

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.CDLENGULFING(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.CDLENGULFING(records.Open, records.High, records.Low, records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.CDLENGULFING(records);
    Log(ret);
}

### talib.CDLEVENINGDOJISTAR

```talib.CDLEVENINGDOJISTAR()```函数用于计算**Evening Doji Star (K线图:黄昏十字星)**。

```talib.CDLEVENINGDOJISTAR()```函数的返回值为:一维数组。
array

talib.CDLEVENINGDOJISTAR(inPriceOHLC)
talib.CDLEVENINGDOJISTAR(inPriceOHLC, optInPenetration)

```inPriceOHLC```参数用于指定K线数据。
inPriceOHLC
true
{@struct/Record Record}结构数组
```optInPenetration```参数用于设置Penetration,默认值为0.3。
optInPenetration
false
number

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.CDLEVENINGDOJISTAR(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.CDLEVENINGDOJISTAR(records.Open, records.High, records.Low, records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.CDLEVENINGDOJISTAR(records);
    Log(ret);
}

### talib.CDLEVENINGSTAR

```talib.CDLEVENINGSTAR()```函数用于计算**Evening Star (K线图:黄昏之星)**。

```talib.CDLEVENINGSTAR()```函数的返回值为:一维数组。
array

talib.CDLEVENINGSTAR(inPriceOHLC)
talib.CDLEVENINGSTAR(inPriceOHLC, optInPenetration)

```inPriceOHLC```参数用于指定K线数据。
inPriceOHLC
true
{@struct/Record Record}结构数组
```optInPenetration```参数用于设置Penetration,默认值为0.3。
optInPenetration
false
number

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.CDLEVENINGSTAR(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.CDLEVENINGSTAR(records.Open, records.High, records.Low, records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.CDLEVENINGSTAR(records);
    Log(ret);
}

### talib.CDLGAPSIDESIDEWHITE

```talib.CDLGAPSIDESIDEWHITE()```函数用于计算**Up/Down-gap side-by-side white lines (K线图:上/下间隙并排的白色线条)**。

```talib.CDLGAPSIDESIDEWHITE()```函数的返回值为:一维数组。
array

talib.CDLGAPSIDESIDEWHITE(inPriceOHLC)

```inPriceOHLC```参数用于指定K线数据。
inPriceOHLC
true
{@struct/Record Record}结构数组

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.CDLGAPSIDESIDEWHITE(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.CDLGAPSIDESIDEWHITE(records.Open, records.High, records.Low, records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.CDLGAPSIDESIDEWHITE(records);
    Log(ret);
}

### talib.CDLGRAVESTONEDOJI

```talib.CDLGRAVESTONEDOJI()```函数用于计算**Gravestone Doji (K线图:墓碑十字线)**。

```talib.CDLGRAVESTONEDOJI()```函数的返回值为:一维数组。
array

talib.CDLGRAVESTONEDOJI(inPriceOHLC)

```inPriceOHLC```参数用于指定K线数据。
inPriceOHLC
true
{@struct/Record Record}结构数组

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.CDLGRAVESTONEDOJI(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.CDLGRAVESTONEDOJI(records.Open, records.High, records.Low, records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.CDLGRAVESTONEDOJI(records);
    Log(ret);
}

### talib.CDLHAMMER

```talib.CDLHAMMER()```函数用于计算**Hammer (K线图:锤)**。

```talib.CDLHAMMER()```函数的返回值为:一维数组。
array

talib.CDLHAMMER(inPriceOHLC)

```inPriceOHLC```参数用于指定K线数据。
inPriceOHLC
true
{@struct/Record Record}结构数组

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.CDLHAMMER(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.CDLHAMMER(records.Open, records.High, records.Low, records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.CDLHAMMER(records);
    Log(ret);
}

### talib.CDLHANGINGMAN

```talib.CDLHANGINGMAN()```函数用于计算**Hanging Man (K线图:吊人)**。

```talib.CDLHANGINGMAN()```函数的返回值为:一维数组。
array

talib.CDLHANGINGMAN(inPriceOHLC)

```inPriceOHLC```参数用于指定K线数据。
inPriceOHLC
true
{@struct/Record Record}结构数组

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.CDLHANGINGMAN(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.CDLHANGINGMAN(records.Open, records.High, records.Low, records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.CDLHANGINGMAN(records);
    Log(ret);
}

### talib.CDLHARAMI

```talib.CDLHARAMI()```函数用于计算**Harami Pattern (K线图:阴阳线)**。

```talib.CDLHARAMI()```函数的返回值为:一维数组。
array

talib.CDLHARAMI(inPriceOHLC)

```inPriceOHLC```参数用于指定K线数据。
inPriceOHLC
true
{@struct/Record Record}结构数组

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.CDLHARAMI(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.CDLHARAMI(records.Open, records.High, records.Low, records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.CDLHARAMI(records);
    Log(ret);
}

### talib.CDLHARAMICROSS

```talib.CDLHARAMICROSS()```函数用于计算**Harami Cross Pattern (K线图:交叉阴阳线)**。

```talib.CDLHARAMICROSS()```函数的返回值为:一维数组。
array

talib.CDLHARAMICROSS(inPriceOHLC)

```inPriceOHLC```参数用于指定K线数据。
inPriceOHLC
true
{@struct/Record Record}结构数组

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.CDLHARAMICROSS(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.CDLHARAMICROSS(records.Open, records.High, records.Low, records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.CDLHARAMICROSS(records);
    Log(ret);
}

### talib.CDLHIGHWAVE

```talib.CDLHIGHWAVE()```函数用于计算**High-Wave Candle (K线图:长脚十字线 )**。

```talib.CDLHIGHWAVE()```函数的返回值为:一维数组。
array

talib.CDLHIGHWAVE(inPriceOHLC)

```inPriceOHLC```参数用于指定K线数据。
inPriceOHLC
true
{@struct/Record Record}结构数组

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.CDLHIGHWAVE(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.CDLHIGHWAVE(records.Open, records.High, records.Low, records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.CDLHIGHWAVE(records);
    Log(ret);
}

### talib.CDLHIKKAKE

```talib.CDLHIKKAKE()```函数用于计算**Hikkake Pattern (K线图:陷阱)**。

```talib.CDLHIKKAKE()```函数的返回值为:一维数组。
array

talib.CDLHIKKAKE(inPriceOHLC)

```inPriceOHLC```参数用于指定K线数据。
inPriceOHLC
true
{@struct/Record Record}结构数组

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.CDLHIKKAKE(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.CDLHIKKAKE(records.Open, records.High, records.Low, records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.CDLHIKKAKE(records);
    Log(ret);
}

### talib.CDLHIKKAKEMOD

```talib.CDLHIKKAKEMOD()```函数用于计算**Modified Hikkake Pattern (K线图:改良的陷阱)**。

```talib.CDLHIKKAKEMOD()```函数的返回值为:一维数组。
array

talib.CDLHIKKAKEMOD(inPriceOHLC)

```inPriceOHLC```参数用于指定K线数据。
inPriceOHLC
true
{@struct/Record Record}结构数组

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.CDLHIKKAKEMOD(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.CDLHIKKAKEMOD(records.Open, records.High, records.Low, records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.CDLHIKKAKEMOD(records);
    Log(ret);
}

### talib.CDLHOMINGPIGEON

```talib.CDLHOMINGPIGEON()```函数用于计算**Homing Pigeon (K线图:信鸽)**。

```talib.CDLHOMINGPIGEON()```函数的返回值为:一维数组。
array

talib.CDLHOMINGPIGEON(inPriceOHLC)

```inPriceOHLC```参数用于指定K线数据。
inPriceOHLC
true
{@struct/Record Record}结构数组

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.CDLHOMINGPIGEON(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.CDLHOMINGPIGEON(records.Open, records.High, records.Low, records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.CDLHOMINGPIGEON(records);
    Log(ret);
}

### talib.CDLIDENTICAL3CROWS

```talib.CDLIDENTICAL3CROWS()```函数用于计算**Identical Three Crows (K线图:相同的三只乌鸦)**。

```talib.CDLIDENTICAL3CROWS()```函数的返回值为:一维数组。
array

talib.CDLIDENTICAL3CROWS(inPriceOHLC)

```inPriceOHLC```参数用于指定K线数据。
inPriceOHLC
true
{@struct/Record Record}结构数组

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.CDLIDENTICAL3CROWS(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.CDLIDENTICAL3CROWS(records.Open, records.High, records.Low, records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.CDLIDENTICAL3CROWS(records);
    Log(ret);
}

### talib.CDLINNECK

```talib.CDLINNECK()```函数用于计算**In-Neck Pattern (K线图:颈纹)**。

```talib.CDLINNECK()```函数的返回值为:一维数组。
array

talib.CDLINNECK(inPriceOHLC)

```inPriceOHLC```参数用于指定K线数据。
inPriceOHLC
true
{@struct/Record Record}结构数组

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.CDLINNECK(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.CDLINNECK(records.Open, records.High, records.Low, records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.CDLINNECK(records);
    Log(ret);
}

### talib.CDLINVERTEDHAMMER

```talib.CDLINVERTEDHAMMER()```函数用于计算**Inverted Hammer (K线图:倒锤)**。

```talib.CDLINVERTEDHAMMER()```函数的返回值为:一维数组。
array

talib.CDLINVERTEDHAMMER(inPriceOHLC)

```inPriceOHLC```参数用于指定K线数据。
inPriceOHLC
true
{@struct/Record Record}结构数组

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.CDLINVERTEDHAMMER(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.CDLINVERTEDHAMMER(records.Open, records.High, records.Low, records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.CDLINVERTEDHAMMER(records);
    Log(ret);
}

### talib.CDLKICKING

```talib.CDLKICKING()```函数用于计算**Kicking (K线图:踢)**。

```talib.CDLKICKING()```函数的返回值为:一维数组。
array

talib.CDLKICKING(inPriceOHLC)

```inPriceOHLC```参数用于指定K线数据。
inPriceOHLC
true
{@struct/Record Record}结构数组

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.CDLKICKING(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.CDLKICKING(records.Open, records.High, records.Low, records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.CDLKICKING(records);
    Log(ret);
}

### talib.CDLKICKINGBYLENGTH

```talib.CDLKICKINGBYLENGTH()```函数用于计算**Kicking - bull/bear determined by the longer marubozu (K线图:踢牛/踢熊)**。

```talib.CDLKICKINGBYLENGTH()```函数的返回值为:一维数组。
array

talib.CDLKICKINGBYLENGTH(inPriceOHLC)

```inPriceOHLC```参数用于指定K线数据。
inPriceOHLC
true
{@struct/Record Record}结构数组

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.CDLKICKINGBYLENGTH(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.CDLKICKINGBYLENGTH(records.Open, records.High, records.Low, records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.CDLKICKINGBYLENGTH(records);
    Log(ret);
}

### talib.CDLLADDERBOTTOM

```talib.CDLLADDERBOTTOM()```函数用于计算**Ladder Bottom (K线图:梯底)**。

```talib.CDLLADDERBOTTOM()```函数的返回值为:一维数组。
array

talib.CDLLADDERBOTTOM(inPriceOHLC)

```inPriceOHLC```参数用于指定K线数据。
inPriceOHLC
true
{@struct/Record Record}结构数组

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.CDLLADDERBOTTOM(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.CDLLADDERBOTTOM(records.Open, records.High, records.Low, records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.CDLLADDERBOTTOM(records);
    Log(ret);
}

### talib.CDLLONGLEGGEDDOJI

```talib.CDLLONGLEGGEDDOJI()```函数用于计算**Long Legged Doji (K线图:长腿十字线)**。

```talib.CDLLONGLEGGEDDOJI()```函数的返回值为:一维数组。
array

talib.CDLLONGLEGGEDDOJI(inPriceOHLC)

```inPriceOHLC```参数用于指定K线数据。
inPriceOHLC
true
{@struct/Record Record}结构数组

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.CDLLONGLEGGEDDOJI(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.CDLLONGLEGGEDDOJI(records.Open, records.High, records.Low, records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.CDLLONGLEGGEDDOJI(records);
    Log(ret);
}

### talib.CDLLONGLINE

```talib.CDLLONGLINE()```函数用于计算**Long Line Candle (K线图:长线)**。

```talib.CDLLONGLINE()```函数的返回值为:一维数组。
array

talib.CDLLONGLINE(inPriceOHLC)

```inPriceOHLC```参数用于指定K线数据。
inPriceOHLC
true
{@struct/Record Record}结构数组

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.CDLLONGLINE(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.CDLLONGLINE(records.Open, records.High, records.Low, records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.CDLLONGLINE(records);
    Log(ret);
}

### talib.CDLMARUBOZU

```talib.CDLMARUBOZU()```函数用于计算**Marubozu (K线图:光头光脚)**。

```talib.CDLMARUBOZU()```函数的返回值为:一维数组。
array

talib.CDLMARUBOZU(inPriceOHLC)

```inPriceOHLC```参数用于指定K线数据。
inPriceOHLC
true
{@struct/Record Record}结构数组

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.CDLMARUBOZU(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.CDLMARUBOZU(records.Open, records.High, records.Low, records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.CDLMARUBOZU(records);
    Log(ret);
}

### talib.CDLMATCHINGLOW

```talib.CDLMATCHINGLOW()```函数用于计算**Matching Low (K线图:匹配低)**。

```talib.CDLMATCHINGLOW()```函数的返回值为:一维数组。
array

talib.CDLMATCHINGLOW(inPriceOHLC)

```inPriceOHLC```参数用于指定K线数据。
inPriceOHLC
true
{@struct/Record Record}结构数组

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.CDLMATCHINGLOW(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.CDLMATCHINGLOW(records.Open, records.High, records.Low, records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.CDLMATCHINGLOW(records);
    Log(ret);
}

### talib.CDLMATHOLD

```talib.CDLMATHOLD()```函数用于计算**Mat Hold (K线图:垫住)**。

```talib.CDLMATHOLD()```函数的返回值为:一维数组。
array

talib.CDLMATHOLD(inPriceOHLC)
talib.CDLMATHOLD(inPriceOHLC, optInPenetration)

```inPriceOHLC```参数用于指定K线数据。
inPriceOHLC
true
{@struct/Record Record}结构数组
```optInPenetration```参数为可选参数,用于指定上升/下降趋势线的宽度占比,默认值为0.5。
optInPenetration
false
number

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.CDLMATHOLD(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.CDLMATHOLD(records.Open, records.High, records.Low, records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.CDLMATHOLD(records);
    Log(ret);
}

### talib.CDLMORNINGDOJISTAR

```talib.CDLMORNINGDOJISTAR()```函数用于计算**Morning Doji Star (K线图:早晨十字星)**。

```talib.CDLMORNINGDOJISTAR()```函数的返回值为:一维数组。
array

talib.CDLMORNINGDOJISTAR(inPriceOHLC)
talib.CDLMORNINGDOJISTAR(inPriceOHLC, optInPenetration)

```inPriceOHLC```参数用于指定K线数据。
inPriceOHLC
true
{@struct/Record Record}结构数组
```optInPenetration```参数用于指定验证开盘价和实体部分重合的程度,默认值为0.3。
optInPenetration
false
number

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.CDLMORNINGDOJISTAR(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.CDLMORNINGDOJISTAR(records.Open, records.High, records.Low, records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.CDLMORNINGDOJISTAR(records);
    Log(ret);
}

### talib.CDLMORNINGSTAR

```talib.CDLMORNINGSTAR()```函数用于计算**Morning Star (K线图:晨星)**。

```talib.CDLMORNINGSTAR()```函数的返回值为:一维数组。
array

talib.CDLMORNINGSTAR(inPriceOHLC)
talib.CDLMORNINGSTAR(inPriceOHLC, optInPenetration)

```inPriceOHLC```参数用于指定K线数据。
inPriceOHLC
true
{@struct/Record Record}结构数组
```optInPenetration```参数为趋势确认所需价格浮动百分比阈值,取值范围[0,1],默认值为0.3。
optInPenetration
false
number

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.CDLMORNINGSTAR(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.CDLMORNINGSTAR(records.Open, records.High, records.Low, records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.CDLMORNINGSTAR(records);
    Log(ret);
}

### talib.CDLONNECK

```talib.CDLONNECK()```函数用于计算**On-Neck Pattern (K线图:颈型)**。

```talib.CDLONNECK()```函数的返回值为:一维数组。
array

talib.CDLONNECK(inPriceOHLC)

```inPriceOHLC```参数用于指定K线数据。
inPriceOHLC
true
{@struct/Record Record}结构数组

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.CDLONNECK(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.CDLONNECK(records.Open, records.High, records.Low, records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.CDLONNECK(records);
    Log(ret);
}

### talib.CDLPIERCING

```talib.CDLPIERCING()```函数用于计算**Piercing Pattern (K线图:穿孔模式)**。

```talib.CDLPIERCING()```函数的返回值为:一维数组。
array

talib.CDLPIERCING(inPriceOHLC)

```inPriceOHLC```参数用于指定K线数据。
inPriceOHLC
true
{@struct/Record Record}结构数组

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.CDLPIERCING(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.CDLPIERCING(records.Open, records.High, records.Low, records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.CDLPIERCING(records);
    Log(ret);
}

### talib.CDLRICKSHAWMAN

```talib.CDLRICKSHAWMAN()```函数用于计算**Rickshaw Man (K线图:车夫)**。

```talib.CDLRICKSHAWMAN()```函数的返回值为:一维数组。
array

talib.CDLRICKSHAWMAN(inPriceOHLC)

```inPriceOHLC```参数用于指定K线数据。
inPriceOHLC
true
{@struct/Record Record}结构数组

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.CDLRICKSHAWMAN(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.CDLRICKSHAWMAN(records.Open, records.High, records.Low, records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.CDLRICKSHAWMAN(records);
    Log(ret);
}

### talib.CDLRISEFALL3METHODS

```talib.CDLRISEFALL3METHODS()```函数用于计算**Rising/Falling Three Methods (K线图:上升/下降三法)**。

```talib.CDLRISEFALL3METHODS()```函数的返回值为:一维数组。
array

talib.CDLRISEFALL3METHODS(inPriceOHLC)

```inPriceOHLC```参数用于指定K线数据。
inPriceOHLC
true
{@struct/Record Record}结构数组

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.CDLRISEFALL3METHODS(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.CDLRISEFALL3METHODS(records.Open, records.High, records.Low, records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.CDLRISEFALL3METHODS(records);
    Log(ret);
}

### talib.CDLSEPARATINGLINES

```talib.CDLSEPARATINGLINES()```函数用于计算**Separating Lines (K线图:分割线)**。

```talib.CDLSEPARATINGLINES()```函数的返回值为:一维数组。
array

talib.CDLSEPARATINGLINES(inPriceOHLC)

```inPriceOHLC```参数用于指定K线数据。
inPriceOHLC
true
{@struct/Record Record}结构数组

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.CDLSEPARATINGLINES(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.CDLSEPARATINGLINES(records.Open, records.High, records.Low, records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.CDLSEPARATINGLINES(records);
    Log(ret);
}

### talib.CDLSHOOTINGSTAR

```talib.CDLSHOOTINGSTAR()```函数用于计算**Shooting Star (K线图:流星)**。

```talib.CDLSHOOTINGSTAR()```函数的返回值为:一维数组。
array

talib.CDLSHOOTINGSTAR(inPriceOHLC)

```inPriceOHLC```参数用于指定K线数据。
inPriceOHLC
true
{@struct/Record Record}结构数组

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.CDLSHOOTINGSTAR(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.CDLSHOOTINGSTAR(records.Open, records.High, records.Low, records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.CDLSHOOTINGSTAR(records);
    Log(ret);
}

### talib.CDLSHORTLINE

```talib.CDLSHORTLINE()```函数用于计算**Short Line Candle (K线图:短线)**。

```talib.CDLSHORTLINE()```函数的返回值为:一维数组。
array

talib.CDLSHORTLINE(inPriceOHLC)

```inPriceOHLC```参数用于指定K线数据。
inPriceOHLC
true
{@struct/Record Record}结构数组

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.CDLSHORTLINE(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.CDLSHORTLINE(records.Open, records.High, records.Low, records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.CDLSHORTLINE(records);
    Log(ret);
}

### talib.CDLSPINNINGTOP

```talib.CDLSPINNINGTOP()```函数用于计算**Spinning Top (K线图:陀螺)**。

```talib.CDLSPINNINGTOP()```函数的返回值为:一维数组。
array

talib.CDLSPINNINGTOP(inPriceOHLC)

```inPriceOHLC```参数用于指定K线数据。
inPriceOHLC
true
{@struct/Record Record}结构数组

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.CDLSPINNINGTOP(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.CDLSPINNINGTOP(records.Open, records.High, records.Low, records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.CDLSPINNINGTOP(records);
    Log(ret);
}

### talib.CDLSTALLEDPATTERN

```talib.CDLSTALLEDPATTERN()```函数用于计算**Stalled Pattern (K线图:停滞模式)**。

```talib.CDLSTALLEDPATTERN()```函数的返回值为:一维数组。
array

talib.CDLSTALLEDPATTERN(inPriceOHLC)

```inPriceOHLC```参数用于指定K线数据。
inPriceOHLC
true
{@struct/Record Record}结构数组

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.CDLSTALLEDPATTERN(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.CDLSTALLEDPATTERN(records.Open, records.High, records.Low, records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.CDLSTALLEDPATTERN(records);
    Log(ret);
}

### talib.CDLSTICKSANDWICH

```talib.CDLSTICKSANDWICH()```函数用于计算**Stick Sandwich (K线图:棍子三明治)**。

```talib.CDLSTICKSANDWICH()```函数的返回值为:一维数组。
array

talib.CDLSTICKSANDWICH(inPriceOHLC)

```inPriceOHLC```参数用于指定K线数据。
inPriceOHLC
true
{@struct/Record Record}结构数组

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.CDLSTICKSANDWICH(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.CDLSTICKSANDWICH(records.Open, records.High, records.Low, records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.CDLSTICKSANDWICH(records);
    Log(ret);
}

### talib.CDLTAKURI

```talib.CDLTAKURI()```函数用于计算**Takuri (Dragonfly Doji with very long lower shadow) (K线图:托里)**。

```talib.CDLTAKURI()```函数的返回值为:一维数组。
array

talib.CDLTAKURI(inPriceOHLC)

```inPriceOHLC```参数用于指定K线数据。
inPriceOHLC
true
{@struct/Record Record}结构数组

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.CDLTAKURI(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.CDLTAKURI(records.Open, records.High, records.Low, records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.CDLTAKURI(records);
    Log(ret);
}

### talib.CDLTASUKIGAP

```talib.CDLTASUKIGAP()```函数用于计算**Tasuki Gap (K线图:翼隙)**。

```talib.CDLTASUKIGAP()```函数的返回值为:一维数组。
array

talib.CDLTASUKIGAP(inPriceOHLC)

```inPriceOHLC```参数用于指定K线数据。
inPriceOHLC
true
{@struct/Record Record}结构数组

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.CDLTASUKIGAP(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.CDLTASUKIGAP(records.Open, records.High, records.Low, records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.CDLTASUKIGAP(records);
    Log(ret);
}

### talib.CDLTHRUSTING

```talib.CDLTHRUSTING()```函数用于计算**Thrusting Pattern (K线图:推模式)**。

```talib.CDLTHRUSTING()```函数的返回值为:一维数组。
array

talib.CDLTHRUSTING(inPriceOHLC)

```inPriceOHLC```参数用于指定K线数据。
inPriceOHLC
true
{@struct/Record Record}结构数组

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.CDLTHRUSTING(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.CDLTHRUSTING(records.Open, records.High, records.Low, records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.CDLTHRUSTING(records);
    Log(ret);
}

### talib.CDLTRISTAR

```talib.CDLTRISTAR()```函数用于计算**Tristar Pattern (K线图:三星模式)**。

```talib.CDLTRISTAR()```函数的返回值为:一维数组。
array

talib.CDLTRISTAR(inPriceOHLC)

```inPriceOHLC```参数用于指定K线数据。
inPriceOHLC
true
{@struct/Record Record}结构数组

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.CDLTRISTAR(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.CDLTRISTAR(records.Open, records.High, records.Low, records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.CDLTRISTAR(records);
    Log(ret);
}

### talib.CDLUNIQUE3RIVER

```talib.CDLUNIQUE3RIVER()```函数用于计算**Unique 3 River (K线图:独特的3河)**。

```talib.CDLUNIQUE3RIVER()```函数的返回值为:一维数组。
array

talib.CDLUNIQUE3RIVER(inPriceOHLC)

```inPriceOHLC```参数用于指定K线数据。
inPriceOHLC
true
{@struct/Record Record}结构数组

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.CDLUNIQUE3RIVER(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.CDLUNIQUE3RIVER(records.Open, records.High, records.Low, records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.CDLUNIQUE3RIVER(records);
    Log(ret);
}

### talib.CDLUPSIDEGAP2CROWS

```talib.CDLUPSIDEGAP2CROWS()```函数用于计算**Upside Gap Two Crows (K线图:双飞乌鸦)**。

```talib.CDLUPSIDEGAP2CROWS()```函数的返回值为:一维数组。
array

talib.CDLUPSIDEGAP2CROWS(inPriceOHLC)

```inPriceOHLC```参数用于指定K线数据。
inPriceOHLC
true
{@struct/Record Record}结构数组

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.CDLUPSIDEGAP2CROWS(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.CDLUPSIDEGAP2CROWS(records.Open, records.High, records.Low, records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.CDLUPSIDEGAP2CROWS(records);
    Log(ret);
}

### talib.CDLXSIDEGAP3METHODS

```talib.CDLXSIDEGAP3METHODS()```函数用于计算**Upside/Downside Gap Three Methods (K线图:上行/下行缺口三方法)**。

```talib.CDLXSIDEGAP3METHODS()```函数的返回值为:一维数组。
array

talib.CDLXSIDEGAP3METHODS(inPriceOHLC)

```inPriceOHLC```参数用于指定K线数据。
inPriceOHLC
true
{@struct/Record Record}结构数组

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.CDLXSIDEGAP3METHODS(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.CDLXSIDEGAP3METHODS(records.Open, records.High, records.Low, records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.CDLXSIDEGAP3METHODS(records);
    Log(ret);
}

### talib.AD

```talib.AD()```函数用于计算**Chaikin A/D Line (线随机指标)**。

```talib.AD()```函数的返回值为:一维数组。
array

talib.AD(inPriceHLCV)

```inPriceHLCV```参数用于指定K线数据。
inPriceHLCV
true
{@struct/Record Record}结构数组

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.AD(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.AD(records.High, records.Low, records.Close, records.Volume)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.AD(records);
    Log(ret);
}

### talib.ADOSC

```talib.ADOSC()```函数用于计算**Chaikin A/D Oscillator (佳庆指标)**。

```talib.ADOSC()```函数的返回值为:一维数组。
array

talib.ADOSC(inPriceHLCV)
talib.ADOSC(inPriceHLCV, optInFastPeriod, optInSlowPeriod)

```inPriceHLCV```参数用于指定K线数据。
inPriceHLCV
true
{@struct/Record Record}结构数组
```optInFastPeriod```参数用于设置快周期。
optInFastPeriod
false
number
```optInSlowPeriod```参数用于设置慢周期。
optInSlowPeriod
false
number

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.ADOSC(records, 3, 10)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.ADOSC(records.High, records.Low, records.Close, records.Volume, 3, 10)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.ADOSC(records, 3, 10);
    Log(ret);
}

### talib.OBV

```talib.OBV()```函数用于计算**On Balance Volume (能量潮)**。

```talib.OBV()```函数的返回值为:一维数组。
array

talib.OBV(inReal)
talib.OBV(inReal, inPriceV)

```inReal```参数用于指定K线数据。
inReal
true
{@struct/Record Record}结构数组、数值数组
```inPriceV```参数用于指定K线数据。
inPriceV
false
{@struct/Record Record}结构数组

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.OBV(records, records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.OBV(records.Close, records.Volume)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.OBV(records);
    Log(ret);
}

### talib.ACOS

```talib.ACOS()```函数用于计算**Vector Trigonometric ACos (反余弦函数)**。

```talib.ACOS()```函数的返回值为:一维数组。
array

talib.ACOS(inReal)

```inReal```参数用于指定K线数据。
inReal
true
{@struct/Record Record}结构数组、数值数组

```javascript
function main() {
    var data = [-1, 0, 1]
    var ret = talib.ACOS(data)
    Log(ret)
}
import talib
import numpy as np
def main():
    data = [-1.0, 0, 1.0]
    ret = talib.ACOS(np.array(data))
    Log(ret)
void main() {
    std::vector<double> data = {-1, 0, 1};
    auto ret = talib.ACOS(data);
    Log(ret);
}

### talib.ASIN

```talib.ASIN()```函数用于计算**Vector Trigonometric ASin (反正弦函数)**。

```talib.ASIN()```函数的返回值为:一维数组。
array

talib.ASIN(inReal)

```inReal```参数用于指定K线数据。
inReal
true
{@struct/Record Record}结构数组、数值数组

```javascript
function main() {
    var data = [-1, 0, 1]
    var ret = talib.ASIN(data)
    Log(ret)
}
import talib
import numpy as np
def main():
    data = [-1.0, 0, 1.0]
    ret = talib.ASIN(np.array(data))
    Log(ret)
void main() {
    std::vector<double> data = {-1, 0, 1};
    auto ret = talib.ASIN(data);
    Log(ret);
}

### talib.ATAN

```talib.ATAN()```函数用于计算**Vector Trigonometric ATan (反正切函数)**。

```talib.ATAN()```函数的返回值为:一维数组。
array

talib.ATAN(inReal)

```inReal```参数用于指定K线数据。
inReal
true
{@struct/Record Record}结构数组、数值数组

```javascript
function main() {
    var data = [-3.14/2, 0, 3.14/2]
    var ret = talib.ATAN(data)
    Log(ret)
}
import talib
import numpy as np
def main():
    data = [-3.14/2, 0, 3.14/2]
    ret = talib.ATAN(np.array(data))
    Log(ret)
void main() {
    std::vector<double> data = {-3.14/2, 0, 3.14/2};
    auto ret = talib.ATAN(data);
    Log(ret);
}

### talib.CEIL

```talib.CEIL()```函数用于计算**Vector Ceil (取整函数)**。

```talib.CEIL()```函数的返回值为:一维数组。
array

talib.CEIL(inReal)

```inReal```参数用于指定K线数据。
inReal
true
{@struct/Record Record}结构数组、数值数组

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.CEIL(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.CEIL(records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.CEIL(records);
    Log(ret);
}

### talib.COS

```talib.COS()```函数用于计算**Vector Trigonometric Cos (余弦函数)**。

```talib.COS()```函数的返回值为:一维数组。
array

talib.COS(inReal)

```inReal```参数用于指定K线数据。
inReal
true
{@struct/Record Record}结构数组、数值数组

```javascript
function main() {
    var data = [-3.14, 0, 3.14]
    var ret = talib.COS(data)
    Log(ret)
}
import talib
import numpy as np
def main():
    data = [-3.14, 0, 3.14]
    ret = talib.COS(np.array(data))
    Log(ret)
void main() {
    std::vector<double> data = {-3.14, 0, 3.14};
    auto ret = talib.COS(data);
    Log(ret);
}

### talib.COSH

```talib.COSH()```函数用于计算**Vector Trigonometric Cosh (双曲余弦值)**。

```talib.COSH()```函数的返回值为:一维数组。
array

talib.COSH(inReal)

```inReal```参数用于指定K线数据。
inReal
true
{@struct/Record Record}结构数组、数值数组

```javascript
function main() {
    var data = [-1, 0, 1]
    var ret = talib.COSH(data)
    Log(ret)
}
import talib
import numpy as np
def main():
    data = [-1.0, 0, 1.0]
    ret = talib.COSH(np.array(data))
    Log(ret)
void main() {
    std::vector<double> data = {-1, 0, 1};
    auto ret = talib.COSH(data);
    Log(ret);
}

### talib.EXP

```talib.EXP()```函数用于计算**Vector Arithmetic Exp (指数函数)**。

```talib.EXP()```函数的返回值为:一维数组。
array

talib.EXP(inReal)

```inReal```参数用于指定K线数据。
inReal
true
{@struct/Record Record}结构数组、数值数组

```javascript
function main() {
    var data = [0, 1, 2]
    var ret = talib.EXP(data)    // e^0, e^1, e^2
    Log(ret)
}
import talib
import numpy as np
def main():
    data = [0, 1.0, 2.0]
    ret = talib.EXP(np.array(data))
    Log(ret)
void main() {
    std::vector<double> data = {0, 1.0, 2.0};
    auto ret = talib.EXP(data);
    Log(ret);
}

### talib.FLOOR

```talib.FLOOR()```函数用于计算**Vector Floor (向下取整)**。

```talib.FLOOR()```函数的返回值为:一维数组。
array

talib.FLOOR(inReal)

```inReal```参数用于指定K线数据。
inReal
true
{@struct/Record Record}结构数组、数值数组

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.FLOOR(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.FLOOR(records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.FLOOR(records);
    Log(ret);
}

### talib.LN

```talib.LN()```函数用于计算**Vector Log Natural (自然对数)**。

```talib.LN()```函数的返回值为:一维数组。
array

talib.LN(inReal)

```inReal```参数用于指定K线数据。
inReal
true
{@struct/Record Record}结构数组、数值数组

```javascript
function main() {
    var data = [1, 2, 3]
    var ret = talib.LN(data)
    Log(ret)
}
import talib
import numpy as np
def main():
    data = [1.0, 2.0, 3.0]
    ret = talib.LN(np.array(data))
    Log(ret)
void main() {
    std::vector<double> data = {1, 2, 3};
    auto ret = talib.LN(data);
    Log(ret);
}

### talib.LOG10

```talib.LOG10()```函数用于计算**Vector Log10 (对数函数)**。

```talib.LOG10()```函数的返回值为:一维数组。
array

talib.LOG10(inReal)

```inReal```参数用于指定K线数据。
inReal
true
{@struct/Record Record}结构数组、数值数组

```javascript
function main() {
    var data = [10, 100, 1000]
    var ret = talib.LOG10(data)
    Log(ret)
}
import talib
import numpy as np
def main():
    data = [10.0, 100.0, 1000.0]
    ret = talib.LOG10(np.array(data))
    Log(ret)
void main() {
    std::vector<double> data = {10, 100, 1000};
    auto ret = talib.LOG10(data);
    Log(ret);
}

### talib.SIN

```talib.SIN()```函数用于计算**Vector Trigonometric Sin (正弦值)**。

```talib.SIN()```函数的返回值为:一维数组。
array

talib.SIN(inReal)

```inReal```参数用于指定K线数据。
inReal
true
{@struct/Record Record}结构数组、数值数组

```javascript
function main() {
    var data = [-3.14/2, 0, 3.14/2]
    var ret = talib.SIN(data)
    Log(ret)
}
import talib
import numpy as np
def main():
    data = [-3.14/2, 0, 3.14/2]
    ret = talib.SIN(np.array(data))
    Log(ret)
void main() {
    std::vector<double> data = {-3.14/2, 0, 3.14/2};
    auto ret = talib.SIN(data);
    Log(ret);
}

### talib.SINH

```talib.SINH()```函数用于计算**Vector Trigonometric Sinh (双曲正弦函数)**。

```talib.SINH()```函数的返回值为:一维数组。
array

talib.SINH(inReal)

```inReal```参数用于指定K线数据。
inReal
true
{@struct/Record Record}结构数组、数值数组

```javascript
function main() {
    var data = [-1, 0, 1]
    var ret = talib.SINH(data)
    Log(ret)
}
import talib
import numpy as np
def main():
    data = [-1.0, 0, 1.0]
    ret = talib.SINH(np.array(data))
    Log(ret)
void main() {
    std::vector<double> data = {-1, 0, 1};
    auto ret = talib.SINH(data);
    Log(ret);
}

### talib.SQRT

```talib.SQRT()```函数用于计算**Vector Square Root (平方根)**。

```talib.SQRT()```函数的返回值为:一维数组。
array

talib.SQRT(inReal)

```inReal```参数用于指定K线数据。
inReal
true
{@struct/Record Record}结构数组、数值数组

```javascript
function main() {
    var data = [4, 64, 100]
    var ret = talib.SQRT(data)
    Log(ret)
}
import talib
import numpy as np
def main():
    data = [4.0, 64.0, 100.0]
    ret = talib.SQRT(np.array(data))
    Log(ret)
void main() {
    std::vector<double> data = {4, 64, 100};
    auto ret = talib.SQRT(data);
    Log(ret);
}

### talib.TAN

```talib.TAN()```函数用于计算**Vector Trigonometric Tan (正切)**。

```talib.TAN()```函数的返回值为:一维数组。
array

talib.TAN(inReal)

```inReal```参数用于指定K线数据。
inReal
true
{@struct/Record Record}结构数组、数值数组

```javascript
function main() {
    var data = [-1, 0, 1]
    var ret = talib.TAN(data)
    Log(ret)
}
import talib
import numpy as np
def main():
    data = [-1.0, 0, 1.0]
    ret = talib.TAN(np.array(data))
    Log(ret)
void main() {
    std::vector<double> data = {-1, 0, 1};
    auto ret = talib.TAN(data);
    Log(ret);
}

### talib.TANH

```talib.TANH()```函数用于计算**Vector Trigonometric Tanh (双曲正切函数)**。

```talib.TANH()```函数的返回值为:一维数组。
array

talib.TANH(inReal)

```inReal```参数用于指定K线数据。
inReal
true
{@struct/Record Record}结构数组、数值数组

```javascript
function main() {
    var data = [-1, 0, 1]
    var ret = talib.TANH(data)
    Log(ret)
}
import talib
import numpy as np
def main():
    data = [-1.0, 0, 1.0]
    ret = talib.TANH(np.array(data))
    Log(ret)
void main() {
    std::vector<double> data = {-1, 0, 1};
    auto ret = talib.TANH(data);
    Log(ret);
}

### talib.MAX

```talib.MAX()```函数用于计算**Highest value over a specified period (最大值)**。

```talib.MAX()```函数的返回值为:一维数组。
array

talib.MAX(inReal)
talib.MAX(inReal, optInTimePeriod)

```inReal```参数用于指定K线数据。
inReal
true
{@struct/Record Record}结构数组、数值数组
```optInTimePeriod```参数用于设置周期,默认值为30。
optInTimePeriod
false
number

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.MAX(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.MAX(records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.MAX(records);
    Log(ret);
}

### talib.MAXINDEX

```talib.MAXINDEX()```函数用于计算**Index of highest value over a specified period (最大值索引)**。

```talib.MAXINDEX()```函数的返回值为:一维数组。
array

talib.MAXINDEX(inReal)
talib.MAXINDEX(inReal, optInTimePeriod)

```inReal```参数用于指定K线数据。
inReal
true
{@struct/Record Record}结构数组、数值数组
```optInTimePeriod```参数用于设置周期,默认值为30。
optInTimePeriod
false
number

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.MAXINDEX(records, 5)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.MAXINDEX(records.Close, 5)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.MAXINDEX(records, 5);
    Log(ret);
}

### talib.MIN

```talib.MIN()```函数用于计算**Lowest value over a specified period (最小值)**。

```talib.MIN()```函数的返回值为:一维数组。
array

talib.MIN(inReal)
talib.MIN(inReal, optInTimePeriod)

```inReal```参数用于指定K线数据。
inReal
true
{@struct/Record Record}结构数组、数值数组
```optInTimePeriod```参数用于设置周期,默认值为30。
optInTimePeriod
false
number

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.MIN(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.MIN(records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.MIN(records);
    Log(ret);
}

### talib.MININDEX

```talib.MININDEX()```函数用于计算**Index of lowest value over a specified period (最小值索引)**。

```talib.MININDEX()```函数的返回值为:一维数组。
array

talib.MININDEX(inReal)
talib.MININDEX(inReal, optInTimePeriod)

```inReal```参数用于指定K线数据。
inReal
true
{@struct/Record Record}结构数组、数值数组
```optInTimePeriod```参数用于设置周期,默认值为30。
optInTimePeriod
false
number

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.MININDEX(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.MININDEX(records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.MININDEX(records);
    Log(ret);
}

### talib.MINMAX

```talib.MINMAX()```函数用于计算**Lowest and highest values over a specified period (最小最大值)**。

```talib.MINMAX()```函数的返回值为:二维数组。该二维数组的第一个元素为最小值数组,第二个元素为最大值数组。
array

talib.MINMAX(inReal)
talib.MINMAX(inReal, optInTimePeriod)

```inReal```参数用于指定K线数据。
inReal
true
{@struct/Record Record}结构数组、数值数组
```optInTimePeriod```参数用于设置周期,默认值为30。
optInTimePeriod
false
number

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.MINMAX(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.MINMAX(records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.MINMAX(records);
    Log(ret);
}

### talib.MINMAXINDEX

```talib.MINMAXINDEX()```函数用于计算**Indexes of lowest and highest values over a specified period (最小最大值索引)**。

```talib.MINMAXINDEX()```函数的返回值为:二维数组。该二维数组的第一个元素为最小值索引数组,第二个元素为最大值索引数组。
array

talib.MINMAXINDEX(inReal)
talib.MINMAXINDEX(inReal, optInTimePeriod)

```inReal```参数用于指定K线数据。
inReal
true
{@struct/Record Record}结构数组、数值数组
```optInTimePeriod```参数用于设置周期,默认值为30。
optInTimePeriod
false
number

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.MINMAXINDEX(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.MINMAXINDEX(records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.MINMAXINDEX(records);
    Log(ret);
}

### talib.SUM

```talib.SUM()```函数用于计算**Summation (求和)**。

```talib.SUM()```函数的返回值为:一维数组。
array

talib.SUM(inReal)
talib.SUM(inReal, optInTimePeriod)

```inReal```参数用于指定K线数据。
inReal
true
{@struct/Record Record}结构数组、数值数组
```optInTimePeriod```参数用于设置周期,默认值为30。
optInTimePeriod
false
number

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.SUM(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.SUM(records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.SUM(records);
    Log(ret);
}

### talib.HT_DCPERIOD

```talib.HT_DCPERIOD()```函数用于计算**Hilbert Transform - Dominant Cycle Period (希尔伯特变换, 主周期)**。

```talib.HT_DCPERIOD()```函数的返回值为:一维数组。
array

talib.HT_DCPERIOD(inReal)

```inReal```参数用于指定K线数据。
inReal
true
{@struct/Record Record}结构数组、数值数组

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.HT_DCPERIOD(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.HT_DCPERIOD(records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.HT_DCPERIOD(records);
    Log(ret);
}

### talib.HT_DCPHASE

```talib.HT_DCPHASE()```函数用于计算**Hilbert Transform - Dominant Cycle Phase (希尔伯特变换,主阶段)**。

```talib.HT_DCPHASE()```函数的返回值为:一维数组。
array

talib.HT_DCPHASE(inReal)

```inReal```参数用于指定K线数据。
inReal
true
{@struct/Record Record}结构数组、数值数组

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.HT_DCPHASE(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.HT_DCPHASE(records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.HT_DCPHASE(records);
    Log(ret);
}

### talib.HT_PHASOR

```talib.HT_PHASOR()```函数用于计算**Hilbert Transform - Phasor Components (希尔伯特变换,相成分)**。

```talib.HT_PHASOR()```函数的返回值为:二维数组。
array

talib.HT_PHASOR(inReal)

```inReal```参数用于指定K线数据。
inReal
true
{@struct/Record Record}结构数组、数值数组

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.HT_PHASOR(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.HT_PHASOR(records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.HT_PHASOR(records);
    Log(ret);
}

### talib.HT_SINE

```talib.HT_SINE()```函数用于计算**Hilbert Transform - SineWave (希尔伯特变换,正弦波)**。

```talib.HT_SINE()```函数的返回值为:二维数组。
array

talib.HT_SINE(inReal)

```inReal```参数用于指定K线数据。
inReal
true
{@struct/Record Record}结构数组、数值数组

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.HT_SINE(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.HT_SINE(records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.HT_SINE(records);
    Log(ret);
}

### talib.HT_TRENDMODE

```talib.HT_TRENDMODE()```函数用于计算**Hilbert Transform - Trend vs Cycle Mode (希尔伯特变换-趋势与周期模式)**。

```talib.HT_TRENDMODE()```函数的返回值为:一维数组。
array

talib.HT_TRENDMODE(inReal)

```inReal```参数用于指定K线数据。
inReal
true
{@struct/Record Record}结构数组、数值数组

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.HT_TRENDMODE(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.HT_TRENDMODE(records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.HT_TRENDMODE(records);
    Log(ret);
}

### talib.ATR

```talib.ATR()```函数用于计算**Average True Range (平均真实波幅)**。

```talib.ATR()```函数的返回值为:一维数组。
array

talib.ATR(inPriceHLC)
talib.ATR(inPriceHLC, optInTimePeriod)

```inPriceHLC```参数用于指定K线数据。
inPriceHLC
true
{@struct/Record Record}结构数组
```optInTimePeriod```参数用于设置周期,默认值为14。
optInTimePeriod
false
number

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.ATR(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.ATR(records.High, records.Low, records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.ATR(records);
    Log(ret);
}

### talib.NATR

```talib.NATR()```函数用于计算**Normalized Average True Range (归一化平均值范围)**。

```talib.NATR()```函数的返回值为:一维数组。
array

talib.NATR(inPriceHLC)
talib.NATR(inPriceHLC, optInTimePeriod)

```inPriceHLC```参数用于指定K线数据。
inPriceHLC
true
{@struct/Record Record}结构数组
```optInTimePeriod```参数用于设置周期,默认值为14。
optInTimePeriod
false
number

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.NATR(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.NATR(records.High, records.Low, records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.NATR(records);
    Log(ret);
}

### talib.TRANGE

```talib.TRANGE()```函数用于计算**True Range (真实范围)**。

```talib.TRANGE()```函数的返回值为:一维数组。
array

talib.TRANGE(inPriceHLC)

```inPriceHLC```参数用于指定K线数据。
inPriceHLC
true
{@struct/Record Record}结构数组

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.TRANGE(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.TRANGE(records.High, records.Low, records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.TRANGE(records);
    Log(ret);
}

### talib.BBANDS

```talib.BBANDS()```函数用于计算**Bollinger Bands (布林带)**。

```talib.BBANDS()```函数的返回值为:二维数组。该数组包含三个元素分别是:上线数组、中线数组、下线数组。
array

talib.BBANDS(inReal)
talib.BBANDS(inReal, optInTimePeriod)
talib.BBANDS(inReal, optInTimePeriod, optInNbDevUp)
talib.BBANDS(inReal, optInTimePeriod, optInNbDevUp, optInNbDevDn)
talib.BBANDS(inReal, optInTimePeriod, optInNbDevUp, optInNbDevDn, optInMAType)

```inReal```参数用于指定K线数据。
inReal
true
{@struct/Record Record}结构数组、数值数组
```optInTimePeriod```参数用于设置周期,默认值为5。
optInTimePeriod
false
number
```optInNbDevUp```参数用于设置上线乘数,默认值为2。
optInNbDevUp
false
number
```optInNbDevDn```参数用于设置下线乘数,默认值为2。
optInNbDevDn
false
number
```optInMAType```参数用于设置均线类型,默认值为0。
optInMAType
false
number

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.BBANDS(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.BBANDS(records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.BBANDS(records);
    Log(ret);
}

### talib.DEMA

```talib.DEMA()```函数用于计算**Double Exponential Moving Average (双指数移动平均线)**。

```talib.DEMA()```函数的返回值为:一维数组。
array

talib.DEMA(inReal)
talib.DEMA(inReal, optInTimePeriod)

```inReal```参数用于指定K线数据。
inReal
true
{@struct/Record Record}结构数组、数值数组
```optInTimePeriod```参数用于设置周期,默认值为30。
optInTimePeriod
false
number

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.DEMA(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.DEMA(records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.DEMA(records);
    Log(ret);
}

### talib.EMA

```talib.EMA()```函数用于计算**Exponential Moving Average (指数移动平均线)**。

```talib.EMA()```函数的返回值为:一维数组。
array

talib.EMA(inReal)
talib.EMA(inReal, optInTimePeriod)

```inReal```参数用于指定K线数据。
inReal
true
{@struct/Record Record}结构数组、数值数组
```optInTimePeriod```参数用于设置周期,默认值为30。
optInTimePeriod
false
number

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.EMA(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.EMA(records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.EMA(records);
    Log(ret);
}

### talib.HT_TRENDLINE

```talib.HT_TRENDLINE()```函数用于计算**Hilbert Transform - Instantaneous Trendline (希尔伯特变换,瞬时趋势)**。

```talib.HT_TRENDLINE()```函数的返回值为:一维数组。
array

talib.HT_TRENDLINE(inReal)

```inReal```参数用于指定K线数据。
inReal
true
{@struct/Record Record}结构数组、数值数组

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.HT_TRENDLINE(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.HT_TRENDLINE(records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.HT_TRENDLINE(records);
    Log(ret);
}

### talib.KAMA

```talib.KAMA()```函数用于计算**Kaufman Adaptive Moving Average (适应性移动平均线)**。

```talib.KAMA()```函数的返回值为:一维数组。
array

talib.KAMA(inReal)
talib.KAMA(inReal, optInTimePeriod)

```inReal```参数用于指定K线数据。
inReal
true
{@struct/Record Record}结构数组、数值数组
```optInTimePeriod```参数用于设置周期,默认值为30。
optInTimePeriod
false
number

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.KAMA(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.KAMA(records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.KAMA(records);
    Log(ret);
}

### talib.MA

```talib.MA()```函数用于计算**Moving average (移动平均线)**。

```talib.MA()```函数的返回值为:一维数组。
array

talib.MA(inReal)
talib.MA(inReal, optInTimePeriod)
talib.MA(inReal, optInTimePeriod, optInMAType)

```inReal```参数用于指定K线数据。
inReal
true
{@struct/Record Record}结构数组、数值数组
```optInTimePeriod```参数用于设置周期,默认值为30。
optInTimePeriod
false
number
```optInMAType```参数用于设置均线类型,默认值为0。
optInMAType
false
number

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.MA(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.MA(records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.MA(records);
    Log(ret);
}

### talib.MAMA

```talib.MAMA()```函数用于计算**MESA Adaptive Moving Average (MESA 移动平均线)**。

```talib.MAMA()```函数的返回值为:二维数组。
array

talib.MAMA(inReal)
talib.MAMA(inReal, optInFastLimit)
talib.MAMA(inReal, optInFastLimit, optInSlowLimit)

```inReal```参数用于指定K线数据。
inReal
true
{@struct/Record Record}结构数组、数值数组
```optInFastLimit```参数用于设置Fast Limit,默认值为0.5。
optInFastLimit
false
number
```optInSlowLimit```参数用于设置Slow Limit,默认值为0.05。
optInSlowLimit
false
number

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.MAMA(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.MAMA(records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.MAMA(records);
    Log(ret);
}

### talib.MIDPOINT

```talib.MIDPOINT()```函数用于计算**MidPoint over period (中点)**。

```talib.MIDPOINT()```函数的返回值为:一维数组。
array

talib.MIDPOINT(inReal)
talib.MIDPOINT(inReal, optInTimePeriod)

```inReal```参数用于指定K线数据。
inReal
true
{@struct/Record Record}结构数组、数值数组
```optInTimePeriod```参数用于设置周期,默认值为14。
optInTimePeriod
false
number

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.MIDPOINT(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.MIDPOINT(records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.MIDPOINT(records);
    Log(ret);
}

### talib.MIDPRICE

```talib.MIDPRICE()```函数用于计算**Midpoint Price over period (中点价格)**。

```talib.MIDPRICE()```函数的返回值为:一维数组。
array

talib.MIDPRICE(inPriceHL)
talib.MIDPRICE(inPriceHL, optInTimePeriod)

```inPriceHL```参数用于指定K线数据。
inPriceHL
true
{@struct/Record Record}结构数组
```optInTimePeriod```参数用于设置周期,默认值为14。
optInTimePeriod
false
number

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.MIDPRICE(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.MIDPRICE(records.High, records.Low)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.MIDPRICE(records);
    Log(ret);
}

### talib.SAR

```talib.SAR()```函数用于计算**Parabolic SAR (抛物线转向)**。

```talib.SAR()```函数的返回值为:一维数组。
array

talib.SAR(inPriceHL)
talib.SAR(inPriceHL, optInAcceleration)
talib.SAR(inPriceHL, optInAcceleration, optInMaximum)

```inPriceHL```参数用于指定K线数据。
inPriceHL
true
{@struct/Record Record}结构数组
```optInAcceleration```参数用于设置Acceleration Factor,默认值为0.02。
optInAcceleration
false
number
```optInMaximum```参数用于设置AF Maximum,默认值为0.2。
optInMaximum
false
number

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.SAR(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.SAR(records.High, records.Low)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.SAR(records);
    Log(ret);
}

### talib.SAREXT

```talib.SAREXT()```函数用于计算**Parabolic SAR - Extended (增强型抛物线转向)**。

```talib.SAREXT()```函数的返回值为:一维数组。
array

talib.SAREXT(inPriceHL)
talib.SAREXT(inPriceHL, optInStartValue)
talib.SAREXT(inPriceHL, optInStartValue, optInOffsetOnReverse)
talib.SAREXT(inPriceHL, optInStartValue, optInOffsetOnReverse, optInAccelerationInitLong)
talib.SAREXT(inPriceHL, optInStartValue, optInOffsetOnReverse, optInAccelerationInitLong, optInAccelerationLong)
talib.SAREXT(inPriceHL, optInStartValue, optInOffsetOnReverse, optInAccelerationInitLong, optInAccelerationLong, optInAccelerationMaxLong)
talib.SAREXT(inPriceHL, optInStartValue, optInOffsetOnReverse, optInAccelerationInitLong, optInAccelerationLong, optInAccelerationMaxLong, optInAccelerationInitShort)
talib.SAREXT(inPriceHL, optInStartValue, optInOffsetOnReverse, optInAccelerationInitLong, optInAccelerationLong, optInAccelerationMaxLong, optInAccelerationInitShort, optInAccelerationShort)
talib.SAREXT(inPriceHL, optInStartValue, optInOffsetOnReverse, optInAccelerationInitLong, optInAccelerationLong, optInAccelerationMaxLong, optInAccelerationInitShort, optInAccelerationShort, optInAccelerationMaxShort)

```inPriceHL```参数用于指定K线数据。
inPriceHL
true
{@struct/Record Record}结构数组
```optInStartValue```参数用于设置Start Value,默认值为0。
optInStartValue
false
number
```optInOffsetOnReverse```参数用于设置Offset on Reverse,默认值为0。
optInOffsetOnReverse
false
number
```optInAccelerationInitLong```参数用于设置AF Init Long,默认值为0.02。
optInAccelerationInitLong
false
number
```optInAccelerationLong```参数用于设置AF Long,默认值为0.02。
optInAccelerationLong
false
number
```optInAccelerationMaxLong```参数用于设置AF Max Long,默认值为0.2。
optInAccelerationMaxLong
false
number
```optInAccelerationInitShort```参数用于设置AF Init Short,默认值为0.02。
optInAccelerationInitShort
false
number
```optInAccelerationShort```参数用于设置AF Short,默认值为0.02。
optInAccelerationShort
false
number
```optInAccelerationMaxShort```参数用于设置AF Max Short,默认值为0.2。
optInAccelerationMaxShort
false
number

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.SAREXT(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.SAREXT(records.High, records.Low)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.SAREXT(records);
    Log(ret);
}

### talib.SMA

```talib.SMA()```函数用于计算**Simple Moving Average (简单移动平均)**。

```talib.SMA()```函数的返回值为:一维数组。
array

talib.SMA(inReal)
talib.SMA(inReal, optInTimePeriod)

```inReal```参数用于指定K线数据。
inReal
true
{@struct/Record Record}结构数组、数值数组
```optInTimePeriod```参数用于设置周期,默认值为30。
optInTimePeriod
false
number

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.SMA(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.SMA(records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.SMA(records);
    Log(ret);
}

### talib.T3

```talib.T3()```函数用于计算**Triple Exponential Moving Average (T3) (三指数移动平均)**。

```talib.T3()```函数的返回值为:一维数组。
array

talib.T3(inReal)
talib.T3(inReal, optInTimePeriod)
talib.T3(inReal, optInTimePeriod, optInVFactor)

```inReal```参数用于指定K线数据。
inReal
true
{@struct/Record Record}结构数组、数值数组
```optInTimePeriod```参数用于设置周期,默认值为5。
optInTimePeriod
false
number
```optInVFactor```参数用于设置Volume Factor,默认值为0.7。
optInVFactor
false
number

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.T3(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.T3(records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.T3(records);
    Log(ret);
}

### talib.TEMA

```talib.TEMA()```函数用于计算**Triple Exponential Moving Average (三指数移动平均)**。

```talib.TEMA()```函数的返回值为:一维数组。
array

talib.TEMA(inReal)
talib.TEMA(inReal, optInTimePeriod)

```inReal```参数用于指定K线数据。
inReal
true
{@struct/Record Record}结构数组、数值数组
```optInTimePeriod```参数用于设置周期,默认值为30。
optInTimePeriod
false
number

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.TEMA(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.TEMA(records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.TEMA(records);
    Log(ret);
}

### talib.TRIMA

```talib.TRIMA()```函数用于计算**Triangular Moving Average (三指数移动平均)**。

```talib.TRIMA()```函数的返回值为:一维数组。
array

talib.TRIMA(inReal)
talib.TRIMA(inReal, optInTimePeriod)

```inReal```参数用于指定K线数据。
inReal
true
{@struct/Record Record}结构数组、数值数组
```optInTimePeriod```参数用于设置周期,默认值为30。
optInTimePeriod
false
number

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.TRIMA(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.TRIMA(records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.TRIMA(records);
    Log(ret);
}

### talib.WMA

```talib.WMA()```函数用于计算**Weighted Moving Average (加权移动平均)**。

```talib.WMA()```函数的返回值为:一维数组。
array

talib.WMA(inReal)
talib.WMA(inReal, optInTimePeriod)

```inReal```参数用于指定K线数据。
inReal
true
{@struct/Record Record}结构数组、数值数组
```optInTimePeriod```参数用于设置周期,默认值为30。
optInTimePeriod
false
number

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.WMA(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.WMA(records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.WMA(records);
    Log(ret);
}

### talib.LINEARREG

```talib.LINEARREG()```函数用于计算**Linear Regression (线性回归)**。

```talib.LINEARREG()```函数的返回值为:一维数组。
array

talib.LINEARREG(inReal)
talib.LINEARREG(inReal, optInTimePeriod)

```inReal```参数用于指定K线数据。
inReal
true
{@struct/Record Record}结构数组、数值数组
```optInTimePeriod```参数用于设置周期,默认值为14。
optInTimePeriod
false
number

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.LINEARREG(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.LINEARREG(records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.LINEARREG(records);
    Log(ret);
}

### talib.LINEARREG_ANGLE

```talib.LINEARREG_ANGLE()```函数用于计算**Linear Regression Angle (线性回归的角度)**。

```talib.LINEARREG_ANGLE()```函数的返回值为:一维数组。
array

talib.LINEARREG_ANGLE(inReal)
talib.LINEARREG_ANGLE(inReal, optInTimePeriod)

```inReal```参数用于指定K线数据。
inReal
true
{@struct/Record Record}结构数组、数值数组
```optInTimePeriod```参数用于设置周期,默认值为14。
optInTimePeriod
false
number

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.LINEARREG_ANGLE(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.LINEARREG_ANGLE(records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.LINEARREG_ANGLE(records);
    Log(ret);
}

### talib.LINEARREG_INTERCEPT

```talib.LINEARREG_INTERCEPT()```函数用于计算**Linear Regression Intercept (线性回归截距)**。

```talib.LINEARREG_INTERCEPT()```函数的返回值为:一维数组。
array

talib.LINEARREG_INTERCEPT(inReal)
talib.LINEARREG_INTERCEPT(inReal, optInTimePeriod)

```inReal```参数用于指定K线数据。
inReal
true
{@struct/Record Record}结构数组、数值数组
```optInTimePeriod```参数用于设置周期,默认值为14。
optInTimePeriod
false
number

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.LINEARREG_INTERCEPT(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.LINEARREG_INTERCEPT(records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.LINEARREG_INTERCEPT(records);
    Log(ret);
}

### talib.LINEARREG_SLOPE

```talib.LINEARREG_SLOPE()```函数用于计算**Linear Regression Slope (线性回归斜率)**。

```talib.LINEARREG_SLOPE()```函数的返回值为:一维数组。
array

talib.LINEARREG_SLOPE(inReal)
talib.LINEARREG_SLOPE(inReal, optInTimePeriod)

```inReal```参数用于指定K线数据。
inReal
true
{@struct/Record Record}结构数组、数值数组
```optInTimePeriod```参数用于设置周期,默认值为14。
optInTimePeriod
false
number

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.LINEARREG_SLOPE(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.LINEARREG_SLOPE(records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.LINEARREG_SLOPE(records);
    Log(ret);
}

### talib.STDDEV

```talib.STDDEV()```函数用于计算**Standard Deviation (标准偏差)**。

```talib.STDDEV()```函数的返回值为:一维数组。
array

talib.STDDEV(inReal)
talib.STDDEV(inReal, optInTimePeriod)
talib.STDDEV(inReal, optInTimePeriod, optInNbDev)

```inReal```参数用于指定K线数据。
inReal
true
{@struct/Record Record}结构数组、数值数组
```optInTimePeriod```参数用于设置周期,默认值为5。
optInTimePeriod
false
number
```optInNbDev```参数用于设置Deviations,默认值为1。
optInNbDev
false
number

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.STDDEV(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.STDDEV(records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.STDDEV(records);
    Log(ret);
}

### talib.TSF

```talib.TSF()```函数用于计算**Time Series Forecast (时间序列预测)**。

```talib.TSF()```函数的返回值为:一维数组。
array

talib.TSF(inReal)
talib.TSF(inReal, optInTimePeriod)

```inReal```参数用于指定K线数据。
inReal
true
{@struct/Record Record}结构数组、数值数组
```optInTimePeriod```参数用于设置周期,默认值为14。
optInTimePeriod
false
number

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.TSF(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.TSF(records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.TSF(records);
    Log(ret);
}

### talib.VAR

```talib.VAR()```函数用于计算**Variance (方差)**。

```talib.VAR()```函数的返回值为:一维数组。
array

talib.VAR(inReal)
talib.VAR(inReal, optInTimePeriod)
talib.VAR(inReal, optInTimePeriod, optInNbDev)

```inReal```参数用于指定K线数据。
inReal
true
{@struct/Record Record}结构数组、数值数组
```optInTimePeriod```参数用于设置周期,默认值为5。
optInTimePeriod
false
number
```optInNbDev```参数用于设置Deviations,默认值为1。
optInNbDev
false
number

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.VAR(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.VAR(records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.VAR(records);
    Log(ret);
}

### talib.ADX

```talib.ADX()```函数用于计算**Average Directional Movement Index (平均趋向指数)**。

```talib.ADX()```函数的返回值为:一维数组。
array

talib.ADX(inPriceHLC)
talib.ADX(inPriceHLC, optInTimePeriod)

```inPriceHLC```参数用于指定K线数据。
inPriceHLC
true
{@struct/Record Record}结构数组
```optInTimePeriod```参数用于设置周期,默认值为14。
optInTimePeriod
false
number

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.ADX(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.ADX(records.High, records.Low, records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.ADX(records);
    Log(ret);
}

### talib.ADXR

```talib.ADXR()```函数用于计算**Average Directional Movement Index Rating (评估指数)**。

```talib.ADXR()```函数的返回值为:一维数组。
array

talib.ADXR(inPriceHLC)
talib.ADXR(inPriceHLC, optInTimePeriod)

```inPriceHLC```参数用于指定K线数据。
inPriceHLC
true
{@struct/Record Record}结构数组
```optInTimePeriod```参数用于设置周期,默认值为14。
optInTimePeriod
false
number

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.ADXR(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.ADXR(records.High, records.Low, records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.ADXR(records);
    Log(ret);
}

### talib.APO

```talib.APO()```函数用于计算**Absolute Price Oscillator (绝对价格振荡指数)**。

```talib.APO()```函数的返回值为:一维数组。
array

talib.APO(inReal)
talib.APO(inReal, optInFastPeriod)
talib.APO(inReal, optInFastPeriod, optInSlowPeriod)
talib.APO(inReal, optInFastPeriod, optInSlowPeriod, optInMAType)

```inReal```参数用于指定K线数据。
inReal
true
{@struct/Record Record}结构数组、数值数组
```optInFastPeriod```参数用于设置快周期,默认值为12。
optInFastPeriod
false
number
```optInSlowPeriod```参数用于设置慢周期,默认值为26。
optInSlowPeriod
false
number
```optInMAType```参数用于设置均线类型,默认值为0。
optInMAType
false
number

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.APO(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.APO(records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.APO(records);
    Log(ret);
}

### talib.AROON

```talib.AROON()```函数用于计算**Aroon (阿隆指标)**。

```talib.AROON()```函数的返回值为:二维数组。
array

talib.AROON(inPriceHL)
talib.AROON(inPriceHL, optInTimePeriod)

```inPriceHL```参数用于指定K线数据。
inPriceHL
true
{@struct/Record Record}结构数组
```optInTimePeriod```参数用于设置周期,默认值为14。
optInTimePeriod
false
number

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.AROON(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.AROON(records.High, records.Low)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.AROON(records);
    Log(ret);
}

### talib.AROONOSC

```talib.AROONOSC()```函数用于计算**Aroon Oscillator (阿隆震荡线)**。

```talib.AROONOSC()```函数的返回值为:一维数组。
array

talib.AROONOSC(inPriceHL)
talib.AROONOSC(inPriceHL, optInTimePeriod)

```inPriceHL```参数用于指定K线数据。
inPriceHL
true
{@struct/Record Record}结构数组
```optInTimePeriod```参数用于设置周期,默认值为14。
optInTimePeriod
false
number

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.AROONOSC(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.AROONOSC(records.High, records.Low)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.AROONOSC(records);
    Log(ret);
}

### talib.BOP

```talib.BOP()```函数用于计算**Balance Of Power (均势指标)**。

```talib.BOP()```函数的返回值为:一维数组。
array

talib.BOP(inPriceOHLC)

```inPriceOHLC```参数用于指定K线数据。
inPriceOHLC
true
{@struct/Record Record}结构数组

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.BOP(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.BOP(records.Open, records.High, records.Low, records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.BOP(records);
    Log(ret);
}

### talib.CCI

```talib.CCI()```函数用于计算**Commodity Channel Index (顺势指标)**。

```talib.CCI()```函数的返回值为:一维数组。
array

talib.CCI(inPriceHLC)
talib.CCI(inPriceHLC, optInTimePeriod)

```inPriceHLC```参数用于指定K线数据。
inPriceHLC
true
{@struct/Record Record}结构数组
```optInTimePeriod```参数用于设置周期,默认值为14。
optInTimePeriod
false
number

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.CCI(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.CCI(records.High, records.Low, records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.CCI(records);
    Log(ret);
}

### talib.CMO

```talib.CMO()```函数用于计算**Chande Momentum Oscillator (钱德动量摆动指标)**。

```talib.CMO()```函数的返回值为:一维数组。
array

talib.CMO(inReal)
talib.CMO(inReal, optInTimePeriod)

```inReal```参数用于指定K线数据。
inReal
true
{@struct/Record Record}结构数组、数值数组
```optInTimePeriod```参数用于设置周期,默认值为14。
optInTimePeriod
false
number

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.CMO(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.CMO(records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.CMO(records);
    Log(ret);
}

### talib.DX

```talib.DX()```函数用于计算**Directional Movement Index (动向指数)**。

```talib.DX()```函数的返回值为:一维数组。
array

talib.DX(inPriceHLC)
talib.DX(inPriceHLC, optInTimePeriod)

```inPriceHLC```参数用于指定K线数据。
inPriceHLC
true
{@struct/Record Record}结构数组
```optInTimePeriod```参数用于设置周期,默认值为14。
optInTimePeriod
false
number

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.DX(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.DX(records.High, records.Low, records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.DX(records);
    Log(ret);
}

### talib.MACD

```talib.MACD()```函数用于计算**Moving Average Convergence/Divergence (指数平滑移动平均线)**。

```talib.MACD()```函数的返回值为:二维数组。
array

talib.MACD(inReal)
talib.MACD(inReal, optInFastPeriod)
talib.MACD(inReal, optInFastPeriod, optInSlowPeriod)
talib.MACD(inReal, optInFastPeriod, optInSlowPeriod, optInSignalPeriod)

```inReal```参数用于指定K线数据。
inReal
true
{@struct/Record Record}结构数组、数值数组
```optInFastPeriod```参数用于设置快周期,默认值为12。
optInFastPeriod
false
number
```optInSlowPeriod```参数用于设置慢周期,默认值为26。
optInSlowPeriod
false
number
```optInSignalPeriod```参数用于设置信号周期,默认值为9。
optInSignalPeriod
false
number

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.MACD(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.MACD(records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.MACD(records);
    Log(ret);
}

### talib.MACDEXT

```talib.MACDEXT()```函数用于计算**MACD with controllable MA type (MA型可控 MACD)**。

```talib.MACDEXT()```函数的返回值为:二维数组。
array

talib.MACDEXT(inReal)
talib.MACDEXT(inReal, optInFastPeriod)
talib.MACDEXT(inReal, optInFastPeriod, optInFastMAType)
talib.MACDEXT(inReal, optInFastPeriod, optInFastMAType, optInSlowPeriod)
talib.MACDEXT(inReal, optInFastPeriod, optInFastMAType, optInSlowPeriod, optInSlowMAType)
talib.MACDEXT(inReal, optInFastPeriod, optInFastMAType, optInSlowPeriod, optInSlowMAType, optInSignalPeriod)
talib.MACDEXT(inReal, optInFastPeriod, optInFastMAType, optInSlowPeriod, optInSlowMAType, optInSignalPeriod, optInSignalMAType)

```inReal```参数用于指定K线数据。
inReal
true
{@struct/Record Record}结构数组、数值数组
```optInFastPeriod```参数用于设置快周期,默认值为12。
optInFastPeriod
false
number
```optInFastMAType```参数用于设置快均线类型,默认值为0。
optInFastMAType
false
number
```optInSlowPeriod```参数用于设置慢周期,默认值为26。
optInSlowPeriod
false
number
```optInSlowMAType```参数用于设置慢均线类型,默认值为0。
optInSlowMAType
false
number
```optInSignalPeriod```参数用于设置信号周期,默认值为9。
optInSignalPeriod
false
number
```optInSignalMAType```参数用于设置信号均线类型,默认值为0。
optInSignalMAType
false
number

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.MACDEXT(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.MACDEXT(records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.MACDEXT(records);
    Log(ret);
}

### talib.MACDFIX

```talib.MACDFIX()```函数用于计算**Moving Average Convergence/Divergence Fix 12/26 (移动平均收敛/发散修复12/26)**。

```talib.MACDFIX()```函数的返回值为:二维数组。
array

talib.MACDFIX(inReal)
talib.MACDFIX(inReal, optInSignalPeriod)

```inReal```参数用于指定K线数据。
inReal
true
{@struct/Record Record}结构数组、数值数组
```optInSignalPeriod```参数用于设置信号周期,默认值为9。
optInSignalPeriod
false
number

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.MACDFIX(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.MACDFIX(records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.MACDFIX(records);
    Log(ret);
}

### talib.MFI

```talib.MFI()```函数用于计算**Money Flow Index (货币流量指数)**。

```talib.MFI()```函数的返回值为:一维数组。
array

talib.MFI(inPriceHLCV)
talib.MFI(inPriceHLCV, optInTimePeriod)

```inPriceHLCV```参数用于指定K线数据。
inPriceHLCV
true
{@struct/Record Record}结构数组
```optInTimePeriod```参数用于设置周期,默认值为14。
optInTimePeriod
false
number

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.MFI(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.MFI(records.High, records.Low, records.Close, records.Volume)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.MFI(records);
    Log(ret);
}

### talib.MINUS_DI

```talib.MINUS_DI()```函数用于计算**Minus Directional Indicator (负向指标)**。

```talib.MINUS_DI()```函数的返回值为:一维数组。
array

talib.MINUS_DI(inPriceHLC)
talib.MINUS_DI(inPriceHLC, optInTimePeriod)

```inPriceHLC```参数用于指定K线数据。
inPriceHLC
true
{@struct/Record Record}结构数组
```optInTimePeriod```参数用于设置周期,默认值为14。
optInTimePeriod
false
number

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.MINUS_DI(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.MINUS_DI(records.High, records.Low, records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.MINUS_DI(records);
    Log(ret);
}

### talib.MINUS_DM

```talib.MINUS_DM()```函数用于计算**Minus Directional Movement (负向运动)**。

```talib.MINUS_DM()```函数的返回值为:一维数组。
array

talib.MINUS_DM(inPriceHL)
talib.MINUS_DM(inPriceHL, optInTimePeriod)

```inPriceHL```参数用于指定K线数据。
inPriceHL
true
{@struct/Record Record}结构数组
```optInTimePeriod```参数用于设置周期,默认值为14。
optInTimePeriod
false
number

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.MINUS_DM(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.MINUS_DM(records.High, records.Low)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.MINUS_DM(records);
    Log(ret);
}

### talib.MOM

```talib.MOM()```函数用于计算**Momentum (动量)**。

```talib.MOM()```函数的返回值为:一维数组。
array

talib.MOM(inReal)
talib.MOM(inReal, optInTimePeriod)

```inReal```参数用于指定K线数据。
inReal
true
{@struct/Record Record}结构数组、数值数组
```optInTimePeriod```参数用于设置周期,默认值为10。
optInTimePeriod
false
number

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.MOM(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.MOM(records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.MOM(records);
    Log(ret);
}

### talib.PLUS_DI

```talib.PLUS_DI()```函数用于计算**Plus Directional Indicator (更向指示器)**。

```talib.PLUS_DI()```函数的返回值为:一维数组。
array

talib.PLUS_DI(inPriceHLC)
talib.PLUS_DI(inPriceHLC, optInTimePeriod)

```inPriceHLC```参数用于指定K线数据。
inPriceHLC
true
{@struct/Record Record}结构数组
```optInTimePeriod```参数用于设置周期,默认值为14。
optInTimePeriod
false
number

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.PLUS_DI(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.PLUS_DI(records.High, records.Low, records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.PLUS_DI(records);
    Log(ret);
}

### talib.PLUS_DM

```talib.PLUS_DM()```函数用于计算**Plus Directional Movement (定向运动)**。

```talib.PLUS_DM()```函数的返回值为:一维数组。
array

talib.PLUS_DM(inPriceHL)
talib.PLUS_DM(inPriceHL, optInTimePeriod)

```inPriceHL```参数用于指定K线数据。
inPriceHL
true
{@struct/Record Record}结构数组
```optInTimePeriod```参数用于设置周期,默认值为14。
optInTimePeriod
false
number

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.PLUS_DM(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.PLUS_DM(records.High, records.Low)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.PLUS_DM(records);
    Log(ret);
}

### talib.PPO

```talib.PPO()```函数用于计算**Percentage Price Oscillator (价格振荡百分比)**。

```talib.PPO()```函数的返回值为:一维数组。
array

talib.PPO(inReal)
talib.PPO(inReal, optInFastPeriod)
talib.PPO(inReal, optInFastPeriod, optInSlowPeriod)
talib.PPO(inReal, optInFastPeriod, optInSlowPeriod, optInMAType)

```inReal```参数用于指定K线数据。
inReal
true
{@struct/Record Record}结构数组、数值数组
```optInFastPeriod```参数用于设置快周期,默认值为12。
optInFastPeriod
false
number
```optInSlowPeriod```参数用于设置慢周期,默认值为26。
optInSlowPeriod
false
number
```optInMAType```参数用于设置均线类型,默认值为0。
optInMAType
false
number

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.PPO(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.PPO(records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.PPO(records);
    Log(ret);
}

### talib.ROC

```talib.ROC()```函数用于计算**Rate of change : ((price/prevPrice)-1)*100 (变动率指标)**。

```talib.ROC()```函数的返回值为:一维数组。
array

talib.ROC(inReal)
talib.ROC(inReal, optInTimePeriod)

```inReal```参数用于指定K线数据。
inReal
true
{@struct/Record Record}结构数组、数值数组
```optInTimePeriod```参数用于设置周期,默认值为10。
optInTimePeriod
false
number

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.ROC(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.ROC(records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.ROC(records);
    Log(ret);
}

### talib.ROCP

```talib.ROCP()```函数用于计算**Rate of change Percentage: (price-prevPrice)/prevPrice (价格变化率)**。

```talib.ROCP()```函数的返回值为:一维数组。
array

talib.ROCP(inReal)
talib.ROCP(inReal, optInTimePeriod)

```inReal```参数用于指定K线数据。
inReal
true
{@struct/Record Record}结构数组、数值数组
```optInTimePeriod```参数用于设置周期,默认值为10。
optInTimePeriod
false
number

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.ROCP(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.ROCP(records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.ROCP(records);
    Log(ret);
}

### talib.ROCR

```talib.ROCR()```函数用于计算**Rate of change ratio: (price/prevPrice) (价格变化率)**。

```talib.ROCR()```函数的返回值为:一维数组。
array

talib.ROCR(inReal)
talib.ROCR(inReal, optInTimePeriod)

```inReal```参数用于指定K线数据。
inReal
true
{@struct/Record Record}结构数组、数值数组
```optInTimePeriod```参数用于设置周期,默认值为10。
optInTimePeriod
false
number

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.ROCR(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.ROCR(records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.ROCR(records);
    Log(ret);
}

### talib.ROCR100

```talib.ROCR100()```函数用于计算**Rate of change ratio 100 scale: (price/prevPrice)*100 (价格变化率)**。

```talib.ROCR100()```函数的返回值为:一维数组。
array

talib.ROCR100(inReal)
talib.ROCR100(inReal, optInTimePeriod)

```inReal```参数用于指定K线数据。
inReal
true
{@struct/Record Record}结构数组、数值数组
```optInTimePeriod```参数用于设置周期,默认值为10。
optInTimePeriod
false
number

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.ROCR100(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.ROCR100(records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.ROCR100(records);
    Log(ret);
}

### talib.RSI

```talib.RSI()```函数用于计算**Relative Strength Index (相对强弱指标)**。

```talib.RSI()```函数的返回值为:一维数组。
array

talib.RSI(inReal)
talib.RSI(inReal, optInTimePeriod)

```inReal```参数用于指定K线数据。
inReal
true
{@struct/Record Record}结构数组、数值数组
```optInTimePeriod```参数用于设置周期,默认值为14。
optInTimePeriod
false
number

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.RSI(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.RSI(records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.RSI(records);
    Log(ret);
}

### talib.STOCH

```talib.STOCH()```函数用于计算**Stochastic (STOCH指标)**。

```talib.STOCH()```函数的返回值为:二维数组。
array

talib.STOCH(inPriceHLC)
talib.STOCH(inPriceHLC, optInFastK_Period)
talib.STOCH(inPriceHLC, optInFastK_Period, optInSlowK_Period)
talib.STOCH(inPriceHLC, optInFastK_Period, optInSlowK_Period, optInSlowK_MAType)
talib.STOCH(inPriceHLC, optInFastK_Period, optInSlowK_Period, optInSlowK_MAType, optInSlowD_Period)
talib.STOCH(inPriceHLC, optInFastK_Period, optInSlowK_Period, optInSlowK_MAType, optInSlowD_Period, optInSlowD_MAType)

```inPriceHLC```参数用于指定K线数据。
inPriceHLC
true
{@struct/Record Record}结构数组
```optInFastK_Period```参数用于设置Fast-K周期,默认值为5。
optInFastK_Period
false
number
```optInSlowK_Period```参数用于设置Slow-K周期,默认值为3。
optInSlowK_Period
false
number
```optInSlowK_MAType```参数用于设置Slow-K均线类型,默认值为0。
optInSlowK_MAType
false
number
```optInSlowD_Period```参数用于设置Slow-D周期,默认值为3。
optInSlowD_Period
false
number
```optInSlowD_MAType```参数用于设置Slow-D均线类型,默认值为0。
optInSlowD_MAType
false
number

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.STOCH(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.STOCH(records.High, records.Low, records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.STOCH(records);
    Log(ret);
}

### talib.STOCHF

```talib.STOCHF()```函数用于计算**Stochastic Fast (快速STOCH指标)**。

```talib.STOCHF()```函数的返回值为:二维数组。
array

talib.STOCHF(inPriceHLC)
talib.STOCHF(inPriceHLC, optInFastK_Period)
talib.STOCHF(inPriceHLC, optInFastK_Period, optInFastD_Period)
talib.STOCHF(inPriceHLC, optInFastK_Period, optInFastD_Period, optInFastD_MAType)

```inPriceHLC```参数用于指定K线数据。
inPriceHLC
true
{@struct/Record Record}结构数组
```optInFastK_Period```参数用于设置Fast-K周期,默认值为5。
optInFastK_Period
false
number
```optInFastD_Period```参数用于设置Fast-D周期,默认值为3。
optInFastD_Period
false
number
```optInFastD_MAType```参数用于设置Fast-D均线类型,默认值为0。
optInFastD_MAType
false
number

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.STOCHF(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.STOCHF(records.High, records.Low, records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.STOCHF(records);
    Log(ret);
}

### talib.STOCHRSI

```talib.STOCHRSI()```函数用于计算**Stochastic Relative Strength Index (随机强弱指数)**。

```talib.STOCHRSI()```函数的返回值为:二维数组。
array

talib.STOCHRSI(inReal)
talib.STOCHRSI(inReal, optInTimePeriod)
talib.STOCHRSI(inReal, optInTimePeriod, optInFastK_Period)
talib.STOCHRSI(inReal, optInTimePeriod, optInFastK_Period, optInFastD_Period)
talib.STOCHRSI(inReal, optInTimePeriod, optInFastK_Period, optInFastD_Period, optInFastD_MAType)

```inReal```参数用于指定K线数据。
inReal
true
{@struct/Record Record}结构数组、数值数组
```optInTimePeriod```参数用于设置周期,默认值为14。
optInTimePeriod
false
number
```optInFastK_Period```参数用于设置Fast-K周期,默认值为5。
optInFastK_Period
false
number
```optInFastD_Period```参数用于设置Fast-D周期,默认值为3。
optInFastD_Period
false
number
```optInFastD_MAType```参数用于设置Fast-D均线类型,默认值为0。
optInFastD_MAType
false
number

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.STOCHRSI(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.STOCHRSI(records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.STOCHRSI(records);
    Log(ret);
}

### talib.TRIX

```talib.TRIX()```函数用于计算**1-day Rate-Of-Change (ROC) of a Triple Smooth EMA (三重指数平滑平均线)**。

```talib.TRIX()```函数的返回值为:一维数组。
array

talib.TRIX(inReal)
talib.TRIX(inReal, optInTimePeriod)

```inReal```参数用于指定K线数据。
inReal
true
{@struct/Record Record}结构数组、数值数组
```optInTimePeriod```参数用于设置周期,默认值为30。
optInTimePeriod
false
number

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.TRIX(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.TRIX(records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.TRIX(records);
    Log(ret);
}

### talib.ULTOSC

```talib.ULTOSC()```函数用于计算**Ultimate Oscillator (极限振子)**。

```talib.ULTOSC()```函数的返回值为:一维数组。
array

talib.ULTOSC(inPriceHLC)
talib.ULTOSC(inPriceHLC, optInTimePeriod1)
talib.ULTOSC(inPriceHLC, optInTimePeriod1, optInTimePeriod2)
talib.ULTOSC(inPriceHLC, optInTimePeriod1, optInTimePeriod2, optInTimePeriod3)

```inPriceHLC```参数用于指定K线数据。
inPriceHLC
true
{@struct/Record Record}结构数组
```optInTimePeriod1```参数用于设置第一周期,默认值为7。
optInTimePeriod1
false
number
```optInTimePeriod2```参数用于设置第二周期,默认值为14。
optInTimePeriod2
false
number
```optInTimePeriod3```参数用于设置第三周期,默认值为28。
optInTimePeriod3
false
number

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.ULTOSC(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.ULTOSC(records.High, records.Low, records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.ULTOSC(records);
    Log(ret);
}

### talib.WILLR

```talib.WILLR()```函数用于计算**Williams' %R (威廉指标)**。

```talib.WILLR()```函数的返回值为:一维数组。
array

talib.WILLR(inPriceHLC)
talib.WILLR(inPriceHLC, optInTimePeriod)

```inPriceHLC```参数用于指定K线数据。
inPriceHLC
true
{@struct/Record Record}结构数组
```optInTimePeriod```参数用于设置周期,默认值为14。
optInTimePeriod
false
number

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.WILLR(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.WILLR(records.High, records.Low, records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.WILLR(records);
    Log(ret);
}

### talib.AVGPRICE

```talib.AVGPRICE()```函数用于计算**Average Price (平均价格)**。

```talib.AVGPRICE()```函数的返回值为:一维数组。
array

talib.AVGPRICE(inPriceOHLC)

```inPriceOHLC```参数用于指定K线数据。
inPriceOHLC
true
{@struct/Record Record}结构数组

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.AVGPRICE(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.AVGPRICE(records.Open, records.High, records.Low, records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.AVGPRICE(records);
    Log(ret);
}

### talib.MEDPRICE

```talib.MEDPRICE()```函数用于计算**Median Price (中位数价格)**。

```talib.MEDPRICE()```函数的返回值为:一维数组。
array

talib.MEDPRICE(inPriceHL)

```inPriceHL```参数用于指定K线数据。
inPriceHL
true
{@struct/Record Record}结构数组

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.MEDPRICE(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.MEDPRICE(records.High, records.Low)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.MEDPRICE(records);
    Log(ret);
}

### talib.TYPPRICE

```talib.TYPPRICE()```函数用于计算**Typical Price (典型价格)**。

```talib.TYPPRICE()```函数的返回值为:一维数组。
array

talib.TYPPRICE(inPriceHLC)

```inPriceHLC```参数用于指定K线数据。
inPriceHLC
true
{@struct/Record Record}结构数组

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.TYPPRICE(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.TYPPRICE(records.High, records.Low, records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.TYPPRICE(records);
    Log(ret);
}

### talib.WCLPRICE

```talib.WCLPRICE()```函数用于计算**Weighted Close Price (加权收盘价)**。

```talib.WCLPRICE()```函数的返回值为:一维数组。
array

talib.WCLPRICE(inPriceHLC)

```inPriceHLC```参数用于指定K线数据。
inPriceHLC
true
{@struct/Record Record}结构数组

```javascript
function main() {
    var records = exchange.GetRecords()
    var ret = talib.WCLPRICE(records)
    Log(ret)
}
import talib
def main():
    records = exchange.GetRecords()
    ret = talib.WCLPRICE(records.High, records.Low, records.Close)
    Log(ret)
void main() {
    auto records = exchange.GetRecords();
    auto ret = talib.WCLPRICE(records);
    Log(ret);
}

WCLPRICE()函数在talib库文档中的描述为:WCLPRICE(Records[High,Low,Close]) = Array(outReal)

结构体