Inventor de documentação de API de quantificação

Autora:Sonhos pequenos, Criado: 2017-11-27 09:05:08, Atualizado: 2023-07-12 16:47:31

void main() {
    Mail("smtp.163.com", "asdf@163.com", "password", "111@163.com", "title", "body");
}
  • MailVersão assíncrona da funçãoMail_GoFunção: Utilização eexchange.GoA função é semelhante.

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

Atenção: O servidor da Ali Cloud pode bloquear algumas portas, o que faz com que o e-mail não possa ser enviado. Se você precisar mudar a porta, pode adicionar diretamente o número do porto no primeiro parâmetro, por exemplo:smtp.qq.com:587O teste de porta está disponível. Se houver um erro:unencryped connectionO que é necessário?MailFunçõessmtpServerO formato dos parâmetros é:ssl://xxx.com:xxxPor exemplo, no QQ.SMTPO método de SSL:ssl://smtp.qq.com:465Ousmtp://xxx.com:xxx

SetErrorFilter ((...)

SetErrorFilter(RegEx), filtragem de logs de erros↑ valor de parâmetro: tipo de string↑ Os registros de erros correspondentes a esta expressão regular não serão carregados para o sistema de registros, podendo ser chamados várias vezes para definir várias condições de filtragem (os registros filtrados não são escritos em arquivos de banco de dados que correspondem ao ID de disco real no diretório do administrador, evitando que erros frequentes causem o excesso de arquivos de banco de dados).

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

Filtrar uma mensagem de erro de interface:

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(), retorna o ID do processo de disco real.

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

GetLastError (()

GetLastError(), para obter informações de erro mais recentes. Geralmente não é necessário, pois o programa envia automaticamente informações de erro para o sistema de logs. Retorna o valor: tipo de string.GetLastError()A função limpa o cache de erro e não retorna a mensagem de erro da última gravação quando for chamada novamente.

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

Obter Comando ((()

GetCommand(), obtém a sequência de comandos interativos ((utf-8)); obtém o comando enviado pela interface de interação da política e limpa o cache, não há comando e retorna a sequência de comandos em branco. O formato do comando de retorno é按钮名称:参数Se o controle interativo não tiver parâmetros (por exemplo, um controle de botão sem caixa de entrada), o comando é o nome do botão.

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

O sistema subjacente tem uma estrutura de fila para registrar as instruções de interação quandoGetCommand()Quando a função é chamada, ela retira o comando de interação que entrou primeiro na fila (e retorna uma string vazia se não houver um comando de interação).

Exemplos de uso de controles interativos, interface de edição de estratégias para configurar controles interativos.

img

A estratégia é projetar código interativo:

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()A função retorna o código de registo da política de geração.MetaO valor que a função retorna é o tipo de string. Cenários de aplicação, como a estratégia de limitar o financiamento de diferentes inquilinos. Nota: O código de registo é geradoMetaA função não pode exceder 190 caracteres de comprimento e é aplicada somente ao disco físico e requer o uso do administrador mais recente.GetMeta()Retorna um valor em branco.

Informações sobre demonstrações de cenários

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

Marque...

Dial(Address, Timeout)O que é isso?SocketAcesso, apoiotcpudptlsunixProtocolo. Parâmetro:AddressPara o tipo de strings,TimeOutPara o tipo de valor, a unidade de valor é o segundo, se ultrapassar o tempoDial(...)A função retorna um valor em branco.

AddressOs parâmetros são detalhados:

Parâmetros
ConfiguraçãoDialParâmetros da função O endereço normal é:wss://ws.okx.com:8443/ws/v5/publicMais tarde|Separador de símbolos, se houver uma string de parâmetros|Os caracteres são:||Como símbolo de separação.&Conexão de caracteres. Por exemplo, os agentes ss5 e os parâmetros de compressão são definidos juntos:Dial("wss://ws.okx.com:8443/ws/v5/public|proxy=socks5://xxx:9999&compress=gzip_raw&mode=recv")
Quando usado no protocolo ws, os parâmetros relacionados à compressão de dados são:compress=参数值 compress como modo de compressão, parâmetros de compressão, opcionalgzip_rawgzipPor exemplo. Se o gzip não for o padrão, pode ser usado como uma extensão:gzip_rawO que é um ponto de separação|Adicionar configurações depoiscompress=gzip_raw, com&O símbolo e o parâmetro de modo seguinte são separados.
Quando usado no protocolo ws, os parâmetros relacionados à compressão de dados são:mode=参数值 modo para o modo, opcionaldualsendrecvTrês.dualPara ambos os lados, enviar dados de compressão e receber dados de compressão.sendPara enviar dados de compressão.recvPara receber os dados de compressão, decomprime localmente.
Os parâmetros relevantes para a configuração do agente socks5 são:proxy=参数值 O proxy é configurado para ser um agente ss5, com o formato de parâmetros:socks5://name:pwd@192.168.0.1:1080O nome é o nome de usuário do servidor ss5, o pwd é o código de acesso ao servidor ss5 e o porto 1080 é o servidor ss5.
Quando usado no protocolo ws, configure os parâmetros relacionados ao reencadeamento automático no nível inferior:reconnect=参数值 O reconnect é para saber se a rede é definida.reconnect=truePara habilitar a recombinação. Não recombinar por defeito sem este parâmetro.
Quando usado no protocolo ws, configure os parâmetros relacionados ao reencadeamento automático no nível inferior:interval=参数值 Intervalo é o intervalo de tempo de reexame, em milissegundos.interval=10000Para tentar de novo com um intervalo de 10 segundos, não defina 1 segundo, ou seja,interval=1000
Quando usado no protocolo ws, configure os parâmetros relacionados ao reencadeamento automático no nível inferior:payload=参数值 mensagens de subscrição que devem ser enviadas quando o payload é religado para ws, por exemplo: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();
    }
}

readA função suporta os seguintes parâmetros:

  • Quando não é transmitido um parâmetro, bloqueia-se e retorna quando há uma mensagem.ws.read()
  • Quando o parâmetro é transmitido, a unidade é de milissegundos, especificando o tempo de espera do overtime do mensagem; por exemplo:ws.read(2000)O tempo de atraso especificado é de dois segundos (~2000 milissegundos).
  • Os dois seguintes parâmetros são apenas válidos.websocketEficaz: Parâmetros de entrada-1A função retorna imediatamente, independentemente da existência de uma mensagem, por exemplo:ws.read(-1)Não, não é. Parâmetros de entrada-2Isso significa que a função retorna imediatamente, independentemente de não haver mensagens, mas só retorna as mensagens mais recentes, e as mensagens do buffer são descartadas; por exemplo:ws.read(-2)

read()A área de buffer da função explica: Os dados enviados pelo protocolo ws, se estiverem na políticaread()O intervalo de tempo entre as chamadas de funções pode ser muito longo, o que pode causar acumulação de dados. Estes dados são armazenados em buffers, com uma estrutura de dados de buffers de filas, com um limite máximo de 2.000. Após 2000, os dados mais recentes entram em buffers e os mais antigos são eliminados.

A cena.readParâmetros de função Sem parâmetros Parâmetros: -1 Parâmetros: -2 Parâmetros: 2000 unidades são milissegundos
Os dados já estão disponíveis. Retorno imediato aos dados mais antigos Retorno imediato aos dados mais antigos Volte imediatamente para os dados atualizados Retorno imediato aos dados mais antigos
Não há dados na zona de reserva Bloquear até que haja dados Retorna um valor em branco imediatamente. Retorna um valor em branco imediatamente. Espere 2000 milissegundos, nenhum dado retornará um valor em branco, mas alguns dados retornarão
Ws quando a conexão é cortada ou quando o fundo é religado A função read (()) retorna uma cadeia de caracteres em branco, como: "", write (()) retorna 0, e detecta essa situação. A função close (()) pode ser usada para fechar a conexão, mas não precisa ser fechada se for definida a reconexão automática.
  • Suporte ao protocolo wss (WebSocket) Para acessar o interface do mercado do websocket da 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();
    }
    

    Para acessar a interface de mercado do websocket do 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("退出");
    }
    

    A interface de mercado do websocket para acessar os tokens:

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

    Para acessar a interface de verificação do websocket do 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), acesso a URLs de rede.

