Notification d'un ordre de négociation Prix: 1000, // Prix de commande; remarquez que cet attribut des ordres de marché peut être 0 ou -1 Montant : 10, // Montant de la commande; notez que cet attribut des ordres de marché peut être le montant de l'argent, et non le numéro de pièce DealAmount : 10, // Volume exécuté; si l'interface de la plateforme ne fournit pas ce type de données, utilisez probablement 0 pour remplir AvgPrice : 1000, // Le prix moyen exécuté; notez que certaines plateformes ne fournissent pas ces données. État : 1, // État de la commande; renvoie à l'état de la commande dans les constantes, telles que ORDER_STATE_CLOSED Type : 0, // type de commande; référence au type de commande dans les constantes, par exemple ORDER_TYPE_BUY Offset: 0 // La direction d'ouverture et de fermeture de l'ordre dans les données d'ordre des contrats à terme de crypto-monnaie;ORDER_OFFSET_OPEN est la position ouverte, tandis que ORDER_OFFSET_CLOSE est la direction de fermeture ContractType : // Cet attribut est pour les ordres au comptant, à savoir la chaîne nulle; La propriété des ordres à terme est le code de contrat spécifique Je ne sais pas.


##### MarketOrder

Market depth order, that is, ```exchange.GetDepth()``` returns the data structure of the elements in the **Bids** and **Asks** arrays in the data.

