FMZ Zwischengeschulung

Schriftsteller:Das Gras, Erstellt: 2019-04-12 14:28:19, Aktualisiert: 2024-02-05 20:07:56

[TOC]

img

Dieses Tutorial wird mehr Details über die FMZ-Plattform, mehr praktische Fähigkeiten zur Verwendung von API abdecken.

Nachdem Sie das gesamte Tutorial gelernt haben, werden Sie FMZ voll ausnutzen und in der Lage sein, maßgeschneiderte, effizientere und komplexere Strategien zu schreiben.

1.Fügen Sie mehrere Börsen hinzu und handeln Sie mit mehreren Symbolen

Sie können auf mehreren Börsen und mehreren Symbolen innerhalb eines Roboter leicht handeln.

  • Wenn der Roboter gestartet wird, fügen Sie eine oder mehrere Schalter hinzu.
  • Die API kann so genannt werdenexchange.GetTicker()wenn eine Umtauschstelle hinzugefügt wird
  • Wenn mehrere Börsen hinzugefügt werden, wird die API wieexchanges[0].GetTicker(), exchanges[1].GetTicker() img
  • Sie können den gleichen Austausch mit verschiedenen Symbolen hinzufügen.img
  • Sie können das Symbol ändern, das mitexchangedurch VerwendungIOFunktion
var symbols = ["BTC_USDT", "LTC_USDT", "EOS_USDT", "ETH_USDT", "BCC_USDT"]
var buyValue = 1000
function main(){
  for(var i=0;i<symbols.length;i++){
      exchange.IO("currency", symbols[i]) // It is always valid until the next change
      var ticker = exchange.GetTicker()
      var amount = _N(buyValue/ticker.Sell, 3)
      exchange.Buy(ticker.Sell, amount)
      Sleep(1000)
  }
}

2.TradeFutures und Swap-Kontrakte

Bisher unterstützt FMZ alle großen Futures-Börsen wie OKEX, HuobiDM, BitMEX, GateIO und Deribit sowie deren Swap-Kontrakte.

Um Futures auf FMZ zu handeln, müssen Sie zuerst eine Futures-Börse hinzufügen, das Symbol beim Starten des Bots einstellen und den Vertragstyp in Ihrem Code einstellen.

Wenn eine Börse sowohl Spot als auch Futures unterstützt, sollten sie dem FMZ separat hinzugefügt werden.img

Das Bild unten zeigt, wie man das Futures-Symbol auf BTC setzt, wenn man den Bot startet.img

Im Folgenden wird beschrieben, wie Sie einen Vertragstyp für jede Börse festlegen.

  • Das ist OK.
    exchange.SetContractType("swap")        
    exchange.SetContractType("this_week")   
    exchange.SetContractType("next_week")  
    exchange.SetContractType("quarter")   
  • HuobiDM
    exchange.SetContractType("this_week")   
    exchange.SetContractType("next_week")  
    exchange.SetContractType("quarter")     
  • BitMEX
    exchange.SetContractType("XBTUSD")  
    exchange.SetContractType("XBTM19") 
  • Schnittstelle
    exchange.SetContractType("swap")    
  • Deribit
    exchange.SetContractType("BTC-PERPETUAL")  
    exchange.SetContractType("BTC-27APR18")

3.Über die Rückprüfung

Grundlegende Einführung

FMZ verfügt über zwei Backtestmodi:real tickundsimulate tick. Die tatsächliche Tick-Ebene enthält die gesamten vollendeten historischen Daten (ein Tick pro Sekunde), so dass die Rückprüfungsergebnisse zuverlässiger sind. Die Simulationsstufe verwendet die Daten der Historie Klines im Intervall, das von Ihrer Strategie verwendet wird. Die Tick-Ebenen innerhalb einer Kline werden durch einen Algorithmus erzeugt, der mit MT4 identisch ist.https://www.mql5.com/en/articles/75In der Zwischenzeit kann ein kürzeres Intervall als Basis-Kline gewählt werden, um Zecken zu erzeugen. Ein kürzerer Kline-Intervall im Simulations-Tick-Modus ist ein Kompromiss zwischen Genauigkeit und Testgeschwindigkeit.