Atenção:

  • HttpQuery(...)Funções apenas suportadasJavaScriptA língua.
  • PythonA linguagem pode ser usadaurllibO Google pode enviar uma solicitação http diretamente.

HttpQuery(...)A maioria das vezes, é usado para acessar interfaces que não requerem assinatura, como as interfaces públicas, como informações de mercado.

Exemplo de interface API que não requer assinatura para acessar o OKX e retorna o valorJSONO que você está fazendo?JavaScriptA estratégia da linguagem pode ser usadaJSON.parse()Função de análise.

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

Retorna o conteúdo de um URL se o segundo parâmetroPostDataPara a stringa=1&b=2&c=abcA forma é:POSTComo enviar. Outros exemplos:PUTA partir de agora, o projeto está em andamento.PostDataO parâmetro é{method:'PUT', data:'a=1&b=2&c=abc'}PostDataO parâmetro também pode serJSONA linha de caracteres.

CookiesEste parâmetro tem a forma:a=10; b=20, cada parâmetro com uma notação;O que você está fazendo?HeadersEste parâmetro tem a forma:User-Agent: Mobile\nContent-Type: text/htmlOs parâmetros são substituídos por símbolos.\nO que você está fazendo?

O segundo parâmetroPostDataA partir daí, a empresa desenvolveu um novo projeto de tecnologia para a construção de um novo projeto.HttpQuery("http://www.abc.com", {method:'PUT', data:'a=1&b=2&c=abc'})Nota: Se necessário, dêHttpQueryA função de tempo extra pode ser configurada em{method:'PUT', data:'a=1&b=2&c=abc'}ParticipaçãotimeoutAtribuições (default 60 seconds)

