Les ressources ont été chargées... Je charge...

Mondial

La version

Renvoie le numéro de version actuel du système.

Numéro de version du système actuel, tel que3.6- Je ne sais pas. chaîne

Version (en)

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

Le numéro de version du système est le numéro de version du programme du docker.

Je dors.

La fonction de sommeil, provoquant la pause du programme pendant une période de temps.

Le sommeil (milliseconde)

LemillisecondLe paramètre est utilisé pour définir la durée du sommeil et le nombre de millisecondes. milliseconde vrai Numéro

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

Par exemple, lors de l'exécution duSleep(1000)Il prend en charge les opérations avec un temps de sommeil inférieur à 1 milliseconde, par exemple le réglageSleep(0.1)Il prend en charge un paramètre minimum de0.000001, c'est-à-dire l'hibernation en nanoseconde, où 1 nanoseconde est égale à1e-6Des millisecondes. Lors de l'écriture de stratégies dans lePythonLa langue, leSleep(millisecond)Il n'est pas recommandé d'utiliser letime.sleep(second)fonction dePythonC' est...timeC'est parce qu'en utilisant letime.sleep(second)fonction dans une stratégie fait attendre le programme de stratégie pendant une période de temps en fait lors du backtesting (pas sauter sur la série temporelle du système de backtesting), de sorte qu'il provoque la stratégie de backtest très lentement.

C' est virtuel

Déterminer si l'environnement de fonctionnement de la stratégie est un système de backtesting.

La stratégie renvoie une valeur réelle, par exemple:trueLa stratégie renvoie une valeur fausse, par exemple:falselorsqu'il est exécuté dans un environnement de négociation en direct. Boole

C' est virtuel?

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

Déterminer si l'environnement en cours est un système de backtesting, qui est utilisé pour être compatible avec la différence entre le backtesting et le trading en direct.

Le courrier

Envoyez un courriel.

Une livraison réussie d'un e-mail renvoie une valeur réelle, par exemple,true, et une livraison ratée renvoie une valeur fausse, par exemple,false- Je ne sais pas. Boole

