Notifizierung einer Handelsanweisung Preis: 1000, // Preis der Auftragserteilung; beachten Sie, dass dieses Merkmal von Marktordern 0 oder -1 sein kann Betrag: 10, // Bestellbetrag; beachten Sie, dass dieses Attribut von Marktordern Geldbetrag und keine Münznummer sein kann DealAmount : 10, // Ausgeführtes Volumen; wenn die Plattformoberfläche diese Art von Daten nicht bereitstellt, verwenden Sie wahrscheinlich 0 zum Ausfüllen AvergPrice : 1000, // Der durchschnittliche ausgeführte Preis; beachten Sie, dass einige Plattformen diese Daten nicht bereitstellen.(In der Situation, in der die Daten nicht bereitgestellt oder berechnet werden können, ist die Einstellung des Attributs 0.) Status: 1, // Bestellstatus; beziehen sich auf den Bestellstatus in den Konstanten, z. B. ORDER_STATE_CLOSED Typ: 0, // Auftragstyp; beziehen sich auf den Auftragstyp in den Konstanten, z. B. ORDER_TYPE_BUY Offset: 0 // Die Auftragsöffnungs- und -schließungsrichtung in den Auftragsdaten von Kryptowährungs-Futures;ORDER_OFFSET_OPEN ist die offene Position, während ORDER_OFFSET_CLOSE die Schließungsrichtung ist ContractType : // Dieses Attribut ist für Spot-Orders, nämlich Nullstring; Die Eigenschaft von Futures-Orders ist der spezifische Vertragskode - Ich weiß.


##### 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
}
Tiefe

Die Markttiefe wird durch die Funktionexchange.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
}
Abrechnung

Kontoinformationen, die von der Funktion zurückgegeben werdenexchange.GetAccount()Die in der Struktur zurückgegebenen Daten beziehen sich auf die derzeit festgelegten Handelspare und Vertragscodes.

{
    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

Für die Informationen über Positionen im Futures-Handel werden dieReihenfolgevon diesemPositionStruktur wird von der Funktion zurückgegebenexchange.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
}

Für die Kryptowährungs-Futures, achten Sie auf diePositionStruktur-Array, zurückgegeben durch die Funktionexchange.GetPosition()- Die Attribute in seiner Positionsdatenstruktur, wieFrozenAmount, ProfitundMargin, verschiedene Datendefinitionen können von verschiedenen Austauschobjekten zurückgegeben werden, wenn sieexchange.GetPosition()Einige Börsen enthalten beispielsweise keine Position eingefrorenen Daten, dieFrozenAmountist 0. Wenn Sie einige Daten berechnen müssen, können Sie die Quelldaten im Attribut verwendenInfozur Berechnung und Analyse.

Globale Funktionen