Configure um segundo de atraso:HttpQuery("http://www.abc.com", {method:'PUT', data:'a=1&b=2&c=abc', timeout:1000})

TransmissãoCookieA string precisa de um terceiro parâmetro, mas não precisaPOSTPor favor, deixe o segundo parâmetro em branco. Quando o teste de simulação é feito, a função retorna uma string fixa porque não é possível simular o acesso à URL.Dummy DataPode ser usado para enviar mensagens de texto ou interagir com outras interfaces de API.

GETExemplos de chamadas de métodos:HttpQuery("http://www.baidu.com")POSTExemplos de chamadas de métodos:HttpQuery("http://www.163.com", "a=1&b=2&c=abc")

De voltaHeaderExemplos de chamadas:

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}
  • HttpQueryA função usa a configuração de um agente:

    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/");
    }
    
  • HttpQueryVersão assíncrona da funçãoHttpQuery_GoO que é isso? Utilização eexchange.GoA função é semelhante, por exemplo, acessar assincronizadamente a interface pública do exchange para obter dados de mercado agregados.

    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)
    }
    
    # 不支持
    
    // 不支持
    
  • Utilização em sistemas de retrospecçãoHttpQuery(...)Função: Pode ser usado em sistemas de retrospecçãoHttpQuery(...)Enviar solicitações (suporta apenas)GET• Limitar o uso de 20 acessos diferentes de URLs durante o retorno.HttpQuery(...)O acesso armazena os dados da mesma URL na segunda visita.HttpQuery(...)A função retorna dados de cache (não há mais solicitações de rede reais).

    Podemos executar um programa de serviço em um servidor ou dispositivo para responder a um programa de política.HttpQuery(...)O programa de serviço de linguagem Go usado para testar os pedidos enviados foi o seguinte:

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

    Usado para revisão de estratégiasHttpQuery(...)Função de envio de solicitações:

    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

  • Suporte para a recodificação de dados de resposta a solicitações, suporte para codificação comum. EspecificarPostDataParâmetros:{method: "GET",charset:"GB18030"}O código de transmissão de dados (GB18030) pode ser implementado.

Codificação

Encode(algo, inputFormat, outputFormat, data, keyFormat, key string)A função codifica os dados de acordo com os parâmetros transmitidos. Retorna o valor: tipo de string.

ParâmetrosalgoAlgoritmos utilizados para o cálculo do código, com configurações de suporte para:??raw (não usar algoritmos),??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.Parâmetros.dataOs dados a serem processados.inputFormat/outputFormat/keyFormatParâmetros suportadosrawhexbase64stringO código é o seguinte: SekeyFormatPara não ser nulo, use os parâmetroskeyCriptografar (HMAC) ou usar o padrãokeyParâmetrosalgoConfiguração"sign"Ou"signTx"Quando você precisa de parâmetroskey

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
}

ParâmetrosalgoTambém apoia:text.encoder.utf8text.decoder.utf8text.encoder.gbktext.decoder.gbk, para codificar e decifrar as strings.

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()Para obter um fuso horário de milissegundos, você pode usar o seguinte código:

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(), retorna o tempo de segundo de nível.

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