Mail ((smtpServeur, smtpNom d'utilisateur, smtpCode d'accès, mailTo, titre, corps)

Utilisé pour spécifier leSMTPl'adresse de service de l'expéditeur du courrier électronique. Le serveur smtp vrai chaîne Utilisé pour spécifier l'adresse e-mail de l'expéditeur. Nom de l'utilisateur vrai chaîne LeSMTPmot de passe de la boîte aux lettres de l'expéditeur. Le mot de passe vrai chaîne Utilisé pour spécifier l'adresse e-mail du destinataire. Envoyer par mailTo vrai chaîne Titre de courriel. titre vrai chaîne Le corps de l'email. corps vrai chaîne

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

LesmtpPasswordparamètre définit le mot de passe pour leSMTPle service, pas le mot de passe de la boîte aux lettres. Lors du réglage dusmtpServerparamètre, si vous avez besoin de changer le port, vous pouvez ajouter le numéro de port directement dans le paramètresmtpServerPar exemple: courrier QQsmtp.qq.com:587, qui est disponible pour les tests. Si une erreur est signalée:unencryped connection, vous devez modifier lesmtpServerde l'annéeMailLe format du paramètre est le suivant:ssl://xxx.com:xxx, par exemple, lesslméthode deSMTPpour le courrier QQ:ssl://smtp.qq.com:465ousmtp://xxx.com:xxx- Je ne sais pas. Il ne fonctionne pas dans le système de backtesting.

Je ne sais pas.

Mail_Go est en cours

Version asynchrone duMail function.

LeMail_Gofonction renvoie un objet concurrent immédiatement, et vous pouvez utiliser lewaitUne livraison courriel réussie renvoie une valeur vraie, par exemple,true, et une livraison ratée renvoie une valeur fausse, par exemple,false- Je ne sais pas. objet

Mail_Go ((smtpServeur, smtpNom d'utilisateur, smtpCode de passe, mailTo, titre, corps)

Il est utilisé pour spécifier leSMTPl'adresse de service de l'expéditeur du courrier électronique. Le serveur smtp vrai chaîne Il est utilisé pour spécifier l'adresse e-mail de l'expéditeur. Nom de l'utilisateur vrai chaîne LeSMTPmot de passe de la boîte aux lettres de l'expéditeur. Le mot de passe vrai chaîne Il est utilisé pour spécifier l'adresse e-mail du destinataire. Envoyer par mailTo vrai chaîne Titre de courriel. titre vrai chaîne Le corps de l'email. corps vrai chaîne

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.

Il ne fonctionne pas dans le système de backtesting.

{@fun/Global/Mail Mail} Je ne peux pas le faire

Régler le filtre d'erreur

Filtrez les journaux d'erreur.

FixerErrorFilter (les filtres)

Chaîne d'expressions régulières. filtres vrai chaîne

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

Filtrer les erreurs courantes.

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

Filtrer un message d'erreur d'interface.

Les journaux d'erreurs correspondant à cette expression régulière ne seront pas téléchargés dans le système de journaux. Vous pouvez l'appeler plusieurs fois (sans limite sur le nombre de fois) pour définir plusieurs conditions de filtre. Les expressions régulières définies plusieurs fois seront accumulées et prendront effet en même temps. Vous pouvez définir une chaîne vide pour réinitialiser l'expression régulière utilisée pour filtrer les journaux d'erreurs:SetErrorFilter("")Les journaux filtrés ne sont plus écrits dans le fichier de base de données correspondant à l'identifiant de trading en direct dans le répertoire docker pour éviter que les rapports d'erreur fréquents ne gonflent le fichier de base de données.

GetPid

Obtenez l'identifiant du processus de négociation en direct.

Retourner l'identifiant du processus de négociation en direct. chaîne

Je ne peux pas.

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

Obtenez la dernière erreur

J'ai reçu le dernier message d'erreur.

Dernier message d'erreur. chaîne

Obtenez la dernière erreur

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

Il ne fonctionne pas dans le système de backtesting.

Obtenez le commandement

Il reçoit la commande d'interaction stratégique.

Le format de la commande retournée estControlName:Data. ControlNameest le nom du contrôle, etDataest les données entrées dans la commande. Si la commande interactive n'a pas de boîtes d'entrée, de boîtes déroulantes et d'autres composants (par exemple, une commande de bouton sans boîtes d'entrée), le format de commande retourné estControlName, qui renvoie uniquement le nom du contrôle. chaîne

Vous avez le commandement?

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

Détecte la commande d'interaction et utilise leLogfonction de sortie de la commande d'interaction lorsqu'elle est détectée.

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

Par exemple, le contrôle interactif de stratégie ajoute un contrôle sans boîte d'entrée, le contrôle interactif est nommé:buy, les informations relatives à la description du contrôle sont les suivantes:buy, qui est une commande de bouton. Continuez en ajoutant une commande avec une boîte d'entrée. La commande interactive est nommée:sellet le message de description du contrôle est le suivant:sellLe code d'interaction est conçu dans la stratégie pour répondre aux différents contrôles d'interaction:

Il ne fonctionne pas dans le système de backtesting.

Obtenez Meta

Obtenez la valeur de Meta écrite lors de la génération du code d'enregistrement de stratégie.

Metales données. chaîne

Je suis désolée.

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

Exemple de scénario d'application: utilisationMetalimiter le montant des actifs exploités par la stratégie.

Scenario d'application: besoin de faire des limites de capital pour les différents locataires de stratégie.Metala valeur définie lors de la génération du code d'enregistrement ne doit pas dépasser 190 caractères et leGetMeta()La fonction ne prend en charge que le trading en direct.Meta) est défini lors de la génération d'un code d'enregistrement de stratégie,GetMeta()La fonction renvoie null. Elle ne fonctionne pas dans le système de backtesting.

Faites le choix

Pour le primitifSocketl'accès, le soutientcp, udp, tls, unixPrise en charge de 4 protocoles de communication populaires:mqtt, nats, amqp, kafka. Prise en charge de la connexion aux bases de données:sqlite3, mysql, postgres, clickhouse.

LeDial()une fonction renvoie null s'il s'éteint. Un appel normal renvoie un objet de connexion qui a trois méthodes:read, writeetcloseLereadLa méthode est utilisée pour lire les données,writeLa méthode est utilisée pour envoyer des données etcloseméthode est utilisée pour fermer la connexion. Lereadla méthode prend en charge les paramètres suivants:

  • Quand aucun paramètre n'est passé, il bloque jusqu'à ce qu'un message soit disponible et renvoie, commews.read().
  • Lorsqu'il est passé en tant que paramètre, l'unité est en millisecondes, spécifiant la période d'attente du message.ws.read(2000)spécifie un temps d'arrêt de deux secondes (2000 millisecondes).
  • Les deux paramètres suivants sont valables uniquement pour WebSocket: Passer le paramètre-1signifie que la fonction renvoie immédiatement, indépendamment de la présence ou de l'absence de messages, par exemple:ws.read(-1)- Je ne sais pas. Passer le paramètre-2signifie que la fonction renvoie immédiatement avec ou sans message, mais que seul le dernier message est renvoyé, et le message tamponné est écarté.ws.read(-2).

read()Description du tampon de fonction: Les données entrantes poussées par le protocole WebSocket peuvent entraîner une accumulation de données si l'intervalle de temps entre la stratégieread()Ces données sont stockées dans le tampon, qui a une structure de données d'une file d'attente avec un maximum de 2000.

Scénario Aucun paramètre Paramètre: -1 Paramètre: -2 Paramètre: 2000, en millisecondes
Données déjà dans le tampon Retournez les données les plus anciennes immédiatement Retournez les données les plus anciennes immédiatement Retournez les dernières données immédiatement Retournez les données les plus anciennes immédiatement
Aucune donnée dans le tampon Retourner lorsque les données sont bloquées Retourner nul immédiatement Retourner nul immédiatement Attendre 2000 ms, retourner nul si aucune donnée, retourner nul si des données sont disponibles
La connexion WebSocket est déconnectée ou reconnectée par le sous-jacent read() fonction renvoie la chaîne vide, c.-à-d.: , et write() fonction renvoie 0. La situation est détectée. Vous pouvez fermer la connexion en utilisant la fonction close(), ou si vous avez configuré la reconnexion automatique, vous n'avez pas besoin de la fermer, le système sous-jacent la reconnectera automatiquement.

objet

Numéro de téléphone (adresse) Numéro (adresse, délai d'attente)

Demandez une adresse. l'adresse vrai chaîne secondes de temps d'arrêt, temps d'arrêt faux Numéro

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

Exemple d'appel à la fonction 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();
}

Pour accéder à l'interface 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");
}

Accès à l'interface du ticker WebSocket 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");
}

Accès à l'interface du ticker 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");
}

Pour accéder à l'interface d'authentification WebSocket 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

