En la carga de los recursos... Cargando...

En todo el mundo

Versión

Devuelve el número de versión actual del sistema.

Número de versión del sistema actual, por ejemplo:3.6- ¿ Por qué? la cuerda

Versión

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

El número de versión del sistema es el número de versión del programa docker.

- ¿ Qué pasa?

La función de sueño, haciendo que el programa se detenga por un período de tiempo.

El sueño (millisegundo)

ElmillisecondParámetro utilizado para establecer la duración del sueño y el número de milisegundos. milisegundos verdadero Número

function main() {
    Sleep(1000 * 10)   // Wait for 10 seconds
    Log("Waited for 10 seconds")
}
def main():
    Sleep(1000 * 10)
    Log("Waited for 10 seconds")
void main() {
    Sleep(1000 * 10);
    Log("Waited for 10 seconds");
}

Por ejemplo, al ejecutar elSleep(1000)Función, el programa permanecerá en reposo durante 1 segundo.Sleep(0.1)Apoya un parámetro mínimo de0.000001, es decir, hibernación de nanosegundos, donde 1 nanosegundo es igual a1e-6milisegundos. Cuando se escriben estrategias en elPythonLa lenguaSleep(millisecond)No se recomienda el uso de la función de intervalo de votación, las operaciones de tiempo de espera.time.sleep(second)Función dePython¿ Qué?timeEsto se debe a que el uso de latime.sleep(second)función en una estrategia hace que el programa de estrategia espere por un período de tiempo en realidad cuando backtesting (no saltando en la serie de tiempo del sistema de backtesting), por lo que hace que la estrategia para backtesting muy lentamente.

Es virtual

Determinar si el entorno de ejecución de la estrategia es un sistema de backtesting.

La estrategia devuelve un valor verdadero, por ejemplo:trueLa estrategia devuelve un valor falso, por ejemplo:falsecuando se ejecuta en un entorno de negociación en vivo. - ¿ Qué?

¿Es Virtual?

function main() {
    if (IsVirtual()) {
        Log("The current backtest system environment.")
    } else {
        Log("The current live trading environment.")
    }
}
def main():
    if IsVirtual():
        Log("The current backtest system environment.")
    else:
        Log("The current live trading environment.")
void main() {
    if (IsVirtual()) {
        Log("The current backtest system environment.");
    } else {
        Log("The current live trading environment.");
    }
}

Determinar si el entorno de funcionamiento actual es un sistema de backtesting, que se utiliza para ser compatible con la diferencia entre backtesting y trading en vivo.

Correos

Envía un correo electrónico.

Una entrega de correo electrónico exitosa devuelve un valor verdadero, por ejemplo,true, y una entrega fallida devuelve un valor falso, por ejemplo,false- ¿ Por qué? - ¿ Qué?

Correo ((smtpServidor, smtpNombre de usuario, smtpPalabra de seguridad, mailTo, título, cuerpo)

Se utiliza para especificar elSMTPdirección de servicio del remitente del correo electrónico. Es un servidor. verdadero la cuerda Se utiliza para especificar la dirección de correo electrónico del remitente. Nombre de usuario verdadero la cuerda ElSMTPcontraseña para el buzón del remitente. ¿ Qué pasa? verdadero la cuerda Se utiliza para especificar la dirección de correo electrónico del destinatario. Envío de correo verdadero la cuerda Título de correo electrónico. Título verdadero la cuerda El cuerpo del correo electrónico. cuerpo verdadero la cuerda

function main(){
    Mail("smtp.163.com", "asdf@163.com", "password", "111@163.com", "title", "body")
}
def main():
    Mail("smtp.163.com", "asdf@163.com", "password", "111@163.com", "title", "body")
void main() {
    Mail("smtp.163.com", "asdf@163.com", "password", "111@163.com", "title", "body");
}

ElsmtpPasswordParámetro establece la contraseña para elSMTPservicio, no la contraseña del buzón. Al ajustar elsmtpServerParámetro, si necesita cambiar el puerto, puede añadir el número de puerto directamente en el parámetrosmtpServerPor ejemplo: correo QQsmtp.qq.com:587, que está disponible para su ensayo. En caso de error:unencryped connection, usted necesita para modificar elsmtpServerde lasMailEl formato del parámetro es:ssl://xxx.com:xxx, por ejemplo, elsslmétodo deSMTPpara el correo QQ:ssl://smtp.qq.com:465o biensmtp://xxx.com:xxx- ¿ Por qué? No funciona en el sistema de backtesting.

¿Por qué no lo haces?

¿ Qué pasa?

Versión asíncrona delMail function.

ElMail_Gofunción devuelve un objeto concurrente inmediatamente, y se puede utilizar elwaitUn correo entregado con éxito devuelve un valor verdadero, por ejemplo,true, y una entrega fallida devuelve un valor falso, por ejemplo,false- ¿ Por qué? Objeto

Mail_Go ((smtpServer, smtpUsername, smtpPassword, mailTo, título, cuerpo)

Se utiliza para especificar elSMTPdirección de servicio del remitente del correo electrónico. Es un servidor verdadero la cuerda Se utiliza para especificar la dirección de correo electrónico del remitente. Nombre de usuario verdadero la cuerda ElSMTPcontraseña para el buzón del remitente. - ¿ Qué pasa? verdadero la cuerda Se utiliza para especificar la dirección de correo electrónico del destinatario del correo electrónico. Envío de correo verdadero la cuerda Título de correo electrónico. Título verdadero la cuerda Corpo del correo electrónico. cuerpo verdadero la cuerda

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)
}
# Not supported.
// Not supported.

No funciona en el sistema de backtesting.

¿Por qué no lo haces?

Seleccionar el filtro de error

Registros de errores de filtro.

ConfigurarErrorFilter (filtros)

Una cadena de expresiones regulares. filtros verdadero la cuerda

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

Filtración de errores comunes.

function main() {
    // A random query for a non-existent order with an id of 123, allowing the interface to report an error deliberately
    var order = exchange.GetOrder("123")
    Log(order)
    // Filter http502 errors, GetOrder interface errors, after setting the error filter, the second call to GetOrder will no longer report errors
    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);
}

Filtrar un mensaje de error de interfaz.

Los registros de errores que coincidan con esta expresión regular no se cargarán en el sistema de registros. Puede llamarlo varias veces (sin límite en el número de veces) para establecer varias condiciones de filtro. Las expresiones regulares establecidas varias veces se acumularán y entrarán en vigencia al mismo tiempo. Puede establecer una cadena vacía para restablecer la expresión regular utilizada para filtrar los registros de errores:SetErrorFilter(""). Los registros filtrados ya no se escriben en el archivo de base de datos correspondiente a la ID de comercio en vivo en el directorio docker para evitar que los informes de errores frecuentes se hinchen en el archivo de base de datos.

- ¿ Qué pasa?

Obtener el proceso de comercio en vivo ID.

Retorno de la identificación del proceso de negociación en vivo. la cuerda

¿ Qué te parece?

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

Obtener el último error

Recibe el último mensaje de error.

Último mensaje de error. la cuerda

Obtenga el último error

function main(){
    // Because the order number 123 does not exist, so there will be an error.
    exchange.GetOrder("123")
    var error = GetLastError()
    Log(error)
}
def main():
    exchange.GetOrder("123")
    error = GetLastError()
    Log(error)
void main() {
    // Order ID type: TId, so you can't pass in a string, we place an order that doesn't meet the exchange specification to trigger
    exchange.GetOrder(exchange.Buy(1, 1));
    auto error = GetLastError();
    Log(error);
}

No funciona en el sistema de backtesting.

Obtener el comando

Obtiene el comando de interacción estratégica.

El formato del comando devuelto esControlName:Data. ControlNamees el nombre del control, yDataSi el control interactivo no tiene cajas de entrada, cajas desplegables y otros componentes (por ejemplo, un control de botón sin cajas de entrada), entonces el formato de comando devuelto esControlName, que devuelve sólo el nombre del control. la cuerda

Obtener el comando

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

Detecta el comando de interacción y utiliza elLogFunción para emitir el comando de interacción cuando se detecta.

function main() {
    while (true) {
        LogStatus(_D())
        var cmd = GetCommand()
        if (cmd) {
            Log("cmd:", cmd)    
            var arr = cmd.split(":")
            if (arr[0] == "buy") {
                Log("Buy, the control without number")
            } else if (arr[0] == "sell") {
                Log("Sell, the control with the number of:", arr[1])
            } else {
                Log("Other controls trigger:", arr)
            }
        }
        Sleep(1000)
    } 
}
def main():
    while True:
        LogStatus(_D())
        cmd = GetCommand()
        if cmd:
            Log("cmd:", cmd)
            arr = cmd.split(":")
            if arr[0] == "buy":
                Log("Buy, the control without number")
            elif arr[0] == "sell":
                Log("Sell, the control with the number of:", arr[1])
            else:
                Log("Other controls trigger:", 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("Buy, the control without number");
            } else if (arr[0] == "sell") {
                Log("Sell, the control with the number of:", arr[1]);
            } else {
                Log("Other controls trigger:", arr);
            }
        }
        Sleep(1000);
    }
}

Por ejemplo, el control interactivo de estrategia agrega un control sin un cuadro de entrada, el control interactivo se llama:buy, la información de descripción del control es:buy, que es un control de botón. Continúe añadiendo un control con un cuadro de entrada. El control interactivo se llama:selly el mensaje de descripción del control es:sell, que es un control interactivo que es una combinación de un botón y un cuadro de entrada.