Ausgabe ((()

Version()Gibt die aktuelle Versionnummer des Systems zurück. Gibt den Wert zurück: Zeichenfolge.

Schlaf (Millisekunde)

Sleep(Millisecond), Schlaffunktion, lässt das Programm für einen bestimmten Zeitraum pausieren.Millisecondist ein Zahlentyp. Die Parametereinheit ist Millisekunde, z. B.:Sleep(1000)bedeutet, für eine Sekunde zu schlafen. Unterstützungsvorgänge mit einer Schlafzeit von weniger als 1 Millisekunde, z. B. EinstellungSleep (0.1). Der minimale unterstützte Parameter ist0.000001Eine Nanosekunde ist gleich1e-6 milliseconds.

Anmerkung: Wenn Sie Strategien inPythonSprache, die FunktionSleep(Millisecond)Es wird nicht empfohlen, diese Funktion zu verwenden.time.time(second)dertimeBibliothek inPythonDenn wenn man die Funktion verwendettime.time(second)In der Strategie wird das Strategieprogramm tatsächlich für eine bestimmte Anzahl von Sekunden warten (der Parametersecondist die zweite Zahl der Pause-Einstellung), was zu einem sehr langsamen Strategie-Backtest führt.

Ist virtuell?

IsVirtual(), um festzustellen, ob es sich um einen simulierten Backtest handelt. Der simulierte Backtest-Status wird zurückgegebentrue, und der echte Bot kehrt zurückfalse.

Nachrichten ((...)

Mail(smtpServer, smtpUsername, smtpPassword, mailTo, title, body)ist eine E-Mail-Sendungsfunktion. Parameterwert: alle sind von String-Typ. Rückgabewert: bool-Typ;truenach erfolgreichem Versand zurückgeschickt wird.smtpServerdient für den Versandpostfachsmtp; smtpUsernameist das Postfachkonto;smtpPasswordist das STMP-Passwort des Postfachs;mailToist das empfangende Postfachkonto;titleist der Titel der gesendeten Post;bodyist der Inhalt der gesendeten Post, z. B.:

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");
}
  • DieMail_GoFunktion ist eine asynchrone Version der FunktionMailDie Kommission Die Verwendung ist ähnlich der Funktionexchange.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
    

Anmerkung: Der Alibaba Cloud Server kann einige Ports blockieren, so dass die Mail nicht gesendet werden kann. Wenn Sie den Port ändern müssen, können Sie die Portnummer direkt in den ersten Parameter hinzufügen, zum Beispiel,smtp.qq.com:587(QQmail), der Anschluss ist für Tests verfügbar. Falls ein Fehler vorliegt:unencrypted connection, müssen Sie das Parameterformat vonsmtpServerin der FunktionMailfür:ssl://xxxxx.com:xxxZum Beispiel die SMTP-SSL-Methode von QQmail:ssl://smtp.qq.com:465odersmtp://xxxxx.com:xxx.

SetErrorFilter(...)

ErrorFilter(RegEx), Filterung von Fehlerprotokollen. Parameterwert: Zeichenfolgeart. Fehler, die mit diesem regulären Ausdruck übereinstimmen, werden nicht in das Protokollsystem hochgeladen, und es kann mehrmals aufgerufen werden (gefilterte Protokolle werden nicht in die Datenbankdatei der entsprechenden Bot-ID in den Protokolle/Bots im Docker-Inhalt geschrieben, um die Datenbankdateiererweiterung durch häufige Fehlermeldungen zu verhindern).

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

Filtern Sie die Fehlerinformationen einer Schnittstelle:

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

GetPid (siehe unten)

GetPid()Gibt die ID des Bot-Prozesses zurück.

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

GetLastError()

GetLastError()Erhält die neuesten Fehlerinformationen; in der Regel muss es nicht verwendet werden, da das Programm die Fehlerinformationen automatisch in das Protokollsystem hochlädt.GetLastError(), wird der Fehler-Cache gelöscht; wenn er erneut aufgerufen wird, werden die Fehlerinformationen, die beim letzten Mal aufgezeichnet wurden, nicht zurückgegeben.

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

GetCommand (siehe unten)

GetCommand()erhält interaktive Befehle (utf-8). Er erhält den von der Strategie-interaktive Schnittstelle gesendeten Befehl und löscht den Cache; wenn kein Befehl vorhanden ist, gibt er eine leere Zeichenfolge zurück. Das zurückgegebene Befehlformat istbutton name: parameter; wenn in den interaktiven Bedienelementen kein Parameter vorhanden ist (z. B. die Tastensteuerung ohne Eingabefeld), ist der Befehl der Tastenname.

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

Das zugrunde liegende System hat eine Warteschlange, um den interaktiven Befehl aufzuzeichnen.GetCommand()wird aufgerufen, wird der interaktive Befehl, der zuerst in die Warteschlange eingegeben wird, herausgenommen (wenn kein interaktiver Befehl vorhanden ist, eine leere Zeichenfolge).

Beispiele für die Verwendung interaktiver Steuerelemente; Einrichtung interaktiver Steuerelemente auf der Schnittstelle zur Strategiebearbeitung:

img

Entwurf interaktiver Codes in der Strategie:

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

GetMeta()

Die FunktionGetMeta()Gibt den Wert vonMetawenn das Strategie-Token generiert wird, ist der Rückgabewert der Funktion String-Typ. Anwendungen: Zum Beispiel muss die Strategie Vermögensbeschränkungen für verschiedene Mieter festlegen. Anmerkung: Wenn das Strategie-Token generiert wird, wird die Länge derMetakann 190 Zeichenfolgen nicht überschreiten; die Funktion ist nur für den tatsächlichen Handel anwendbar und erfordert den neuesten Docker.GetMeta()Gibt null zurück.

die entsprechenden Informationen, die durch Anträge nachgewiesen werden

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

Wählen Sie...

Dial(Address, Timeout), Original Socket-Zugriff, Stützentcp, udp, tlsundunix- Parameterwert:Addressist ein String-Typ; Einheit ist zweite; wenn die Zeit aus ist, die FunktionDial(...)Gibt einen leeren Wert zurück.

Ausführliche Beschreibung derAddressParameter:

Details der Parameter
Parameter für die Einstellung der FunktionDial Trennen durch Hinzufügen der|Symbol nach der normalen Adresse:wss://ws.okx.com:8443/ws/v5/public- wenn vorhanden|Zeichen in der Parameterzeile, Verwendung||Als Grenzschlüssel.&; beispielsweise werden ss5-Proxy- und Kompressionsparameter zusammengestellt:Dial("wss://ws.okx.com:8443/ws/v5/public|proxy=socks5://xxx:9999&compress=gzip_raw&mode=recv").
Im WS-Protokoll werden folgende Datenkomprimierungsparameter angegeben:compress=parameter value Komprimieren ist die Komprimierungsmethode; Komprimierungsparameter können ausgzip_rawundgzip, etc. Wenn die gzip-Methode nicht-standardmäßig gzip ist, können Sie die Erweiterungsmethode verwenden:gzip_raw, das heißt, fügen Sie die Einstellungcompress=gzip_rawnach dem Trennschalter|, und verwenden Sie&Symbol und der nächste zu trennende Modusparameter.
Im WS-Protokoll werden folgende Datenkomprimierungsparameter angegeben:mode=parameter value Modus ist der Modus mit drei Optionen, nämlichdual, sendundrecv. dualist bidirektional und sendet und empfängt komprimierte Daten.sendist, komprimierte Daten zu senden.recvist, komprimierte Daten zu empfangen und lokal zu entschließen.
Verwandte Parameter für die Einstellung von Socken5 Proxy:proxy=parameter value proxy ist die proxy-Einstellung ss5; Parameterwertformat:socks5://name:pwd@192.168.0.1:1080name ist der Benutzername des ss5-Servers; pwd ist das Anmeldepasswort des ss5-Servers; 1080 ist der Port des ss5-Servers
Im WS-Protokoll werden die entsprechenden Parameter für die Einstellung der zugrunde liegenden automatischen Wiederverbindung angegeben:reconnect=parameter value "Wiederanschluss" bedeutet, ob erneutanschluss eingestellt werden soll;reconnect=trueist die Wiederverbindung aufzurufen; die Standardeinstellung ist nicht wiederzuverknüpfen.
Im WS-Protokoll werden die entsprechenden Parameter für die Einstellung der zugrunde liegenden automatischen Wiederverbindung angegeben:interval=parameter value Intervall ist der Intervall für erneute Versuche in Millisekunden,interval=10000ist das Wiederversuchsintervall von 10 Sekunden, und die Standardeinstellung beträgt 1 Sekunde, d. h.interval=1000.
Im WS-Protokoll werden die entsprechenden Parameter für die Einstellung der zugrunde liegenden automatischen Wiederverbindung angegeben:payload= parameter value Nutzlast ist die Abonnementnachricht, die gesendet werden soll, wenn ws wieder verbunden wird, z. B.: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();
    }
}