```javascript
{
    Price   : 1000,              // Price
    Amount  : 1                  // Volume
}
Profondeur

La profondeur de marché est renvoyée par la fonctionexchange.GetDepth().

{
    Asks    : [...],             // The array of sell orders, namely MarketOrder array, sorted by price from low to high
    Bids    : [...],             // The array of buy orders, namely MarketOrder array, sorted by price from high to low
    Time    : 1567736576000      // Millisecond-level timestamp
}
Compte

Informations sur le compte, renvoyées par la fonctionexchange.GetAccount()Les données renvoyées dans la structure sont liées aux paires de négociation et aux codes de contrats actuellement définis.

{
    Info            : {...},     // After requesting the platform interface, this attribute is not available in the raw data that the platform interface responds to, during the backtest
    Balance         : 1000,      // The available amount of quote currency; if the trading pair is BTC_USDT in the spot trading, "balance" refers to the current USDT amount. In the USDT-margined futures contract, "balance" refers to the available margin amount in USDT
    FrozenBalance   : 0,         // Here "balance" refers to the frozen amount of the assets for pending orders
    Stocks          : 1,         // The available amount of base currency; if the trading pair is BTC_USDT in the spot trading, "stocks" refers to the current BTC amount. In the crypto-margined futures contract, "stocks" refers to the available margin amount (base currency)
    FrozenStocks    : 0          // Here "stocks" refers to the frozen amount of the assets for pending orders
}
Position de l'appareil

Pour les informations sur les positions détenues dans le commerce à terme, leséquencede cettePositionstructure est renvoyée par la fonctionexchange.GetPosition() function.

{
    Info            : {...},     // After requesting the platform interface, this attribute is not available in the raw data that the platform interface responds to, during the backtest
    MarginLevel     : 10,        // The leverage size of positions; if this data is not provided by the platform interface, fill in the data by calculation, possibly with errors
    Amount          : 100,       // Position volume; the contract quantity of positions is normally positive integer. Notice every platform might have different contract specifications, such as contract multiplier and value, etc., so the rules for ordering might be different; for example, Binance contract might order by 0.1
    FrozenAmount    : 0,         // The quantity of frozen positions, used as the number of temporary position freeze when close positions and pending orders
    Price           : 10000,     // Average position price; in principle, the attribute is the average price of the entire position (which does not involve in the settlement); if the platform interface does not provide the data, use the existing average position price of the platform to fill in (which involves in the settlement)
    Profit          : 0,         // Position floating profit and loss, namely the failure of realizing position profit and loss. If the platform interface does not provide the data, use other profit and loss data from the interface to fill in; the unit of the profit and loss values is the same as the unit of the current contract margin 

    Type            : 0,         // PD_LONG is a long position, while PD_SHORT is a short position
    ContractType    : "quarter", // Contract code; for more details, refer to the transmitted parameters in the description of the function "SetContractType"
    Margin          : 1          // Margin occupied by positions; if the platform interface does not provide the data, use 0 to fill in
}

Pour les contrats à terme de crypto-monnaie, faites attention à laPositiontableau de structure renvoyé par la fonctionexchange.GetPosition()En ce qui concerne les attributs dans sa structure de données de position, tels queFrozenAmount, ProfitetMargin, différentes définitions de données peuvent être renvoyées par différents objets d'échange, lorsqu'ils appellentexchange.GetPosition()Par exemple, certains échanges n'incluent pas les données de position gelées, ce qui indique que les données de position gelées sont conservées dans les échanges.FrozenAmountest 0. Si vous avez besoin de calculer des données, vous pouvez utiliser les données de source dans l'attributInfopour le calcul et l'analyse.

Fonctions globales

Version (en)

Version()renvoie le numéro de version actuel du système; valeur renvoyée: type de chaîne.

Le sommeil (milliseconde)

Sleep(Millisecond), fonction de sommeil, fait mettre le programme en pause pendant une période de temps.Millisecondest un type de nombre. L'unité de paramètre est la milliseconde, par exemple:Sleep(1000)Ça veut dire dormir une seconde. Opérations d'assistance avec une durée de sommeil inférieure à 1 milliseconde, telles que la réglageSleep (0.1). Le paramètre minimum pris en charge est0.000001Une nanoseconde est égale à1e-6 milliseconds.

Note: le numéro de série Quand vous écrivez des stratégies dansPythonLe langage, la fonctionSleep(Millisecond)Il n'est pas recommandé d'utiliser la fonctiontime.time(second)de l'annéetimebibliothèquePythonParce que lorsque vous utilisez la fonctiontime.time(second)Dans la stratégie, le programme de stratégie va effectivement attendre un certain nombre de secondes (le paramètresecondest le deuxième chiffre du paramètre de pause), ce qui conduira à un backtest de stratégie très lent.

C' est virtuel?

IsVirtual(), pour déterminer s'il s'agit d'un backtest simulé. Retour de l'état du backtest simulétrue, et le vrai robot revientfalse.

Le courrier

Mail(smtpServer, smtpUsername, smtpPassword, mailTo, title, body)est une fonction d'envoi de courrier. Valeur du paramètre: tous sont de type chaîne. Valeur de retour: type bool;trueest renvoyé après un envoi réussi.smtpServersert pour la boîte aux lettres d'envoismtp; smtpUsernameest le compte de boîte aux lettres;smtpPasswordest le mot de passe STMP de la boîte aux lettres;mailToest le compte de boîte aux lettres destinataire;titleest le titre du courrier envoyé;bodyest le contenu du courrier envoyé, par exemple:

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");
}
  • LeMail_Gola fonction est une version asynchrone de la fonctionMailLe texte est le suivant: Son utilisation est similaire à la fonctionexchange.Go.

    function main() {
        var r1 = Mail_Go("smtp.163.com", "asdf@163.com", "password", "111@163.com", "title", "body")
        var r2 = Mail_Go("smtp.163.com", "asdf@163.com", "password", "111@163.com", "title", "body")
        
        var ret1 = r1.wait()
        var ret2 = r2.wait()
        
        Log("ret1:", ret1)
        Log("ret2:", ret2)
    }
    
    # Not supported
    
    // Not supported
    

Nom de l'organisme: Le serveur Alibaba Cloud peut bloquer certains ports, de sorte que le courrier ne peut pas être envoyé.smtp.qq.com:587(QQmail), le port est disponible pour les tests. Si une erreur se produit:unencrypted connection, vous devez modifier le format de paramètre desmtpServerdans la fonctionMailà:ssl://xxxxx.com:xxxPar exemple, la méthode SMTP ssl de QQmail:ssl://smtp.qq.com:465ousmtp://xxxxx.com:xxx.

- Je suis désolé.

ErrorFilter(RegEx), filtrage des journaux d'erreur. Valeur du paramètre: type de chaîne. Les erreurs correspondant à cette expression régulière ne seront pas téléchargées dans le système de journaux, et il peut être appelé plusieurs fois (les journaux filtrés ne seront pas écrits dans le fichier de base de données de l'ID de bot correspondant dans les journaux / bots dans le contenu du docker, pour éviter l'expansion du fichier de base de données causée par des rapports d'erreur fréquents).

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 informations d'erreur d'une interface:

function main() {
    // Randomly check a non-existent order with ID 123; intentionally make the interface report an error
    var order = exchange.GetOrder("123")
    Log(order)
    // Filter http502 errors and GetOrder interface errors; after set the error filter, the second time to call GetOrder no longer reports 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);
}

Je ne peux pas.

GetPid()renvoie l'identifiant du processus bot. Retourne la valeur: type de chaîne.

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

GetLastError()obtient les dernières informations d'erreur; généralement, il n'est pas nécessaire de l'utiliser, car le programme téléchargera automatiquement les informations d'erreur dans le système de journaux.GetLastError(), le cache d'erreur sera effacé; lorsqu'il est appelé à nouveau, les informations d'erreur enregistrées la dernière fois ne seront pas renvoyées.

function main(){
    // Because the order with ID number of 123 does not exist, an error is reported
    exchange.GetOrder("123")
    var error = GetLastError()
    Log(error)
}
def main():
    exchange.GetOrder("123")
    error = GetLastError()
    Log(error)
void main() {
    // The type of order ID: TId; so no string can be passed in, and we can trigger it by placing an order that does not meet the exchange specifications
    exchange.GetOrder(exchange.Buy(1, 1));
    auto error = GetLastError();
    Log(error);
}

Vous avez le commandement?

GetCommand()obtient des commandes interactives (utf-8). Il obtient la commande envoyée par l'interface interactive de stratégie et efface le cache; s'il n'y a pas de commande, il renvoie une chaîne vide. Le format de commande renvoyé estbutton name: parameter; s'il n'y a pas de paramètre dans les commandes interactives (par exemple, la commande de bouton sans boîte d'entrée), la commande est le nom du bouton.

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

Le système sous-jacent a une structure de file d'attente pour enregistrer la commande interactive.GetCommand()est appelé, la commande interactive qui entre en première dans la file d'attente sera retirée (s'il n'y a pas de commande interactive, une chaîne vide).

Exemples d'utilisation de commandes interactives; définir des commandes interactives sur l'interface d'édition de stratégie:

img

Concevoir des codes interactifs dans la stratégie:

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 quantity")
            } else if (arr[0] == "sell") {
                Log("Sell, the control with quantity: ", 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 quantity")
            elif arr[0] == "sell":
                Log("Sell, the control with quantity:", 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 quantity");
            } else if (arr[0] == "sell") {
                Log("Sell, the control with quantity:", arr[1]);
            } else {
                Log("Other controls trigger:", arr);
            }
        }
        Sleep(1000);
    }
}

Je suis désolée.

La fonctionGetMeta()renvoie la valeur deMetaécrit lorsque le jeton de stratégie est généré, la valeur de retour de la fonction est de type chaîne. Applications: par exemple, la stratégie doit faire des limitations d'actifs pour différents locataires. Remarque: lorsque le jeton de stratégie est généré, la durée deMetane peut pas dépasser 190 chaînes; la fonction, applicable uniquement au trading réel et nécessite le plus récent docker.GetMeta()renvoie nul.

les informations connexes démontrées par les demandes

function main() {
    // The largest assets value of quote currency allowed by the strategy
    
    // Get the metadata generated when the strategy token is established
    var level = GetMeta()
    
    // Check the corresponding conditions of "Meta"
    if (level == "level1") {
        // "-1" indicates no limitation 
        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()
        
        // Check the assets value
        var acc = exchange.GetAccount()
        if (maxBaseCurrency != -1 && maxBaseCurrency < acc.Stocks + acc.FrozenStocks) {
            // Stop the execution of the strategy trading logic 
            LogStatus(_D(), "level:", level, "The position exceeds the strategy token's using limitation, and stop the execution of the strategy trading logic!")
            continue
        }
        
        // Other trading logic
        
        // Export the information of status bar normally
        LogStatus(_D(), "level:", level, "The strategy runs normally! 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, "The position exceeds the strategy token's using limitation, and stop the execution of the strategy trading logic!")
            continue        
        
        # Other trading logic
        
        # Export the information of status bar normally
        LogStatus(_D(), "level:", level, "The strategy runs normally! 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 the execution of the strategy trading logic
            LogStatus(_D(), "level:", level, "The position exceeds the strategy token's using limitation, and stop the execution of the strategy trading logic!");
            continue;
        }
        
        // Other trading logic
        
        // Export the information of status bar normally
        LogStatus(_D(), "level:", level, "The strategy runs normally! Ticker data: \n", ticker);
    }
}

Faites le numéro...

Dial(Address, Timeout), accès à la prise originale, supportstcp, udp, tlsetunixvaleur du paramètre:Addressest un type de chaîne; l'unité est seconde; si le temps est épuisé, la fonctionDial(...)renvoie une valeur vide.

Description détaillée deAddressparamètre:

Détails des paramètres
Paramètres de réglage de la fonctionDial Séparer en ajoutant le|le symbole suivant l'adresse normale:wss://ws.okx.com:8443/ws/v5/public; s'il y en a une|caractères dans la chaîne de paramètres, utilisation||connectez chaque paramètre avec&; par exemple, les paramètres de substitution et de compression ss5 sont définis ensemble:Dial("wss://ws.okx.com:8443/ws/v5/public|proxy=socks5://xxx:9999&compress=gzip_raw&mode=recv").
Dans le protocole ws, les paramètres connexes de compression des données:compress=parameter value compresser est la méthode de compression; les paramètres de compression peuvent être choisis à partirgzip_rawetgzip, etc. Si la méthode gzip est gzip non standard, vous pouvez utiliser la méthode d'extension:gzip_raw, c'est à dire, ajouter le réglagecompress=gzip_rawaprès le séparateur|, et utiliser le&le symbole et le paramètre de mode suivant à séparer.
Dans le protocole ws, les paramètres connexes de compression des données:mode=parameter value le mode est le mode comprenant trois options, à savoir:dual, sendetrecv. dualest bidirectionnelle, envoie et reçoit des données compressées.sendest d'envoyer des données compressées.recvest de recevoir des données compressées et de les décompresser localement.
Paramètres connexes pour le réglage des chaussettes5proxy=parameter value proxy est le paramètre de paramètre ss5;socks5://name:pwd@192.168.0.1:1080; name est le nom d'utilisateur du serveur ss5; pwd est le mot de passe de connexion du serveur ss5; 1080 est le port du serveur ss5
Dans le protocole ws, les paramètres connexes pour définir la reconnexion automatique sous-jacente:reconnect=parameter value reconnecter indique s'il est nécessaire de régler la reconnexion;reconnect=trueest d'appeler une reconnexion; le paramètre par défaut est de ne pas reconnecter.
Dans le protocole ws, les paramètres connexes pour définir la reconnexion automatique sous-jacente:interval=parameter value l'intervalle est l'intervalle de réessayage en millisecondes,interval=10000est l'intervalle de 10 secondes de réessayage, et le réglage par défaut est de 1 seconde, c'est-à-direinterval=1000.
Dans le protocole ws, les paramètres connexes pour définir la reconnexion automatique sous-jacente:payload= parameter value La charge utile est le message d'abonnement à envoyer lorsque ws se reconnecte, par exemple:payload=okok.
function main(){
    // Dial supports tcp://, udp://, tls://, unix:// protocol, so you can add a parameter to specify the number of seconds to timeout
    var client = Dial("tls://www.baidu.com:443")  
    if (client) {
        // "Write" can be followed by a numeric parameter to specify the timeout, and "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 to specify the timeout, in millisecond. Return null to indicate error, timeout or closed socket
            var buf = client.read()
            if (!buf) {
                 break
            }
            Log(buf)
        }
        client.close()
    }
}
def main():
    client = Dial("tls://www.baidu.com:443")
    if client:
        client.write("GET / HTTP/1.1\nConnection: Closed\n\n")
        while True:
            buf = client.read()
            if not buf:
                break
            Log(buf)
        client.close()
void main() {
    auto client = Dial("tls://www.baidu.com:443");
    if(client.Valid) {
        client.write("GET / HTTP/1.1\nConnection: Closed\n\n");
        while(true) {
            auto buf = client.read();
            if(buf == "") {
                break;
            }
            Log(buf);
        }
        client.close();
    }
}

La fonctionreadprend en charge les paramètres suivants:

  • Quand aucun paramètre n'est passé, il bloque jusqu'à ce qu'il y ait un message, tel quews.read().
  • Lors du passage de paramètres, spécifier le temps d'attente pour les messages en attente en millisecondes, par exemple:ws.read(2000)spécifie que le temps d'arrêt est de deux secondes (2000 millisecondes).
  • Les deux paramètres suivants ne sont valables que pourwebsocketLe texte est le suivant: Passage de paramètre-1signifie retourner immédiatement indépendamment du fait qu'il y ait un message, tel quews.read(-1)Je suis désolée. Passage de paramètre-2signifie retourner immédiatement indépendamment du fait qu'il y ait un message, mais seul le dernier message est retourné, et le message dans le tampon sera rejeté, commews.read(-2).

La fonctionread()Description du tampon: Si les données transmises par le protocole ws sont de longs intervalles entre la stratégieread()La structure de données du tampon est une file d'attente, avec une limite supérieure de 2000. Après avoir dépassé 2000, les dernières données entrent dans le tampon et les plus anciennes sont effacées.

Les scénariosReadParamètre de fonction Aucun paramètre Paramètre: -1 Paramètre: -2 Paramètre: 2000 (unité: ms)
Le tampon a déjà des données. 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 les données lorsque des données sont bloquées Retourner nul immédiatement Retourner nul immédiatement Attendez 2000ms, retournez nul s'il n'y a pas de données, retournez les données s'il y a des données
La connexion Ws est déconnectée ou la couche inférieure est reconnectée La fonction read() renvoie null, c'est-à-dire: , et la fonction write() renvoie 0. Si cette situation est détectée, la fonction close() peut être utilisée pour fermer la connexion. Si la reconnexion est définie automatiquement, elle n'aura pas besoin de se fermer et la couche inférieure du système se reconnectera automatiquement.
  • Prise en charge du protocole wss (WebSocket) Accéder à l'interface de marché du websocket Binance:

    function main() {
        LogStatus("connecting...")
        // Access Binance websocket interface
        var client = Dial("wss://stream.binance.com:9443/ws/!ticker@arr")
        if (!client) {
            Log("connection failed, program exited")
            return
        }
        
        while (true) {
            // "read" only returns the obtained data after call "read" 
            var buf = client.read()      
            if (!buf) {
                break
            }
            var table = {
                type: 'table',
                title: 'Quote Chart',
                cols: ['Currency', 'Highest', 'Lowest', 'Buy One', 'Sell One', 'Last Executed 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" : "Quote Chart", 
                "cols" : ['Currency', 'Highest', 'Lowest', 'Buy One', 'Sell One', 'Last Executed 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" : "Quote Chart", 
                "cols" : ['Currency', 'Highest', 'Lowest', 'Buy One', 'Sell One', 'Last Executed 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();
    }
    

    Interface de marché des connexions web OKX:

    var ws = null 
    function main(){
          var param = {
            "op": "subscribe",
            "args": [{
                "channel": "tickers",
                "instId": "BTC-USDT"
            }]
        }
        // When call the function "Dial", specify "reconnect=true" and set to reconnect; specify "payload" as the message to be sent when reconnect. When websocket closes the connection, it will automatically reconnect and send the message
        ws = Dial("wss://ws.okx.com:8443/ws/v5/public|compress=gzip_raw&mode=recv&reconnect=true&payload="+ JSON.stringify(param))
        if(ws){
            ws.write(JSON.stringify(param))
            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": ["spot/ticker:ETH-USDT"]})"_json;
             "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éder à l'interface de marché de Huobi:

    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
                try {
                    var jsonRet = JSON.parse(ret)
                    if(typeof(jsonRet.ping) == "number") {
                        var strPong = JSON.stringify({"pong" : jsonRet.ping})
                        ws.write(strPong)
                        Log("respond 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 function ws.close()")
    }
    
    import json
    ws = None  
    
    def main():
        global ws
        param = {"sub" : "market.btcusdt.detail", "id" : "id1"}
        ws = Dial("wss://api.huobi.pro/ws|compress=gzip&mode=recv&reconnect=true&payload=" + json.dumps(param))
        if ws:
            while True:
                ret = ws.read()
                Log("ret:", ret)              
                # Respond to heartbeat 
                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 ping, send pong:", strPong, "#FF0000")
                except Exception as e:
                    Log("e:", e)
                    
                LogStatus("current time: ", _D())
                Sleep(1000)
        
    def onexit():
        ws.close()
        Log("execute function ws.close()")  
    
    using namespace std;
    void main() {
        json param = R"({"sub" : "market.btcusdt.detail", "id" : "id1"})"_json;
        auto ws = Dial("wss://api.huobi.pro/ws|compress=gzip&mode=recv&reconnect=true&payload=" + param.dump());
        if(ws.Valid) {
            while(true) {
                auto ret = ws.read();
                Log("ret:", ret);              
                // Respond to heartbeat
                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 ping, send pong:", strPong, "#FF0000");
                    }
                } catch(exception &e) 
                {
                    Log("e:", e.what());
                }
                
                LogStatus("current time:", _D());
                Sleep(1000);
            }
        }
    }  
    
    void onexit() {
        // ws.close();
        Log("execute function ws.close()");
    }
    

    Interface de vérification de l'interface du websocket accédant à OKX:

      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)
            }]
        }    
        return login
    }    
    
    var client_private = null 
    function main() {
        // Because the read function adopts the timeout setting, the timeout error is filtered, otherwise there will be redundant error output
        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, we cannot subscribe to private channels immediately, we 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, connection closed, 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, connection closed, 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)
    

Le client automatique_privé = Dial ((wss://ws.okx.com:8443/ws/v5/private);

json getLogin ((string pAccessKey, chaîne pSecretKey, chaîne pPassphrase) { le code de l'appareil est le même que celui de l'appareil. json login = R"({ op: connexion, Je suis désolé. apiKey: , phrase de passe: , heure de sortie: , signe: Je ne sais pas. Je ne sais pas si c'est vrai. login[args][0][apiKey] = pAccessKey; login[args][0][passphrase] = pPassphrase; le code de connexion [args][0][timestamp] = ts; login[args][0][sign] = exchange.HMAC(sha256, base64, ts + GET + /users/self/verify, pSecretKey); retour de connexion; Je ne sais pas.

- Je ne sais pas. Le filtrage d'erreur est défini (timeout); Json posSubscribe = R"({ op: abonner, Je ne sais pas. channel: positions, instType: any Je ne sais pas. Je ne sais pas si c'est vrai.

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, connection closed, 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;
        }
    }
}

}

Il est nul. client_private.close (); Le numéro d'enregistrement est le numéro d'enregistrement suivant: Je ne sais pas.


#### HttpQuery(...)

```HttpQuery(Url, PostData, Cookies, Headers, IsReturnHeader)``` is an access of web URL. Parameter value: all are of string types.

Note:
* The ```HttpQuery(...)``` function only supports ```JavaScript``` language.
* For the ```Python``` language, you can use ```urllib``` to send http requests directly.

```HttpQuery(...)``` is mainly used to access the exchange interfaces that do not require signatures, such as public interfaces including market information.
An example of an API that does not require a signature to access OKX: the return value is a ```JSON``` string, which can be parsed by using the function ```JSON.parse()``` in JavaScript language strategies.

```js
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 urllib/urllib2 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);
}

