Изобретатели количественно документируют API

Автор:Маленькие мечты, Создано: 2017-11-27 09:05:08, Обновлено: 2023-07-12 16:47:31

void main() {
    Mail("smtp.163.com", "asdf@163.com", "password", "111@163.com", "title", "body");
}
  • MailАсинхронная версия функцииMail_GoФункция: Использование иexchange.GoФункции похожи.

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

Обратите внимание: Сервер Ali Cloud может перекрывать некоторые порты, в результате чего сообщения не могут быть отправлены. Если вам нужно изменить порт, вы можете сразу добавить номер порта в первом параметре, например:smtp.qq.com:587, этот порт доступен для тестирования. В случае ошибки:unencryped connectionНеобходимо изменить.MailФункцииsmtpServerФормат параметров:ssl://xxx.com:xxxНапример, в почтовом ящике QQSMTPСсылки на сайтыssl://smtp.qq.com:465Илиsmtp://xxx.com:xxx

SetErrorFilter ((...)

SetErrorFilter(RegEx), фильтрация ошибочных журналов. Ошибочные журналы, которые совпадают с этим правильным выражением, не будут загружаться в систему журналов, и можно многократно вызывать настройки нескольких условий фильтрации (фильтрованные журналы не записываются в файлы базы данных, соответствующие ID реального диска в каталоге хостов, чтобы предотвратить частые ошибки, которые приводят к разрастанию файлов базы данных).

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

GetPid ((()

GetPid(), возвращает ID процесса реального диска. Вернуто значение: тип строки.

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

ПолучитьLastError()

GetLastError(), получает информацию о последних ошибках. Обычно это не требуется, поскольку программа автоматически загружает информацию об ошибках в систему журналов.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(), получает интерактивную командную строку ((utf-8)); получает команду, отправленную с помощью политики интерактивного интерфейса, и очищает кэш, без которой команды возвращают пустую строку. Формат возвращаемой команды按钮名称:参数Если интерактивный контроллер не имеет параметров (например, кнопка-контроль без вводной рамки), команда - это имя кнопки.

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

В нижней системе есть строка, записывающая взаимодействующие команды, когдаGetCommand()Когда функция вызывается, она забирает первое входящее в очередь взаимодействие (в случае отсутствия взаимодействия возвращает пустую строку).

Примеры использования интерактивных контроллеров, настройки интерактивных контроллеров в интерфейсе редактора стратегии.

img

В стратегии разработки интерактивного кода:

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

GetMeta ((()

GetMeta()Функция возвращает код, записанный при создании реестра политикиMetaВ этом случае значение, которое функция возвращает, является типом строки. Сценарии применения, например, стратегии, требующие ограничения средств для разных арендаторов. Примечание: при создании регистрационного кодаMetaдлина не может превышать 190 символов. Функция применяется только для реального диска и требует использования последнего хостера.GetMeta()Возвращается пустое значение.

Информация о демонстрациях с использованием сцен

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

Нажмите...

Dial(Address, Timeout)ПервобытныйSocketДоступ, поддержкаtcpudptlsunixПротокол.AddressВ этом случае мы можем использовать:TimeOutДля типа значения, числовая единица в секундах, если задержкаDial(...)Функция возвращает пустое значение.

AddressПараметры подробно описаны:

Параметры
НастройкаDialПараметры функции На официальном сайте:wss://ws.okx.com:8443/ws/v5/publicПосле этого|Символическое разделение, если в строке есть параметры.|Иногда это означает:||Используется как знак разделения.&Соединение символов. Например, ссылки на ss5 и компрессионные параметры:Dial("wss://ws.okx.com:8443/ws/v5/public|proxy=socks5://xxx:9999&compress=gzip_raw&mode=recv")
При использовании протокола ws параметры, связанные с сжатием данных:compress=参数值 compress как компрессионный режим, параметры компрессии, опциональныеgzip_rawgzipЕсли gzip не является стандартным gzip, можно использовать расширение:gzip_rawЭто означает, что|Добавить настройки позжеcompress=gzip_rawИспользовать&Символ и следующий параметр mode разделены.
При использовании протокола ws параметры, связанные с сжатием данных:mode=参数值 Mode как режим, опциональныйdualsendrecvТри вида.dualДля обоих направлений, отправляя сжатые данные, получая сжатые данные.sendДля отправки сжатых данных.recvДля получения сжатых данных декомпрессируйте локально.
Параметры, используемые для настройки агента socks5:proxy=参数值 Proxy настроили для агента ss5, формат параметров:socks5://name:pwd@192.168.0.1:1080,name - это имя пользователя сервера ss5, pwd - это пароль при входе на сервер ss5, 1080 - это порт службы ss5.
При использовании ws протокола устанавливаются параметры, связанные с базовым автоматическим перекрестным соединением:reconnect=参数值 reconnect указывает на то, настроить ли пересоединение.reconnect=trueДля включения пересоединения.
При использовании ws протокола устанавливаются параметры, связанные с базовым автоматическим перекрестным соединением:interval=参数值 Interval - интервал времени повторного тестирования, в миллисекундах.interval=10000Для повторной пробы интервал 10 секунд, не установленный по умолчанию на 1 секунду, т.е.interval=1000
При использовании ws протокола устанавливаются параметры, связанные с базовым автоматическим перекрестным соединением:payload=参数值 Подписка на сообщение, которое нужно отправить при перезагрузке payload на ws, например:payload=okok
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();
    }
}

readФункция поддерживает следующие параметры:

  • Если параметры не передаются, блокируют до тех пор, пока не будет сообщения; например:ws.read()
  • При вводе параметров единицей является миллисекунда, указывающая время ожидания отсрочки сообщения.ws.read(2000)Указанное время задержки составляет две секунды ((2000 миллисекунд).
  • Следующие два параметра должны быть верными.websocketЭффективность: Передача параметров-1Означает, что функция возвращается незамедлительно, независимо от того, есть ли сообщение или нет, например:ws.read(-1)Я не знаю. Передача параметров-2Означает, что функция возвращает немедленно, независимо от того, есть ли сообщения, но возвращает только последние сообщения, сообщения в буферном поле будут отброшены; например,ws.read(-2)

read()Функционные буферы: В принципе, если вы используете Ws-протокол, то вы можете использовать его, если вы используете его.read()Слишком длинный интервал времени между вызовами функций может привести к накоплению данных. Данные хранятся в буферных зонах, где структура данных буферных зон состоит из очередей, максимальная численность которых составляет 2000 человек. После превышения 2000 последней данной входит в буфер, а самая старая информация удаляется.

СценаreadПараметры функций Без параметров Параметры: -1 Параметры: -2 Параметры: 2000 единиц - миллисекунды
Данные в буферном регионе Немедленное возвращение старых данных Немедленное возвращение старых данных Немедленно вернитесь к обновленным данным Немедленное возвращение старых данных
Нет данных о буферной зоне Блокировать до тех пор, пока нет данных Немедленно возвращает пустое значение. Немедленно возвращает пустое значение. Подождите 2000 миллисекунд, без данных возвращается пустое значение, с данными возвращается
ws соединение отключается или подключается снова Функция read (()) возвращает пустую строку, то есть:"",write (()) возвращает 0, обнаруживает это положение. Можно использовать функцию close (()) для закрытия соединения, если установлено автоматическое пересоединение, то не нужно закрывать, а подсистема автоматически пересоединяется.
  • Поддержка протокола wss ((WebSocket) На сайте Binance можно посмотреть на интерфейс вебсокета:

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

    Для доступа к интерфейсу websocket в OKX:

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

    В этом случае, если вы хотите получить доступ к токену, вы можете использовать следующий интерфейс:

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

    Доступ к интерфейсу проверки веб-сокета OKX:

    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)
            }]
        }    
        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("退出");
    }
    

