avatar of 发明者量化-小小梦 发明者量化-小小梦
konzentrieren Sie sich auf Private Nachricht
4
konzentrieren Sie sich auf
1271
Anhänger

Lernen Sie, eine Vorlagenbibliothek zu entwerfen, um K-Line-Daten einer bestimmten Länge zu erhalten

Erstellt in: 2023-06-27 13:37:01, aktualisiert am: 2023-09-18 19:34:23
comments   0
hits   1285

Lernen Sie, eine Vorlagenbibliothek zu entwerfen, um K-Line-Daten einer bestimmten Länge zu erhalten

Lernen Sie, eine Vorlagenbibliothek zu entwerfen, um K-Line-Daten einer bestimmten Länge zu erhalten

Beim Entwurf einiger Trendstrategien ist für die Berechnung von Indikatoren häufig eine ausreichende Anzahl von K-Linien-Balken erforderlich. Hängt von der FMZ-Plattform-API ab:exchange.GetRecords()Die von der Funktion gelieferte Datenmenge undexchange.GetRecords()Es handelt sich um die Kapselung der K-Line-Schnittstelle der Vermittlungsstelle. Im frühen Design der API-Schnittstellen für Kryptowährungsbörsen gab es keine Paging-Abfrage, und die K-Line-Schnittstelle der Börse stellte nur eine begrenzte Datenmenge bereit, sodass die Anforderungen einiger Entwickler nach Indikatorberechnungen mit größeren Parametern nicht erfüllt werden konnten.

Die K-line-Schnittstelle der Binance-Vertrags-API unterstützt paginierte Abfragen. Dieser Artikel verwendet die Binance K-line-API-Schnittstelle als Beispiel, um Ihnen beizubringen, wie Sie eine paginierte Abfrage implementieren und die FMZ-Plattformvorlagenbibliothek angeben, um die Anzahl der Balken zu erhalten.

Binance K-Line-Schnittstelle

Lernen Sie, eine Vorlagenbibliothek zu entwerfen, um K-Line-Daten einer bestimmten Länge zu erhalten

Zuerst müssen Sie die Exchange-API-Dokumentation lesen, um die spezifischen Parameter der Schnittstelle anzuzeigen. Wir können sehen, dass beim Aufrufen dieser K-Line-Schnittstelle das Produkt, der K-Line-Zeitraum, der Datenbereich (Start- und Endzeit), die Seitenzahl usw. angegeben werden müssen.

Da unsere Entwurfsanforderung darin besteht, eine bestimmte Anzahl von K-Liniendaten abzufragen, z. B. die 1-Stunden-K-Linie abzufragen und von der aktuellen Zeit in die Vergangenheit zu pushen, beträgt die Anzahl 5.000 Balken. Auf diese Weise können Sie offensichtlich nicht die gewünschten Daten erhalten, indem Sie die Abfrage der Exchange-API-Schnittstelle nur einmal aufrufen.

Anschließend führen wir die Abfrage seitenweise durch und verarbeiten die Verarbeitung in Segmenten vom aktuellen Moment bis zu einem bestimmten Moment in der Historie. Solange wir den Zeitraum der erforderlichen K-Line-Daten kennen, ist es einfach, die Start- und Endzeit jedes Segments zu berechnen. Suchen Sie einfach der Reihe nach nach historischen Momenten, bis Sie genügend Takte gefunden haben. Die Idee klingt einfach, oder? Lasst es uns umsetzen!

Entwurf „JavaScript-Version der Paging-Abfrage-Vorlage für historische K-Line-Daten“

Designvorlagen-Schnittstellenfunktion:$.GetRecordsByLength(e, period, length)

/**
 * desc: $.GetRecordsByLength 是该模板类库的接口函数,该函数用于获取指定K线长度的K线数据
 * @param {Object} e - 交易所对象
 * @param {Int} period - K线周期,秒数为单位
 * @param {Int} length - 指定获取的K线数据的长度,具体和交易所接口限制有关
 * @returns {Array<Object>} - K线数据
 */