No funciona en el sistema de backtesting.

ObtenerMeta

Obtener el valor de Meta escrito al generar el código de registro de la estrategia.

Metalos datos. la cuerda

Obtener Meta()

function main() {
    // The maximum asset value of the denominated currency allowed by the strategy.
    var maxBaseCurrency = null
    
    // Get the metadata when creating the registration code.
    var level = GetMeta()
    
    // Detecting the conditions corresponding to Meta.
    if (level == "level1") {
        // -1 for unrestricted
        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()
        
        // Detect asset values
        var acc = exchange.GetAccount()
        if (maxBaseCurrency != -1 && maxBaseCurrency < acc.Stocks + acc.FrozenStocks) {
            // Stop executing strategy trading logic
            LogStatus(_D(), "level:", level, "Positions exceeding the usage limit of the registration code will no longer execute the strategy trading logic!")
            continue
        }
        
        // Other trading logic
        
        // Normal output of status bar information
        LogStatus(_D(), "level:", level, "The strategy is working properly! ticker data: \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, "Positions exceeding the usage limit of the registration code will no longer execute the strategy trading logic!")
            continue        
        
        # Other trading logic
        
        # Normal output of status bar information
        LogStatus(_D(), "level:", level, "The strategy is working properly! ticker data: \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) {
            // Stop execution strategy trading logic.
            LogStatus(_D(), "level:", level, "Positions exceeding the usage limit of the registration code will no longer execute the strategy trading logic!");
            continue;
        }
        
        // Other trading logic
        
        // Normal output of status bar information
        LogStatus(_D(), "level:", level, "The strategy is working properly! ticker data: \n", ticker);
    }
}

Ejemplo de escenario de aplicación: usoMetalimitar el importe de los activos gestionados por la estrategia.

Escenario de aplicación: necesidad de hacer límites de capital para los diferentes arrendatarios de estrategia.Metael valor fijado al generar el código de registro no podrá exceder de 190 caracteres, yGetMeta()Si no hay metadatos (Meta) se establece al generar un código de registro de la estrategia, el código de registro de la estrategiaGetMeta()No funciona en el sistema de backtesting.

Marca el número.

Para el primitivoSocketacceso, apoyotcp, udp, tls, unixSoporte para 4 protocolos de comunicación populares:mqtt, nats, amqp, kafkaApoyo para conectar a bases de datos:sqlite3, mysql, postgres, clickhouse.

ElDial()Una llamada normal devuelve un objeto de conexión que tiene tres métodos:read, writeycloseEl.readEl método se utiliza para leer los datos, elwriteEl método se utiliza para enviar datos y elcloseEl método se utiliza para cerrar la conexión. Elreadel método admite los siguientes parámetros:

  • Cuando no se pasan parámetros, se bloquea hasta que un mensaje está disponible y devuelve, comows.read().
  • Cuando se pasa como un parámetro, la unidad es milisegundos, especificando el período de espera del mensaje.ws.read(2000)especifica un tiempo de espera de dos segundos (2000 milisegundos).
  • Los siguientes dos parámetros son válidos sólo para WebSocket: Pasando el parámetro-1significa que la función devuelve inmediatamente, independientemente de la presencia o ausencia de mensajes, por ejemplo:ws.read(-1)- ¿ Por qué? Pasando el parámetro-2significa que la función devuelve inmediatamente con o sin un mensaje, pero sólo el último mensaje se devuelve, y el mensaje tamponado se descarta.ws.read(-2).

read()Descripción del búfer de función: Los datos entrantes empujados por el protocolo WebSocket pueden causar acumulación de datos si el intervalo de tiempo entre la estrategiaread()Estos datos se almacenan en el búfer, que tiene una estructura de datos de una cola con un máximo de 2000.

Escenario No hay parámetro Parámetro: -1 Parámetro: -2 Parámetro: 2000, en milisegundos
Datos ya en el búfer Devuelva los datos más antiguos inmediatamente Devuelva los datos más antiguos inmediatamente Devuelva los últimos datos inmediatamente. Devuelva los datos más antiguos inmediatamente
No hay datos en el búfer Regresar cuando se bloquea a los datos Devuelva nulo inmediatamente Devuelva nulo inmediatamente Espera 2000 ms, devuelve nulo si no hay datos, devuelve nulo si hay datos
La conexión WebSocket se desconecta o se vuelve a conectar por el subyacente read() devuelve la cadena vacía, es decir: , y write() devuelve 0. La situación se detecta. Puede cerrar la conexión utilizando la función close(), o si ha configurado la reconexión automática, no necesita cerrarla, el sistema subyacente la reconectará automáticamente.

objetos

Número de teléfono y dirección Número de teléfono (dirección, tiempo límite)

Solicita la dirección. Dirección verdadero la cuerda segundos de tiempo de espera, tiempo de espera falsos Número

function main(){
    // Dial supports tcp://,udp://,tls://,unix://protocol, you can add a parameter to specify the number of seconds for the timeout
    var client = Dial("tls://www.baidu.com:443")  
    if (client) {
        // write can be followed by a numeric parameter to specify the timeout, write returns the number of bytes successfully sent
        client.write("GET / HTTP/1.1\nConnection: Closed\n\n")
        while (true) {
            // read can be followed by a numeric parameter specifying the timeout in milliseconds. Returning null indicates an error or timeout or that the socket has been closed
            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();
    }
}

Ejemplo de llamada de la función Dial:

function main() {
    LogStatus("Connecting...")
    // Accessing WebSocket interface of Binance
    var client = Dial("wss://stream.binance.com:9443/ws/!ticker@arr")
    if (!client) {
        Log("Connection failed, program exited")
        return
    }
    
    while (true) {
        // read returns only the data retrieved after the read call
        var buf = client.read()      
        if (!buf) {
            break
        }
        var table = {
            type: 'table',
            title: 'Ticker Chart',
            cols: ['Currency', 'Highest', 'Lowest', 'Buy 1', 'Sell 1', 'Last traded price', 'Volume', 'Update time'],
            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("Connecting...")
    client = Dial("wss://stream.binance.com:9443/ws/!ticker@arr")
    if not client:
        Log("Connection failed, program exited")
        return 
    
    while True:
        buf = client.read()
        if not buf:
            break
        table = {
            "type" : "table", 
            "title" : "Ticker Chart", 
            "cols" : ['Currency', 'Highest', 'Lowest', 'Buy 1', 'Sell 1', 'Last traded price', 'Volume', 'Update time'], 
            "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("Connecting...");
    auto client = Dial("wss://stream.binance.com:9443/ws/!ticker@arr");
    if(!client.Valid) {
        Log("Connection failed, program exited");
        return;
    }
    
    while(true) {
        auto buf = client.read();
        if(buf == "") {
            break;
        }
        json table = R"({
            "type" : "table", 
            "title" : "Ticker Chart", 
            "cols" : ["Currency", "Highest", "Lowest", "Buy 1", "Sell 1", "Last traded price", "Volume", "Update time"], 
            "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 WebSocket de Binance:

var ws = null 
function main(){
    var param = {
        "op": "subscribe",
        "args": [{
            "channel": "tickers",
            "instId": "BTC-USDT"
        }]
    }
    // When calling Dial function, specify reconnect=true to set reconnection mode and payload to be the message sent when reconnecting. When the WebSocket connection is disconnected, it will reconnect and send messages automatically.
    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("Send : ping", "#FF0000")
            }
            LogStatus("Current time:", _D())
            Sleep(1000)
        }
    }
}              

function onexit() {
    ws.close() 
    Log("exit")
}
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("Send: ping", "#FF0000")
            LogStatus("Current time:", _D())
            Sleep(1000)              

def onexit():
    ws.close()
    Log("exit")
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("Send: ping", "#FF0000");
            }
            LogStatus("Current time:", _D());
            Sleep(1000);
        }
    }
}              

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

Acceso a la interfaz del ticker de WebSocket de OKX:

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)
            // Respond to heartbeat packet operations
            try {
                var jsonRet = JSON.parse(ret)
                if(typeof(jsonRet.ping) == "number") {
                    var strPong = JSON.stringify({"pong" : jsonRet.ping})
                    ws.write(strPong)
                    Log("Respond to ping, send pong:", strPong, "#FF0000")
                }
            } catch(e) {
                Log("e.name:", e.name, "e.stack:", e.stack, "e.message:", e.message)
            }
            
            LogStatus("Current time:", _D())
            Sleep(1000)
        }
    }
}              

function onexit() {
    ws.close() 
    Log("Execute the ws.close() function")
}
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)              
            # Respond to heartbeat packet operations
            try:
                jsonRet = json.loads(ret)
                if "ping" in jsonRet and type(jsonRet["ping"]) == int:
                    strPong = json.dumps({"pong" : jsonRet["ping"]})
                    ws.write(strPong)
                    Log("Respond to ping, send pong:", strPong, "#FF0000")
            except Exception as e:
                Log("e:", e)
                
            LogStatus("Current time:", _D())
            Sleep(1000)
    
def onexit():
    ws.close()
    Log("Execute the ws.close() function")  
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);              
            // Respond to heartbeat packet operations
            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("Respond to ping, send pong:", strPong, "#FF0000");
                }
            } catch(exception &e) 
            {
                Log("e:", e.what());
            }
            
            LogStatus("Current time:", _D());
            Sleep(1000);
        }
    }
}              

void onexit() {
    // ws.close();
    Log("Execute the ws.close() function");
}