HttpQuery ((...)

HttpQuery(Url, PostData, Cookies, Headers, IsReturnHeader), доступ к сетевому URL. Параметровое значение: все для типа строки.

Обратите внимание:

  • HttpQuery(...)Функции поддерживаются толькоJavaScriptЯзык.
  • PythonЯзык может быть использованurllibПосмотрите на это видео.

HttpQuery(...)В основном используется для доступа к интерфейсам бирж, которые не требуют подписи, например, к общедоступным интерфейсам, таким как рыночная информация.

Пример API-интерфейса для доступа к OKX, который не требует подписи, возвращает значениеJSONЯ не знаю, как это сделать.JavaScriptЯзык может быть использован в стратегииJSON.parse()Рассмотрение функций.

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

Получить возвращенное содержимое URL, если второй параметрPostDataДля строкиa=1&b=2&c=abcФорма - этоPOSTКак подать заявку.PUTПосмотрите на это.PostDataПараметры:{method:'PUT', data:'a=1&b=2&c=abc'}PostDataПараметры могут бытьJSONСтроки.

CookiesЭтот параметр имеет форму:a=10; b=20, параметры с запятой;Я не хочу, чтобы это происходило.HeadersЭтот параметр имеет форму:User-Agent: Mobile\nContent-Type: text/htmlПараметры с заменой символов\nЯ не хочу, чтобы это происходило.

Второй параметрPostDataНапример, можно настроить:HttpQuery("http://www.abc.com", {method:'PUT', data:'a=1&b=2&c=abc'})Обратите внимание:HttpQueryФункция устанавливает отсрочку, которая может быть выполнена в{method:'PUT', data:'a=1&b=2&c=abc'}ПрисоединитьсяtimeoutАтрибуты ((дефолт 60 секунд) ⇒

Настройка на 1 секунду задержки:HttpQuery("http://www.abc.com", {method:'PUT', data:'a=1&b=2&c=abc', timeout:1000})

ПередачаCookieТретий параметр нужен строке, но не нуженPOSTПожалуйста, оставьте второй параметр пустым. При аналогическом тестировании функция возвращает фиксированную строку, поскольку не может быть смоделирован доступ к URL.Dummy DataС помощью этого интерфейса можно отправлять текстовые сообщения или взаимодействовать с другими API-интерфейсами.

GETПримеры методов вызова:HttpQuery("http://www.baidu.com")POSTПримеры методов вызова:HttpQuery("http://www.163.com", "a=1&b=2&c=abc")

ВозвращениеHeaderПримеры вызова:

HttpQuery("http://www.baidu.com", null, "a=10; b=20", "User-Agent: Mobile\nContent-Type: text/html", true)  // will return {Header: HTTP Header, Body: HTML}
  • HttpQueryФункция использует настройки агента:

    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Асинхронная версия функцииHttpQuery_Go"Слушайте, ребята. Использование иexchange.GoФункции аналогичны, например, синхронный доступ к общественному интерфейсу биржи для получения агрегированных данных о рынке.

    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)
    }
    
    # 不支持
    
    // 不支持
    
  • Использование в системе рецензированияHttpQuery(...)Функция: Использование в системе рецензированияHttpQuery(...)Отправка запроса ((только поддержка)GET• ограничить использование 20 различных URL-адресов при повторном просмотре;HttpQuery(...)Доступ хранит данные при повторном посещении того же URLHttpQuery(...)Функция возвращает кэшированные данные (в настоящее время не происходит фактических сетевых запросов).

    Мы можем запустить на сервере или устройстве сервисную программу, чтобы ответить на политические запросы.HttpQuery(...)Запрос отправлен, и программа Go Language Service, используемая для тестирования, выглядит так:

    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","open","high","low","close","vol"},
                "data" : []interface{}{
                    []int64{1564315200000,9531300,9531300,9497060,9497060,787},
                    []int64{1564316100000,9495160,9495160,9474260,9489460,338},
                },
            }
            b, _ := json.Marshal(ret)
            w.Write(b)
        }()
    }
    
    func main () {
        fmt.Println("listen http://localhost:9090")
        http.HandleFunc("/data", Handle)
        http.ListenAndServe(":9090", nil)
    }
    

    Использование при рецензировании стратегииHttpQuery(...)Запрос на отправку функции:

    function main() {
        // 可以写自己运行服务程序所在设备的IP地址
        Log(HttpQuery("http://xxx.xx.x.xxx:9090/data?msg=hello"));
        Log(exchange.GetAccount());
    }
    
    # HttpQuery不支持Python,可以使用Python的urllib2库
    
    void main() {
        // 可以写自己运行服务程序所在设备的IP地址
        Log(HttpQuery("http://xxx.xx.x.xxx:9090/data?msg=hello"));
        Log(exchange.GetAccount());
    }
    

    img

  • Поддержка перекодирования данных ответа на запрос, поддержка обычного кодирования. ОпределитеPostDataПараметры:{method: "GET",charset:"GB18030"}, который может быть реализован с помощью кода передачи данных (GB18030).

