Documentación de la API cuantificada por el inventor

El autor:Un sueño pequeño., Creado: 2017-11-27 09:05:08, Actualizado: 2023-07-12 16:47:31

void main() {
    Mail("smtp.163.com", "asdf@163.com", "password", "111@163.com", "title", "body");
}
  • MailVersión asíncrona de la funciónMail_GoFunción: Uso y usoexchange.GoLas funciones son similares.

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

No hay que olvidarlo. El servidor de Ali Cloud puede bloquear algunos puertos, lo que hace que el correo no pueda enviarse. Si se necesita cambiar el puerto, se puede agregar el número de puerto directamente en el primer parámetro, por ejemplo:smtp.qq.com:587, la prueba de puerto está disponible. En caso de que se produzca un error:unencryped connection¿Qué hay que hacer?MailLa funciónsmtpServerEl formato de los parámetros es:ssl://xxx.com:xxxPor ejemplo, el correo electrónico de QQ.SMTPEl uso de SSL:ssl://smtp.qq.com:465¿Qué es esto?smtp://xxx.com:xxx

SetErrorFilter ((...) y el resto de las aplicaciones

SetErrorFilter(RegEx), Filtrando el registro de errores. El valor del parámetro: tipo de cadena. Los registros de errores que coinciden con esta expresión regular no se subirán al sistema de registros, y se pueden llamar varias veces para establecer varias condiciones de filtro (los registros filtrados no se escriben en los archivos de la base de datos correspondientes al ID de disco real en el directorio de los administradores, lo que evita que los errores frecuentes causen la inflación de los archivos de la base de datos).

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

En el caso de los usuarios de Internet, los mensajes de errores de las interfaces pueden filtrarse:

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

¿ Qué te parece?

GetPid(), devuelve el ID del proceso de disco real.

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

Obtenga el último error

GetLastError(), para obtener la información de error más reciente. Generalmente no es necesario, ya que el programa sube la información de error automáticamente al sistema de registros.GetLastError()La función luego borrará el error de caché y no devolverá el mensaje de error de la última vez que se llame de nuevo.

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

Obtener el comando

GetCommand(), obtenga la cadena de comandos de interacción ((utf-8)); obtenga la instrucción enviada por la interfaz de interacción de la política y limpie el caché, sin instrucciones, devuelva la cadena de comandos vacía; el formato de instrucción devuelto es按钮名称:参数Si el control interactivo no tiene parámetros (por ejemplo, un control de botón sin cuadro de entrada), el comando es el nombre del botón.

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

El sistema subyacente tiene una estructura de cola que registra las instrucciones de interacción cuandoGetCommand()Cuando se llama a una función, se extrae la orden de interacción que entra primero en la cola (devuelve una cadena vacía si no hay una orden de interacción).

Ejemplos de uso de controles interactivos, configuración de controles interactivos en la interfaz de edición de políticas.

img

La estrategia para diseñar código interactivo es:

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

Obtener Meta()

GetMeta()La función devuelve el código de registro de la política de generación.MetaEl valor que la función devuelve es el tipo de cadena. Escenarios de aplicación, por ejemplo, estrategias que requieren una limitación de fondos para diferentes inquilinos. Nota: Cuando se genera un código de registroMetaNo puede ser más de 190 caracteres de largo. Esta función solo se aplica a discos físicos y requiere el uso del administrador más reciente.GetMeta()Devuelve un valor en blanco.

Información sobre el uso de la demostración de escenarios

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

Marca el número.

Dial(Address, Timeout)¿Qué es esto?SocketAcceso y apoyotcpudptlsunixEl protocolo.AddressPara el tipo de strings,TimeOutTipo de valor, unidad de valor en segundos, si está fuera de tiempoDial(...)La función devuelve un valor en blanco.

AddressLos parámetros se explican en detalle:

Indicación de parámetros
ConfiguraciónDialParámetros de las funciones En su dirección normal:wss://ws.okx.com:8443/ws/v5/publicDespués|Separación de símbolos, si hay una cadena de parámetros|Los caracteres están en||Se usa como símbolo de separación.&Conexión de caracteres. Por ejemplo, el agente ss5 y los parámetros de compresión se establecen juntos:Dial("wss://ws.okx.com:8443/ws/v5/public|proxy=socks5://xxx:9999&compress=gzip_raw&mode=recv")
Cuando se usa el protocolo ws, los parámetros relacionados con la compresión de datos son:compress=参数值 compress como modo de compresión, parámetros de compresión, opcionalgzip_rawgzipPor ejemplo. Si el método gzip no es el estándar gzip, se puede usar el método de extensión:gzip_rawEs decir, en el separador.|Añadir configuración despuéscompress=gzip_raw¿Qué es esto?&El símbolo y el siguiente parámetro de modo separados.
Cuando se usa el protocolo ws, los parámetros relacionados con la compresión de datos son:mode=参数值 Modo para el modo, opcionaldualsendrecvHay tres.dualPara ambos lados, enviar datos de compresión y recibir datos de compresión.sendPara enviar datos comprimidos.recvPara recibir los datos de compresión, descomprima localmente.
Los parámetros para configurar el agente de socks5 son:proxy=参数值 Proxy está configurado como un agente ss5, con un formato de parámetros:socks5://name:pwd@192.168.0.1:1080.name es el nombre de usuario del servidor ss5, pwd es el código de inicio de sesión del servidor ss5 y 1080 es el puerto del servicio ss5.
Cuando se utiliza el protocolo ws, se establecen los parámetros relacionados con la recombinación automática de fondo:reconnect=参数值 reconnect para saber si se ha configurado el reconnect.reconnect=truePara habilitar el reconexión. Si no se establece este parámetro, no se reconecta por defecto.
Cuando se utiliza el protocolo ws, se establecen los parámetros relacionados con la recombinación automática de fondo:interval=参数值 El intervalo es el intervalo de tiempo de repetición, en milisegundos.interval=10000Para volver a intentar, el intervalo de 10 segundos no está configurado para 1 segundo por defecto, es decir,interval=1000
Cuando se utiliza el protocolo ws, se establecen los parámetros relacionados con la recombinación automática de fondo:payload=参数值 Mensajes de suscripción que se necesitan para enviar cuando el payload se vuelve a conectar a ws, por ejemplo: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();
    }
}