Pour obtenir le contenu de retour d'une URL, si le deuxième paramètrePostDataest sous forme de chaînea=1&b=2&c=abc, présenté parPOST, d'autres parPUT; le paramètre dePostDataest{method:'PUT', data:'a=1&b=2&c=abc'}.

LePostDataParamètre peut également être unJSON string.

Le format du paramètreCookiesest:a=10; b=20; chaque paramètre est séparé par un point-virgule;Je suis désolée. Le format du paramètreHeadersest:User-Agent: Mobile\nContent-Type: text/html; chaque paramètre est séparé par un caractère de nouvelle ligne\n.

Le deuxième paramètre,PostData, peut être personnalisé, par exemple:HttpQuery("http://www.abc.com", {method:'PUT', data:'a=1&b=2&c=abc'}); note: si vous avez besoin de définir le temps d'arrêt pour leHttpQueryfonction, vous pouvez ajouter letimeoutattribut dans{method:'put',data:'a=1&B=2&C=ABC'}(la valeur par défaut est de 60 secondes).

Réglez une pause de 1 seconde:HttpQuery("http://www.abc.com", {method:'PUT', data:'a=1&b=2&c=abc', timeout:1000})

Le troisième paramètre est requis pour passer la chaîneCookie, maisPOSTn'est pas nécessaire pour définir le deuxième paramètre à zéro. Pendant le test de simulation, parce que l'URL ne peut pas être simulée, la fonction renvoie une chaîne fixeDummy DataVous pouvez utiliser cette interface pour envoyer des messages texte ou interagir avec d'autres interfaces API.