Die Funktionreadunterstützt folgende Parameter:

  • Wenn keine Parameter übergeben werden, blockiert es, bis es eine Nachricht gibt, wiews.read().
  • Bei der Eingabe von Parametern ist die Auslaufzeit für Wartemeldungen in der Einheit Millisekunden anzugeben, beispielsweise:ws.read(2000)Der Timeout wird als zwei Sekunden (2000 Millisekunden) angegeben.
  • Die folgenden beiden Parameter gelten nur fürwebsocketDie Kommission Übermittlung von Parametern-1bedeutet, sofort zurückzukehren, unabhängig davon, ob eine Nachricht vorliegt, wie z. B.ws.read(-1)- Ich weiß. Übermittlung von Parametern-2bedeutet, unabhängig davon, ob eine Nachricht vorhanden ist, sofort zurückzugeben, aber nur die letzte Nachricht wird zurückgegeben, und die Nachricht im Puffer wird verworfen, z. B.ws.read(-2).

Die Funktionread()Beschreibung des Puffers: Wenn die Daten, die durch das ws-Protokoll geschoben werden, lange Intervalle zwischen der Strategieread()Die Datenstruktur des Puffers ist eine Warteschlange mit einer oberen Grenze von 2000. Nach Überschreitung von 2000 werden die neuesten Daten in den Puffer eingegeben und die ältesten Daten gelöscht.