readLa función admite los siguientes parámetros:

  • Cuando no se transmite un parámetro, se bloquea hasta que hay un mensaje y se devuelve.ws.read()
  • Cuando se introduce un parámetro, la unidad es de milisegundos, y se especifica el tiempo de espera del mensaje. Por ejemplo:ws.read(2000)El tiempo de tiempo de espera es de dos segundos (~2000 ms).
  • Los siguientes dos parámetros son válidoswebsocket¿Qué es lo que sucede? Parámetros de entrada-1Esto significa que la función regresa inmediatamente, sin importar si hay un mensaje o no, por ejemplo:ws.read(-1)¿Qué es esto? Parámetros de entrada-2Esto significa que la función regresa inmediatamente, sin importar si hay ningún mensaje, pero solo devuelve el mensaje más reciente, y los mensajes en el área de reserva se desechan; por ejemplo:ws.read(-2)

read()El área de amortiguación de la función explica: Los datos enviados por el protocolo ws, si están en la políticaread()Los intervalos de tiempo entre las llamadas de funciones pueden ser demasiado largos, lo que puede causar acumulación de datos. Estos datos se almacenan en buffers, con una estructura de datos de buffers en colas, con un límite de 2000; después de superar el 2000, los datos más recientes entran en buffers, y los datos más antiguos se eliminan.

La escenareadParámetros de las funciones Sin parámetros Parámetros: -1 Parámetros: -2 Parámetros: 2000, la unidad es milisegundo
Ya hay datos en la zona de reserva. Volver a los datos más antiguos inmediatamente. Volver a los datos más antiguos inmediatamente. Volver a los datos más recientes inmediatamente. Volver a los datos más antiguos inmediatamente.
No hay datos en la zona de reserva. Bloquear hasta que haya datos Devuelve el valor en blanco de inmediato Devuelve el valor en blanco de inmediato Esperar 2000 ms, no hay datos devuelve valores en blanco, pero hay datos devuelve
cuando la conexión ws se corta o se vuelve a conectar por debajo La función read (()) devuelve una cadena vacía, es decir: "", write (()) devuelve 0, y detecta esta situación. Puede utilizar la función close (()) para cerrar la conexión, sin necesidad de cerrarla si está configurada para una reconexión automática.
  • Soporte para el protocolo wss (WebSocket) Para acceder a la interfaz de mercado del websocket de 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 acceder a la interfaz de mercado del websocket de 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("退出");
    }
    

    La interfaz de mercado del websocket para acceder a los 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 acceder a la interfaz de verificación del websocket de 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 (en inglés)