L'objet de connexion renvoyé par la fonction Dial lors de la connexion à une base de données possède deux fonctions de méthode qui lui sont propres:

  • exec(sqlString): Utilisé pour exécuter des instructions SQL de manière similaire à laDBExec() function.
  • fd()Lefd()fonction renvoie une poignée (par exemple, la variable poignée est poignée) à utiliser par d'autres threads pour se reconnecter (même si l'objet créé par Dial a déjà été fermé par l'exécution duclose()La fonction de fermeture de la connexion) en passant la poignée dans leDial()la fonction, par exemple,Dial(handle)connexion de réutilisation. Ce qui suit est un exemple de la fonction Dial se connectant à unsqlite3 database.

Détails de laaddressparamètre, séparé par le|le symbole suivant l'adresse normale:wss://ws.okx.com:8443/ws/v5/publicS' il y en a|les caractères dans la chaîne de paramètres, puis||La partie après que ce sont quelques paramètres de paramètres de fonction, et chaque paramètre est connecté avec&Il s'agit par exemple dess5Les paramètres de substitution et de compression peuvent être définis ensemble comme suit:Dial("wss://ws.okx.com:8443/ws/v5/public|proxy=socks5://xxx:9999&compress=gzip_raw&mode=recv")

Fonctions prises en charge par le paramètre d'adresse de la fonction Dial Description du paramètre
Paramètres liés à la compression des données du protocole WebSocket: compress=valeur du paramètre compresser est la méthode de compression, les options de paramètres compresser sont: gzip_raw, gzip, etc. Si la méthode gzip n'est pas gzip standard, vous pouvez utiliser la méthode étendue: gzip_raw
Paramètres liés à la compression des données du protocole WebSocket: mode=valeur du paramètre mode est le mode de compression, le paramètre de mode peut être double, envoyer, recv. double est la compression bidirectionnelle, envoyer des données compressées, recevoir des données compressées. envoyer est envoyer des données compressées. recv est recevoir des données compressées, décompression locale.
Le protocole WebSocket définit les paramètres sous-jacents liés à la reconnexion automatique: reconnect=valeur du paramètre reconnect est la définition de reconnect, reconnect=true est la définition de reconnect.
Le protocole WebSocket définit les paramètres sous-jacents liés à la reconnexion automatique: interval=valeur du paramètre l'intervalle est l'intervalle de réessayage, en millisecondes, l'intervalle=10000 est l'intervalle de réessayage de 10 secondes, la valeur par défaut est de 1 seconde lorsqu'il n'est pas réglé, c'est-à-dire l'intervalle=1000.
Le protocole WebSocket définit les paramètres sous-jacents liés à la reconnexion automatique: charge utile=valeur du paramètre payload est le message d'abonnement qui doit être envoyé lorsque le WebSocket est reconnecté, par exemple: payload=okokok.
Paramètres liés aux chaussettes5 proxy: proxy=valeur du paramètre Proxy est le paramètre de paramètre de configuration de proxy ss5: socks5://name:pwd@192.168.0.1:1080, le nom est le nom d'utilisateur du serveur ss5, pwd est le mot de passe de connexion du serveur ss5, 1080 est le port de service ss5.

LeDial()La fonction n'est prise en charge que pour le trading en direct. Lors de la connexion à une base de données à l'aide de la fonction Dial, la chaîne de connexion est écrite en référence au projet de pilote de langage go pour chaque base de données.

Base de données prise en charge Projets moteurs Chaîne de connexion Les commentaires
- Je ne sais pas. github.com/mattn/go-sqlite3 sqlite3://fichier:test.db?cache=partagé et mode=mémoire Lesqlite3://le préfixe indique qu'une base de données sqlite3 est utilisée, exemple d'appel:Dial("sqlite3://test1.db")
Je vais essayer. github.com/go-sql-driver/mysql Je suis désolée.localhost:3306) /votre base de données?charset=utf8mb4
les produits de postgres github.com/lib/pq le nom de l'utilisateur et le nom de la base de données sslmode
maison de jeu github.com/ClickHouse/clickhouse-go Cliquez sur le lien suivant:

Veuillez noter que lorsque lepayloadcontenus définis dans leaddressparamètre contient des caractères=ou d'autres caractères spéciaux, il peut affecter l'analyse de laaddressparamètre duDialfonction, comme dans l'exemple suivant.

Exemple d'appel à l'interface privée 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}}")
}

L'appel suivant dans le code fonctionne bien:

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

Si vous l'écrivez directement danspayload, il ne fonctionnera pas correctement, par exemple:

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

À l'heure actuelle, seul JavaScript prend en charge l'utilisation demqtt, nats, amqp, etkafkaLe code de stratégie du langage JavaScript est utilisé comme exemple pour montrer l'utilisation des quatre protocoles:mqtt, nats, amqp, etkafka:

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

Référence de la documentation détaillée:Exploration de FMZ: pratique du protocole de communication entre les stratégies de négociation en direct

HttpQuery est une requête

Envoyez une demande Http.

Retourne les données de réponse de la requête.JSONstring, il peut être analysé par leJSON.parse()fonction dans leJavaScriptLa stratégie linguistique, et par lejson::parse()fonction dans leC++Si le débogage est réglé sur true dans la structure d'options, la valeur de retour est un objet (JSON); si le débogage est réglé sur false, la valeur de retour est une chaîne. chaîne, objet