Design$.GetRecordsByLengthDiese Funktion wird normalerweise in der frühen Phase der Strategieausführung verwendet, wenn zur Berechnung des Indikators eine lange K-Linie erforderlich ist. Nachdem diese Funktion ausgeführt wurde, erhält sie ausreichend lange Daten und muss dann nur noch die neuen K-Line-Daten aktualisieren. Es ist nicht erforderlich, diese Funktion aufzurufen, um sehr lange K-Line-Daten zu erhalten, da dies zu unnötigen Schnittstellenaufrufen führen würde.

Daher ist es auch notwendig, eine Schnittstelle für spätere Datenaktualisierungen zu konzipieren:$.UpdataRecords(e, records, period)

/**
 * desc: $.UpdataRecords 是该模板类库的接口函数,该函数用于更新K线数据
 * @param {Object} e - 交易所对象
 * @param {Array<Object>} records - 需要更新的K线数据源
 * @param {Int} period - K线周期,需要和records参数传入的K线数据周期一致
 * @returns {Bool}  - 是否更新成功
 */

Der nächste Schritt besteht darin, diese Schnittstellenfunktionen zu implementieren.

/**
 * desc: $.GetRecordsByLength 是该模板类库的接口函数,该函数用于获取指定K线长度的K线数据
 * @param {Object} e - 交易所对象
 * @param {Int} period - K线周期,秒数为单位
 * @param {Int} length - 指定获取的K线数据的长度,具体和交易所接口限制有关
 * @returns {Array<Object>} - K线数据
 */
$.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 币安期货交易所获取K线数据函数的具体实现
 * @param {Object} e - 交易所对象
 * @param {Int} period - K线周期,秒数为单位
 * @param {Int} length - 指定获取的K线数据的长度,具体和交易所接口限制有关
 * @returns {Array<Object>} - K线数据
 */
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 -> 分钟; h -> 小时; d -> 天; w -> 周; M -> 月
    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 最大值: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
        // startTime 与 endTime 之间最多只可以相差200天
        // limit 最大值: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) {
        // 计算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
        }

        // 超出交易所可查询范围,查询不到数据时
        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 是该模板类库的接口函数,该函数用于更新K线数据
 * @param {Object} e - 交易所对象
 * @param {Array<Object>} records - 需要更新的K线数据源
 * @param {Int} period - K线周期,需要和records参数传入的K线数据周期一致
 * @returns {Bool}  - 是否更新成功
 */
$.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) {
            // 添加新Bar
            records.push(r[i])
            // 更新上一个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) {
            // 更新Bar
            records[records.length - 1] = r[i]
        }
    }
    return true
}

In der Vorlage implementieren wir nur die Unterstützung der Binance-Vertrags-K-Line-Schnittstelle, d. h.getRecordsForFuturesBinanceFunktion: Es kann auch erweitert werden, um K-Line-Schnittstellen anderer Kryptowährungsbörsen zu unterstützen.

Testen

Sie sehen, dass die Vorlage zur Implementierung dieser Funktionen nicht viel Code enthält, wahrscheinlich weniger als 200 Zeilen. Nachdem der Vorlagencode geschrieben wurde, ist ein Testen unbedingt erforderlich. Und für eine solche Datenerfassung müssen wir sie auch so gründlich wie möglich testen.

Der Test erfordert das Kopieren dieser “JavaScript-Version der Seitenabfrage K-line historische Datenvorlage” und der “Linienzeichnungsbibliothek”-Vorlage in Ihre eigene Strategiebibliothek (inStrategieplatzkann durchsucht werden in ). Dann erstellen wir eine neue Strategie und prüfen diese beiden Vorlagen:

Lernen Sie, eine Vorlagenbibliothek zu entwerfen, um K-Line-Daten einer bestimmten Länge zu erhalten

Lernen Sie, eine Vorlagenbibliothek zu entwerfen, um K-Line-Daten einer bestimmten Länge zu erhalten

Lernen Sie, eine Vorlagenbibliothek zu entwerfen, um K-Line-Daten einer bestimmten Länge zu erhalten

Die „Linienzeichnungsbibliothek“ wird verwendet, weil wir die erhaltenen K-Liniendaten zur Beobachtung zeichnen müssen.