HttpQuery(Url, PostData, Cookies, Headers, IsReturnHeader), URL de acceso a la red. Values de parámetros: todo tipo de cadena.

No hay que olvidarlo.

  • HttpQuery(...)Función sólo es compatibleJavaScriptEl idioma también.
  • PythonLa lengua puede ser usadaurllibEn la actualidad, la mayoría de los usuarios de Facebook están usando la aplicación para enviar sus solicitudes a otros usuarios.

HttpQuery(...)Se utiliza principalmente para acceder a interfaces de intercambio que no requieren la firma, como las interfaces públicas de información de mercado.

Ejemplo de API que accede a OKX sin necesidad de firmar y que devuelve un valor deJSON¿Qué es lo que está sucediendo?JavaScriptLas estrategias del lenguaje pueden ser usadasJSON.parse()El análisis de funciones.

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

Obtener el contenido de una URL que se devuelve si el segundo parámetroPostDataPara las cuerdasa=1&b=2&c=abcLa forma es:POSTCómo presentar.PUTLos medios de comunicación también están involucrados.PostDataEl parámetro es{method:'PUT', data:'a=1&b=2&c=abc'}PostDataLos parámetros también pueden serJSONLa leyenda de la leyenda de la ley.

CookiesEste parámetro tiene la forma:a=10; b=20Los parámetros están marcados con puntos.;El tiempo que pasa.HeadersEste parámetro tiene la forma:User-Agent: Mobile\nContent-Type: text/htmlLos parámetros se cambian por signos.\nEl tiempo que pasa.

La segunda opción.PostDataLos métodos personalizados pueden ser:HttpQuery("http://www.abc.com", {method:'PUT', data:'a=1&b=2&c=abc'})Si es necesario:HttpQueryLa función de tiempo de espera se puede configurar{method:'PUT', data:'a=1&b=2&c=abc'}UnirsetimeoutEl usuario puede usar la función de etiquetado de la página.

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

TransmisiónCookieLa cadena requiere un tercer parámetro, pero no lo necesitaPOSTPor favor, deje el segundo parámetro en blanco. Cuando se realiza la prueba de simulación, la función devuelve una cadena fija porque no se puede simular el acceso a la URL.Dummy DataPuede enviarse mensajes de texto o interactuar con otras interfaces API.

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

Volver hacia atrásHeaderEjemplos de llamadas:

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}
  • HttpQueryLa función utiliza un agente para establecer:

    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/");
    }
    
  • HttpQueryVersión asíncrona de la funciónHttpQuery_Go¿Qué es esto? Uso y usoexchange.GoLas funciones son similares, por ejemplo, acceder sincronizadamente a la interfaz pública de los intercambios para obtener datos 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)
    }
    
    # 不支持
    
    // 不支持
    
  • Uso en sistemas de retrospecciónHttpQuery(...)Función: Se puede usar en sistemas de retrospecciónHttpQuery(...)Envío de solicitudes (Sólo soportado)GETLos usuarios pueden solicitar) obtener datos; • limitar el uso de 20 visitas diferentes a URLs durante la revisión; yHttpQuery(...)El acceso guarda los datos de la misma URL la segunda vez que se visitaHttpQuery(...)La función devuelve los datos de caché (ya no se realizan solicitudes reales de red).

    Podemos ejecutar un programa de servicio en un servidor o un dispositivo para responder a un programa de política.HttpQuery(...)El programa de servicio de lenguaje Go utilizado para probar las solicitudes enviadas es el siguiente:

    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 la revisión de estrategiasHttpQuery(...)Envía una solicitud de función:

    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

  • Soporte para la recodificación de datos de respuesta a las solicitudes, soporte para la codificación común. EspecificarPostDataParámetros:{method: "GET",charset:"GB18030"}El código de transferencia de datos de la respuesta (GB18030) es el siguiente:

Codificación

Encode(algo, inputFormat, outputFormat, data, keyFormat, key string)La función codifica los datos según los parámetros transmitidos.

ParámetrosalgoLos algoritmos que se utilizan para el cálculo de la codificación son los siguientes:??raw (sin 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,??mdrip160,??blake2b.256,??blake2b.512,??blake2s.128,??blake2s.256.dataLos datos para los que se trata.inputFormat/outputFormat/keyFormatApoyo de parámetrosrawhexbase64stringLa codificación también está disponible en las páginas web. ¿Qué pasa sikeyFormatSi no es nulo, usemos los parámetroskeySe utiliza el cifrado (HMAC) o el uso predeterminado.keyLos parámetrosalgoSe puede configurar"sign"¿Qué es esto?"signTx"Cuando se necesitan 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ámetrosalgoTambién apoya:text.encoder.utf8text.decoder.utf8text.encoder.gbktext.decoder.gbkEn la actualidad, la mayoría de las aplicaciones de código abierto están disponibles en la web.

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()Si se necesita obtener un tiempo en milisegundos, se puede usar el siguiente 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(), regresa el tiempo de segundo a nivel de tiempo.

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

¿Qué quieres decir?

GetOS()En el caso de los servidores, los servidores pueden enviar mensajes a los servidores de otros servidores, y los servidores pueden enviar mensajes a otros servidores.

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

En las computadoras de AppleMac OSLa entrada de los registros de administradores que se ejecutan en el sistema operativo:

- ¿Qué quieres decir?

darwinEs decir,Mac OSEl nombre del sistema.

MD5 (cuadrícula)

MD5(String), valor de parámetro: tipo de cadena.

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

El log de salida:

¿Qué es lo que está pasando?

DbExec ((...)

DBExec(), valor de parámetro: puede ser de tipo de cadena, valor numérico, valor de boolean, valor de espacio, etc.; valor de retorno: objetos que contienen el resultado de la ejecución de una declaración de SQLite. Función de interfaz de la base de datosDBExec()Se puede operar la base de datos de disco real (base de datos SQLite) mediante la entrada de parámetros. Se pueden realizar operaciones de adición, eliminación, verificación y modificación de datos en la base de datos de disco real.SQLiteSincronización. Las tablas de reserva del sistema en la base de datos de disco real:kvdbcfglogprofitchartNo hagas ningún tipo de manipulación con estas tablas.DBExec()La función sólo admite discos físicos.

  • Apoyo para la base de datos de memoria En cuanto aDBExecLos parámetros de una función, siCuadradoLas frases se escriben:Para comenzar, se opera en la base de datos en memoria, sin escribir documentos, más rápido. Es adecuado para operaciones de base de datos que no requieren una conservación 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;"));
    }
    
  • Crear una tabla

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);
}
  • Añadir, borrar, revisar y modificar los registros de la tabla
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(), que devuelve un UUID único de 32 bits, que solo se aplica a los discos físicos.

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 (tiempo muerto)

EventLoop(timeout)En cualquier lugarwebsocketSe puede leer oexchange.GoHttpQuery_GoDe esta manera, las tareas simultáneas se regresan después de que se hayan completado.timeoutSi se establece como 0, se devuelve hasta que ocurra un evento, si es mayor a 0, se establece que el evento se retrase, y si es menor a 0, se devuelve inmediatamente el evento más reciente.nullEn este caso, el contenido de la página es el contenido de la página.EventTipo de activación de eventos. Esta función sólo se aplica al disco físico.