HttpQuery (URL) HttpQuery ((url, options)

L'URL de la demande HTTP. le nom de l'adresse vrai chaîne Par exemple, les paramètres liés aux requêtes HTTP peuvent être structurés comme suit:

{
    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
}
  • profil: Utilisé pour simuler le navigateurtlsDes empreintes digitales. Les paramètres pris en charge comprennent les options suivantes: Je ne sais pas."chrome_103", "chrome_104", "chrome_105", "chrome_106", "chrome_107", "chrome_108", "chrome_109", "chrome_110", "chrome_111", "chrome_112", "chrome_117"Je suis désolée. - Je ne sais pas."safari_15_6_1", "safari_16_0", "safari_ipad_15_6", "safari_ios_15_5", "safari_ios_15_6", "safari_ios_16_0"Je suis désolée. Je ne sais pas."firefox_102", "firefox_104", "firefox_105", "firefox_106", "firefox_108", "firefox_110", "firefox_117"Je suis désolée. - Je ne sais pas."opera_89", "opera_90", "opera_91"Je suis désolée. Je ne sais pas."zalando_android_mobile", "zalando_ios_mobile"Je suis désolée. Je suis désolée."nike_ios_mobile", "nike_android_mobile"Je suis désolée. le gratte-ciel:"cloudscraper"Je suis désolée. Je suis désolé."mms_ios"Je suis désolée. Je ne sais pas."mesh_ios", "mesh_ios_1", "mesh_ios_2", "mesh_android", "mesh_android_1", "mesh_android_2"Je suis désolée. Confirmé:"confirmed_ios", "confirmed_android"Je suis désolée. Ça va."okhttp4_android_7", "okhttp4_android_8", "okhttp4_android_9", "okhttp4_android_10", "okhttp4_android_11", "okhttp4_android_12", "okhttp4_android_13",
  • débogage: quand il est réglé surtrue, leHttpQueryl'appel de la fonction renvoie le message de réponse complet.false, uniquement les donnéesBodyde la réponse est renvoyée.
  • temps d'arrêt: paramètre de temps d'arrêt, réglé sur 1000 signifie 1 seconde de temps d'arrêt.
  • Charset: Il prend en charge le transcodage des données de réponse demandées, telles que GB18030. Tous les champs de cette structure sont facultatifs, par exemple:profilele champ peut être laissé de côté.

les options faux objet

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 exemple d'accès à l'interface API de ticker publique 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 fonction HttpQuery utilise des paramètres de proxy.

LeHttpQuery()fonction ne supporte queJavaScript, C++le langage,PythonLa langue peut être utiliséeurllibLa bibliothèque est utilisée pour envoyer directement des requêtes HTTP.HttpQuery()Il est principalement utilisé pour accéder aux interfaces de l'échange qui ne nécessitent pas de signature, telles que les interfaces publiques telles que les informations des tickers.HttpQuery()peut être utilisé dans le système de backtesting pour envoyer des demandes (uniquementGETLes tests en arrière-plan sont limités à l'utilisation de 20 visites à desURLs, etHttpQuery()Les visites vont mettre en cache les données.URLest consulté une deuxième fois, leHttpQuery()La fonction renvoie les données mises en cache et aucune autre demande de réseau n'est effectuée.

Je ne sais pas si je peux le faire.

HttpQuery_Go est en cours de développement

Envoie une requête HTTP, une version asynchrone duHttpQuery function.

LeHttpQuery_Go()fonction retourne immédiatement un objet concurrent qui peut être utilisé pour obtenir le résultat d'une requête HTTP en utilisant lewaitLa méthodeJSON.parse()fonction peut être utilisée pour analyser leJSON.parse()fonction dans leJavaScriptLa stratégie de la langue.
objet

HttpQuery_Go (URL) HttpQuery_Go (URL, options)

L'URL de la demande HTTP. le nom de l'adresse vrai chaîne Par exemple, les paramètres liés aux requêtes HTTP peuvent être structurés comme suit:

{
    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
}
  • profil: Utilisé pour simuler le navigateurtls fingerprints.
  • débogage: quand il est réglé surtrue, ceciHttpQuery_Gol'appel de la fonction renvoie le message de réponse complet.false, uniquement les donnéesBodyde la réponse est renvoyée.
  • temps d'arrêt: paramètre de temps d'arrêt, réglé sur 1000 signifie 1 seconde de temps d'arrêt. Tous les champs de cette structure sont facultatifs, par exemple:profilele champ peut être laissé de côté.

les options faux objet

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

Accès asynchrone à l'interface publique de l'échange pour les données de ticker agrégées.

LeHttpQuery_Go()fonction ne supporte queJavaScript, lePythonLa langue peut être utiliséeurllibLa bibliothèque est utilisée pour envoyer directement des requêtes HTTP.HttpQuery_Go()Il est principalement utilisé pour accéder aux interfaces qui ne nécessitent pas de signature sur l'échange, telles que les interfaces publiques telles que les informations de ticker.HttpQuery_Gofonction n'est pas prise en charge dans le système de backtesting.

{@fun/Global/HttpQuery HttpQuery} Je suis désolé

Codifier

Cette fonction encode les données en fonction des paramètres transmis.

LeEncodefonction renvoie les données après le codage et le cryptage. chaîne

Encode ((algo, format d'entrée, format de sortie, données) Encode ((algo, inputFormat, outputFormat, données, cléFormat, clé)

Le paramètrealgoest l'algorithme utilisé dans le calcul du codage.raw(aucun algorithme n'est utilisé), le "signe", signTx, md4, md5, sha256, sha512, sha1, keccak256, sha3.224, sha3.256, sha3.384, sha3.512, sha3.keccak256, sha3.keccak512, sha512.384, sha512.256, sha512.224, ripemd160, blake2b.256, 2b.512, blake2s.128, blake2s.256 Le paramètre.algoIl prend également en charge: text.encoder.utf8, text.decoder.utf8, text.encoder.gbk, text.decoder.gbk, encode et décode les chaînes. Le paramètrealgosupporte également: ed25519 algorithme. Supporte l'utilisation de différents algorithmes de hachage, par exemple le paramètrealgopeut être écrit comme ed25519.md5, ed25519.sha512, etc. Il prend en chargeed25519.seedle calcul. quelque chose vrai chaîne Utilisé pour spécifier le format de données dudataParamètre.inputFormatle paramètre peut être défini comme l'un des paramètres suivants:raw, hex, base64, string. raw signifie que les données sont brutes, hex signifie que les données sonthexcodé, base64 signifie que les données sontbase64encodé, et string signifie que les données sont une chaîne. Le format d'entrée vrai chaîne Utilisé pour spécifier le format de données de la sortie.outputFormatle paramètre peut être défini comme l'un des paramètres suivants:raw, hex, base64, string. raw signifie que les données sont brutes, hex signifie que les données sonthexcodé, base64 signifie que les données sontbase64encodé, et string signifie que les données sont une chaîne. SortieFormat vrai chaîne Le paramètredataest les données à traiter. données vrai chaîne Utilisé pour spécifier le format de données dukeyParamètre.keyle paramètre peut être défini comme l'un des paramètres suivants:raw, hex, base64, string. raw signifie que les données sont brutes, hex signifie que les données sonthexcodé, base64 signifie que les données sontbase64encodé, et string signifie que les données sont une chaîne. Le format faux chaîne Le paramètrekeyest la clé secrète utilisée pourHMACLe paramètrekeyest nécessaire lorsque le paramètrealgoest réglée sursignousignTxLekeyle paramètre n'est pas utilisé pourHMACle chiffrement lorsque lealgole paramètre est réglé sur raw (parce que l'algorithme doit être spécifié pour le chiffrement HMAC). clé faux chaîne

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
}

Exemple d'appel à la fonction Encode.

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

Le paramètrealgoIl prend également en charge: text.encoder.utf8, text.decoder.utf8, text.encoder.gbk, text.decoder.gbk pour encoder et décoder les chaînes.

LeEncode()La fonction n'est prise en charge que pour le trading en direct.keyetkeyFormatles paramètres ne sont pas passés, alorskeyle chiffrement n'est pas utilisé.

UnixNano

Obtenez l'horodatage nanoseconde du moment actuel.

LeUnixNano()La fonction renvoie l'horodatage de la nanoseconde. Numéro

UnixNano (en anglais)

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

Si vous avez besoin d'obtenir des horodatages en millisecondes, vous pouvez utiliser le code suivant:

Je ne sais pas.

Unix

Obtenez l'horodatage du moment actuel au deuxième niveau.

Retourne l'horodatage de deuxième niveau. Numéro

Unix (()

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

Je ne sais pas si je peux vous aider.

GetOS

Obtenez les informations du système de l'appareil où se trouve le dock.

Informations sur le système. chaîne

Je suis désolée.

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

Par exemple, un appel à laGetOS()fonction pour un docker exécuté sur leMac OSle système d'exploitation pourrait renvoyer:darwin/amd64Parce que les ordinateurs Apple ont plusieurs architectures matérielles.darwinest le nom de laMac OS system.

MD5

Calcule le hachage MD5 du paramètredata.

Valeur de hachage MD5. chaîne

MD5 (données)

Les données qui nécessitent un calcul MD5. données vrai chaîne

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

On appelle leMD5("hello world")fonction, la valeur de retour est:5eb63bbbe01eeed093cb22bb8f5acdc3.

{@fun/Global/Encode Encode} Je suis désolé.

DBExec

Fonctions d'interface de base de données.

Un objet contenant le résultat de l'exécution d'unLe secteurdéclaration, par exemple:


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

objet

DBExec ((sql)

Le secteurune chaîne d'instructions. Le secteur vrai chaîne

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

Prise en charge de la base de données en mémoire, pourDBExecparamètres de fonction, siLe secteurLa déclaration commence par::Il convient aux opérations de base de données qui ne nécessitent pas d'enregistrement persistant, par exemple:

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

Créez une table.

function main() {
    var strSql = [
        "CREATE TABLE TEST_TABLE(", 
        "TS INT PRIMARY KEY NOT NULL,",
        "HIGH REAL NOT NULL,", 
        "OPEN REAL NOT NULL,", 
        "LOW REAL NOT NULL,", 
        "CLOSE REAL NOT NULL,", 
        "VOLUME REAL NOT NULL)"
    ].join("")
    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));
}

Ajouter, supprimer, vérifier et modifier les enregistrements dans le tableau.

La fonctionDBExec()Il peut utiliser la base de données de négociation en direct (base de données SQLite) en passant des paramètres.SQLiteLe système a réservé des tables dans la base de données de négociation en direct:kvdb, cfg, log, profit, chartNe pas utiliser ces tables.Les opérationsIl n'est pas recommandé d'effectuer de telles opérations, car elles peuvent provoquer des conflits dans le système.DBExec()La fonction n'est prise en charge que pour le trading en direct.

Je ne sais pas.

UUID

Créez un UUID.

Un UUID de 32 bits. chaîne

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

LeUUID()La fonction supporte uniquement le trading en direct.

La boucle d'événement

Écoutez les événements, il revient quand il y a unWebSocketdonnées lisibles ou tâches simultanées, telles que:exchange.Go(), HttpQuery_Go(), etc. sont achevés.

Si l'objet retourné n'est pas une valeur nulle, leEventle type de déclencheur d'événement est contenu dans le contenu de retour.

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

objet

La boucle d'événement Le temps d'arrêt

Le paramètretimeoutest le paramètre de temps d'arrêt, en millisecondes.timeoutattend qu'un événement se produise avant de retourner s'il est défini sur 0, s'il est supérieur à 0, il définit l'événement en attendant un temps d'arrêt, et renvoie immédiatement l'événement le plus récent s'il est inférieur à 0. Le temps mort faux Numéro

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

Le premier appel à laEventLoop()fonction dans le code initie le mécanisme pour cet événement écouté, et si le premierEventLoop()Le système sous-jacent enveloppe une structure de file d'attente qui cache un maximum de 500 callbacks d'événements.EventLoop()fonction n'est pas appelée à temps pour les retirer pendant l'exécution du programme, les appels ultérieurs d'événements en dehors du cache 500 seront perdus.EventLoop()fonction n'affectent pas la file d'attente de cache du système WebSocket sous-jacent ou les caches de fonctions simultanées telles queexchange.Go()Pour ces caches, il est toujours nécessaire d'utiliser les méthodes respectives pour récupérer les données.EventLoop()fonction pour les données qui ont été récupérées avant leEventLoop()Le but principal de l'analyse est deEventLoop()La fonction principale de la stratégie est d'informer la couche de stratégie que de nouvelles données réseau ont été reçues par le système sous-jacent.EventLoop()fonction renvoie un événement, passe juste à travers toutes les sources de données.exchange.Go()- Je vais essayer d'obtenir des données.EventLoop()La fonction supporte uniquement le trading en direct. Écouter les événements dans le fil principal lorsqu'il est appelé depuis la fonction principalemain()Dans les stratégies écrites dans leJavaScriptLa langue, lethreading.Thread()fonction crée un thread, qui peut également être appelé dans la fonction d'exécution du threads, pour écouter les événements dans le thread actuel.

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

__ Servir

Le__Servefonction est utilisée pour créer le service Http, le service TCP et le service Websocket (basé sur le protocole Http).

Renvoie une chaîne qui enregistre l'adresse IP et le port du service créé.127.0.0.1:8088, [::]:8089.

une chaîne

__Serve (serveURI, traitement) __Service (serveURI, gestionnaire,... args)

LeserveURIparamètre est utilisé pour configurer le protocole, l'adresse IP, le port et d'autres paramètres de la liaison de service, tels quehttp://0.0.0.0:8088?gzip=true, c'est à dire,http://:8088?gzip=true.

  • Protocole TCPserveURIréglage des paramètres tels quetcp://127.0.0.1:6666?tls=true; vous pouvez ajouter des certificats et des clés privées, commetls=true&cert_pem=xxxx&cert_key_pem=xxxx.
  • Protocole HTTPserveURIparamètres, tels quehttp://127.0.0.1:6666?gzip=true; vous pouvez définir les paramètres de compression:gzip=true- Je ne sais pas. LeserveURIparamètre est utilisé pour Https, tels quehttps://127.0.0.1:6666?tls=true&gzip=true; vous pouvez ajoutercert_pemetcert_key_pemles paramètres de chargement du certificat.

serveURI vrai chaîne LehandlerLe paramètre est utilisé pour passer dans la fonction de traitement du routage (protocole HTTP), la fonction de traitement des messages (protocole TCP) et la fonction de traitement du flux (Websocket). La fonction de rappel passée par le paramètrehandlerpeut définir plusieurs paramètres, le premier paramètre étant l'objet ctx (objet contextuel).

le gestionnaire vrai fonction Le paramètre réel de la fonction de rappel passé comme paramètrehandlerIl peut y avoir plusieurs paramètresarg, par exemple:

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

Les paramètres1, 2, 3Il est passé à l'appel__Serve()fonction correspondent aux paramètresa, b, cpassé dans la fonction de rappel.

arg faux chaîne, nombre, bool, objet, tableau, fonction, valeur nulle et autres types pris en charge par le système

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
  • Cette fonction prend en charge uniquement les stratégies du langage JavaScript.
  • Le fil de service est isolé de la portée globale, il ne prend donc pas en charge les clôtures ou les références à des variables externes, des fonctions personnalisées, etc.; cependant, il peut appeler toutes les fonctions API de la plateforme.
  • LeWebsocketVous pouvez définir une branche de routage dans le chemin et concevoir le code de mise en œuvre pourWebsocketVous pouvez consulter l'exemple de code dans cette section.

La fonction de rappel passée par le paramètrehandlerIl reçoit unctxParamètre.ctxparamètre est un objet contextuel utilisé pour obtenir et écrire des données, avec les méthodes suivantes:

  • Je suis désolé. Appliqué au protocole Http/TCP, renvoie le nom du protocole lorsqu'il est appelé.HTTP/1.1, tcp.
  • ctx.host(l) Appliqué au protocole Http, il renvoie des informations sur l'hôte lorsqu'il est appelé adresse IP et port.
  • Ctx.path (en anglais) Appliqué au protocole Http, renvoie le chemin de demande lorsqu'il est appelé.
  • Ctx.query (clé) Appliqué au protocole Http, renvoie la valeur correspondant à la clé de la requête dans la requête lorsqu'elle est appelée.http://127.0.0.1:8088?num=123, et la fonction de traitement de rappel passée par le paramètrehandlerrendements"123"quand?ctx.query("num")est appelé.
  • ctx.rawQuery (en anglais seulement) Appliqué au protocole Http, lorsqu'il est appelé, renvoie la requête d'origine dans la requête (la requête de la requête Http).
  • Les titres ctx.header Appliqué au protocole Http, et renvoie l'information de l'en-tête de demande dans la demande lorsqu'elle est appelée.
  • Ctx.titre (clé) Appliqué au protocole Http, il renvoie la valeur d'une clé dans l'en-tête de demande spécifié lorsqu'il est appelé.User-Agentdans les titres de la demande en cours:ctx.header("User-Agent").
  • méthode ctx ()) Appliqué au protocole Http, renvoie la méthode de demande lorsqu'elle est appelée, telle queGET, POST, etc.
  • Ctx. corps Appliqué à la requête POST du protocole HTTP, et renvoie le corps de la requête lorsqu'il est appelé.
  • ctx.setHeader (clé, valeur) Appliqué au protocole Http pour définir les informations de l'en-tête de demande du message de réponse.
  • ctx.setStatus (code) Appliqué au protocole HTTP, définit le code d'état du message HTTP. Habituellement, le code d'état HTTP est défini à la fin de la branche de routage. La valeur par défaut est 200.
  • Ctx.remoteAddr (en anglais) Appliqué au protocole Http/TCP, renvoie l'adresse du client distant et le port dans la demande lorsqu'il est appelé.
  • Ctx.localAddr (() Appliqué au protocole HTTP/TCP, renvoie l'adresse locale et le port du service lorsqu'il est appelé.
  • Ctx.upgrade ((websocket) est un logiciel de connexion pour les téléphones mobiles. Appliqué à la mise en œuvre du protocole Websocket basé sur le protocole Http, en basculant lectxobjet de contexte au protocole Websocket; renvoie une valeur booléenne (true) si le commutateur est réussi, et une valeur booléenne (fausse) si elle échoue.
  • Ctx.read ((timeout_ms) Appliqué à la mise en œuvre du protocole Websocket / protocole TCP basé sur le protocole Http, lit les données de la connexion Websocket et la connexion TCP.readCette méthode n'est pas prise en charge dans le protocole HTTP ordinaire.timeout_msen millisecondes.
  • Ctx. écrire (s) Appliqué au protocole HTTP/TCP, utilisé pour écrire des données de chaîne.JSON.stringify()pour encoder l'objet JSON dans une chaîne de caractères et l'écrire.WebSocketprotocole, vous pouvez utiliser cette méthode pour passer la chaîne codée au client.

{@fun/Global/HttpQuery HttpQuery}, {@fun/Global/HttpQuery_Go HttpQuery_Go} Vous pouvez utiliser le nom de domaine de l'utilisateur.

_G

La structure de données est une table KV qui est sauvegardée en permanence dans le fichier de base de données locale du docker.

Les données de valeur de clé enregistrées en permanence dansk-vles paires de valeurs-clés. chaîne, nombre, bool, objet, tableau, valeur nulle

Je ne sais pas. Je ne sais pas. - Je ne sais pas.

Le paramètrekest le nom de la clé dans la paire clé-valeur enregistrée et n'est pas sensible à la case. K faux chaîne, valeur nulle Le paramètrevest la valeur clé dans la paire clé-valeur enregistrée, qui peut être n'importe quelle donnée qui peut êtreJSONIl est en série. v faux chaîne, nombre, bool, objet, tableau, valeur nulle

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

Une base de données distincte pour chaque transaction en direct, les données enregistrées par le_G()La fonction sera toujours présente si la stratégie est redémarrée ou si le docker cesse de fonctionner._G()Lorsque vous utilisez le_G()fonction de conserver les données enregistrées, il doit être utilisé de manière raisonnable en fonction de la mémoire et de l'espace disque dur du périphérique matériel, et ne doit pas être abusé. Lorsque vous appelez le_G()Les paramètres sont passés dans le cadre d'une fonction de trading en direct et aucun paramètre n'est passé, le_G()Retourne leIdLes échanges en direct actuels._G()fonction, le paramètrevest passé comme nul pour indiquer la suppression de lak-vLorsque vous appelez le_G()fonction, seulement le paramètrekest passé dans la chaîne, et le_G()fonction renvoie la valeur de clé correspondant au paramètre enregistrékLorsque vous appelez le_G()fonction, seulement le paramètrekest passé en valeur nulle, indiquant que tous les enregistrements de lak-vLorsque la clé-valeur est supprimée,k-vles paires de clés-valeurs ont été sauvegardées de façon persistante,_G()la fonction est appelée à nouveau, en passant le nom de la clé qui a été sauvegardée de manière persistante comme paramètrek. Passer la nouvelle valeur de clé comme paramètrevJe vais le mettre à jour.k-vune paire clé-valeur.

Je ne sais pas.

- Je ne sais pas.

Convertisse les horodatages en millisecondes ouDateobjets à des chaînes de temps.

Une chaîne temporelle. chaîne

Je suis désolé. _D (heure) _D (horodatage, fmt)

Marque d'heure en millisecondes ouDateJe suis un objet. l' étiquette faux Numéro, objet Format de la chaîne,JavaScriptFormat par défaut de la langue:yyyy-MM-dd hh:mm:ss; PythonFormat par défaut de la langue:%Y-%m-%d %H:%M:%S; C++Format par défaut de la langue:%Y-%m-%d %H:%M:%S- Je ne sais pas. fmt faux chaîne

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

Obtenez et imprimez la chaîne de temps courante:

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

L'horodatage est 1574993606000, en utilisant le code de conversion:

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
}

Formatage avec le paramètrefmtest différente pourJavaScript, Python, etC++les langues, comme indiqué dans les exemples suivants:

Retourne la chaîne de temps en cours sans passer de paramètres._D()fonction dans lePythonDans le cas d'une stratégie, vous devez être conscient que les paramètres passés sont des horodatages de deuxième niveau (horodatages de niveau milliseconde dans les stratégies JavaScript et C++, où 1 seconde équivaut à 1000 millisecondes)._D()fonction pour analyser une chaîne d'heure avec un horodatage lisible dans le commerce en direct, vous devez faire attention au fuseau horaire et le réglage de l'heure du système d'exploitation où le programme docker est situé._D()fonction analyse un horodatage dans une chaîne de temps lisible en fonction de l'heure du système dockers.

Je ne sais pas si je peux vous aider.

_ N

Formater un numéro en virgule flottante.

Le numéro en virgule flottante formaté selon le réglage de précision. Numéro

_N() Nombre _N (numéro, précision)

Le numéro à virgule flottante à formater. Numéro vrai Numéro Le paramètre de précision de mise en formeprecisionest un entier, et le paramètreprecisionpar défaut à 4. précision faux Numéro

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

Par exemple,_N(3.1415, 2)supprimera la valeur après3.1415deux décimales et la fonction renvoie3.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 vous avez besoin de changer tous les N chiffres à gauche de la virgule à 0, vous pouvez l'écrire comme ceci:

Le paramètreprecisionpeut être un entier positif, un entier négatif.

{@fun/Trade/exchange.SetPrecision échange.SetPrecision} Je suis désolé

_C

Réessayez la fonction de tolérance à la défaillance de l'interface.

La valeur de retour de la fonction de rappel lorsqu'elle est exécutée. Tous les types sont pris en charge par le système saufvaleur logique fausseetvaleur nulle.

Je ne sais pas. Je ne sais pas.

Le paramètrepfnest une référence de fonction, qui est unefonction de rappel- Je ne sais pas. pfn vrai fonction Paramètres àles fonctions de rappel, il peut y avoir plusieurs paramètresarg. Le type et le nombre de paramètresargdépend des paramètres dufonction de rappelJe suis désolée. arg faux chaîne, nombre, bool, objet, tableau, fonction, tous les types sont pris en charge par le système, tels que les valeurs nulles

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

Pour les fonctions de tolérance à l'erreur sans paramètres:

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

Pour les fonctions dont les paramètres sont tolérants aux erreurs:

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

Il peut également être utilisé pour la tolérance aux pannes des fonctions personnalisées:

Le_C()fonction continuera à appeler la fonction spécifiée jusqu'à ce qu'elle renvoie avec succès (la fonction référencée par le paramètrepfnrendementsNuloufauxQuand il est appelé, il recommence à appelerpfnPar exemple:_C(exchange.GetTicker). L'intervalle de réessayer par défaut est de 3 secondes, vous pouvez appeler le_CDelay()fonction pour régler l'intervalle de réessayage._CDelay(1000)Les moyens de modifier l'intervalle de réessayage du_C()fonction à 1 seconde. La tolérance à la défaillance peut être effectuée pour, mais sans s'y limiter, les fonctions suivantes:

  • exchange.GetTicker()
  • exchange.GetDepth()
  • exchange.GetTrades()
  • exchange.GetRecords()
  • exchange.GetAccount()
  • exchange.GetOrders()
  • exchange.GetOrder()
  • exchange.GetPositions()Tous peuvent être appelés par le_C()La fonction de tolérance aux défauts_C()la fonction n'est pas limitée à la fonction de tolérance à la défaillance énumérée ci-dessus, le paramètrepfnest une référence de fonction plutôt qu'un appel de fonction. Notez qu'il est_C(exchange.GetTicker), pas_C(exchange.GetTicker()).

_Croix

Renvoie le nombre de périodes d'intersection du tableauarr1et le tableauarr2.

Le nombre de périodes transversales du tableauarr1et le tableauarr2- Je ne sais pas. Numéro

_Cross ((arr1, arr2)

Les éléments sont des tableaux de typenumber- Je ne sais pas. Arr1 vrai séquence Les éléments sont des tableaux de typenumber- Je ne sais pas. Arr2 vrai séquence

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

Un ensemble de données peut être simulé pour tester la fonction _Cross ((Arr1, Arr2):

Si la valeur de retour du_Cross()Si la fonction est un nombre positif, elle indique la période de pénétration ascendante, si elle est un nombre négatif, elle indique la période de pénétration descendante, 0 signifie la même chose que le prix actuel.Analyse et instructions d'utilisation concernant la fonction intégrée.

JSONParse

La fonctionJSONParse()est utilisé pour analyserJSON strings.

JSONJe suis un objet. objet

JSONParse (s)

JSONUne corde. s vrai chaîne

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

Les chaînes JSON avec de grandes valeurs peuvent être analysées correctement, et il analysera de grandes valeurs comme des types de chaînes.JSONParse()fonction n'est pas prise en charge dans le système de backtest.

Le journal