Acceso a la interfaz de ticker de WebSocket de Huobi:

function getLogin(pAccessKey, pSecretKey, pPassphrase) {
    // Signature function for login
    var ts = (new Date().getTime() / 1000).toString()
    var login = {
        "op": "login",
        "args":[{
            "apiKey"    : pAccessKey,
            "passphrase" : pPassphrase,
            "timestamp" : ts,
            "sign" : exchange.HMAC("sha256", "base64", ts + "GET" + "/users/self/verify", pSecretKey)   // exchange.HMAC has been deprecated and is temporarily supported. Please use the latest exchange.Encode function instead.
        }]
    }    
    return login
}                

var client_private = null 
function main() {
    // Because the read function uses a timeout setting, filtering the timeout reports errors that would otherwise be output with redundant errors
    SetErrorFilter("timeout")
    
    // Position channel subscription information
    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)  // When logging in, you cannot subscribe to private channels immediately, you need to wait for server response
    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)
            }
            
            // Detect disconnection, reconnect
            if (buf == "" && client_private.write(JSON.stringify(posSubscribe)) == 0) {
                Log("Disconnection detected, close connection, reconnect")
                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))
            }
            
            // Send heartbeat packets
            var nowPingTS = new Date().getTime()
            if (nowPingTS - lastPingTS > 10 * 1000) {
                client_private.write("ping")
                lastPingTS = nowPingTS
            }            
        }        
    }
}                