La primera llamada en el códigoEventLoopEl mecanismo que inicializa el evento de interceptación, si se inicia por primera vez después de que el evento se recuerda.EventLoopLlamadas que pierden los eventos anteriores. La estructura de cola envuelta en el sistema subyacente guarda un caché de hasta 500 llamadas de eventos si el programa no se llama a tiempo durante la ejecución.EventLoopSi se extrae, se perderán 500 cajas de eventos más tarde.EventLoopLas llamadas de funciones no afectan el fondo del sistema.websocketLa cola de caché no tiene ningún efecto.exchange.GoLa caché de funciones simultáneas, por ejemplo, todavía requiere que se extraigan los datos de cada caché utilizando sus propios métodos.EventLoopLa función regresa los datos extraídos, pero no se pueden ver en la pantalla.EventLoopLa función tiene un evento de retorno.

EventLoopEl principal uso de la función es informar a la capa de política, la base del sistema, que recibe nuevos datos de la red.EventLoopCuando una función devuelve un evento, sólo tiene que recorrer todos los datos; por ejemplo,websocket¿Cómo se puede hacer esto?exchange.GoLos objetos creados intentan obtener datos.Enlaces a las bibliotecas

En la función principalmain()En el momento de la llamada, escucha los eventos del hilo principal.JavaScriptEn la estrategia de escritura de la lengua, la mayoría de las palabras son usadas para expresar lo que se siente.__Thread()Los hilos creados por las funciones también pueden ser llamados en la función ejecutiva del hilo para escuchar los eventos del hilo actual.

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

Más.

¿Qué es esto?Hay un problema con la función_C. ¿Trabajará siempre o solo una vez?