GetOS ((()

GetOS()O sistema é executado através de um servidor que retorna informações do sistema onde o administrador está.

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

Em computadores AppleMac OSO registro de administradores executado no sistema operacional é executado:

GetOS:darwin/amd64

darwinOu seja,Mac OSO nome do sistema.

MD5 ((String)

MD5(String), valor do parâmetro: tipo de string.

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

O resultado do log:

MD5 5eb63bbbe01eeed093cb22bb8f5acdc3

DBExec ((...)

DBExec(), valor de parâmetro: pode ser de tipo string, valor numérico, valor boolean, valor em branco, etc.; valor de retorno: objeto que contém o resultado da execução de uma instrução SQLite. Funções de interface de banco de dadosDBExec()Por meio de parâmetros de entrada, é possível operar o banco de dados em disco real (SQLite database) e realizar operações de adição, exclusão, verificação e alteração de dados no banco de dados em disco real.SQLiteO sistema de reserva de tabelas no banco de dados do disco real:kvdbcfglogprofitchartNão faça nenhuma operação nessas tabelas.DBExec()A função só suporta disco físico.

  • Suporte para banco de dados em memória ParaDBExecOs parâmetros de uma função, seQuadradoA frase é::Inicialmente, é mais rápido operar em um banco de dados em memória, sem escrever documentos; adequado para operações de banco de dados que não exigem a conservação permanente, como:

    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;"));
    }
    
  • Criação de tabelas

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);
}
  • Operações de adição, exclusão e alteração de registros na tabela
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(), retorna um único UUID de 32 bits, que é aplicado apenas ao disco físico.

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 (Timeout)

EventLoop(timeout)E, em qualquerwebsocketPode ser lido ouexchange.GoHttpQuery_GoRetorne depois de concluir a tarefa simultânea.timeoutSe for definido como 0 para esperar que ocorra um evento, retornará, se for maior que 0 será definido como o tempo de espera do evento, e menor que 0 retornará imediatamente o evento mais recente.nullO que é que você está fazendo?EventTipo de gatilho para eventos. Esta função é aplicada somente ao disco físico.

Primeira chamada no códigoEventLoopA primeira vez que o mecanismo de interação é iniciado é após o retorno do evento.EventLoopChamadas, que perdem eventos anteriores. A estrutura de fila embalada pelo sistema subjacente armazenará até 500 chamadas de eventos se o programa não for chamado em tempo hábil durante a execução.EventLoopA partir daí, o usuário pode remover o arquivo e perder o arquivo de 500 cache.EventLoopAs chamadas de funções não afetam o fundo do sistemawebsocketA queima de cache também não é afetada.exchange.GoO cache de funções simultâneas, por exemplo, ainda precisa usar seus próprios métodos para extrair dados.EventLoopA função não vai voltar até que os dados já retirados não estejam em seu lugar.EventLoopA função gerou um evento de retorno.

EventLoopA função principal é a de notificar a camada de políticas, que recebe novos dados da rede no fundo do sistema.EventLoopQuando a função retorna eventos, basta percorrer todas as fontes de dados.websocketO que é a Internet?exchange.GoOs objetos criados tentam obter dados.Links para bibliotecas

Em funções principaismain()O evento do fio principal é ouvido durante a chamada.JavaScriptA estratégia para escrever uma linguagem é simples:__Thread()Os fios criados por funções podem ser chamados de funções executadas por funções, para ouvir os eventos do atual 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秒,并发的函数

Mais.

QQ89520Um problema é se a função C vai tentar novamente ou apenas uma vez.

Ai, ai!_C ((function, args...) é o padrão de 3s? Modificar o padrão para colocar diretamente _CDelay ((1000) antes de _C ((function, args...)?

lanchaiyeCluster: se você criar 1000 robôs em simultâneo, sem qualquer pressão, você pode criar vários administradores para distribuir tarefas. Há exemplos de código para criar clusters? Como criar vários administradores para descentralizar tarefas?

- O que é?Log ((talib.help (('MACD')); só pode ser usado em js, Python não tem a propriedade talib.help...

Cjz140O que é que a diferença entre a função _C (função, args...) e a função Sleep?

3263243yComo limpar o ErrorFilter após o SetErrorFilter? sem filtrar mensagens de erro.

QQ47898077Se você quiser usar uma biblioteca de terceiros, há alguma maneira de fazer isso?

QQ47898077O que deve ser preenchido pela classe pai se quisermos herdar uma nova classe definida pelo objeto da bolsa?

ethanwuHá ferramentas de depuração locais?

PenglihengO que é exange.IO (status)?

PenglihengPor que a função sell está em cinza, ou a função de representação não está disponível?

PenglihengPor que a função sell está em cinza, ou a função de representação não está disponível?

PenglihengEu não sei inglês, haha, mas gostaria de saber se o es6 é compatível.

PenglihengEu não sei inglês, haha, mas gostaria de saber se o es6 é compatível.

Don.Como escrever a linha média do volume?

ZjuturtleSe você comprar no exchange.Buy (Buy) 1000 pelo preço de mercado, o que você receberá se não for bem sucedido?

Minha filhaEssa nova fonte é linda.

hipopótamoA rede de testes da Bitmex (testnet.bitmex.com) também possui uma interface API, mas atualmente as bolsas só podem selecionar o terminal Bitmex. O endereço do documento API é https://testnet.bitmex.com/app/apiOverview. Por favor, como apoiar?

- Não, não.Var ret1 = exchanges[0].IO (("api", "future_estimated_price", "symbol=btc_usd"); Log (('ok futures estimado preço de entrega', ret1); https://dn-filebox.qbox.me/d1ed268c1e75753c5d289447d279aa9d81e41b5f.png O que é que acontece quando um usuário faz uma chamada para uma interface de outras exchanges e escreve uma mensagem de erro?

allenfrostlineA diferença entre realTicker e Ticker é que o realTicker é um software que funciona como um conjunto de ferramentas, mas que não parece ser mencionado na primeira API.

visõesOlá, como desenvolvedor de Python, o que você acha que a sua documentação API está escrevendo?

allenfrostlineGetAccount: [EAPI: Rate limit exceeded] Gostaria de saber como resolver isso?

zhjx2314Não tem suporte para StochRSI, pode ser adicionado logo?

YhfggO script está em seu próprio servidor da nuvem Ali ou no botvs cluster?

YhfggQual é a versão do Python?

FkyslyA interpretação do GetFee deve ser que o getFee retorna uma estrutura de getFee, menos um composto.

ZkwapComo usar o jss para chamar o talib?

YhfggPeça documentação Python

Wmjbs123O fundo do código para a edição de estratégias pode ser preto? Olhos pontiagudos brancos, código escrito à noite, fácil de miopia

Don.Como é que se pode configurar o sumário no bot WeChat?

Número: loucoPode-se adicionar um campo de preço igual na estrutura da ordem?

PequenoGetOrders: Retorna todos os pedidos incompletos, retorna uma estrutura de ordem de arquivo, na China Bitcoin transação ETH, retorna apenas os últimos 10 itens, aqui há uma função que retorna todos os pedidos incompletos da China Bitcoin ETH, o que significa que outras plataformas podem retornar tudo com GetOrders, só que este fantasma da China Bitcoin retorna 10 itens, o que significa que você pode usar GetOrders para retornar todos os pedidos incompletos.

YhfggA função matemática que é necessária para a probabilidade estatística, onde é que ela é usada?

JiebangQual é o significado do valor que a função $.Cross ((x, y) retorna?

A minha tia chamava-meO LogReset limpa todos os registros e pode ter um parâmetro numérico para especificar o número de registros reservados. Como é que isso elimina os últimos registos?

Edward GywA função CORRE no talib parece não ter sido transplantada ou foi perdida?

A montanha pobre de LiuyangParece que não há função de referência de indicadores!

PequenoComo é que o tempo de leitura da linha k traduz para o tempo presente?

PequenoComo escrever o número de um arquivo para removê-lo, eu acho que isso não funciona com records.remove ((records[0])

SerpenteA linha K da hora é normalmente obtida, mas como chamar ATR da linha K do dia?

SerpenteA linha K da hora é normalmente obtida, mas como chamar ATR da linha K do dia?

57278863Aprenda como os futuros tradicionais recebem preços e compras, desculpe, a base é tênue.

KirinO exemplo de negociação de futuros tradicionais!

Pequenozero, pode escrever um exemplo de negociação de futuros tradicionais?

PequenoComo imprimir o estado de armazenamento de vários blocos vazios ao mesmo tempo, como imprimir meu objeto, como obter o estado de armazenamento de vários blocos e blocos vazios, e também GetTicker, como obter o preço da semana, da próxima semana e do trimestre.

- Não, não.As bolsas de futuros podem usar o GetTicker para obter transações?

Venda em massaO StochRSI é um indicador que pode ser adicionado?

MomoxCancelOrder ((orderId) cancelar um pedido com base no número da ordem, retornar true ou false, por favor, pergunte true= a célula foi cancelada com sucesso, certo?

Momox_G(K, V) Lista de dicionários globais que podem ser salvos Este método armazena variáveis globais que podem ser usadas para compartilhar dados entre diferentes políticas?

Fluffy3dA popularidade

Zero.O registro de ganhos pode ser reiniciado com o LogProfitReset. O histórico do gráfico de ganhos anterior desaparece.

xyPode-se copiar o EA diretamente?

SJIRONMANEu sinto que a plataforma é ótima, muito boa, muito mais interação em grupo.

PequenoO que é essa língua, há material para aprender?

jxhbtcData error: uma semana sem conectar o robô.

- O quê?O banco de dados TA é apenas para calcular o preço de fechamento?

btcrobotOlá, mundo.

Sonhos pequenosA função _C tentará novamente sem pensar até obter um resultado.

Sonhos pequenosA biblioteca talib do python precisa ser instalada. https://www.botvs.com/bbs-topic/669 pode ser consultado neste post.

Sonhos pequenosSleep é o número de milissegundos em que o programa não faz nada e espera que o parâmetro seja definido, _C é a função que re-chamou o parâmetro.

Sonhos pequenosSem herança, o JS é embalado diretamente no objeto {name: "novo objeto", old_exchange : exchange[0],...... }

Sonhos pequenosO editor local, o plugin de sincronização remota, basicamente, é o editor local, o decote remoto.

Sonhos pequenosPode vir ao grupo QQ, é fácil discutir.

Sonhos pequenosEm documentos da API, o significado de cinza é que a função não tem muita explicação de expansão e mostra representados em cinza e azul.

Sonhos pequenosO ES6 está fora de suporte, ^^

Sonhos pequenosEu, descreva o problema e eu vou responder ^^

Sonhos pequenosA primeira coisa que você pode fazer é fazer um pedido de compra, mas o resultado é um erro, e você não pode fazer o pedido (ou seja, comprar, não há dinheiro suficiente!).

ZjuturtlePor exemplo, OKCoin, se o volume de compras for superior ao de empréstimos, o que será o retorno?

Sonhos pequenosA questão é: em qual bolsa eu devolveria um número de ordem no OK Futures?

Zero.Já é suportado para trocar transações em tempo de execução, sendo necessário o download do mais recente host. Suporte Bter/Poloniex API detalhada documentação Descrição da função de transação abaixo (descreva se não for possível limpar o cache do navegador e atualizar se não for possível)

Sonhos pequenosQQ, eu ajudo-te a encontrar a pergunta.

Família profissionalA lista branca precisa ser definida, e eu defino o IP do host?

Sonhos pequenosEste é o link subterrâneo Não foi criado O servidor não respondeu; O endereço IP foi configurado quando o API KEY foi solicitado?

Família profissionalIsso é embaraçoso. A política que eu poderia executar foi interrompida na era do Bitcoin, e o GetAccount não conseguiu acessar o 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 Era BitEras Erro GetAccount: timeout 2017-05-23 21:08:02 Era do Bitcoin Erro GetAccount: timeout 2017-05-23 21:07:40 Bit Era Erro GetAccount: timeout 2017-05-23 21:07:20 Reiniciar É o problema da lista branca de IP???

Sonhos pequenosO servidor da bolsa não respondeu e o protocolo TCP não foi estabelecido em três apertos de mão.

Família profissionalUma tentativa de conexão falhou porque a parte conectada não respondeu adequadamente depois de um período de tempo.

Sonhos pequenosOlá! A função exchange.IO ((api, ApiName, Args) não é suportada, veja https://www.botvs.com/bbs-topic/812

Família profissionalUma tentativa de ligação falhou porque a parte ligada não respondeu adequadamente após um período de tempo,

Família profissionalA era dos bitcoins não é favorável?

Sonhos pequenoshttps://dn-filebox.qbox.me/a709b30c6cc0a3565234b9e0c99b073f7ba8b454.png O que você está fazendo é errado.

Minha filhaPor exemplo, eu queria fazer uma transação em todas as moedas do poloniex, mas apenas algumas moedas são suportadas pelo BOTvs, e o exchange.IO não parece suportar a P-Net.

Sonhos pequenosO exchange.IO pode ser chamado assim.

Minha filhaE a API que precisa de autenticação de contas?

Sonhos pequenosSe as APIs que não exigem a verificação de contas podem ser usadas com httpQuery (veja mais documentação sobre BotVS), as APIs de transações reais precisam ser acessadas.

Sonhos pequenosOs parâmetros da API podem ser transmitidos usando o HttpQuery: https://www.okcoin.com/api/v1/future_estimated_price.do?symbol=btc_usd. O post: https://www.botvs.com/bbs-topic/850

visõesMuito obrigado, espero ter uma boa e perfeita documentação API.

Sonhos pequenosPor favor, onde é que a API do realTicker foi vista?

Sonhos pequenoshttps://dn-filebox.qbox.me/fe1a6f5563ed43a5357f858ecf8a50239619228e.png A documentação da API é a linguagem JavaScript. A descrição da versão em Python é publicada no topo da página de discussão da comunidade de chat chat. Se você tem alguma dúvida, é bem-vindo a escrever.

Zero.Olá, obrigado pela sugestão, a documentação da API está sendo reconstruída.

Sonhos pequenosOlá ~ mostra que a frequência de acesso ultrapassou o limite. https://dn-filebox.qbox.me/a09498920d04cac62624b7438a058d2098d8fb00.png O objetivo é controlar a frequência de acesso à API, porque algumas exchanges definem um limite máximo de acesso, um certo tempo além de um certo número de visitas será recusado o acesso, bloqueando o endereço IP.

Sonhos pequenoshttps://dn-filebox.qbox.me/c29ab7fc279e1b758355f137907cf52dc8257df6.png O que eu escrevi pessoalmente é que os indicadores do STOCHRSI, que já foram comparados com o OK, concordam que a velocidade é um pouco lenta e precisa ser otimizada, por enquanto.

Zero.Pode escolher se o botvs fornecerá o seu servidor ou o seu servidor host, versão 2.7.5.

Sonhos pequenosAgora adicionado.

Sonhos pequenosAgora você pode configurar seu próprio estilo de fundo.

Sonhos pequenosA documentação python está sendo escrita.

Sonhos pequenosO talib é um livro que pode ser lido em português.

Hzzgood48 https://www.botvs.com/bbs-topic/276

Sonhos pequenosParece que há um exemplo na Praça da Estratégia: https://www.botvs.com/strategy/15098

Zero.Acesse a propriedade AvgPrice do Order, que é suportada pelas exchanges, e as que não são suportadas serão sempre 0

YhfggComo é que a terceira parte cita?

Zero.Se o mathjs não for capaz de satisfazer as necessidades, basta procurar políticas de importação e cópia de bibliotecas de terceiros. Para facilitar a compilação, o sistema tem apenas uma pequena quantidade de bibliotecas internas.

Sonhos pequenosNão é simpático, há um problema no grupo, pode-se M-me - eu estou basicamente online.

JiebangObrigado.

Sonhos pequenosVocê pode ver a análise de código do catálogo de transações de moeda digital na versão de notas.

Zero.Não é possível excluir o mais recente, só é possível manter alguns dos mais recentes... excluindo todos os antigos.

KirinPara obter cada posicionamento com a posição [i], a posição é um conjunto

Minha filhaexchange.GetRecords ((PERIODO_D1));

KirinO meu futuro tradicional é sempre o "GetAccount: not login", "password não errado, ou login impossível".

Zero.Por padrão, o SetContractType é necessário para obter o tipo de contrato especificado.

Zero.Como você pode ver, o verdadeiro é o valor de retorno da ação de cancelar a ordem que o exchange devolveu, mas o cancelamento real não foi cancelado, dependendo de como foi processado dentro do exchange.

Momox3q

Zero.Não, não, não, não.

XuanxuanClaro que não, isso é exclusivo do MT4.

Zero.O Javascript está em toda parte na internet.

Venda em massaO seu problema resolvido?

Zero.A maior parte do tempo, os dados podem ser transmitidos diretamente como registros ou como uma matriz de preço puro.