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 :
##### 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
}
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
}
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
}
Für die Informationen über Positionen im Futures-Handel werden dieReihenfolgevon diesemPosition
Struktur 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 diePosition
Struktur-Array, zurückgegeben durch die Funktionexchange.GetPosition()
- Die Attribute in seiner Positionsdatenstruktur, wieFrozenAmount
, Profit
undMargin
, verschiedene Datendefinitionen können von verschiedenen Austauschobjekten zurückgegeben werden, wenn sieexchange.GetPosition()
Einige Börsen enthalten beispielsweise keine Position eingefrorenen Daten, dieFrozenAmount
ist 0. Wenn Sie einige Daten berechnen müssen, können Sie die Quelldaten im Attribut verwendenInfo
zur Berechnung und Analyse.
Version()
Gibt die aktuelle Versionnummer des Systems zurück. Gibt den Wert zurück: Zeichenfolge.
Sleep(Millisecond)
, Schlaffunktion, lässt das Programm für einen bestimmten Zeitraum pausieren.Millisecond
ist 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.000001
Eine Nanosekunde ist gleich1e-6
milliseconds.
Anmerkung:
Wenn Sie Strategien inPython
Sprache, die FunktionSleep(Millisecond)
Es wird nicht empfohlen, diese Funktion zu verwenden.time.time(second)
dertime
Bibliothek inPython
Denn wenn man die Funktion verwendettime.time(second)
In der Strategie wird das Strategieprogramm tatsächlich für eine bestimmte Anzahl von Sekunden warten (der Parametersecond
ist die zweite Zahl der Pause-Einstellung), was zu einem sehr langsamen Strategie-Backtest führt.
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
.
Mail(smtpServer, smtpUsername, smtpPassword, mailTo, title, body)
ist eine E-Mail-Sendungsfunktion. Parameterwert: alle sind von String-Typ. Rückgabewert: bool-Typ;true
nach erfolgreichem Versand zurückgeschickt wird.smtpServer
dient für den Versandpostfachsmtp
; smtpUsername
ist das Postfachkonto;smtpPassword
ist das STMP-Passwort des Postfachs;mailTo
ist das empfangende Postfachkonto;title
ist der Titel der gesendeten Post;body
ist 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_Go
Funktion ist eine asynchrone Version der FunktionMail
Die 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 vonsmtpServer
in der FunktionMail
für:ssl://xxxxx.com:xxx
Zum Beispiel die SMTP-SSL-Methode von QQmail:ssl://smtp.qq.com:465
odersmtp://xxxxx.com:xxx
.
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()
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()
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()
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:
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);
}
}
Die FunktionGetMeta()
Gibt den Wert vonMeta
wenn 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 derMeta
kann 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);
}
}
Dial(Address, Timeout)
, Original Socket-Zugriff, Stützentcp
, udp
, tls
undunix
- Parameterwert:Address
ist ein String-Typ; Einheit ist zweite; wenn die Zeit aus ist, die FunktionDial(...)
Gibt einen leeren Wert zurück.
Ausführliche Beschreibung derAddress
Parameter:
– | 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_raw undgzip , 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_raw nach 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 , send undrecv . dual ist bidirektional und sendet und empfängt komprimierte Daten.send ist, komprimierte Daten zu senden.recv ist, 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:1080 |
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=true ist 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=10000 ist 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 Funktionread
unterstützt folgende Parameter:
ws.read()
.ws.read(2000)
Der Timeout wird als zwei Sekunden (2000 Millisekunden) angegeben.websocket
Die Kommission
Übermittlung von Parametern-1
bedeutet, sofort zurückzukehren, unabhängig davon, ob eine Nachricht vorliegt, wie z. B.ws.read(-1)
- Ich weiß.
Übermittlung von Parametern-2
bedeutet, 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.
SzenarienRead Funktionsparameter |
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 |
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 ((
json getLogin ((String pAccessKey, String pSecretKey, String pPassphrase) {
Auto ts = std::to_string ((Unix)));
json Login = R"({
Nicht mehr verfügbar.
SetErrorFilter ((
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 ((
#### 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 ParameterPostData
ist in Form einer Zeichenkettea=1&b=2&c=abc
, eingereicht vonPOST
, andere durchPUT
Der Parameter derPostData
ist{method:'PUT', data:'a=1&b=2&c=abc'}
.
DiePostData
Parameter kann auch einJSON
string.
Format des ParametersCookies
ist:a=10; b=20
; wobei jeder Parameter durch ein Semikolon getrennt wird;
- Ich weiß.
Format des ParametersHeaders
ist: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 dieHttpQuery
Funktion, können Sie dietimeout
Attribut 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 übergebenCookie
Aber...POST
ist 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.
GET
Beispiel für den Aufruf einer Methode:HttpQuery("http://www.baidu.com")
.
POST
Beispiel 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 FunktionHttpQuery
verwendet 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 FunktionHttpQuery
ist eine asynchrone VersionHttpQuery_Go
Die 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)GET
In 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());
}
Es unterstützt die Transcodierung der Antwortdaten in der Anfrage und unterstützt auch die gemeinsame Codierung.
Angabe derPostData
Parameter:{method: "GET", charset: "GB18030"}
kann das Transcodieren der Antwortdaten (GB18030) realisieren.
Encode(algo, inputFormat, outputFormat, data, keyFormat, key string)
, die Funktion kodiert die Daten nach den übergebenen Parametern und gibt einen Zeichenfolgewert zurück.
Der Parameteralgo
ist der Algorithmus, der für die Codierung berechnet wird und auf: data
Die Daten, die verarbeitet werden sollen, sindinputFormat
/outputFormat
/keyFormat
Parameter unterstützen Codierungsmethoden wieraw
, hex
, base64
undstring
- Ich weiß.
Wenn diekeyFormat
Parameter ist nicht leer, diekey
Parameter wird für die Verschlüsselung (HMAC) verwendet, ansonsten wird der Standardkey
Wenn die ` `