Backtestkonfiguration

Hier sind die Standardeinstellungen:imgVerborgene Steche:img

Backtest-Ergebnis

img

4.Fehlertoleranz

Wenn Funktionen aufgerufen werden, die auf die Exchange-API zugreifen (z. B.GetTicker, Buy, CancelOrder, etc...), können Sie aufgrund eines Exchange-Serverproblems, falscher Parameter, Netzwerkübertragungsproblems usw. einen Zugriffsfehler erhalten.nullSie müssen also wissen, wie man mit Fehlern umgeht.

Wo liegt der Fehler?

Der Bot wird eine Fehlermeldung zurückgeben, wenn ein Fehler auftritt.{"result":false,"error_code":20049}wird beim Anruf zurückgegebenexchange.GetAccount()auf OKEX.OKEX 20049Hier ist das Ergebnis:imgSie können auch den Fehlercode auf Exchange API Doc überprüfen, wieOKEX Fehlercode für Futures

Fehler bei der Abwicklung

Sie sollten sich überlegen, wie Sie mit Fehlern umgehen, wenn Sie den Strategiecode schreiben.

 // 1.Deal when the result is null
 var ticker = exchange.GetTicker()
 while(ticker == null){
     Log('GetTicker error')
     Sleep(100)
     ticker = exchange.GetTicker()
 }
 Log(ticker.Last);
 // 2.Refer when the result is not null
 var ticker = exchange.GetTicker()
 if(!ticker){
     Log(ticker.Last)
 }
 // 3._C() fucntion retry
 var ticker = _C(exchange.GetTicker) // can't  apply _C to CancelOrder, Why?
 Log(ticker.Last)
 // 4. try catch
 try{
     var ticker = exchange.GetTicker()
     Log(ticker.Last)
 }
 catch(err){
     Log('GetTicker error: ', err)
     Log(GetLastError()) //literal means, get last error
 } 

5.Direkte Verbindung zur Börse

FMZ wickelt alle verschiedenen Austauschdaten in ein und dasselbe Format, was es einfacher macht, eine plattformübergreifende Strategie zu schreiben.

GetRawJSON

Gib den ursprünglichen Inhalt (String) zurück, der durch die letzte REST-API-Anfrage zurückgegeben wurde, die verwendet werden kann, um die Rohinformationen selbst zu analysieren.

function main(){
    var account = exchange.GetAccount() //the account doesn't contain all data returned by the request
    var raw = JSON.parse(exchange.GetRawJSON())//raw data returned by GetAccount()
    Log(raw)
}

HttpQuery

Finden Sie alle Details überHttpQueryaufSie werden von den zuständigen Behörden des Mitgliedstaats, in dem sie sich befinden, angezeigt.

HttpQuerygibt die Rohdaten dieser Anfrage zurück, die zuerst analysiert werden sollten.

//FMZ doesn't have a standard function for exchangeInfo that return the trading-information about all symbols. 
var exchangeInfo = JSON.parse(HttpQuery('https://api.binance.com/api/v1/exchangeInfo'))
Log(exchangeInfo) // FMZ doesn't have a standard function for this API
var ticker = JSON.parse(HttpQuery('https://api.binance.com/api/v1/ticker/24hr'))
Log(ticker)

Für diese öffentlichen APIs,HttpQueryDas ist eine wirklich nützliche Funktion.HttpQueryunterstützt nur JavaScript, für Python, mit derurlib2oderrequestSie haben die Möglichkeit, die Web-Library zu verwenden, um HTTP-Anfragen direkt zu senden.

Zwischenzeit

Für diese privaten APIs, mitHttpQuerywird sehr kompliziert sein, weil Sie mit API-Schlüssel, Zeichen, Hash, usw. umgehen müssen.IOist eine praktische Funktion für diesen Zustand, überprüfen Sie es aufSiehe auch Abschnitt 6.2.3.. IOIn diesem Teil konzentrieren wir uns nur auf den Zugriff auf private APIs.