GETExemple d'appel de méthode:HttpQuery("http://www.baidu.com"). POSTExemple d'appel de méthode:HttpQuery("http://www.163.com", "a=1&b=2&c=abc").

Exemple d'invocation de retourHeader:

HttpQuery("http://www.baidu.com", null, "a=10; b=20", "User-Agent: Mobile\nContent-Type: text/html", true)  // will return {Header: HTTP Header, Body: HTML}
  • La fonctionHttpQueryutilise les paramètres du proxy:

    function main() {
        // This time, set proxy and send http request; without username and password, this http request will be sent through the proxy
        HttpQuery("socks5://127.0.0.1:8889/http://www.baidu.com/")
    
        // Set the proxy and send http request this time, enter the user name and password, only the current call of HttpQuery takes effect, then call HttpQuery ("http://www.baidu.com") again so that the proxy will not be used
        HttpQuery("socks5://username:password@127.0.0.1:8889/http://www.baidu.com/")
    }
    
    # If HttpQuery does not support Python, you can use Python urllib2 library
    
    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 fonctionHttpQueryest une version asynchroneHttpQuery_GoLe texte est le suivant: La méthode d'utilisation est similaire à la fonctionexchange.Go, comme accéder à l'interface publique de la bourse de manière asynchrone pour obtenir des données de marché agrégées.

    function main() {
        // Set up the first asyncthread
        var r1 = HttpQuery_Go("https://www.okx.com/api/v5/market/tickers?instType=SPOT")
        // Set up the second asyncthread
        var r2 = HttpQuery_Go("https://api.huobi.pro/market/tickers")
        
        // Get the return value of the first asyncthread
        var tickers1 = r1.wait()
        // Get the return value of the second asyncthread
        var tickers2 = r2.wait()
        
        // Print result
        Log("tickers1:", tickers1)
        Log("tickers2:", tickers2)
    }
    
    # Not supported
    
    // Not supported
    
  • Utilisation de la fonctionHttpQuery(...)dans le système de backtest: Les données peuvent être obtenues en utilisantHttpQuery(...)pour envoyer des demandes (support uniquement)GETLes tests sont effectués en fonction de la fréquence des demandes et de la fréquence des demandes.HttpQuery(...)accès cache les données, tandis que la fonctionHttpQuery(...)renvoie les données mises en cache lors du deuxième accès à la même URL (pas plus de requêtes Web réelles).

    Nous pouvons exécuter un programme de service sur un serveur ou un appareil qui répond aux demandes envoyées parHttpQuery(...)dans le programme de stratégie, et le programme de service en langage Go pour les tests est indiqué comme suit:

    package main
    import (
        "fmt"
        "net/http"
        "encoding/json"
    )
    
    func Handle (w http.ResponseWriter, r *http.Request) {
        defer func() {
            fmt.Println("req:", *r)
            ret := map[string]interface{}{
                "schema" : []string{"time","open","high","low","close","vol"},
                "data" : []interface{}{
                    []int64{1564315200000,9531300,9531300,9497060,9497060,787},
                    []int64{1564316100000,9495160,9495160,9474260,9489460,338},
                },
            }
            b, _ := json.Marshal(ret)
            w.Write(b)
        }()
    }
    
    func main () {
        fmt.Println("listen http://localhost:9090")
        http.HandleFunc("/data", Handle)
        http.ListenAndServe(":9090", nil)
    }
    

    Utilisez la fonctionHttpQuery(...)pour envoyer des demandes lors du backtesting de la stratégie:

    function main() {
        // You can write the IP address of the device where the service program is run
        Log(HttpQuery("http://xxx.xx.x.xxx:9090/data?msg=hello"));
        Log(exchange.GetAccount());
    }
    
    # If HttpQuery does not support Python, you can use Python urllib2 library
    
    void main() {
        //  You can write the IP address of the device where the service program is run
        Log(HttpQuery("http://xxx.xx.x.xxx:9090/data?msg=hello"));
        Log(exchange.GetAccount());
    }
    

    img

    Il prend en charge le transcodage des données de réponse dans la demande, et il prend également en charge le codage commun. Préciser lePostDataparamètre:{method: "GET", charset: "GB18030"}peut réaliser le transcodage des données de réponse (GB18030).

Le code

Encode(algo, inputFormat, outputFormat, data, keyFormat, key string), la fonction encode les données en fonction des paramètres passés et renvoie une valeur de chaîne.

Le paramètrealgoest l'algorithme utilisé pour le calcul du codage, qui peut être réglé sur: raw (pas d'algorithme), sign, signTx, md4, md5, sha256, sha512, sha1, keccak256, sha3.224, sha3.256, sha3.384, sha3.512, sha3.keccak256, sha3.keccak512, sha512.384, sha512.256, sha512.224, emd160, blake2rip2b.256, blake2b.512, blake2s.1288, blake2s.256 paramètre.dataLes données à traiter.inputFormat/outputFormat/keyFormatles paramètres prennent en charge des méthodes de codage telles queraw, hex, base64etstringJe suis désolée. Si lekeyFormatparamètre n'est pas vide, lekeyparamètre est utilisé pour le chiffrement (HMAC), sinon le paramètre par défautkeyLorsque l'on utilise le