SzenarienReadFunktionsparameter Keine Parameter Parameter: -1 Parameter: -2 Parameter: 2000 (Einheit: ms)
Buffer hat bereits Daten. Die ältesten Daten sofort zurückgeben Die ältesten Daten sofort zurückgeben Gib die neuesten Daten sofort zurück. Die ältesten Daten sofort zurückgeben
Keine Daten im Puffer Zurückgeben der Daten, wenn Daten blockiert sind Null sofort zurückgeben Null sofort zurückgeben Warten Sie für 2000ms, Null zurückgeben, wenn es keine Daten gibt, die Daten zurückgeben, wenn es Daten
Ws Verbindung ist getrennt oder die untere Schicht ist wieder verbunden Die Funktion read() gibt null zurück, d.h.: , und die Funktion write() gibt 0 zurück. Wenn diese Situation erkannt wird, kann die Funktion close() verwendet werden, um die Verbindung zu schließen. Wenn die Wiederverbindung automatisch eingestellt ist, muss sie nicht geschlossen werden, und die untere Schicht des Systems wird automatisch wieder verbunden.
  • Unterstützung des Protokolls wss (WebSocket) Zugriff auf Binance Websocket-Marktoberfläche:

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

    Zugang zu OKX Websocket Marktoberfläche:

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

    Zugriff auf die Huobi Websocket-Marktoberfläche:

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

    Überprüfungsschnittstelle der Websocket-Schnittstelle, die auf OKX zugreift:

      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)
    

Auto-Client_private = Wählen Sie ((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, Ich habe eine Frage. - Ich bin nicht derjenige. Passwort: , Zeitstempel: , Zeichen : - Ich weiß. }) "_json; Login[args][0][apiKey] = pAccessKey; Login[args][0][passphrase] = pPassphrase; Login[args][0][Zeitstempel] = ts; login[args][0][sign] = exchange.HMAC(sha256, base64, ts + GET + /users/self/verify, pSecretKey); Rückmeldung; - Ich weiß.

Nicht mehr verfügbar. SetErrorFilter ((zeitsausfall); Json postSubscribe = R"({ op: abonnieren, Ich bin nicht derjenige. Kanal: Positionen, instType: ANY Ich bin nicht hier. }) "_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, 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;
        }
    }
}

}