function onexit() {    
    var ret = client_private.close()
    Log("Close the connection!", 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("Disconnection detected, close connection, reconnect")
                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("Close the connection!", 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("Disconnection detected, close connection, reconnect");
                    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("exit");
}

Para acceder a la interfaz de autenticación de WebSocket de OKX:

var client = null 
function main() {
    // client = Dial("sqlite3://:memory:")   // Using an in-memory database
    client = Dial("sqlite3://test1.db")      // Open/connect to the database file in the docker's directory
    
    // record handle
    var sqlite3Handle = client.fd()
    Log("sqlite3Handle:", sqlite3Handle)
    
    // Querying tables in the database
    var ret = client.exec("SELECT name FROM sqlite_master WHERE type='table'")
    Log(ret)
}

function onexit() {
    Log("Execute client.close()")
    client.close()
}
// Not supported
// Not supported

El objeto de conexión devuelto por la función Dial al conectarse a una base de datos tiene dos funciones de método que son únicas para él:

  • exec(sqlString): Se utiliza para ejecutar instrucciones SQL de una manera similar a laDBExec() function.
  • fd()Elfd()función devuelve un mango (por ejemplo, la variable mango es mango) para ser utilizado por otros hilos para reconectar (incluso si el objeto creado por Dial ya ha sido cerrado por la ejecución de laclose()La función de cierre de la conexión) mediante el paso de la manija en elDial()función, por ejemplo,Dial(handle)Conexión de reutilización. El siguiente es un ejemplo de la función Dial que se conecta a unsqlite3 database.

Detalles de laaddressParámetro, separado por el|símbolo después de la dirección normal:wss://ws.okx.com:8443/ws/v5/publicSi hay|caracteres en la cadena de parámetros, entonces||La parte después de eso es algunas configuraciones de parámetros de función, y cada parámetro está conectado con&Por ejemplo, elss5Los parámetros de sustitución y compresión se pueden establecer de la siguiente manera:Dial("wss://ws.okx.com:8443/ws/v5/public|proxy=socks5://xxx:9999&compress=gzip_raw&mode=recv")

Funciones soportadas por el parámetro de dirección de la función Dial Descripción del parámetro
Parámetros relacionados con la compresión de datos del protocolo WebSocket: compress=valor del parámetro comprimir es el método de compresión, las opciones de parámetros comprimir son: gzip_raw, gzip, etc. Si el método gzip no es gzip estándar, se puede utilizar el método extendido: gzip_raw
Parámetros relacionados con la compresión de datos del protocolo WebSocket: modo=valor del parámetro el modo es el modo de compresión, el parámetro de modo puede ser dual, enviar, recv. dual es compresión bidireccional, enviar datos comprimidos, recibir datos comprimidos. enviar es enviar datos comprimidos. recv es recibir datos comprimidos, descompresión local.
El protocolo WebSocket establece los parámetros relacionados con la auto-reconexión subyacente: reconnect=valor del parámetro reconnect es si se debe configurar reconnect, reconnect=true es para habilitar reconnect.
El protocolo WebSocket establece los parámetros subyacentes relacionados con la reconexión automática: intervalo=valor del parámetro el intervalo es el intervalo de reintentos, en milisegundos, el intervalo=10000 es el intervalo de reintentos de 10 segundos, el valor predeterminado es 1 segundo cuando no está establecido, es decir, el intervalo=1000.
El protocolo WebSocket establece los parámetros subyacentes relacionados con la reconexión automática: carga útil=valor del parámetro carga útil es el mensaje de suscripción que debe enviarse cuando se vuelve a conectar el WebSocket, por ejemplo: carga útil=okokok.
Parámetros relacionados con los calcetines5 proxy: proxy=valor del parámetro Proxy es el ajuste de proxy ss5, formato de valor del parámetro: socks5://name:pwd@192.168.0.1:1080, el nombre es el nombre de usuario del servidor ss5, pwd es la contraseña de inicio de sesión del servidor ss5, 1080 es el puerto de servicio ss5.

ElDial()La función solo es compatible con el comercio en vivo. Al conectarse a una base de datos utilizando la función Dial, la cadena de conexión se escribe con referencia al proyecto de controlador de lenguaje go para cada base de datos.

Bases de datos soportadas Proyectos impulsores Cuadrícula de conexión Las observaciones
el mismo github.com/mattn/go-sqlite3 sqlite3://file:test.db?cache=compartido y modo=memoria Elsqlite3://Prefijo indica que se está utilizando una base de datos sqlite3, ejemplo de llamada:Dial("sqlite3://test1.db")
¿ Qué quieres decir con eso? github.com/go-sql-driver/mysql mysql://nombre de usuario:su contraseña@tcp(localhost:3306) / tu base de datos?
las plantas herbáceas github.com/lib/pq el nombre de la base de datos sslmode=disable password=yourpassword host=localhost port=5432
La casa de click github.com/ClickHouse/clickhouse-go clickhouse://tcp://host:9000?nombre de usuario=nombre de usuario& contraseña=tu contraseña& base de datos=youdatabase

Por favor, tenga en cuenta que cuando elpayloadcontenido establecido en eladdressParámetro contiene caracteres=o otros caracteres especiales, puede afectar al análisis de laaddressParámetro delDialFunción, como el siguiente ejemplo.

Ejemplo de llamada de interfaz privada del websocket de backPack Exchange:

var client = null

function main() {
    // Base64-encoded public key of the key pair, i.e. the access key configured on FMZ
    var base64ApiKey = "xxx"

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

    // Since signEd25519 returns a base64 encoding, it contains the character "="
    var signature = signEd25519(data)
    
    // The payload may contain the character "=" after being encoded by JSON
    payload = {
        "method": "SUBSCRIBE",
        "params": ["account.orderUpdate"],
        "signature": [base64ApiKey, signature, ts, "5000"]
    }

    client = Dial("wss://ws.backpack.exchange")
    client.write(JSON.stringify(payload))
    if (!client) {
        Log("Connection failed, program exited")
        return
    }
    
    while (true) {
        var buf = client.read()      
        Log(buf)
    }    
}

function onexit() {
    client.close()
}

function signEd25519(data) {
    return exchange.Encode("ed25519.seed", "raw", "base64", data, "base64", "{{secretkey}}")
}

La siguiente llamada en el código funciona bien:

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

Si lo escribe directamente enpayload, no funcionará correctamente, por ejemplo:

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

Actualmente, sólo JavaScript admite el uso de lamqtt, nats, amqp, ykafkaEl código de estrategia del lenguaje JavaScript se utiliza como ejemplo para mostrar el uso de los cuatro protocolos:mqtt, nats, amqp, ykafka:

// We need to configure and deploy proxy servers for each protocol first.
// For the sake of demonstration, the subscription (read operation) and publishing (write operation) of the topic test_topic are all performed in the current strategy.
var arrConn = []
var arrName = []

function main() {
    LogReset(1)
    conn_nats = Dial("nats://admin@127.0.0.1:4222?topic=test_topic")
    conn_mqtt = Dial("mqtt://127.0.0.1:1883?topic=test_topic")
    conn_amqp = Dial("amqp://q:admin@127.0.0.1:5672/?queue=test_Queue")
    conn_kafka = Dial("kafka://localhost:9092/test_topic")
    arrConn = [conn_nats, conn_amqp, conn_mqtt, conn_kafka]
    arrName = ["nats", "amqp", "mqtt", "kafka"]

    while (true) {
        for (var i in arrConn) {
            var conn = arrConn[i]
            var name = arrName[i]

            // Write data
            conn.write(name + ", time: " + _D() + ", test msg.")
            
            // Read data
            var readMsg = conn.read(1000)
            Log(name + " readMsg: ", readMsg, "#FF0000")
        }

        Sleep(1000)
    }
}

function onexit() {
    for (var i in arrConn) {
        arrConn[i].close()
        Log("close", arrName[i], "connect")
    }
}

Referencia de la documentación detallada:Explorando FMZ: Práctica del protocolo de comunicación entre las estrategias de negociación en vivo

HttpQuery (cuestionario de búsqueda)

Envía una solicitud Http.

Devuelve los datos de respuesta de la solicitud.JSONstring, puede ser analizado por elJSON.parse()La función en elJavaScriptLa estrategia lingüística, y por eljson::parse()La función en elC++Si el depuración está configurado en true en la estructura de opciones, el valor de retorno es un objeto (JSON); si el depuración está configurado en false, el valor de retorno es una cadena. cadena, objeto

HttpQuery ((url) HttpQuery ((url, opciones)

URL de solicitud de HTTP. - ¿ Qué pasa? verdadero la cuerda Por ejemplo, las configuraciones relacionadas con las solicitudes HTTP pueden estructurarse de la siguiente manera:

{
    method: "POST",
    body: "a=10&b=20&c=30",
    charset: "UTF-8",
    cookie: "session_id=12345; lang=en",
    profile: "chrome_103",
    debug: false,
    headers: {"TEST-HTTP-QUERY": "123"},
    timeout: 1000
}
  • Perfil: Se utiliza para simular el navegadortlsLas huellas. Los ajustes admitidos incluyen las siguientes opciones: ¿ Por qué no?"chrome_103", "chrome_104", "chrome_105", "chrome_106", "chrome_107", "chrome_108", "chrome_109", "chrome_110", "chrome_111", "chrome_112", "chrome_117"- ¿ Por qué? ¿Qué quieres decir?"safari_15_6_1", "safari_16_0", "safari_ipad_15_6", "safari_ios_15_5", "safari_ios_15_6", "safari_ios_16_0"- ¿ Por qué? ¿ Qué haces?"firefox_102", "firefox_104", "firefox_105", "firefox_106", "firefox_108", "firefox_110", "firefox_117"- ¿ Por qué? ¿ Qué quieres decir?"opera_89", "opera_90", "opera_91"- ¿ Por qué? ¿ Qué haces?"zalando_android_mobile", "zalando_ios_mobile"- ¿ Por qué? No lo sé."nike_ios_mobile", "nike_android_mobile"- ¿ Por qué? rascacielos:"cloudscraper"- ¿ Por qué? ¿ Qué es eso?"mms_ios"- ¿ Por qué? - ¿ Por qué no?"mesh_ios", "mesh_ios_1", "mesh_ios_2", "mesh_android", "mesh_android_1", "mesh_android_2"- ¿ Por qué? Confirmado"confirmed_ios", "confirmed_android"- ¿ Por qué? Está bien."okhttp4_android_7", "okhttp4_android_8", "okhttp4_android_9", "okhttp4_android_10", "okhttp4_android_11", "okhttp4_android_12", "okhttp4_android_13",
  • Debug: Cuando está configurado paratrue, elHttpQueryLa llamada de la función devuelve el mensaje de respuesta completo.false, sólo los datos en elBodydel mensaje de respuesta se devuelve.
  • tiempo de espera: ajuste de tiempo de espera, establecido en 1000 significa 1 segundo de tiempo de espera.
  • Charset: admite la transcodificación de los datos de respuesta solicitados, como GB18030. Todos los campos de esta estructura son opcionales, por ejemplo,profileel campo puede ser dejado fuera.

opciones falsos Objeto

function main(){
    // An example of GET access without parameters
    var info = JSON.parse(HttpQuery("https://www.okx.com/api/v5/public/time"))
    Log(info)
    // An example of GET access with parameters
    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 does not support Python, you can use the urllib/urllib2 library instead
    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);
}

Un ejemplo de acceso a la interfaz API de ticker pública OKX.

function main() {
    // Setting proxy and sending an http request for this time, no username, no password, this http request will be sent through the proxy
    HttpQuery("socks5://127.0.0.1:8889/http://www.baidu.com/")            

    // Setting proxy and sending an http request for this time, enter the user name and password, only the current call to HttpQuery takes effect, and then call HttpQuery again ("http://www.baidu.com") so that the proxy will not be used.
    HttpQuery("socks5://username:password@127.0.0.1:8889/http://www.baidu.com/")
}
# HttpQuery does not support Python, you can use the urllib/urllib2 library instead
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/");
}

La función HttpQuery utiliza la configuración de proxy.

ElHttpQuery()Función sólo soportaJavaScript, C++el lenguaje,PythonEl lenguaje puede utilizar elurllibla biblioteca para enviar peticiones HTTP directamente.HttpQuery()El sistema de intercambio de datos se utiliza principalmente para acceder a las interfaces del intercambio que no requieren una firma, como las interfaces públicas como la información del ticker.HttpQuery()El sistema de backtesting puede utilizarse para enviar solicitudes (sóloGETLas pruebas de retroceso se limitan a utilizar 20 visitas a diferentesURLs, yHttpQuery()Las visitas cacharán los datos.URLSe puede acceder por segunda vez, elHttpQuery()La función devuelve los datos almacenados en caché y no se producen más solicitudes reales de red.

¿Por qué no lo haces?

HttpQuery_Go es una aplicación de búsqueda de datos.

Envía una solicitud HTTP, una versión asíncrona delHttpQuery function.

ElHttpQuery_Go()función devuelve inmediatamente un objeto concurrente que se puede utilizar para obtener el resultado de una solicitud HTTP utilizando elwaitEl método deJSON.parse()Función puede ser utilizado para analizar elJSON.parse()La función en elJavaScriptLa estrategia del lenguaje.
objetos

HttpQuery_Go ((url) HttpQuery_Go ((url, opciones)

URL de solicitud de HTTP. - ¿ Qué pasa? verdadero la cuerda Por ejemplo, las configuraciones relacionadas con las solicitudes HTTP pueden estructurarse de la siguiente manera:

{
    method: "POST",
    body: "a=10&b=20&c=30",
    charset: "UTF-8",
    cookie: "session_id=12345; lang=en",
    // profile: "",
    debug: false,
    headers: {"TEST-HTTP-QUERY": "123"},
    timeout: 1000
}
  • Perfil: Se utiliza para simular el navegadortls fingerprints.
  • Debug: Cuando está configurado paratrue, estoHttpQuery_GoLa llamada de la función devuelve el mensaje de respuesta completo.false, sólo los datos en elBodydel mensaje de respuesta se devuelve.
  • tiempo de espera: ajuste de tiempo de espera, establecido en 1000 significa 1 segundo de tiempo de espera. Todos los campos de esta estructura son opcionales, por ejemplo,profileel campo puede ser dejado fuera.

opciones falsos Objeto

function main() {
    // Create the first asynchronous thread
    var r1 = HttpQuery_Go("https://www.okx.com/api/v5/market/tickers?instType=SPOT")
    // Create the second asynchronous thread
    var r2 = HttpQuery_Go("https://api.huobi.pro/market/tickers")
    
    // Get the return value of the first asynchronous thread call
    var tickers1 = r1.wait()
    // Get the return value of the second asynchronous thread call
    var tickers2 = r2.wait()
    
    // Print results
    Log("tickers1:", tickers1)
    Log("tickers2:", tickers2)
}
# Not supported
// Not supported

Acceso asíncrono a la interfaz pública de la bolsa para datos agregados de ticker.

ElHttpQuery_Go()Función sólo soportaJavaScript, elPythonEl lenguaje puede utilizarse con elurllibla biblioteca para enviar peticiones HTTP directamente.HttpQuery_Go()El sistema de intercambio de datos se utiliza principalmente para acceder a interfaces que no requieren una firma en el intercambio, como las interfaces públicas como la información del ticker.HttpQuery_GoFunción no soportada en el sistema de backtesting.

¿Por qué no lo haces?

Codificación

Esta función codifica los datos según los parámetros transmitidos.

ElEncodefunción devuelve los datos después de codificación y cifrado. la cuerda

Encódigo ((algo, inputFormat, outputFormat, datos) Encódigo ((algo, inputFormat, outputFormat, datos, claveFormat, clave)

El parámetroalgoes el algoritmo utilizado en el cálculo de la codificación.raw(no se utiliza algoritmo), el"signo", signoTx, 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, 2b.512, blake2s.128, blake2s.256 El parámetro.algotambién admite: text.encoder.utf8, text.decoder.utf8, text.encoder.gbk, text.decoder.gbk, cadenas de código y decodificación. El parámetroalgotambién admite: ed25519 algoritmo. admite el uso de diferentes algoritmos de hash, por ejemplo, el parámetroalgopuede escribirse como ed25519.md5, ed25519.sha512, etc.ed25519.seedel cálculo. algo verdadero la cuerda Se utiliza para especificar el formato de datos deldatael parámetro.inputFormatel parámetro puede establecerse como uno de los siguientes:raw, hex, base64, string. raw significa que los datos son datos en bruto, hex significa que los datos sonhexcodificado, base64 significa que los datos estánbase64codificado, y string significa que los datos son una cadena. EntradaFormato verdadero la cuerda Se utiliza para especificar el formato de datos de la salida.outputFormatel parámetro puede establecerse como uno de los siguientes:raw, hex, base64, string. raw significa que los datos son datos en bruto, hex significa que los datos sonhexcodificado, base64 significa que los datos estánbase64codificado, y string significa que los datos son una cadena. ProducciónFormato verdadero la cuerda El parámetrodataes los datos a tratar. datos verdadero la cuerda Se utiliza para especificar el formato de datos delkeyel parámetro.keyel parámetro puede establecerse como uno de los siguientes:raw, hex, base64, string. raw significa que los datos son datos en bruto, hex significa que los datos sonhexcodificado, base64 significa que los datos estánbase64codificado, y string significa que los datos son una cadena. claveFormato falsos la cuerda El parámetrokeyes la clave secreta utilizada paraHMACEl parámetrokeyse requiere cuando el parámetroalgoestá configurado para:signo biensignTxEl.keyel parámetro no se utiliza paraHMACcifrado cuando elalgoel parámetro está establecido en raw (porque el algoritmo debe especificarse para el cifrado HMAC). llave falsos la cuerda

function main() {
    Log(Encode("raw", "raw", "hex", "example", "raw", "123"))            // 6578616d706c65
    Log(Encode("raw", "raw", "hex", "example"))                          // 6578616d706c65
    Log(Encode("sha256", "raw", "hex", "example", "raw", "123"))         // 698d54f0494528a759f19c8e87a9f99e75a5881b9267ee3926bcf62c992d84ba
    Log(Encode("sha256", "raw", "hex", "example", "", "123"))            // 50d858e0985ecc7f60418aaf0cc5ab587f42c2570a884095a9e8ccacd0f6545c
    Log(Encode("sha256", "raw", "hex", "example", null, "123"))          // 50d858e0985ecc7f60418aaf0cc5ab587f42c2570a884095a9e8ccacd0f6545c
    Log(Encode("sha256", "raw", "hex", "example", "string", "123"))      // 698d54f0494528a759f19c8e87a9f99e75a5881b9267ee3926bcf62c992d84ba
    
    Log(Encode("raw", "raw", "hex", "123"))           // 313233
    Log(Encode("raw", "raw", "base64", "123"))        // MTIz
    
    Log(Encode("sha256", "raw", "hex", "example", "hex", "313233"))      // 698d54f0494528a759f19c8e87a9f99e75a5881b9267ee3926bcf62c992d84ba
    Log(Encode("sha256", "raw", "hex", "example", "base64", "MTIz"))     // 698d54f0494528a759f19c8e87a9f99e75a5881b9267ee3926bcf62c992d84ba
}
def main():
    Log(Encode("raw", "raw", "hex", "example", "raw", "123"))            # 6578616d706c65
    Log(Encode("raw", "raw", "hex", "example", "", ""))                  # 6578616d706c65
    Log(Encode("sha256", "raw", "hex", "example", "raw", "123"))         # 698d54f0494528a759f19c8e87a9f99e75a5881b9267ee3926bcf62c992d84ba
    Log(Encode("sha256", "raw", "hex", "example", "", "123"))            # 50d858e0985ecc7f60418aaf0cc5ab587f42c2570a884095a9e8ccacd0f6545c            

    Log(Encode("sha256", "raw", "hex", "example", "string", "123"))      # 698d54f0494528a759f19c8e87a9f99e75a5881b9267ee3926bcf62c992d84ba
    
    Log(Encode("raw", "raw", "hex", "123", "", ""))           # 313233
    Log(Encode("raw", "raw", "base64", "123", "", ""))        # MTIz
    
    Log(Encode("sha256", "raw", "hex", "example", "hex", "313233"))      # 698d54f0494528a759f19c8e87a9f99e75a5881b9267ee3926bcf62c992d84ba
    Log(Encode("sha256", "raw", "hex", "example", "base64", "MTIz"))     # 698d54f0494528a759f19c8e87a9f99e75a5881b9267ee3926bcf62c992d84ba
void main() {
    Log(Encode("raw", "raw", "hex", "example", "raw", "123"));            // 6578616d706c65
    Log(Encode("raw", "raw", "hex", "example"));                          // 6578616d706c65
    Log(Encode("sha256", "raw", "hex", "example", "raw", "123"));         // 698d54f0494528a759f19c8e87a9f99e75a5881b9267ee3926bcf62c992d84ba
    Log(Encode("sha256", "raw", "hex", "example", "", "123"));            // 50d858e0985ecc7f60418aaf0cc5ab587f42c2570a884095a9e8ccacd0f6545c            

    Log(Encode("sha256", "raw", "hex", "example", "string", "123"));      // 698d54f0494528a759f19c8e87a9f99e75a5881b9267ee3926bcf62c992d84ba
                
    Log(Encode("raw", "raw", "hex", "123"));           // 313233
    Log(Encode("raw", "raw", "base64", "123"));        // MTIz
                
    Log(Encode("sha256", "raw", "hex", "example", "hex", "313233"));      // 698d54f0494528a759f19c8e87a9f99e75a5881b9267ee3926bcf62c992d84ba
    Log(Encode("sha256", "raw", "hex", "example", "base64", "MTIz"));     // 698d54f0494528a759f19c8e87a9f99e75a5881b9267ee3926bcf62c992d84ba
}

Ejemplo de llamada de función de codificación.

function main(){
    var ret1 = Encode("text.encoder.utf8", "raw", "hex", "hello")     // e4bda0e5a5bd
    Log(ret1)    
    var ret2 = Encode("text.decoder.utf8", "hex", "string", ret1)   
    Log(ret2)            

    var ret3 = Encode("text.encoder.gbk", "raw", "hex", "hello")      // c4e3bac3
    Log(ret3)
    var ret4 = Encode("text.decoder.gbk", "hex", "string", ret3)
    Log(ret4)
}
def main():
    ret1 = Encode("text.encoder.utf8", "raw", "hex", "hello", "", "")     # e4bda0e5a5bd
    Log(ret1)    
    ret2 = Encode("text.decoder.utf8", "hex", "string", ret1, "", "")   
    Log(ret2)            

    ret3 = Encode("text.encoder.gbk", "raw", "hex", "hello", "", "")      # c4e3bac3
    Log(ret3)
    ret4 = Encode("text.decoder.gbk", "hex", "string", ret3, "", "")
    Log(ret4)
void main(){
    auto ret1 = Encode("text.encoder.utf8", "raw", "hex", "hello");     // e4bda0e5a5bd
    Log(ret1);    
    auto ret2 = Encode("text.decoder.utf8", "hex", "string", ret1);   
    Log(ret2);            

    auto ret3 = Encode("text.encoder.gbk", "raw", "hex", "hello");      // c4e3bac3
    Log(ret3);
    auto ret4 = Encode("text.decoder.gbk", "hex", "string", ret3);
    Log(ret4);
}

El parámetroalgoTambién admite: text.encoder.utf8, text.decoder.utf8, text.encoder.gbk, text.decoder.gbk para codificar y decodificar cadenas.

ElEncode()la función sólo se admite para el comercio en vivo.keyykeyFormatlos parámetros no se pasan, entonceskeyno se utiliza el cifrado.

UnixNano también

Obtenga la marca de tiempo del nanosegundo del momento actual.

ElUnixNano()La función devuelve la marca de tiempo del nanosegundo. Número

UnixNano (()

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

Si necesita obtener marcas de tiempo de milisegundos, puede usar el siguiente código:

¿Qué quieres decir con eso?

Unix

Obtenga la fecha del momento actual en el segundo nivel.

Devuelve la marca de tiempo de segundo nivel. Número

Unix ((()

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

¿Por qué no lo haces?

¿ Qué haces?

Obtener la información del sistema del dispositivo donde se encuentra el docker.

Información del sistema. la cuerda

¿Qué quieres decir?

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

Por ejemplo, una llamada a laGetOS()Función para un docker que se ejecuta en elMac OSel sistema operativo puede devolver:darwin/amd64Porque las computadoras de Apple tienen múltiples arquitecturas de hardware.darwines el nombre de laMac OS system.

El MD5

Computa el hash MD5 del parámetrodata.

Valor hash de MD5. la cuerda

MD5 (datos)

Los datos que requieren el cálculo MD5. datos verdadero la cuerda

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

Llamando alMD5("hello world")función, el valor de retorno es:5eb63bbbe01eeed093cb22bb8f5acdc3.

¿Por qué no lo haces?

DBExec también

Funciones de interfaz de base de datos.

Objeto que contiene el resultado de la ejecución de unCuadradouna declaración, por ejemplo:


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

objetos

DBExec (sql)

Cuadradola cadena de instrucciones. Cuadrado verdadero la cuerda

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)
    
    // Add a piece of data
    Log(DBExec(":INSERT INTO TEST_TABLE (TS, HIGH, OPEN, LOW, CLOSE, VOLUME) VALUES (1518970320000, 100, 99.1, 90, 100, 12345.6);"))
    
    // Query data
    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)
    
    # Add a piece of data
    Log(DBExec(":INSERT INTO TEST_TABLE (TS, HIGH, OPEN, LOW, CLOSE, VOLUME) VALUES (1518970320000, 100, 99.1, 90, 100, 12345.6);"))
    
    # Query data
    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);
    
    // Add a piece of data
    Log(DBExec(":INSERT INTO TEST_TABLE (TS, HIGH, OPEN, LOW, CLOSE, VOLUME) VALUES (1518970320000, 100, 99.1, 90, 100, 12345.6);"));
    
    // Query data
    Log(DBExec(":SELECT * FROM TEST_TABLE;"));
}

Apoyo a la base de datos en memoria, paraDBExecparámetros de función, siCuadradola declaración comienza con:Es adecuado para operaciones de base de datos que no requieren de un almacenamiento persistente, por ejemplo:

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

Crea una mesa.

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))
    
    // Add a piece of data
    Log(DBExec("INSERT INTO TEST_TABLE (TS, HIGH, OPEN, LOW, CLOSE, VOLUME) VALUES (1518970320000, 100, 99.1, 90, 100, 12345.6);"))
    
    // Query data
    Log(DBExec("SELECT * FROM TEST_TABLE;"))
    
    // Modify data
    Log(DBExec("UPDATE TEST_TABLE SET HIGH=? WHERE TS=?", 110, 1518970320000))    
    
    // Delete data
    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))
    
    # Add a piece of data
    Log(DBExec("INSERT INTO TEST_TABLE (TS, HIGH, OPEN, LOW, CLOSE, VOLUME) VALUES (1518970320000, 100, 99.1, 90, 100, 12345.6);"))
    
    # Query data
    Log(DBExec("SELECT * FROM TEST_TABLE;"))
    
    # Modify data
    Log(DBExec("UPDATE TEST_TABLE SET HIGH=? WHERE TS=?", 110, 1518970320000))
    
    # Delete data
    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));            

    // Add a piece of data
    Log(DBExec("INSERT INTO TEST_TABLE (TS, HIGH, OPEN, LOW, CLOSE, VOLUME) VALUES (1518970320000, 100, 99.1, 90, 100, 12345.6);"));
    
    // Query data
    Log(DBExec("SELECT * FROM TEST_TABLE;"));
    
    // Modify data
    Log(DBExec("UPDATE TEST_TABLE SET HIGH=? WHERE TS=?", 110, 1518970320000));
    
    // Delete data
    Log(DBExec("DELETE FROM TEST_TABLE WHERE HIGH=?", 110));
}