¡Qué bien!_C ((function, args...) ¿Es este el 3s por defecto? ¿Se puede cambiar por defecto para poner directamente _CDelay ((1000) antes de _C ((function, args...)? ¿Se puede establecer una vez?

- ¿ Qué es eso?Cluster: Si creas 1000 robots simultáneamente y sin estrés, puedes crear varios administradores para distribuir las tareas. ¿Hay ejemplos de código para construir un cluster? ¿Cómo construir varios administradores para distribuir las tareas?

- ¿Qué quieres?Log ((talib.help (('MACD')); sólo se puede usar en js, Python no tiene la propiedad talib.help...

Cjz140¿Cuál es la diferencia entre _C (función, args...) y la función de sueño, que creo que significa esperar para volver a intentarlo?

3263243y¿Cómo borrar ErrorFilter después de SetErrorFilter? sin filtrar el mensaje de error.

¿Qué quiere decir?¿Hay alguna manera de usar una biblioteca de terceros?

¿Qué quiere decir?¿Qué debe rellenar la clase padre si se quiere heredar una nueva clase definida por un objeto de intercambio?

yhanwu¿Hay herramientas de depuración locales?

el pingüino¿Qué pasa con el exange.IO?

el pingüino¿Por qué la función sell está en gris, es que la función de representación ya no está disponible?

el pingüino¿Por qué la función sell está en gris, es que la función de representación ya no está disponible?

el pingüinoNo entiendo el lenguaje de los js.

el pingüinoNo entiendo el lenguaje de los js.

Don.¿Cómo se escribe la línea media del volumen?

la tortuga¿Qué se devuelve si no se consigue?

El hombre de NingEsta nueva tipografía es hermosa.

hipopótamoLa red de pruebas de Bitmex (testnet.bitmex.com) también tiene una interfaz API, pero actualmente las bolsas solo pueden elegir la base de Bitmex, y la dirección del archivo de API es https://testnet.bitmex.com/app/apiOverview. ¿Cómo apoyar?

- ¿Qué quieres decir?var ret1 = exchanges[0].IO (("api", "future_estimated_price", "symbol=btc_usd"); Log (('ok futuros precio de entrega estimado', ret1); https://dn-filebox.qbox.me/d1ed268c1e75753c5d289447d279aa9d81e41b5f.png ¿Por qué llamar a las interfaces de otras bolsas y escribir este error?

todosfrostline¿Cuál es la diferencia entre realTicker y Ticker? Recientemente se ha reescrito la estrategia de los paquetes, y ambos aparecen al mismo tiempo, pero parece que no se menciona en la primera API.

las visionesHola, como desarrollador de Python, ¿qué crees que escribe tu documentación API? Algunas interfaces de función de campo parecen extrañas, ¿puedes escribir un documento como githubpage y readdocs?

todosfrostlineGetAccount: [EAPI: Rate limit exceeded] ¿Quieren saber cómo se resuelve esto?

Zjx2314No soporta StochRSI, ¿se puede añadir pronto?

Yhfgg¿El guión está en su propio servidor en la nube Ali o en el botvs cluster?

Yhfgg¿Qué versión de python usas?

muy bien.La explicación de GetFee debería ser que regrese una estructura de Fee, con una estructura menos.

¿Qué quieres decir?¿Puedo llamar a talib con js?

YhfggBuscar documentación en python

- ¿Qué quieres decir?¿Puede el fondo de código de la estrategia de edición tener un negro? ojos blancos, escribir código en la noche, fácil de miopía.

Don.¿Cómo configurar el resumen en el bot WeChat?

El número de locos¿Se puede añadir un campo de precio de transacción en la estructura de la orden?

El pequeño.GetOrders: Obtener todos los pedidos incompletos, devolver una estructura de orden de la matriz, en el comercio de Bitcoin en China ETH, sólo devuelve los últimos 10 artículos, aquí hay una función que devuelve todos los pedidos incompletos de Bitcoin en China ETH, lo que significa que otras plataformas pueden devolver todo con GetOrders, sólo que este fantasma de China Bitcoin devuelve 10 artículos.

Yhfgg¿Cuál es la función matemática que se necesita para la teoría de probabilidades estadísticas?

- ¿ Qué?¿Qué significa el valor que devuelve la función $.Cross ((x, y)?

Mi abuela dice:El LogReset puede borrar todos los registros con un parámetro numérico para especificar los registros reservados. ¿Cómo se borran los últimos registros?

- ¿Qué quieres?¿La función CORRE en talib parece no haber sido trasladada o se perdió?

El pueblo pobre.¡Parece que no hay una función de referencia de indicadores!

Pequeño¿Cómo se traduce el tiempo de la línea k de lectura en el tiempo actual oh, no entiendo, demasiado largo uno, resuelto, gracias

Pequeño¿Cómo se escribe para eliminar números de las matrices, me parece que no funciona con records.remove ((records[0])

el serpiente¿Cómo llamar ATR a la línea K de día?

el serpiente¿Cómo llamar ATR a la línea K de día?

57278863Aprenda cómo obtener precios y pedidos de futuros tradicionales, lo siento, sus raíces son muy finas.

el mismo¡El ejemplo de los futuros tradicionales!

Pequeño¿Puedes escribir un ejemplo de comercio de futuros tradicionales?

Pequeño¿Cómo imprimir el estado de la posesión de varios ordenes en el mismo tiempo, cómo imprimir mi [object object], cómo obtener el estado de la posesión de varios ordenes y ordenes en el mismo tiempo, y GetTicker ((), cómo obtener la semana, la próxima semana y el trimestre de la semana en el precio, la semana, la próxima semana y el trimestre en paréntesis que escribí.

- ¿Qué quieres decir?¿Pueden los mercados de futuros obtener transacciones con GetTicker (??), y devuelven el tipo de mercado de contrato (?? de la semana, de la semana siguiente...)?

Vender mucho¿Qué indicador del StochRSI se puede añadir?

el momoxCancelOrder ((orderId) para cancelar un pedido basado en el número de la orden, devuelve true o false, pregunta true= la celda fue cancelada con éxito, ¿verdad?

el momox_G(K, V) Se puede guardar una lista de dicionarios globales ¿Puede este método guardar variables globales para compartir datos entre diferentes políticas?

¿Qué quieres decir?La popularidad

No hay nadaLos registros de ganancias se pueden restablecer con LogProfitReset. El historial de los gráficos de ganancias anteriores desaparece.

- ¿ Qué?¿Se puede copiar directamente la EA para usarla?

El hombre de los cielosSiento que esta plataforma es genial, más interacción en el grupo.

Pequeño¿Qué idioma es este? ¿Hay material para aprender?

JxhbtcError de datos Una semana sin conectar el robot, ¿cómo resolverlo?

¿Qué quieres decir?¿Es el índice TA sólo un cálculo del precio de cierre?

¿ Qué pasa?Hola, mundo.

Un sueño pequeño.La función _C intentará repetidamente sin pensarlo hasta que obtenga un resultado exitoso.

Un sueño pequeño.La biblioteca talib de python requiere una instalación. https://www.botvs.com/bbs-topic/669 puede verse en este post.

Un sueño pequeño.Sleep es el número de milisegundos en que el programa no hace nada y espera que el parámetro se establezca, _C es la función que vuelve a llamar el parámetro.

Un sueño pequeño.Sin necesidad de herencia, JS se envuelve directamente en el objeto {name: "nuevo objeto", old_exchange: exchange[0],...... }

Un sueño pequeño.Los editores locales, los complementos de sincronización remota, basicamente, son editores locales, desinstalación remota.

Un sueño pequeño.¿Por qué no vienes al grupo de QQ para hablar?

Un sueño pequeño.En la documentación de la API, gris significa que la función no tiene demasiadas explicaciones de despliegue, se muestra en gris, los representantes de azul tienen más explicaciones, eso es todo.

Un sueño pequeño.ES6 está fuera de soporte.

Un sueño pequeño.¿Puedes ir al grupo de QQ? Yo, describe el problema, yo voy a responder ^^

Un sueño pequeño.En la actualidad, la mayoría de las aplicaciones de Google no están disponibles para los usuarios, pero en la actualidad, la mayoría de las aplicaciones están disponibles para los usuarios de Google.

la tortugaPor ejemplo, OKCoin, si la cantidad comprada es mayor que la cantidad de monedas que se tienen, ¿qué se devuelve?

Un sueño pequeño.En concreto, en qué bolsa de valores voy a devolver un número de orden en OK Futures?

No hay nadaYa se admite el cambio de transacciones en ejecución, se requiere la descarga del último administrador. Se admite Bter/Poloniex Detalles API Documentación Descripción de la función de transacción en la barra de abajo ((Limpiar la caché del navegador y actualizar si no se ve)

Un sueño pequeño.QQ, me voy a ayudar a encontrar la pregunta. 359706687

Familias de criadores profesionales¿Cómo puedo configurar una lista blanca? ¿Cómo configuro la dirección IP del host?

Un sueño pequeño.Este es el enlace subyacente No se ha creado El servidor no responde. ¿Se ha configurado la dirección IP cuando se solicita la API KEY?

Familias de criadores profesionalesEsto es embarazoso. La política que podía ejecutarse cambió a la era de los bites, y GetAccount no puede acceder a 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 de los Bites Error en el registro de GetAccount: timeout 2017-05-23 21:08:02 Era de los Bitcoins Error en el GetAccount: tiempo de espera 2017-05-23 21:07:40 Era bit error GetAccount: tiempo de espera 2017-05-23 21:07:20 Reinicio del proyecto ¿Es el problema de la lista blanca de IP???

Un sueño pequeño.Los servidores de la bolsa no respondieron, el protocolo TCP no se estableció ni se estrechó la mano tres veces.

Familias de criadores profesionalesA connection attempt failed because the connected party did not properly respond after a period of time (Un intento de conexión fracasó porque la parte conectada no respondió adecuadamente después de un período de tiempo)

Un sueño pequeño.Hola! Hablo de la función exchange.IO ((api, ApiName, Args) que no es compatible, por favor vea https://www.botvs.com/bbs-topic/812

Familias de criadores profesionalesUn intento de conexión falló porque la parte conectada no respondió adecuadamente después de un período de tiempo,

Familias de criadores profesionales¿No es compatible con la era de los bitcoins?

Un sueño pequeño.https://dn-filebox.qbox.me/a709b30c6cc0a3565234b9e0c99b073f7ba8b454.png ¿Cómo se puede hacer eso?

El hombre de NingPor ejemplo, quiero hacer un intercambio de todas las monedas de poloniex, pero solo hay unas pocas monedas compatibles con BOTvs, y exchange.IO parece no admitir la red P.

Un sueño pequeño.Se puede llamar exchange.IO.

El hombre de Ning¿Qué pasa con las API que requieren la verificación de cuentas?

Un sueño pequeño.Si la API no requiere la verificación de la cuenta, puede utilizar httpQuery (ver documentación BotVS para más información), la API de transacción real requiere acceso.

Un sueño pequeño.Los parámetros de la API HttpQuery se pueden transmitir a través de: https://www.okcoin.com/api/v1/future_estimated_price.do?symbol=btc_usd. Esto es suficiente. En la página de Facebook del botvs.com se puede leer:

las visionesGracias, espero que haya una excelente documentación de la API.

Un sueño pequeño.¿Dónde se puede ver la API realTicker?

Un sueño pequeño.En la actualidad, la mayoría de los archivos están en manos de personas que no son miembros de la comunidad. La documentación de la API es el lenguaje JavaScript. Descrito en la versión de python. Descrito en la parte superior de la página de la comunidad de chat de chat.

No hay nadaHola, gracias por la sugerencia, la documentación de la API está siendo reconstruida.

Un sueño pequeño.Bienvenido ~ muestra que la frecuencia de acceso está fuera de la limitación. En la actualidad, la mayoría de los archivos de la red social están en manos de personas que no son miembros de la comunidad. ¿Utilizan la función Sleep (?1000) en la política?, Este 1000 es para que el programa se detenga un segundo por ronda, que se puede configurar por sí mismo, el objetivo es controlar la frecuencia de acceso del programa a la API, ya que algunos intercambios establecen un límite máximo de acceso, un cierto tiempo más de un cierto número de visitas se negará el acceso, bloqueando la dirección IP.

Un sueño pequeño.https://dn-filebox.qbox.me/c29ab7fc279e1b758355f137907cf52dc8257df6.png Lo que yo personalmente he escrito sobre los indicadores de STOCHRSI que ya se han comparado con OK, es que la velocidad es un poco lenta y debe ser optimizada, por el momento.

No hay nadaSe puede elegir si se reanudará en el servidor proporcionado por botvs o en el servidor de su propio administrador, la versión es 2.7.5

Un sueño pequeño.Ahora añadido.

Un sueño pequeño.Ahora puedes configurar tu propio estilo de fondo.

Un sueño pequeño.El archivo de python está siendo escrito.

Un sueño pequeño.También puede acceder a la biblioteca talib.

¿Qué quieres decir? https://www.botvs.com/bbs-topic/276

Un sueño pequeño.Parece que hay un ejemplo en Strategy Square, https://www.botvs.com/strategy/15098

No hay nadaEl acceso a las propiedades de Orders de AvgPrice, que los intercambios pueden apoyar, los intercambios que no lo hacen siempre tendrán la propiedad 0.

Yhfgg¿Cómo se cita una fuente de terceros?

No hay nadaSi mathjs no puede hacerlo, solo puede buscar una política de copia e importación de una biblioteca de terceros. Para compiler más rápido, el sistema solo tiene una pequeña cantidad de bibliotecas integradas.

Un sueño pequeño.No soy muy amable, hay problemas en el grupo, ¿puedes decirme que estoy en línea?

- ¿ Qué?Gracias.

Un sueño pequeño.¿En el grupo? Puedes ver el análisis de código de la biblioteca de transacciones de monedas digitales en la versión de comentarios, donde hay comentarios sobre la función $.Cross.

No hay nadaNo se puede borrar lo más reciente, solo se pueden guardar los últimos artículos... se borran todos los viejos.

el mismoPara obtener cada posición con la posición [i], la posición es un conjunto.

El hombre de NingEn el caso de los registros de datos, el número de datos de los registros de datos es el número de datos de los registros.

el mismoMis futuros tradicionales siempre me han dicho: "GetAccount: no login", "No hay error de contraseña, no puedo iniciar sesión".

No hay nadaPor defecto es semana, para obtener el tipo de contrato especificado se necesita SetContractType primero.

No hay nadaComo se ha visto, este true es el valor de retorno de la acción de cancelar la orden que el intercambio devuelve, pero la cancelación real no se cancela, dependiendo de cómo se trate dentro del intercambio.

el momox3q

No hay nada¡No! ¡Está separado!

- ¿ Qué?Por supuesto que no, eso es exclusivo de MT4.

No hay nadaLa información de JavaScript está en todas partes en la red.

Vender mucho¿Está resuelto su problema?

No hay nadaLa mayoría de las veces, los datos que se envían pueden ser directamente registros o un conjunto de precios puros.