function main() {
	LogReset(1)
	var testPeriod = PERIOD_M5
    Log("当前测试的交易所:", exchange.GetName())

    // 如果是期货则需要设置合约
    exchange.SetContractType("swap")

    // 使用$.GetRecordsByLength获取指定长度的K线数据
    var r = $.GetRecordsByLength(exchange, testPeriod, 8000)
    Log(r)

    // 使用画图测试,方便观察
    $.PlotRecords(r, "k")

    // 检测数据
    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++) {
            // 检查重复Bar
            if (i != j && r[i].Time == r[j].Time) {
                Log(r[i].Time, i, r[j].Time, j)
                throw "有重复Bar"
            }
        }
        
        // 检查Bar连续性
        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不连续"
            }            
        }
    }
    Log("检测通过")

    Log("$.GetRecordsByLength函数返回的数据长度:", r.length)

    // 更新数据
    while (true) {
        $.UpdataRecords(exchange, r, testPeriod)
        LogStatus(_D(), "r.length:", r.length)
        $.PlotRecords(r, "k")
        Sleep(5000)
    }
}

Hier verwenden wirvar testPeriod = PERIOD_M5Dieser Satz setzt die K-Linienperiode auf 5 Minuten und gibt an, dass 8000 Balken abgerufen werden sollen. Dann fürvar r = $.GetRecordsByLength(exchange, testPeriod, 8000)Die Schnittstelle gibt lange K-Liniendaten zum Zeichnen des Tests zurück:

    // 使用画图测试,方便观察
    $.PlotRecords(r, "k")

Als nächstes werden wir diese sehr langen K-Line-Daten testen:

    // 检测数据
    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++) {
            // 检查重复Bar
            if (i != j && r[i].Time == r[j].Time) {
                Log(r[i].Time, i, r[j].Time, j)
                throw "有重复Bar"
            }
        }
        
        // 检查Bar连续性
        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不连续"
            }            
        }
    }
    Log("检测通过")
  1. Überprüfen Sie, ob die K-Line-Leiste Duplikate enthält.
  2. Überprüfen Sie die Kontinuität des K-Linienbalkens (ob der Zeitstempelunterschied benachbarter Balken gleich ist).

Nachdem diese Prüfungen bestanden wurden, überprüfen Sie die Schnittstelle, die zur Aktualisierung der K-Zeile verwendet wird$.UpdataRecords(exchange, r, testPeriod)Normal:

    // 更新数据
    while (true) {
        $.UpdataRecords(exchange, r, testPeriod)
        LogStatus(_D(), "r.length:", r.length)
        $.PlotRecords(r, "k")
        Sleep(5000)
    }

Dieser Code gibt während der Ausführung im realen Handel kontinuierlich die K-Linie auf dem Strategiediagramm aus, sodass wir überprüfen können, ob die K-Linienbalkendaten normal aktualisiert und hinzugefügt werden.

Lernen Sie, eine Vorlagenbibliothek zu entwerfen, um K-Line-Daten einer bestimmten Länge zu erhalten

Lernen Sie, eine Vorlagenbibliothek zu entwerfen, um K-Line-Daten einer bestimmten Länge zu erhalten

Verwenden Sie die tägliche K-Line-Erfassungsfunktion, stellen Sie die Erfassung auf 8.000 ein (wissen Sie, dass vor 8.000 Tagen keine Marktdaten vorliegen), und führen Sie einen Brute-Force-Test wie diesen durch:

Lernen Sie, eine Vorlagenbibliothek zu entwerfen, um K-Line-Daten einer bestimmten Länge zu erhalten

Da es nur 1309 tägliche Linien gibt, vergleichen Sie die Daten im Wechselkursdiagramm:

Lernen Sie, eine Vorlagenbibliothek zu entwerfen, um K-Line-Daten einer bestimmten Länge zu erhalten

Lernen Sie, eine Vorlagenbibliothek zu entwerfen, um K-Line-Daten einer bestimmten Länge zu erhalten

Sie sehen, dass die Daten konsistent sind.

END

Vorlagenadresse:„JavaScript-Version der seitenweisen Abfragevorlage für historische K-Line-Daten“ Vorlagenadresse:Strichzeichnungsbibliothek

Die oben genannten Vorlagen und Strategiecodes dienen nur zu Lehr- und Lernzwecken. Bitte optimieren und ändern Sie sie entsprechend Ihren tatsächlichen Anforderungen.