Die Ressourcen sind geladen. Beförderung...

Lernen Sie, die Template-Klassenbibliothek zu entwerfen, um K-Zeilendaten der angegebenen Länge zu erhalten

Schriftsteller:FMZ~Lydia, Erstellt: 2023-06-29 17:27:59, Aktualisiert: 2023-09-18 19:33:33

img

Lernen Sie, die Template-Klassenbibliothek zu entwerfen, um K-Zeilendaten der angegebenen Länge zu erhalten

Bei der Konzeption von Trendstrategien ist oft eine ausreichende Anzahl von K-Linienbalken für die Berechnung der Indikatoren erforderlich.exchange.GetRecords()In den frühen Entwürfen von Kryptowährungs-Austausch-APIs gab es keine Unterstützung für die Paginierung in der K-Line-Schnittstelle, und die K-Line-Schnittstelle der Börse stellte nur eine begrenzte Menge an Daten zur Verfügung.

Die K-Line-Schnittstelle von Binances Kontrakt-API unterstützt Pagination. In diesem Artikel werden wir die Binance K-Line-API-Schnittstelle als Beispiel verwenden, um Ihnen beizubringen, wie Sie Pagination implementieren und die Anzahl der zu abrufenden Balken mit der FMZ-Plattformvorlagebibliothek angeben.

K-Line-Schnittstelle von Binance

K-Liniendaten

Die Öffnungszeit jeder K-Linie in derGET /dapi/v1/klinesDer Endpunkt kann als eindeutige Kennung betrachtet werden.

Das Gewicht des Antrags hängt vom Wert des Parameters LIMIT ab.

img

Parameter:

img

Zuerst müssen wir uns auf die API-Dokumentation der Exchange beziehen, um die spezifischen Parameter der K-Line-Schnittstelle zu verstehen. Wir können sehen, dass wir beim Aufrufen dieses K-Line-Endpunkts den Typ, den K-Line-Periode, den Datenbereich (Start- und Endzeit) und die Anzahl der Seiten usw. angeben müssen.

Da unsere Konstruktionsanforderung darin besteht, eine bestimmte Anzahl von K-Linie-Daten abzufragen, zum Beispiel die 1-Stunden-K-Linie, 5000 Stäbe von 1-Stunden-K-Linie-Daten vom aktuellen Moment in die Vergangenheit abzufragen, ist es offensichtlich, dass ein einziger API-Aufruf an die Börse die gewünschten Daten nicht abruft.

Um dies zu erreichen, können wir die Pagination implementieren und die Abfrage in Segmente vom aktuellen Moment zu einem bestimmten historischen Moment aufteilen. Da wir die gewünschte K-Liniendatenperiode kennen, können wir die Anfangs- und Endzeit für jedes Segment leicht berechnen. Wir können dann jedes Segment in Folge zum historischen Moment abfragen, bis wir genügend Balken abrufen. Der Ansatz klingt einfach, also lasst uns vorgehen und implementieren!

Entwurf JavaScript-Version der K-Line-Historische Datenvorlage für die Paginierte Abfrage

Schnittstellenfunktion für Entwurfsvorlagen:$.GetRecordsByLength(e, period, length).

/**
 * desc: $.GetRecordsByLength is the interface function of this template library, this function is used to get the K-line data of the specified K-line length
 * @param {Object} e - exchange object
 * @param {Int} period - K-line period, in seconds
 * @param {Int} length - Specify the length of the acquired K-line data, which is related to the exchange interface limits
 * @returns {Array<Object>} - K-line data
 */

Entwurf der Funktion$.GetRecordsByLength, die in der Regel in der Anfangsphase der Strategieausführung verwendet wird, um Indikatoren auf der Grundlage einer langen Periode von K-Liniendaten zu berechnen. Sobald diese Funktion ausgeführt wurde und ausreichend Daten erhalten wurden, müssen nur neue K-Liniendaten aktualisiert werden. Es ist nicht notwendig, diese Funktion erneut aufzurufen, um übermäßig lange K-Liniendaten abzurufen, da dies zu unnötigen API-Aufrufen führen würde.