Die Verwendung dieser Funktion erfordert zunächst das Verständnis der ursprünglichen API der Börse. Im Folgenden finden Sie die Schritte, um eine Stop-Order zu erstellen, die von FMZ auf BitMEX nicht unterstützt wird.

Der endgültige JavaScript-Code:

var id = exchange.IO("api", "POST", "/api/v1/order", "symbol=XBTUSD&side=Buy&orderQty=1&stopPx=4000&ordType=Stop")

6.Verwenden Sie Websocket

Grundsätzlich unterstützen alle digitalen Währungsaustauschstellen das Senden von Marktdaten über Websocket, und einige Börsen unterstützen sogar das Aktualisieren von Kontoinformationen. Verglichen mit der Rest-API hat Websocket im Allgemeinen die Vorteile geringer Latenzzeit, hoher Frequenz und ist nicht durch die Anforderungsfrequenz der Plattform Rest-API begrenzt. Der Nachteil ist, dass er unterbrochen werden kann und die Verarbeitung nicht intuitiv ist.

Für JavaScript können SieDialFunktion, um sich mit Websocket zu verbinden. Für Python können SieDialoderwebsocket_client libray.

Dieses Tutorial konzentriert sich auf die Verbindung von Websockets mit dem JavaScript undDialDie Funktion Dial wurde mehrmals aktualisiert, um die verschiedenen Anwendungen zu erweitern. Dieses Tutorial zeigt die websocketbasierte Ereignis-gesteuerte Strategie und wie man sich mit mehreren Börsen verbindet.

Verbunden mit Websocket

  • 1.In den meisten Fällen können Sie sich direkt verbinden.Hier ist ein Beispiel für die Verbindung mit Binance all ticker.
    var client = Dial("wss://stream.binance.com:9443/ws/!ticker@arr")
    
  • 2.Für die zurückgegebenen Daten des komprimierten Formats müssen diese zum Zeitpunkt des Anschlusses angegeben werden.compressbedeutet, dass die Daten in komprimiertem Format sind, und der Parametermodestellt dar, ob das Senden oder Empfangen komprimiert ist. Ein Beispiel für die Verbindung mit OKEX
    var client = Dial("wss://real.okex.com:10441/websocket?compress=true|compress=gzip_raw&mode=recv")
    
  • 3.Die Dial-Funktion unterstützt die automatische Wiederverbindung, die durch die zugrunde liegende Go-Sprache durchgeführt wird. Für die Anfrage ist der Dateninhalt bereits in der URL enthalten, wie zum Beispiel bei Biannce, dies ist praktisch und empfehlenswert. Für diejenigen, die eine Abonnementnachricht senden müssen, können Sie die Wiederverbindung selbst durchführen.
    var client = Dial("wss://stream.binance.com:9443/ws/!ticker@arr?reconnect=true")
    
  • 4.Einige Börsen Abonnement-Kanäle sind in der URL enthalten, wie Binance, aber einige erfordern, dass Benutzer abonnierte Kanäle senden, wie Coinbase:
    var client = Dial("wss://ws-feed.pro.coinbase.com", 60)
    client.write('{"type": "subscribe","product_ids": ["BTC-USD"],"channels": ["ticker","heartbeat"]}')
    

Daten empfangen

Im Allgemeinen können die Daten von Websocket kontinuierlich ohne Schlaf in einer unendlichen Schleife gelesen werden.

function main() {
    var client = Dial("wss://stream.binance.com:9443/ws/!ticker@arr")
    while (true) {
        var msg = client.read() //receve data from client
        var data = JSON.parse(msg) //change raw string to js object
        // do something, don't need sleep. 
    }
}

Der zugrunde liegende Docker speichert alle Daten in der Warteschlange und gibt dann die ersten zurück, wenn das Programm aufruftread. Die Netzwerkoperationen des Roboters wieBuy,GetAccount,CancelOrderDie Daten, die wir in den letzten Jahren erhoben haben, sind in der Regel nur auf die neuesten Daten angewiesen.