Nichtiger Ausgang Client_private.close (); Protokoll ((Ausfahrt); - Ich weiß.


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

Um den Rückgabeinhalt einer URL zu erhalten, wenn der zweite ParameterPostDataist in Form einer Zeichenkettea=1&b=2&c=abc, eingereicht vonPOST, andere durchPUTDer Parameter derPostDataist{method:'PUT', data:'a=1&b=2&c=abc'}.

DiePostDataParameter kann auch einJSON string.

Format des ParametersCookiesist:a=10; b=20; wobei jeder Parameter durch ein Semikolon getrennt wird;- Ich weiß. Format des ParametersHeadersist:User-Agent: Mobile\nContent-Type: text/html; wobei jeder Parameter durch einen neuen Zeilenzeichen getrennt wird\n.

Der zweite Parameter:PostData, können angepasst werden, zum Beispiel:HttpQuery("http://www.abc.com", {method:'PUT', data:'a=1&b=2&c=abc'})Anmerkung: Wenn Sie die Auslaufzeit für dieHttpQueryFunktion, können Sie dietimeoutAttribut in{method:'put',data:'a=1&B=2&C=ABC'}(Standard 60 Sekunden)

1 Sekunde Ausfallzeit setzen:HttpQuery("http://www.abc.com", {method:'PUT', data:'a=1&b=2&c=abc', timeout:1000})

Der dritte Parameter ist erforderlich, um die Zeichenfolge zu übergebenCookieAber...POSTist nicht erforderlich, um den zweiten Parameter auf null zu setzen. Während des Simulationstests, da die URL nicht simuliert werden kann, gibt die Funktion eine feste Zeichenfolge zurückDummy Data. Sie können diese Schnittstelle verwenden, um SMS zu senden oder mit anderen API-Schnittstellen zu interagieren.

GETBeispiel für den Aufruf einer Methode:HttpQuery("http://www.baidu.com"). POSTBeispiel für den Aufruf einer Methode:HttpQuery("http://www.163.com", "a=1&b=2&c=abc").

Einladungsbeispiel für die RückgabeHeader:

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}
  • Die FunktionHttpQueryverwendet die Proxy-Einstellungen:

    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/");
    }
    
  • Die FunktionHttpQueryist eine asynchrone VersionHttpQuery_GoDie Kommission Die Verwendung ist ähnlich wie die Funktionexchange.Go, wie z. B. asynchron auf die öffentliche Schnittstelle der Börse zuzugreifen, um aggregierte Marktdaten zu erhalten.

    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
    
  • Die Verwendung der FunktionHttpQuery(...)im Rückprüfungssystem: Die Daten können durchHttpQuery(...)Anfragen (nur Unterstützung)GETIn den meisten Fällen wird die Anzahl der Anfragen im Backtest-System mit einer Höchstzahl von 20 angezeigt.HttpQuery(...)Die Daten werden von Access zwischenspeichert, während die FunktionHttpQuery(...)gibt die zwischengespeicherten Daten beim zweiten Zugriff auf dieselbe URL zurück (keine tatsächlichen Webanfragen mehr).

    Wir können ein Serviceprogramm auf einem Server oder einem Gerät ausführen, das auf die Anfragen reagiert, die vonHttpQuery(...)in dem Strategieprogramm, und das Serviceprogramm in der Testsprache Go ist wie folgt dargestellt:

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

    Die Funktion verwendenHttpQuery(...)für die Übermittlung von Anfragen während der Strategie-Backtesting:

    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

    Es unterstützt die Transcodierung der Antwortdaten in der Anfrage und unterstützt auch die gemeinsame Codierung. Angabe derPostDataParameter:{method: "GET", charset: "GB18030"}kann das Transcodieren der Antwortdaten (GB18030) realisieren.

Verschlüsselung

Encode(algo, inputFormat, outputFormat, data, keyFormat, key string), die Funktion kodiert die Daten nach den übergebenen Parametern und gibt einen Zeichenfolgewert zurück.

Der Parameteralgoist der Algorithmus, der für die Codierung berechnet wird und auf: raw (kein Algorithmus), 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 festgelegt werden kann.dataDie Daten, die verarbeitet werden sollen, sindinputFormat/outputFormat/keyFormatParameter unterstützen Codierungsmethoden wieraw, hex, base64undstring- Ich weiß. Wenn diekeyFormatParameter ist nicht leer, diekeyParameter wird für die Verschlüsselung (HMAC) verwendet, ansonsten wird der StandardkeyWenn die ` `