Daher ist auch eine Schnittstelle für nachfolgende Datenaktualisierungen zu entwerfen:$.UpdataRecords(e, records, period).

/**
 * desc: $.UpdataRecords is the interface function of this template library, this function is used to update the K-line data.
 * @param {Object} e - exchange object
 * @param {Array<Object>} records - K-line data sources that need to be updated
 * @param {Int} period - K-line period, needs to be the same as the K-line data period passed in the records parameter
 * @returns {Bool}  - Whether the update was successful
 */

Der nächste Schritt ist die Implementierung dieser Schnittstellenfunktionen.

/**
 * desc: $.GetRecordsByLength is the interface function of this template library, this function is used to get the K-line data of the specified K-line length
 * @param {Object} e - exchange object
 * @param {Int} period - K-line period, in seconds
 * @param {Int} length - Specify the length of the acquired K-line data, which is related to the exchange interface limits
 * @returns {Array<Object>} - K-line data
 */
$.GetRecordsByLength = function(e, period, length) {
    if (!Number.isInteger(period) || !Number.isInteger(length)) {
        throw "params error!"
    }

    var exchangeName = e.GetName()
    if (exchangeName == "Futures_Binance") {
        return getRecordsForFuturesBinance(e, period, length)
    } else {
        throw "not support!"
    }
}

/**
 * desc: getRecordsForFuturesBinance, the specific implementation of the function to get K-line data for Binance Futures Exchange
 * @param {Object} e - exchange object
 * @param {Int} period - K-line period, in seconds
 * @param {Int} length - Specify the length of the acquired K-line data, which is related to the exchange interface limits
 * @returns {Array<Object>} - K-line data
 */
function getRecordsForFuturesBinance(e, period, length) {
    var contractType = e.GetContractType()
    var currency = e.GetCurrency()
    var strPeriod = String(period)

    var symbols = currency.split("_")
    var baseCurrency = ""
    var quoteCurrency = ""
    if (symbols.length == 2) {
        baseCurrency = symbols[0]
        quoteCurrency = symbols[1]
    } else {
        throw "currency error!"
    }

    var realCt = e.SetContractType(contractType)["instrument"]
    if (!realCt) {
        throw "realCt error"
    }
    
    // m -> minute; h -> hour; d -> day; w -> week; M -> month
    var periodMap = {}
    periodMap[(60).toString()] = "1m"
    periodMap[(60 * 3).toString()] = "3m"
    periodMap[(60 * 5).toString()] = "5m"
    periodMap[(60 * 15).toString()] = "15m"
    periodMap[(60 * 30).toString()] = "30m"
    periodMap[(60 * 60).toString()] = "1h"
    periodMap[(60 * 60 * 2).toString()] = "2h"
    periodMap[(60 * 60 * 4).toString()] = "4h"
    periodMap[(60 * 60 * 6).toString()] = "6h"
    periodMap[(60 * 60 * 8).toString()] = "8h"
    periodMap[(60 * 60 * 12).toString()] = "12h"
    periodMap[(60 * 60 * 24).toString()] = "1d"
    periodMap[(60 * 60 * 24 * 3).toString()] = "3d"
    periodMap[(60 * 60 * 24 * 7).toString()] = "1w"
    periodMap[(60 * 60 * 24 * 30).toString()] = "1M"
    
    var records = []
    var url = ""
    if (quoteCurrency == "USDT") {
        // GET https://fapi.binance.com  /fapi/v1/klines  symbol , interval , startTime , endTime , limit 
        // limit maximum value:1500

        url = "https://fapi.binance.com/fapi/v1/klines"
    } else if (quoteCurrency == "USD") {
        // GET https://dapi.binance.com  /dapi/v1/klines  symbol , interval , startTime , endTime , limit
        // The difference between startTime and endTime can be up to 200 days.
        // limit maximum value:1500

        url = "https://dapi.binance.com/dapi/v1/klines"
    } else {
        throw "not support!"
    }

    var maxLimit = 1500
    var interval = periodMap[strPeriod]
    if (typeof(interval) !== "string") {
        throw "period error!"
    }

    var symbol = realCt
    var currentTS = new Date().getTime()

    while (true) {
        // Calculate limit
        var limit = Math.min(maxLimit, length - records.length)
        var barPeriodMillis = period * 1000
        var rangeMillis = barPeriodMillis * limit
        var twoHundredDaysMillis = 200 * 60 * 60 * 24 * 1000
        
        if (rangeMillis > twoHundredDaysMillis) {
            limit = Math.floor(twoHundredDaysMillis / barPeriodMillis)
            rangeMillis = barPeriodMillis * limit
        }

        var query = `symbol=${symbol}&interval=${interval}&endTime=${currentTS}&limit=${limit}`
        var retHttpQuery = HttpQuery(url + "?" + query)
        
        var ret = null 
        try {
            ret = JSON.parse(retHttpQuery)
        } catch(e) {
            Log(e)
        }
        
        if (!ret || !Array.isArray(ret)) {
            return null
        }

        // When the data cannot be searched because it is beyond the searchable range of the exchange
        if (ret.length == 0 || currentTS <= 0) {
            break
        }

        for (var i = ret.length - 1; i >= 0; i--) {
            var ele = ret[i]
            var bar = {
                Time : parseInt(ele[0]),
                Open : parseFloat(ele[1]),
                High : parseFloat(ele[2]),
                Low : parseFloat(ele[3]), 
                Close : parseFloat(ele[4]),
                Volume : parseFloat(ele[5])
            }

            records.unshift(bar)
        }

        if (records.length >= length) {
            break
        }

        currentTS -= rangeMillis
        Sleep(1000)
    }

    return records
}