Dieread()Funktion gibt die ältesten Daten in der Warteschlange zurück, wenn keine Argumente vorhanden sind, und blockiert, wenn keine Daten vorhanden sind (das Programm wird hier pausiert).read(-2)die neuesten Daten unverzüglich zurückzugeben undnullWenn keine Daten in der Warteschlange sind, wird das Programm nicht pausiert.

Verbindung mit mehreren Websockets

In diesem Fall ist es offensichtlich, dass das Programm einfach nicht verwenden kannread()Der Grund dafür ist, dass eine Börse blockiert und auf neue Daten wartet, und eine andere Börse ihre eigenen neuen Daten nicht sofort empfängt.

function main() {
    var binance = Dial("wss://stream.binance.com:9443/ws/!ticker@arr")
    var coinbase = Dial("wss://ws-feed.pro.coinbase.com")
    coinbase.write('{"type": "subscribe","product_ids": ["BTC-USD"],"channels": ["ticker","heartbeat"]}')
    while (true) {
        var msgBinance = binance.read(-1)
        var msgCoinbase = coinbase.read(-1)
        if(msgBinance){
            // Binance has new data
        }
        if(msgCoinbase){
            // coinbase has new data
        }
        Sleep(1) // just sleep 1ms
    }
}

Allgemeiner Rahmen für die Nutzung von Websockets

Da die Push-Daten bereits verwendet wurden, wird das Programm natürlich als ereignisgesteuerter Typ geschrieben, wobei auf die API-Anforderungsfrequenz geachtet wird.

var tradeTime = Date.now()
var accountTime = Date.now()
function trade(data){
    if(Date.now() - tradeTime > 2000){//only trade once within 2s
        tradeTime = Date.now()
        //trading code
    }
}
function GetAccount(){
    if(Date.now() - accountTime > 5000){//only get account once within 5s
        accountTime = Date.now()
        return exchange.GetAccount()
    }
}
function main() {
    var client = Dial("wss://stream.binance.com:9443/ws/!ticker@arr|reconnect=true")
    while (true) {
        var msg = client.read()
        var data = JSON.parse(msg)
        var account = GetAccount()
        trade(data)
    }
}

Alle Prameter

Die Parameter derDial(Address, Timeout): Timeout: Ausfallzeit der Verbindung Die Adresse kann von anderen Parametern, die mit&. Adresse und Parameter werden durch|,

Parameter Beschreibung
Kompressen Komprimierungsmethode, kanngzip_raw, gzip. OKEX verwendetgzip_raw
Modus kann seindualbedeutet, dass sowohl der Sende als auch der Empfang komprimiert werden müssen,sendbedeutet, dass sie komprimiert werden müssen undrecvbedeutet empfangen.
Stellvertreter Proxy-Einstellungen für ss5.socks5://name:pwd@192.168.0.1:1080
Wiederanschluss Reconnect=trueum eine Wiederaufnahme zu ermöglichen
Abstand intervalist das Wiederversuchsintervall, Standard ist 1000ms
Nutzlast Die Abonnementnachricht, die gesendet werden muss, wenn wss wieder verbunden wird

Die Parameter derread()Die Kommission: Als die Websocket-Verbindung abgerissen wurde,read()wird eine leere Zeichenfolge zurückgeben.

Parameter Keine -1 -2 2000
Schlange ist nicht leer Rückgabe der ältesten Daten sofort Rückgabe der ältesten Daten sofort Rückgabe der letzten Daten sofort Rückgabe der ältesten Daten sofort
Schlange ist leer Blockieren bis neue Daten zurück Rückkehrnullsofort Rückkehrnullsofort Warten Sie weniger als 2000 ms, bis neue Daten zurück, andernfalls zurücknull

Die Anwendung vonclose()Die Kommission Schließen Sie die Websocket-Verbindung.