Кодировка ((...)

Encode(algo, inputFormat, outputFormat, data, keyFormat, key string), которая кодирует данные в зависимости от параметров, которые передаются. Вернутое значение: тип строки.

ПараметрыalgoАлгоритмы, используемые при кодировании, поддерживаются настройками: raw (без использования алгоритма), sign, signTx, md4, md5, sha256, sha512, sha1, keccak256, sha3.224, sha3.256, sha3.384, sha3.512, sha3.keccak256, sha3.keccak512, sha512.384, sha512.256, sha512.224, ripemd160, blake2b.256, blake2b.512, blake2s.128, blake2s.256. Параметры.dataС другой стороны, мы не знаем, что делать с данными.inputFormat/outputFormat/keyFormatПоддержка параметровrawhexbase64stringКак это сделать? ЕслиkeyFormatЕсли нет нуля, используйте параметры.keyИспользуйте шифрование (HMAC), иначе используйте по умолчаниюkeyПараметрыalgoУстановка на"sign"Или"signTx"Когда параметры нужныkey

function main(){
    Log(Encode("md5", "raw", "hex", "hello"))
    Log(Encode("sha512", "raw", "base64", "hello"))
    Log(Encode("keccak256", "raw", "hex", "unwrapWETH9(uint256,address)"))

    Log(Encode("raw", "string", "hex", "example"))          // 6578616d706c65
    Log(Encode("raw", "hex", "string", "6578616d706c65"))   // example
}
def main():
    Log(Encode("md5", "raw", "hex", "hello", "", ""))
    Log(Encode("sha512", "raw", "base64", "hello", "", ""))
    Log(Encode("keccak256", "raw", "hex", "unwrapWETH9(uint256,address)", "", ""))

    Log(Encode("raw", "string", "hex", "example", "", ""))
    Log(Encode("raw", "hex", "string", "6578616d706c65", "", ""))
void main(){
    Log(Encode("md5", "raw", "hex", "hello"));
    Log(Encode("sha512", "raw", "base64", "hello"));
    Log(Encode("keccak256", "raw", "hex", "unwrapWETH9(uint256,address)"));
    
    Log(Encode("raw", "string", "hex", "example"));          // 6578616d706c65
    Log(Encode("raw", "hex", "string", "6578616d706c65"));   // example
}

ПараметрыalgoОн также поддерживает:text.encoder.utf8text.decoder.utf8text.encoder.gbktext.decoder.gbk, кодировать и декодировать строки.

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

UnixNano ((()

UnixNano(), возвращает наносекундный временной фрагмент, если требуется получить миллисекундный временной фрагмент, можно использовать следующий код:

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

Unix ((()

Unix(), возвращает секундовую шкалу времени.

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

GetOS ((()

GetOS(), возвращает информацию о системе, в которой находится администратор.

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

На компьютере AppleMac OSВывод журналов администраторов, работающих на операционной системе:

GetOS:darwin/amd64

darwinТо естьMac OSНазвание системы.

MD5 ((String)

MD5(String), параметровое значение: тип строки.

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

Вывод журналов:

MD5 5eb63bbbe01eeed093cb22bb8f5acdc3

DBExec ((...)

DBExec(), параметровые значения: могут быть типами строки, числовых значений, буров, пустоты и т. д.; возвращаемые значения: объекты, содержащие результаты выполнения SQLite-заявлений. Функции интерфейсов баз данныхDBExec()С помощью ввода параметров можно управлять реальной базой данных (SQLite database) ; осуществлять операции по добавлению, удалению, проверке, изменению и т. д. данных в реальной базе данных, поддержкаSQLiteСинтаксис. Таблицы системного сохранения в реальной базе данных:kvdbcfglogprofitchartНе используйте эти таблицы. Обратите внимание:DBExec()Функция поддерживает только реальные диски.

  • Поддержка баз данных в памяти ДляDBExecПараметры функции, есликв. мЭто слово используется для::Начало работы в базе данных в памяти, без записи файлов, быстрее. Подходит для операций с базы данных, которые не требуют постоянного сохранения, например:

    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;"));
    }
    
  • Создать таблицу

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

UUID (()

UUID(), возвращает 32-разрядный уникальный 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);
}

СобытиеLoop ((Timeout)

EventLoop(timeout)В любом случаеwebsocketЧитать илиexchange.GoHttpQuery_GoВторой вариант - вернуть параметры после выполнения параллельных задач.timeoutЕсли настройка на 0 возвращается до того, как произойдет событие, если больше 0 - это настройка события на время ожидания, если меньше 0 - немедленно возвращается к последнему событию.nullВ этом случае, если вы хотите, чтобы ваш сайт был более открытым,EventТип, который запускается для событий. Функция применяется только для диска.

Первый вызов в кодеEventLoopВ случае, если вы хотите, чтобы ваш телефон прослушивался, вы должны установить механизм, который инициирует прослушивание, если вы начинаете его впервые после того, как вы откликаете сообщение.EventLoopВызов, который пропустит предыдущие события. Структура очередей, упакованная в базовую систему, кэширует до 500 вызовов событий, если при исполнении программы не было своевременного вызова.EventLoopЕсли вытащить, то потеряете более 500 кэшей для повторного вызова событий позже.EventLoopВызов функции не влияет на системуwebsocketЭто не влияет ни на каждую из них, ни на какую из них.exchange.GoДля кэшей с параллельными функциями, например, для этих кэшей все еще требуется использовать свои методы для извлечения данных.EventLoopПока функция не вернется, данные, которые были извлечены, не будут использованы.EventLoopВозвращение событий в функции.

EventLoopОсновное назначение функции - уведомлять уровень политики, который получает новые сетевые данные в нижней части системы.EventLoopКогда функция возвращает события, ей нужно просто пройти через все источники данных.websocketОн был очень активным.exchange.GoОбъекты, которые создаются, пытаются получить данные.Ссылки на библиотеки

В основной функцииmain()При входе в сеть прислушивается к событиям, происходящим в сети.JavaScriptПоскольку язык является одним из самых популярных языков в мире, он является одним из самых популярных языков в мире.__Thread()Тренинг, созданный функцией, также может быть вызван в исполнительной функции, чтобы прослушивать события текущего потока.

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秒,并发的函数

Больше

qq89520Вопрос в том, повторяется ли функция C постоянно или только один раз.

Эй, эй, эй!_C ((function, args...) Это по умолчанию 3s? Можно ли изменить по умолчанию, чтобы поставить _CDelay ((1000) прямо перед _C ((function, args...)?

ЛанчайеКластер: если вы создаете 1000 ботов одновременно и без стресса, вы можете создать несколько администраторов для распределения задач. Есть примеры кода для создания кластеров? Как создать несколько хостеров для распределения задач

Вэнги1Log ((talib.help (('MACD')); используется только в js, а в python нет свойства talib.help...

cjz140Что отличает _C ((function, args...) от функции Sleep, и я думаю, что это означает, что мы должны перепробовать.

3263243yКак очистить ErrorFilter после SetErrorFilter?

- Я не знаю.Есть ли другие способы использовать сторонние библиотеки?

- Я не знаю.Что должен заполнить родительский класс, если вы хотите унаследовать новый класс, определенный объектом биржи?

ЭтанвуЕсть ли настраиваемые инструменты для декомпиляции?

ПэнглихенгА как насчет exange.IO (("status"))?

ПэнглихенгПочему функция sell в сером цвете, это означает, что функция представления не используется?

ПэнглихенгПочему функция sell в сером цвете, это означает, что функция представления не используется?

ПэнглихенгЯ не знаю языка, ха-ха-ха, я хотел бы спросить, поддерживает ли es6

ПэнглихенгЯ не знаю языка, ха-ха-ха, я хотел бы спросить, поддерживает ли es6

Don.Как вы пишете среднюю линию объема?

черепахаЧто будет возвращено, если не удастся купить exchange.Buy ((1000) по рыночной цене?

Нинг-цзыНовый шрифт выглядит потрясающе.

гиппопотамBitmex Test Network ((testnet.bitmex.com) также имеет API-интерфейс, но на данный момент биржа может выбрать только Bitmex Mother Station, адрес API-документации https://testnet.bitmex.com/app/apiOverview Как вы можете помочь?

Чжидзинvar ret1 = exchanges[0].IO (("api", "future_estimated_price", "symbol=btc_usd"); Log (('ok futures estimated delivery price', ret1); https://dn-filebox.qbox.me/d1ed268c1e75753c5d289447d279aa9d81e41b5f.png Почему мы не можем позвонить на интерфейсы других бирж и написать ошибку?

Аллен ФростлайнНедавно была переписана стратегия набора, и оба появились одновременно, но в первом API, похоже, нет упоминания.

виденияПривет, как разработчик Python, что вы думаете, что пишут ваши API-документы?

Аллен ФростлайнGetAccount: [EAPI:Rate limit exceeded] Хотите узнать, как это решить?

zhjx2314Не поддерживает StochRSI, можно ли добавить как можно скорее

ЕфГГГКогда Python в режиме реального времени, сценарий находится на собственном сервере Ali Cloud или на кластере botvs?

ЕфГГГКакую версию python вы используете?

- Очень хорошо.Пояснение GetFee должно было быть таким: "Верните Fee-структуру, а не один слог".

ЗвапКак вы можете вызвать талиб с помощью js?

ЕфГГГПоиск документации Python

Wmjbs123Если вы хотите, чтобы ваш код был чёрным, белыми глазами, написать код ночью, легко близоруко.

Don.Как настроить резюме в вейсбуке бота?

Число: безумныйМожно ли добавить в структуру ордера поле с равной ценой сделки?

МаленькийGetOrders: получает все незавершенные заказы, возвращает структуру Array Order, в китайской биткойн-торговли ETH, возвращает только последние 10 пунктов.

ЕфГГГЕсли мы хотим, чтобы математические функции, которые нужны для статистической теории вероятности, были использованы, где они используются?

ЦзибангЧто означает значение, возвращаемое функцией $.Cross ((x, y)?

Моя мама.Это LogReset, который очищает все журналы и может использовать цифровой параметр, чтобы указать количество записей, которые нужно сохранить. Как это удаляет последние несколько журналов?

Эдвард ГьюКак вы думаете, какая-то функция CORRE в talib не переносится или пропускается?

Бедная гора ЯньньКажется, нет возможности ссылаться на показатели!

МаленькийКак переводить время k-линии, которое читается, в настоящее время, о, я не понимаю, слишком длинный, решен, спасибо

МаленькийКак удалить числа из матриц, я использую record.remove ((records[0])

ЗмейкаюОбычно мы получаем часовую линию K, но как вызвать ATR на дневную линию K?

ЗмейкаюОбычно мы получаем часовую линию K, но как вызвать ATR на дневную линию K?

57278863Узнайте, как традиционные фьючерсы получают цены и заказы, к сожалению, их корни очень тонкие.

КиринВ частности, в Китае существует более 10 тысяч фьючерсных рынков.

МаленькийНу, ну, ну, ну, ну, ну, ну, ну, ну, ну, ну, ну, ну, ну, ну, ну, ну, ну, ну, ну, ну, ну.

МаленькийКак печатать состояние хранения, как я печатаю [object object][object object], как получить состояние хранения множества и пустых блоков, а также GetTicker ((), как получить неделю, следующую неделю и квартал.

ЧжидзинМогут ли фьючерсные биржи использовать GetTicker для получения рынка?

ПродажиКакой StochRSI можно добавить?

МомоксCancelOrder ((orderId) Отменить заказ по номеру заказа, вернуть true или false, попросите true= ячейка была успешно отменена, верно?

Момокс_G(K, V) Сохраняется глобальный словарный список Этот метод сохраняет глобальные переменные, которые могут использоваться для обмена данными между различными политиками.

Флуфи 3DВсплеск популярности

НульВы можете использовать LogProfitReset для перезагрузки журналов доходов.

xyМожно ли непосредственно скопировать EA?

СиронманЯ чувствую, что эта платформа прекрасна, она прекрасна, больше общения в группах.

МаленькийКакой это язык, есть ли какие-либо учебные материалы?

jxhbtcОшибка с данными неделю не подключается к роботу.

ДюхуИндекс TA - это просто расчет цены на закрытие?

btcrobotПривет, мир.

Маленькие мечтыФункция _C будет бездумно повторяться, пока не получит успешный результат.

Маленькие мечтыТалиб библиотека для python требует установки. http://www.botvs.com/bbs-topic/669

Маленькие мечтыSleep - это время, когда программа ничего не делает и ждет, пока параметры не будут установлены.

Маленькие мечтыНе требуя наследования, JS непосредственно завернулся в объект {name: "new object", old_exchange : exchange[0],...... }

Маленькие мечтыУстройства, используемые для создания локальных редакторов, удаленного синхронизации, в основном являются локальными редакторами, удаленными диспетчерами.

Маленькие мечтыЕсли вы не хотите, чтобы кто-то из ваших друзей поделился вашим мнением, приходите в QQ-группу.

Маленькие мечтыВ API-документации серое означает, что эта функция не имеет слишком большого объяснения, показывает серое, синий представитель имеет больше объяснений, и все.

Маленькие мечтыES6 не поддерживается, ^^

Маленькие мечтыЕсли вы хотите, чтобы я рассказал вам об этой проблеме, я отвечу на нее.

Маленькие мечтыЕсли вы не хотите, чтобы ваш товар был куплен, вы можете купить его, если вы не хотите, чтобы он был куплен.

черепахаНапример, OKCoin, что вы получаете, если вы покупаете больше, чем у вас есть?

Маленькие мечтыВ частности, на какой бирже я верну номер заказа на OK Futures?

НульУже поддерживается переключение пары транзакций при запуске, требуется загрузка последнего хостера. Поддержка Bter/Poloniex Подробная API-документация Описание транзакционной функции внизу ((очистить кэш браузера после обновления, если не видно)

Маленькие мечтыQQ, я помогу вам найти вопрос.

Профессиональные кормильцыЕсли вы хотите установить белый список, я настраиваю IP-адрес хоста.

Маленькие мечтыЭто базовая ссылка не создана Сервер не отвечает. При запросе API KEY устанавливается IP-адрес?

Профессиональные кормильцыЭто смущает... Я могу запустить политику, которая не работает в бит-эпоху, и GetAccount не может получить доступ к GetAccount: Post http://api.btc38.com/v1/getMyBalance.php: read tcp 192.168.0.227:58596->211.149.148.144:80: wsarecv: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond. 2017-05-23 21:08:24 Битэпоха Ошибка GetAccount: timeout 2017-05-23 21:08:02 Биткойн-эпоха Ошибка GetAccount: timeout 2017-05-23 21:07:40 Бит эпоха Ошибка GetAccount: timeout 2017-05-23 21:07:20 Возобновить Может быть, это вопрос о белом списке IP-адресов?

Маленькие мечтыСерверы биржи не ответили, протокол TCP не был установлен и три раза рукопожатия не были проведены.

Профессиональные кормильцыA connection attempt failed because the connected party did not properly respond after a period of time (попытка подключения потерпела неудачу, потому что подключенная сторона не отреагировала должным образом после определенного периода времени)

Маленькие мечтыПривет! Речь идет об exchange.IO ((api, ApiName, Args) Функция не поддерживается, см. https://www.botvs.com/bbs-topic/812

Профессиональные кормильцыПопытка подключения не удалась, потому что подключенная сторона не ответила должным образом через определенный период времени,

Профессиональные кормильцыНе поддерживает бит-эпоха?

Маленькие мечтыhttps://dn-filebox.qbox.me/a709b30c6cc0a3565234b9e0c99b073f7ba8b454.png Я думаю, что это нормально.

Нинг-цзыНапример, я хочу сделать полную валютную сделку с poloniex, но поддерживает только несколько валют, а exchange.IO, похоже, не поддерживает P-Net.

Маленькие мечтыЭто может быть вызвано exchange.IO.

Нинг-цзыА как насчет API, требующих проверки аккаунта?

Маленькие мечтыЕсли API, не требующие проверки аккаунта, можно использовать с помощью httpQuery (подробнее о документации BotVS), фактический API для транзакций требует доступа.

Маленькие мечтыПараметры API передаются с помощью HttpQuery: https://www.okcoin.com/api/v1/future_estimated_price.do?symbol=btc_usd. Для API бирж, которые не требуют проверки аккаунта, используйте HttpQuery прямо на платформе, а те, которые связаны с аккаунтом, используют IO API. Пост: https://www.botvs.com/bbs-topic/850

виденияСпасибо, надеюсь, что у вас будет прекрасная документация на API.

Маленькие мечтыГде вы видели этот API realTicker?

Маленькие мечтыhttps://dn-filebox.qbox.me/fe1a6f5563ed43a5357f858ecf8a50239619228e.png API-документация является языком JavaScript. Описание, версия python описание в верхней части страницы обмена сообществами в Python.

НульЗдравствуйте, спасибо за совет, сейчас перестраивается документация API.

Маленькие мечтыПривет - показывает, что частота доступа превышает ограничения. https://dn-filebox.qbox.me/a09498920d04cac62624b7438a058d2098d8fb00.png В политике используется функция Sleep ((1000)?, эта 1000 - это позволяет программе приостановить один секунд в каждом раунде, что можно настроить самостоятельно, целью является контроль программы частота доступа к API, поскольку некоторые биржи устанавливают максимальное ограничение доступа, определенное время, превышающее определенное количество посещений, будет отказывать в доступе, блокируя IP-адреса.

Маленькие мечтыhttps://dn-filebox.qbox.me/c29ab7fc279e1b758355f137907cf52dc8257df6.png Я лично пишу, что уже сравнил показатели STOCHRSI с OK, и согласен, что скорость немного медленная, оптимизирована и временно доступна.

НульВы можете выбрать, на сервере botvs или на сервере своего хостера, версия 2.7.5.

Маленькие мечтыВ этом случае, вы должны быть готовы.

Маленькие мечтыТеперь вы можете настроить свой собственный стиль фона.

Маленькие мечтыПитонская документация пишется.

Маленькие мечтыТалибская библиотека поддерживает:

Хззгуд48 https://www.botvs.com/bbs-topic/276

Маленькие мечтыПо-видимому, есть пример на площади стратегии, http://www.botvs.com/strategy/15098

НульДоступ к свойствам AvergPrice для Orders, которые поддерживаются биржами, может, а те, которые не поддерживаются, всегда будут иметь свойство 0.

ЕфГГГКак ссылаться на сторонние источники?

НульДля быстрого компиляции, система встроена только в небольшое количество библиотек.

Маленькие мечтыНеприветливая, проблема в том, что в группе можно "М" мне - я в основном онлайн.

ЦзибангСпасибо.

Маленькие мечтыВы можете посмотреть на комментарий к кодовому анализу библиотеки криптовалютных операций, где есть комментарий к функции $.Cross.

НульНельзя удалять последние, можно сохранить только последние несколько статей... удалить все старые.

КиринЧтобы получить каждую позицию с помощью position[i], position является матрицей.

Нинг-цзыexchange.GetRecords ((PERIOD_D1));

КиринМой традиционный фьючерс всегда был: "GetAccount: not login", "пароль не ошибся, значит не сможешь войти".

НульПо умолчанию это неделя, для получения указанного требуется SetContractType.

НульКак видите, true - это значение, которое будет возвращаться биржевой операцией отмены ордера, но действительно отмены не отменены, зависит от того, как они обрабатываются внутри биржи.

Момокс3q

НульНе может быть, они отделены друг от друга.

СюаньшуаньКонечно, нет, это исключительно для MT4.

НульЯвление Javascript есть повсюду в Интернете.

ПродажиВы решили свой вопрос?

НульВ большинстве случаев, данные, которые мы передаем, могут быть прямыми записями или чистыми ценами.