/**
 * desc: $.UpdataRecords is the interface function of this template library, this function is used to update the K-line data.
 * @param {Object} e - exchange object
 * @param {Array<Object>} records - K-line data sources that need to be updated
 * @param {Int} period - K-line period, needs to be the same as the K-line data period passed in the records parameter
 * @returns {Bool}  - Whether the update was successful
 */
$.UpdataRecords = function(e, records, period) {
    var r = e.GetRecords(period)
    if (!r) {
        return false 
    }

    for (var i = 0; i < r.length; i++) {
        if (r[i].Time > records[records.length - 1].Time) {
            // Add a new Bar
            records.push(r[i])
            // Update the previous Bar
            if (records.length - 2 >= 0 && i - 1 >= 0 && records[records.length - 2].Time == r[i - 1].Time) {
                records[records.length - 2] = r[i - 1]
            }            
        } else if (r[i].Time == records[records.length - 1].Time) {
            // Update Bar
            records[records.length - 1] = r[i]
        }
    }
    return true
}

In der Vorlage haben wir nur Unterstützung für die Binance Futures-Kontrakt K-Line-Schnittstelle implementiert, dh diegetRecordsForFuturesBinanceEs kann auch erweitert werden, um K-Line-Schnittstellen anderer Kryptowährungsbörsen zu unterstützen.

Testsitzung

Wie Sie sehen können, ist der Code für die Implementierung dieser Funktionalitäten in der Vorlage nicht umfangreich, insgesamt weniger als 200 Zeilen. Nach dem Schreiben des Vorlagecodes ist das Testen entscheidend und sollte nicht übersehen werden.