function main() {
    var client = Dial("wss://stream.binance.com:9443/ws/!ticker@arr|reconnect=true")
    client.close()
}
    

7.Asynchrone oder Mehrthreaded

Sie haben vielleicht bemerkt, dass alle Codes, die wir jetzt haben, einzelner Thread, sequentielle Ausführung sind.GODas ist sehr begrenzt.Gowenn man sich wirklich um Verzögerungen und den Zeitverbrauch jeder API-Anfrage kümmert.

Auswechselung.Go (Methode, Args)

Methode: ein Funktionsname. Die Argumente der Methode.

Liste der unterstützten FunktionenGetTicker, GetDepth, GetTrades, GetRecords, GetAccount, GetOrders, GetOrder, CancelOrder, Buy, Sell, GetPosition.

Ein Beispiel für JavaScript:

function main(){
    var a = exchange.Go("GetTicker"); //GetTicker Asynchronous multithreaded execution
    var b = exchange.Go("GetDepth");
    var c = exchange.Go("Buy", 1000, 0.1);
    var d = exchange.Go("GetRecords", PERIOD_H1);
    // The above four operations are concurrent multi-threaded asynchronous execution, will not block and immediately return
    var ticker = a.wait(); // Call wait method wait for return to asynchronous get ticker result
    var depth = b.wait(); // Return depth, it is also possible to return null if it fails
    var orderId = c.wait(1000); // Return the order number, 1 second timeout, timeout returns undefined, this object can continue to call wait until the last wait timeout
    var records = d.wait(); // Wait for K-line result
    var ret = d.wait();  // Here waits for an asynchronous operation that has waited and ended, returns null, and logs an error message.
}

wait()Funktion muss nachGoFunktion, andernfalls wird sich die Thread-Ressource bis 2000 ansammeln und einen Fehler zurückgeben.

8.Tabellen und Diagramme

LogStatusund Tabellen

LogStatus wird eine Nachricht oder Tabellen auf der Statusleiste der Bots protokollieren, wird jedes Mal aktualisiert.

//Normal uses of LogStatus
LogStatus(" This is a normal status prompt")
LogStatus(" This is a red font status prompt #ff0000")
LogStatus(" This is a multi-line status message\n I'm the second line")

LogStatus kann Tabellen auf Ihrer Roboterseite protokollieren.`Sie werden von der Kommission und der Kommission in Zusammenarbeit mit den Mitgliedstaaten und der Kommission geprüft.

var table = {type: 'table', title: ' Account information support color #ff0000', cols: ['BTC', 'ETH', 'USDT'], rows: [ ['free', 1, 2000], ['frozen', 0, 3000]]}
LogStatus('`' + JSON.stringify(table)+'`')
//Another example, information can also appear in multiple lines:
LogStatus("First line message\n" + JSON.stringify(table)+"`\n third line message")
//Log multiple tables in a group, switching by TAB:
var table1 = {type: 'table', title: ' Account information 1', cols: ['BTC', 'ETH', 'USDT'], rows: [ ['free', 1, 2000], ['frozen', 0, 3000]]}
var table2 = {type: 'table', title: ' Account information 2', cols: ['BTC', 'ETH', 'USDT'], rows: [ ['free', 1, 2000], ['frozen', 0, 3000]]}
LogStatus('`' + JSON.stringify([table1, table2])+'`')

Schaubild

Zeichnen Sie Zahlen auf der Seite für Robotern. Chartunterstützung HighStocks und HighCharts, überprüfenhttps://www.highcharts.com/demoundhttps://www.highcharts.com/stock/demoFür weitere Beispiele. Das Chart-Objekt hat eine__isStockAttribut, das im Original nicht vorhanden ist__isStockist falsch, wird das Diagramm als HighCharts angezeigt.__isStockist wahr, wird das Diagramm als HighStocks angezeigt.reset()um die Daten zu löschen.

Ein JavaScript-Beispiel für die Verwendung von Chart, um die Preise von zwei Symbolen zu ziehen:

// This chart is an object in the JS language. Before using the Chart function, we need to declare an object variable chart that configures the chart.
var chart = {
    // Whether the mark is a general chart, if you are interested, you can change it to false and run it.
    __isStock: true,
    tooltip: {xDateFormat: '%Y-%m-%d %H:%M:%S, %A'},    // Zoom tool
    title : { text : 'Spread Analysis Chart'},          // title
    rangeSelector: {                                    // Selection range
        buttons:  [{type: 'hour',count: 1, text: '1h'}, {type: 'hour',count: 3, text: '3h'}, {type: 'hour', count: 8, text: '8h'}, {type: 'all',text: 'All'}],
        selected: 0,
        inputEnabled: false
    },
    xAxis: { type: 'datetime'},                         // The horizontal axis of the coordinate axis is the x axis and the current setting type is :time
    yAxis : {                                           // The vertical axis of the axis is the y axis, and the default value is adjusted with the data size.
        title: {text: 'Spread'},                        // title
        opposite: false,                                // Whether to enable the right vertical axis
    },
    series : [                                          // Data series, this attribute is saved for each data series (line, K-line graph, label, etc...)
        {name : "line1", id : "Line 1,buy1Price", data : []},  // The index is 0, the data array is stored in the index series of data
        {name : "line2", id : "Line 2,lastPrice", dashStyle : 'shortdash', data : []},
        // The index is 1, dashStyle is set: 'shortdash' ie: Set the dotted line.
    ]
};
function main(){
    var ObjChart = Chart(chart);                      // Call the Chart function to initialize the chart.
    ObjChart.reset();                                 // Empty the chart
    while(true){
        var nowTime = new Date().getTime();           // Get the timestamp of this poll, which is a millisecond timestamp. Used to determine the position of the X axis written to the chart.
        var tickerOne = _C(exchanges[0].GetTicker);   // Get market data
        var tickerTwo = _C(exchanges[1].GetTicker);
        ObjChart.add([0, [nowTime, tickerOne.Last]]); // Use the timestamp as the X value and buy the price as the Y value to pass the index 0 data sequence.
        ObjChart.add([1, [nowTime, tickerTwo.Last]]); // Same as above
        ObjChart.update(chart);                       // Update the chart to show it.
        Sleep(2000);
    }
}

Unterstützt die Anzeige mehrerer Figuren, ein vollständiges Beispiel:https://www.fmz.com/strategy/136056 img

9.Strategievorlage

Template ist eine Bibliothek, die viele erweiterte Funktionen umfasst, die es einfacher machen, Ihre Strategie zu schreiben. Um eine Vorlage zu verwenden, sollten Sie zuerst die vorlage kopieren, die Sie benötigen. Nehmen Sie JavaScript Plot Bibliothek zum Beispiel, kopieren Sie es vonhttps://www.fmz.com/strategy/27293und speichern. Dann wählen Sie es auf der Strategiebearbeitungsseite aus.imgDie Funktionen werden nach$.in der JavaScript-Vorlage und nachext.in der Python-Vorlage.

function main() {
    var isFirst = true
    while (true) {
        var records = exchange.GetRecords();
        if (records && records.length > 0) {
            $.PlotRecords(records, 'BTC')
            if (isFirst) {
                $.PlotFlag(records[records.length - 1].Time, 'Start', 'S')
                isFirst = false
                $.PlotHLine(records[records.length - 1].Close, 'Close')
            }
        }
        var ticker = exchange.GetTicker()
        if (ticker) {
            $.PlotLine('Last', ticker.Last)
            $.PlotTitle('Last ' + ticker.Last)
        }
        Sleep(60000)
    }
}

Hier ist ein weiteres einfaches Beispiel, das eine Plotvorlage verwendet:https://www.fmz.com/strategy/121917


Mehr

q25459768- Danke.

Das GrasIch arbeite an diesem Tutorial. Es wird ein paar Tage dauern, bis es fertig ist. Fühlen Sie sich frei, Fragen zu stellen.