Añadir, borrar, comprobar y cambiar los registros en la tabla.

La funciónDBExec()Puede operar la base de datos de operaciones en vivo (base de datos SQLite) mediante el paso de parámetros.Es muy bueno.El sistema reservó tablas en la base de datos de operaciones en vivo:kvdb, cfg, log, profit, chart, no opere en estas mesas.Las transaccionesLas funciones de control de los datos no son compatibles y no se recomienda realizar tales operaciones, que pueden causar conflictos en el sistema.DBExec()La función solo es compatible con el comercio en vivo.

¿Por qué no lo haces?

UUID

Crear un UUID.

UUID de 32 bits. la cuerda

UUID (()

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

ElUUID()La función soporta sólo el comercio en vivo.

Loop de eventos

Escucha los acontecimientos, que vuelve cuando hay algunaWebSocketdatos legibles o tareas concurrentes, como por ejemplo:exchange.Go(), HttpQuery_Go(), etc. se han completado.

Si el objeto devuelto no es un valor nulo, elEventel contenido de la devolución es el tipo de activador de eventos. Por ejemplo, la siguiente estructura de valor de devolución:

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

objetos

Loop de evento EventLoop (tiempo muerto)

El parámetrotimeoutes la configuración de tiempo de espera, en milisegundos.timeoutespera que ocurra un evento antes de devolverlo si está establecido en 0, si es mayor que 0, establece el evento para esperar un tiempo de espera, y devuelve el evento más reciente inmediatamente si es menor que 0. tiempo de espera falsos Número

function main() {
    var routine_getTicker = exchange.Go("GetTicker")
    var routine_getDepth = exchange.Go("GetDepth")
    var routine_getTrades = exchange.Go("GetTrades")
    
    // Sleep(2000), if the Sleep statement is used here, it will cause the subsequent EventLoop function to miss the previous events, because after waiting for 2 seconds, the concurrent function has received the data, and the subsequent EventLoop listening mechanism started, it misses these events.
    // These events will not be missed unless EventLoop(-1) is called at the beginning of the first line of code to first initialize the EventLoop's listening mechanism.            

    // Log("GetDepth:", routine_getDepth.wait()) If the wait function is called in advance to retrieve the result of a concurrent call to the GetDepth function, the event that the GetDepth function receives the result of the request will not be returned in the EventLoop function.
    var ts1 = new Date().getTime()
    var ret1 = EventLoop(0)
    
    var ts2 = new Date().getTime()
    var ret2 = EventLoop(0)
    
    var ts3 = new Date().getTime()
    var ret3 = EventLoop(0)
    
    Log("The first concurrent task completed was:", _D(ts1), ret1)
    Log("The second concurrent task completed was:", _D(ts2), ret2)
    Log("The third concurrent task completed was:", _D(ts3), ret3)
    
    Log("GetTicker:", routine_getTicker.wait())
    Log("GetDepth:", routine_getDepth.wait())
    Log("GetTrades:", routine_getTrades.wait())
}
import time
def main():
    routine_getTicker = exchange.Go("GetTicker")
    routine_getDepth = exchange.Go("GetDepth")
    routine_getTrades = exchange.Go("GetTrades")
    
    ts1 = time.time()
    ret1 = EventLoop(0)
    
    ts2 = time.time()
    ret2 = EventLoop(0)
    
    ts3 = time.time()
    ret3 = EventLoop(0)
    
    Log("The first concurrent task completed was:", _D(ts1), ret1)
    Log("The second concurrent task completed was:", _D(ts2), ret2)
    Log("The third concurrent task completed was:", _D(ts3), ret3)
    
    Log("GetTicker:", routine_getTicker.wait())
    Log("GetDepth:", routine_getDepth.wait())
    Log("GetTrades:", routine_getTrades.wait())
void main() {
    auto routine_getTicker = exchange.Go("GetTicker");
    auto routine_getDepth = exchange.Go("GetDepth");
    auto routine_getTrades = exchange.Go("GetTrades");
    
    auto ts1 = Unix() * 1000;
    auto ret1 = EventLoop(0);
    
    auto ts2 = Unix() * 1000;
    auto ret2 = EventLoop(0);
    
    auto ts3 = Unix() * 1000;
    auto ret3 = EventLoop(0);
    
    Log("The first concurrent task completed was:", _D(ts1), ret1);
    Log("The second concurrent task completed was:", _D(ts2), ret2);
    Log("The third concurrent task completed was:", _D(ts3), ret3);
    
    Ticker ticker;
    Depth depth;
    Trades trades;
    routine_getTicker.wait(ticker);
    routine_getDepth.wait(depth);
    routine_getTrades.wait(trades);
    
    Log("GetTicker:", ticker);
    Log("GetDepth:", depth);
    Log("GetTrades:", trades);
}

La primera llamada a laEventLoop()función en el código inicializa el mecanismo para ese evento escuchado, y si el primeroEventLoop()El sistema subyacente envuelve una estructura de cola que almacena en caché un máximo de 500 devoluciones de llamada de eventos.EventLoop()La función no se llama a tiempo para sacarlos durante la ejecución del programa, las llamadas posteriores de eventos fuera de la caché 500 se perderán.EventLoop()función no afectan a la cola de caché del sistema subyacente WebSocket o las caché de funciones concurrentes tales comoexchange.Go(). Para estos cachés, todavía es necesario utilizar los métodos respectivos para recuperar los datos.EventLoop()Función para los datos que se han recuperado antes de laEventLoop()El objetivo principal de laEventLoop()La función principal de la red es la de notificar a la capa de estrategia que los nuevos datos de red han sido recibidos por el sistema subyacente.EventLoop()Por ejemplo, conexiones WebSocket, objetos creados porexchange.Go()Los datos de laEventLoop()La función soporta sólo el comercio en vivo. Escuchar eventos en el hilo principal cuando se llama desde la función principalmain()En las estrategias escritas en elJavaScriptLa lenguathreading.Thread()función crea un hilo, que también puede ser llamado en la función de ejecución del hilos, para escuchar eventos en el hilo actual.

En el caso de las empresas que se encuentran en una situación de riesgo, la información que se proporciona es la siguiente:

Se sirve

El__ServeLa función se utiliza para crear el servicio HTTP, el servicio TCP y el servicio Websocket (basado en el protocolo HTTP).

Devuelve una cadena que registra la dirección IP y el puerto del servicio creado. Por ejemplo:127.0.0.1:8088, [::]:8089.

la cuerda

__Servir (servirURI, manejador de datos) __Service ((serveURI, manejador,...args)

ElserveURIEl parámetro se utiliza para configurar el protocolo, dirección IP, puerto y otras configuraciones del servicio de vinculación, tales comohttp://0.0.0.0:8088?gzip=true, es decir,http://:8088?gzip=true.

  • Protocolo TCPserveURIconfiguración de parámetros, comotcp://127.0.0.1:6666?tls=true; puede añadir certificados y claves privadas, tales comotls=true&cert_pem=xxxx&cert_key_pem=xxxx.
  • El protocolo HTTPserveURIconfiguración de parámetros, tales comohttp://127.0.0.1:6666?gzip=true; puede configurar la configuración de compresión:gzip=true- ¿ Por qué? ElserveURIEl parámetro se utiliza para Https, comohttps://127.0.0.1:6666?tls=true&gzip=true; puede añadircert_pemycert_key_pemlos parámetros para cargar el certificado.

servicioURI verdadero la cuerda ElhandlerEl parámetro se utiliza para pasar en la función de procesamiento de enrutamiento (protocolo HTTP), la función de procesamiento de mensajes (protocolo TCP) y la función de procesamiento de flujo (Websocket). La función de devolución de llamada transmitida por el parámetrohandlerpuede definir múltiples parámetros, el primer parámetro es el objeto ctx (objeto de contexto).

manipuladora verdadero Función El parámetro real de la función de devolución de llamada pasado como el parámetrohandlerPuede haber varios parámetros.arg, por ejemplo:

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

Los parámetros1, 2, 3En el momento de llamar a la__Serve()función corresponde a los parámetrosa, b, cPasado en la función de devolución de llamada.

el falsos cadena, número, bool, objeto, matriz, función, valor nulo y otros tipos compatibles con el sistema

function main() {
    let httpServer = __Serve("http://:8088?gzip=true", function (ctx) {
        Log("http connect from: ", ctx.remoteAddr(), "->", ctx.localAddr())
        let path = ctx.path()
        if (path == "/") {
            ctx.write(JSON.stringify({
                path: ctx.path(),
                method: ctx.method(),
                headers: ctx.headers(),
                cookie: ctx.header("Cookie"),
                remote: ctx.remoteAddr(),
                query: ctx.rawQuery()
            }))
        } else if (path == "/tickers") {
            let ret = exchange.GetTickers()
            if (!ret) {
                ctx.setStatus(500)
                ctx.write(GetLastError())
            } else {
                ctx.write(JSON.stringify(ret))
            }
        } else if (path == "/wss") {
            if (ctx.upgrade("websocket")) { // upgrade to websocket
                while (true) {
                    let r = ctx.read(10)
                    if (r == "") {
                        break
                    } else if (r) {
                        if (r == "ticker") {
                            ctx.write(JSON.stringify(exchange.GetTicker()))
                        } else {
                            ctx.write("not support")
                        }
                    }
                }
                Log("websocket closed", ctx.remoteAddr())
            }
        } else {
            ctx.setStatus(404)
        }
    })
    let echoServer = __Serve("tcp://:8089", function (ctx) {
        Log("tcp connect from: ", ctx.remoteAddr(), "->", ctx.localAddr())
        while (true) {
            let d = ctx.read()
            if (!d) {
                break
            }
            ctx.write(d)
        }
        Log("connect closed")
    })
    Log("http serve on", httpServer, "tcp serve on", echoServer)
    
    for (var i = 0; i < 5; i++) {
        if (i == 2) {
            // test Http
            var retHttp = HttpQuery("http://127.0.0.1:8088?num=123&limit=100", {"debug": true})
            Log("retHttp:", retHttp)
        } else if (i == 3) {
            // test TCP
            var tcpConn = Dial("tcp://127.0.0.1:8089")
            tcpConn.write("Hello TCP Server")
            var retTCP = tcpConn.read()
            Log("retTCP:", retTCP)
        } else if (i == 4) {
            // test Websocket
            var wsConn = Dial("ws://127.0.0.1:8088/wss|compress=gzip")
            wsConn.write("ticker")
            var retWS = wsConn.read(1000)
            Log("retWS:", retWS)
            // no depth
            wsConn.write("depth")
            retWS = wsConn.read(1000)
            Log("retWS:", retWS)
        }
        Sleep(1000)
    }
}
# Unsupported
// Unsupported
  • Esta función soporta sólo las estrategias del lenguaje JavaScript.
  • El hilo de servicio está aislado del alcance global, por lo que no admite cierres o referencias a variables externas, funciones personalizadas, etc.; sin embargo, puede llamar a todas las funciones de la API de la plataforma.
  • ElWebsocketel servicio se implementa basado en el protocolo Http. Puede establecer una rama de enrutamiento en la ruta y diseñar el código de implementación paraWebsocketSe puede consultar el código de muestra en esta sección.

La función de devolución de llamada transmitida por el parámetrohandlerrecibe unactxel parámetro.ctxParámetro es un objeto de contexto utilizado para obtener y escribir datos, con los siguientes métodos:

  • ¿Qué es lo que está pasando? Aplicado al protocolo HTTP/TCP, devuelve el nombre del protocolo cuando se llama.HTTP/1.1, tcp.
  • ctx.host(i) Aplicado al protocolo HTTP, devuelve información de host cuando se llama dirección IP y puerto.
  • Ctx.path (en inglés) Aplicado al protocolo HTTP, devuelve la ruta de solicitud cuando se llama.
  • Ctx.query (clave) Aplicado al protocolo HTTP, devuelve el valor correspondiente a la clave de la consulta en la solicitud cuando se llama.http://127.0.0.1:8088?num=123, y la función de procesamiento de devoluciones de llamada transmitida por el parámetrohandlerlas devoluciones"123"¿Cuándo?ctx.query("num")se llama.
  • Ctx.rawQuery (() Aplicado al protocolo Http, cuando se llama, devuelve la consulta original en la solicitud (la consulta de la solicitud Http).
  • Ctx.header (en inglés) Aplicado al protocolo HTTP, y devuelve la información de encabezado de solicitud en la solicitud cuando se llama.
  • Ctx.cabeza (clave) Aplicado al protocolo HTTP, devuelve el valor de una clave en el encabezado de solicitud especificado cuando se llama.User-Agenten los encabezados de la solicitud actual:ctx.header("User-Agent").
  • el método ctx. Aplicado al protocolo HTTP, devuelve el método de solicitud cuando se llama, comoGET, POST, etc.
  • El cuerpo del ctx. Se aplica a la solicitud POST del protocolo HTTP, y devuelve el cuerpo de la solicitud cuando se llama.
  • Ctx.setHeader (clave, valor) Aplicado al protocolo HTTP para establecer la información de encabezado de solicitud del mensaje de respuesta.
  • ctx.setStatus (código) Aplicado al protocolo Http, establece el código de estado del mensaje Http. Por lo general, el código de estado Http se establece al final de la rama de enrutamiento. El valor predeterminado es 200.
  • Ctx.remoteAddr ((() Aplicado al protocolo HTTP/TCP, devuelve la dirección del cliente remoto y el puerto en la solicitud cuando se llama.
  • Ctx.localAddr ((() Aplicado al protocolo HTTP/TCP, devuelve la dirección local y el puerto del servicio cuando se llama.
  • ctx.upgrade ((socket web) Aplicado a la implementación del protocolo Websocket basado en el protocolo Http, cambiando elctxobjeto de contexto al protocolo Websocket; devolviendo un valor booleano (verdadero) si el cambio es exitoso, y un valor booleano (falso) si falla.
  • Ctx.read (tiempo de espera) Aplicado a la implementación del protocolo Websocket / protocolo TCP basado en el protocolo HTTP, lee los datos de la conexión Websocket y la conexión TCP.readmétodo no es compatible en el protocolo HTTP ordinario. Puede especificar el parámetro de tiempo de esperatimeout_msen milisegundos.
  • Ctx. write (s) Aplicado al protocolo HTTP/TCP, utilizado para escribir datos de cadena.JSON.stringify()para codificar el objeto JSON en una cadena y luego escribirlo.WebSocketProtocolo, se puede utilizar este método para pasar la cadena codificada al cliente.

En el caso de las aplicaciones que se utilicen para la búsqueda de datos, el número de páginas que se utilicen para la búsqueda de datos es el número de páginas que se utilicen para la búsqueda de datos.

_G

La estructura de datos es una tabla KV que se guarda permanentemente en el archivo de base de datos local del docker.

Datos de valores clave guardados de forma persistente enk-vlas parejas clave-valor. cadena, número, bool, objeto, matriz, valor nulo

- ¿Qué quieres decir? _G(k) - ¿Por qué no?

El parámetrokes el nombre de la clave en el par clave-valor guardado y no es sensible a mayúsculas y minúsculas. el falsos cadena, valor cero El parámetroves el valor clave en el par clave-valor guardado, que puede ser cualquier dato que pueda serJSONen serie. V falsos cadena, número, bool, objeto, matriz, valor nulo

function main(){
    // Set a global variable num with a value of 1
    _G("num", 1)     
    // Change a global variable num to the value of the string ok
    _G("num", "ok")    
    // Delete the global variable num
    _G("num", null)
    // Returns the value of the global variable num
    Log(_G("num"))
    // Delete all global variables
    _G(null)
    // Return to live trading ID
    var robotId = _G()
}
def main():
    _G("num", 1)     
    _G("num", "ok")    
    _G("num", None)
    Log(_G("num"))
    _G(None)
    robotId = _G()
void main() {
    _G("num", 1);
    _G("num", "ok");
    _G("num", NULL);
    Log(_G("num"));
    _G(NULL);
    // Not support auto robotId = _G();
}

Una base de datos separada para cada operación en vivo, los datos guardados por el_G()La función siempre estará allí si se reinicia la estrategia o si el docker deja de funcionar._G()Cuando se utilice el_G()Función para persistir los datos guardados, debe ser utilizado razonablemente de acuerdo con la memoria y el espacio en disco duro del dispositivo de hardware, y no debe ser mal utilizado. Cuando se llama a la_G()En el caso de las transacciones en vivo y no se pasan parámetros, el_G()Función devuelve elIdEn el caso de las transacciones en vivo._G()función, el parámetrovse pasa como nulo para indicar la eliminación de lak-vCuando se llama el_G()función, sólo el parámetrokse pasa en la cadena, y el_G()función devuelve el valor de clave correspondiente al parámetro guardadokCuando llamas a la_G()función, sólo el parámetrokse pasa en un valor nulo, lo que indica que todos los registros de lak-vCuando el par de valores clave se elimina.k-vLos pares de valores clave se han guardado de forma persistente, el_G()la función se llama de nuevo, pasando en el nombre de la clave que se ha guardado persistentemente como parámetrok. Pasando el nuevo valor clave como parámetrovLo actualizaremos.k-vel par clave-valor.

¿Por qué no lo haces?

- ¿ Qué pasa?

Convierte marcas de tiempo de milisegundos oDateobjetos a las cadenas de tiempo.

Una cadena de tiempo. la cuerda

¿Qué es esto? _D (tiempo) _D (tiempo, fmt)

Marca de tiempo de milisegundos oDateObjeto. el sello de tiempo falsos Número, objeto El formato de la cadena,JavaScriptformato predeterminado del idioma:yyyy-MM-dd hh:mm:ss; Pythonformato predeterminado del idioma:%Y-%m-%d %H:%M:%S; C++formato predeterminado del idioma:%Y-%m-%d %H:%M:%S- ¿ Por qué? Fmt también falsos la cuerda

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

Obtener e imprimir la cadena de tiempo actual:

function main() {
    Log(_D(1574993606000))
}
def main():
    # Running this code on a server in Beijing time: 2019-11-29 10:13:26 , a docker on another server in another region results in: 2019-11-29 02:13:26
    Log(_D(1574993606))
void main() {
    Log(_D(1574993606000));
}

La marca de tiempo es 1574993606000, utilizando la conversión de código:

function main() {
    Log(_D(1574993606000, "yyyy--MM--dd hh--mm--ss"))   // 2019--11--29 10--13--26
}
def main():
    # 1574993606 is timestamped in seconds.
    Log(_D(1574993606, "%Y--%m--%d %H--%M--%S"))        #  2019--11--29 10--13--26
void main() {
    Log(_D(1574993606000, "%Y--%m--%d %H--%M--%S"));    // 2019--11--29 10--13--26
}

Formato con el parámetrofmtes diferente paraJavaScript, Python, yC++lenguas, como se muestra en los siguientes ejemplos:

Devuelve la cadena de tiempo actual sin pasar ningún parámetro._D()La función en elPythonestrategia, usted necesita ser consciente de que los parámetros pasados son marcas de tiempo de segundo nivel (marcas de tiempo de nivel de milisegundos en las estrategias JavaScript y C ++, donde 1 segundo es igual a 1000 milisegundos)._D()función para analizar una cadena de tiempo con una marca de tiempo legible en el comercio en vivo, usted necesita prestar atención a la zona horaria y la configuración de tiempo del sistema operativo donde se encuentra el programa docker._D()La función analiza una marca de tiempo en una cadena de tiempo legible dependiendo del tiempo del sistema docker.

¿Por qué no lo haces?

- ¿Qué es?

Formate un número con coma flotante.

El número de coma flotante formateado de acuerdo con el ajuste de precisión. Número

_N() _N (número) _N (número, precisión)

El número de coma flotante que debe ser formateado. No verdadero Número El ajuste de precisión para el formato, el parámetroprecisiones un número entero, y el parámetroprecisionpor defecto a 4. Precisión falsos Número

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

Por ejemplo,_N(3.1415, 2)borrará el valor después3.1415dos decimales y la función devuelve3.14.

function main(){
    var i = 1300
    Log(i)
    var ii = _N(i, -3)
    // Check the logs and see that it is 1000
    Log(ii)
}
def main():
    i = 1300
    Log(i)
    ii = _N(i, -3)
    Log(ii)
void main() {
    auto i = 1300;
    Log(i);
    auto ii = _N(i, -3);
    Log(ii);
}

Si necesitas cambiar todos los dígitos N a la izquierda del punto decimal a 0, puedes escribirlo así:

El parámetroprecisionpuede ser un número entero positivo, negativo.

¿Por qué no lo haces?

_C

Intentar de nuevo la función de tolerancia a fallas de la interfaz.

El valor de retorno de la función de llamada de retorno cuando se ejecuta. Todos los tipos son compatibles con el sistema exceptovalor lógico falsoyvalor nulo.

- ¿Qué es eso? - ¿Por qué no lo haces?

El parámetropfnes una referencia de función, que es unFunción de devolución de llamada- ¿ Por qué? Pfn verdadero Función Parámetros paraLas funciones de devolución de llamada, puede haber más de un parámetroargTipo y número de parámetrosargdependerá de los parámetros de laFunción de devolución de llamada¿ Qué pasa? el falsos cadena, número, bool, objeto, matriz, función, todos los tipos son compatibles con el sistema, como valores nulos

function main(){
    var ticker = _C(exchange.GetTicker)
    // Adjust _C() function retry interval to 2 seconds
    _CDelay(2000)
    var depth = _C(exchange.GetDepth)
    Log(ticker)
    Log(depth)
}
def main():
    ticker = _C(exchange.GetTicker)
    _CDelay(2000)
    depth = _C(exchange.GetDepth)
    Log(ticker)
    Log(depth)
void main() {
    auto ticker = _C(exchange.GetTicker);
    _CDelay(2000);
    auto depth = _C(exchange.GetDepth);
    Log(ticker);
    Log(depth);
}

Para las funciones tolerantes a errores sin parámetros:

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

Para las funciones con parámetros tolerantes a errores:

var test = function(a, b){
    var time = new Date().getTime() / 1000
    if(time % b == 3){
        Log("Eligible!", "#FF0000")
        return true
    }
    Log("Retry!", "#FF0000")
    return false
}            

function main(){
    var ret = _C(test, 1, 5)
    Log(ret)
}
import time
def test(a, b):
    ts = time.time()
    if ts % b == 3:
        Log("Eligible!", "#FF0000")
        return True
    Log("Retry!", "#FF0000")
    return False            

def main():
    ret = _C(test, 1, 5)
    Log(ret)
// C++ does not support fault tolerance for custom functions in this way

También se puede utilizar para la tolerancia a fallos de las funciones personalizadas:

El_C()función seguirá llamando a la función especificada hasta que devuelva con éxito (la función a la que se refiere el parámetropfnlas devolucionesNo hay nadao bien- No es cierto.Cuando lo llamen, volverá a llamar.pfnPor ejemplo:_C(exchange.GetTicker)El intervalo de reintentos predeterminado es de 3 segundos, puede llamar al_CDelay()Función para establecer el intervalo de reintentos._CDelay(1000)El uso de un dispositivo de control de la velocidad es un medio para cambiar el intervalo de repetición de las pruebas de_C()Función a 1 segundo. La tolerancia a fallos puede realizarse para, entre otras cosas, las siguientes funciones:

  • exchange.GetTicker()
  • exchange.GetDepth()
  • exchange.GetTrades()
  • exchange.GetRecords()
  • exchange.GetAccount()
  • exchange.GetOrders()
  • exchange.GetOrder()
  • exchange.GetPositions()Todos pueden ser llamados por el_C()La función de tolerancia a fallos_C()la función no se limita a la función de tolerancia a fallas mencionada anteriormente, el parámetropfnes una referencia de función en lugar de una llamada de función. Observe que es_C(exchange.GetTicker), no_C(exchange.GetTicker()).

_Cruz

Devuelve el número de períodos de intersección de la matrizarr1y la matrizarr2.

El número de períodos transversales de la matrizarr1y la matrizarr2- ¿ Por qué? Número

_Cruz ((arr1, arr2)

Los elementos son matrices de tiponumber- ¿ Por qué? Arr1 verdadero el conjunto Los elementos son matrices de tiponumber- ¿ Por qué? arr2 verdadero el conjunto

// Fast line indicator
var arr1 = [1,2,3,4,5,6,8,8,9]
// Slow line indicator
var arr2 = [2,3,4,5,6,7,7,7,7]
function main(){
    Log("_Cross(arr1, arr2) : ", _Cross(arr1, arr2))
    Log("_Cross(arr2, arr1) : ", _Cross(arr2, arr1))
}
arr1 = [1,2,3,4,5,6,8,8,9]     
arr2 = [2,3,4,5,6,7,7,7,7]
def main():
    Log("_Cross(arr1, arr2) : ", _Cross(arr1, arr2))
    Log("_Cross(arr2, arr1) : ", _Cross(arr2, arr1))
void main() {
    vector<double> arr1 = {1,2,3,4,5,6,8,8,9};
    vector<double> arr2 = {2,3,4,5,6,7,7,7,7};
    Log("_Cross(arr1, arr2) : ", _Cross(arr1, arr2));
    Log("_Cross(arr2, arr1) : ", _Cross(arr2, arr1));
}

Se puede simular un conjunto de datos para probar la función _Cross ((Arr1, Arr2):

Si el valor de retorno de la_Cross()Si la función es un número positivo, indica el período de penetración ascendente, si es un número negativo, indica el período de penetración descendente, 0 significa lo mismo que el precio actual.Análisis e instrucciones de uso sobre la función integrada _Cross.

JSONParse

La funciónJSONParse()se utiliza para analizarJSON strings.

JSONObjeto. Objeto

JSONParse (s)

JSONla cuerda. el verdadero la cuerda

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

def main():
    s1 = '{"num": 8754613216564987646512354656874651651358}'
    Log("json.loads:", json.loads(s1))    # json.loads: map[num:8.754613216564987e+39]
    Log("JSONParse:", JSONParse(s1))      # JSONParse:  map[num:8754613216564987646512354656874651651358]
    
    s2 = '{"num": 123}'
    Log("json.loads:", json.loads(s2))    # json.loads: map[num:123]
    Log("JSONParse:", JSONParse(s2))      # JSONParse:  map[num:123]
void main() {
    auto s1 = "{\"num\":8754613216564987646512354656874651651358}";
    Log("json::parse:", json::parse(s1));
    // Log("JSONParse:", JSONParse(s1));   // The function is not supported.
    
    auto s2 = "{\"num\":123}";
    Log("json::parse:", json::parse(s2));
    // Log("JSONParse:", JSONParse(s2));   // The function is not supported.
}

Las cadenas JSON con valores grandes se pueden analizar correctamente, y analizará los valores grandes como tipos de cadena.JSONParse()Función no soportada en el sistema de backtest.

Registro