Um es zu testen, müssen Sie sowohl die JavaScript-Version von Pagination Query K-Line Historical Data Template als auch die Plot Library-Vorlagen in Ihre Strategiebibliothek kopieren (die in derStrategieplatzDann erstellen Sie eine neue Strategie und wählen Sie diese beiden Vorlagen aus.

img

img

Die Plot Library wird verwendet, weil wir die erhaltenen K-Liniendaten zur Beobachtung ziehen müssen.

function main() {
	LogReset(1)
	var testPeriod = PERIOD_M5
    Log("Current exchanges tested:", exchange.GetName())

    // If futures, you need to set up a contract
    exchange.SetContractType("swap")

    // Get K-line data of specified length using $.GetRecordsByLength
    var r = $.GetRecordsByLength(exchange, testPeriod, 8000)
    Log(r)

    // Use the Plot test for easy observation
    $.PlotRecords(r, "k")

    // Test data
    var diffTime = r[1].Time - r[0].Time 
    Log("diffTime:", diffTime, " ms")
    for (var i = 0; i < r.length; i++) {
        for (var j = 0; j < r.length; j++) {
            // Check the repeat bar
            if (i != j && r[i].Time == r[j].Time) {
                Log(r[i].Time, i, r[j].Time, j)
                throw "With duplicate Bar"
            }
        }
        
        // Check Bar continuity
        if (i < r.length - 1) {            
            if (r[i + 1].Time - r[i].Time != diffTime) {
                Log("i:", i, ", diff:", r[i + 1].Time - r[i].Time, ", r[i].Time:", r[i].Time, ", r[i + 1].Time:", r[i + 1].Time)
                throw "Bar discontinuity"
            }            
        }
    }
    Log("Test passed")

    Log("The length of the data returned by the $.GetRecordsByLength function:", r.length)

    // Update data
    while (true) {
        $.UpdataRecords(exchange, r, testPeriod)
        LogStatus(_D(), "r.length:", r.length)
        $.PlotRecords(r, "k")
        Sleep(5000)
    }
}

Hier benutzen wir die Linievar testPeriod = PERIOD_M5Dann können wir einen Plot-Test auf die langen K-Linie Daten durchführen, die von dervar r = $.GetRecordsByLength(exchange, testPeriod, 8000) interface.

    // Use the plot test for easy observation
    $.PlotRecords(r, "k")

Der nächste Test für die langen K-Liniendaten ist:

    // Test data
    var diffTime = r[1].Time - r[0].Time 
    Log("diffTime:", diffTime, " ms")
    for (var i = 0; i < r.length; i++) {
        for (var j = 0; j < r.length; j++) {
            // Check the repeat Bar
            if (i != j && r[i].Time == r[j].Time) {
                Log(r[i].Time, i, r[j].Time, j)
                throw "With duplicate Bar"
            }
        }
        
        // Check Bar continuity
        if (i < r.length - 1) {            
            if (r[i + 1].Time - r[i].Time != diffTime) {
                Log("i:", i, ", diff:", r[i + 1].Time - r[i].Time, ", r[i].Time:", r[i].Time, ", r[i + 1].Time:", r[i + 1].Time)
                throw "Bar discontinuity"
            }            
        }
    }
    Log("Test passed")
  1. Überprüfen Sie, ob es in den K-Liniendaten doppelte Balken gibt.
  2. Überprüfen Sie die Kohärenz der K-Liniendaten (ob die Zeitstempeldifferenz zwischen benachbarten Strippen gleich ist).

Nach Abschluss dieser Prüfungen überprüfen Sie, ob die Schnittstelle zur Aktualisierung der K-Liniendaten verwendet wird.$.UpdateRecords(exchange, r, testPeriod), funktioniert korrekt.

    // Update data
    while (true) {
        $.UpdataRecords(exchange, r, testPeriod)
        LogStatus(_D(), "r.length:", r.length)
        $.PlotRecords(r, "k")
        Sleep(5000)
    }

Dieser Code liefert kontinuierlich K-Liniendaten auf dem Strategie-Chart während des Live-Handels, so dass wir überprüfen können, ob die Aktualisierungen und Ergänzungen der K-Liniendaten korrekt funktionieren.

img

img

Mit den täglichen K-Line-Daten setzen wir es auf die Abgabe von 8000 Bars (wobei wir wissen, dass keine Marktdaten für 8000 Tage vorhanden sind).

img

Da es nur 1309 tägliche K-Linien gibt, vergleichen Sie die Daten auf den Wechselkursdiagrammen:

img

img

Sie können sehen, dass die Daten auch übereinstimmen.

Ende

Adresse der Vorlage:JavaScript-Version von Pagination Query K-Line historische DatenvorlageAdresse der Vorlage:Plot-Bibliothek

Die vorstehende Vorlage und der Strategiecode sind nur für den Lehr- und Lernzweck bestimmt, bitte optimieren und ändern Sie sie entsprechend den spezifischen Bedürfnissen des Live-Handels.


Verwandt

Mehr