Lernen Sie, eine Template-Klasse zu entwerfen, die Daten von bestimmten Strängen von K-Länge abruft

Schriftsteller:Kleine Träume, Erstellt: 2023-06-27 13:37:01, aktualisiert: 2023-09-18 19:34:23

img

Lernen Sie, eine Template-Klasse zu entwerfen, die Daten von bestimmten Strängen von K-Länge abruft

Bei der Entwicklung von Trendstrategien benötigen die Indikatoren oft eine ausreichende Anzahl von K-Line-Bars.exchange.GetRecords()Die Datenmenge, die die Funktion gibt,exchange.GetRecords()Die K-Line-Schnittstelle der Börse war ein Umschlag für die K-Line-Schnittstelle der Börse. Die frühen API-Entwürfe für Kryptowährungen enthielten keine Seitenquests und die K-Line-Schnittstelle der Börse war nur für begrenzte Datenmengen verfügbar, so dass einige Entwickler die Anforderungen an die Berechnung von größeren Parametern nicht erfüllen konnten.

Die K-Line-Interface der Binance-Kontrakt-API unterstützt Split-Queries, so dass Sie mit der Binance-K-Line-API eine Split-Query durchführen und die Anzahl der Bar für FMZ-Plattform-Template-Klassenbestände angeben können.

Die K-Line-Schnittstelle von Binance

img

Zuerst müssen Sie sich die API-Dokumentation der Börse ansehen, um die spezifischen Parameter der Schnittstelle zu sehen. Wir können sehen, dass bei Anrufen dieser K-Leitung die Art, die K-Leitungszyklus, den Datenspektrum (Anfangs- und Endzeit), die Anzahl der Seiten usw. angegeben werden müssen.

Da wir die Entwurfsbedürfnisse haben, eine bestimmte Menge von K-Liniendaten zu abfragen, z. B. eine 1-Stunden-K-Line, die von der gegenwärtigen Zeit in die Richtung der vergangenen Zeit geschoben wird, mit einer Anzahl von 5000 Bar.

Dann machen wir eine Seiten-Abfrage, die von der gegenwärtigen Zeit bis zu einer bestimmten historischen Zeit in Abstufungen verarbeitet wird. Wir wissen, dass die Periode der benötigten K-Liniendaten die Beginn- und Endzeit jeder Abstufung berechnet.

Entwerfen von "K-Line Historie-Daten-Vorlagen für JavaScript-Version-Seitenquests"

Die Schnittstellenfunktionen für die Entwurfsvorlage:$.GetRecordsByLength(e, period, length)

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

Entwurf$.GetRecordsByLengthDiese Funktion benötigt in der Regel lange K-Linien, um zu Beginn der Strategie zu berechnen. Wenn die Funktion lang genug Daten hat, muss sie nur die neuen K-Linien aktualisieren. Es ist nicht mehr notwendig, diese Funktion zu rufen, um die sehr langen K-Linien zu erhalten, was zu unnötigen Anrufen führt.

Es ist also notwendig, eine Schnittstelle zu entwickeln, um die Daten zu aktualisieren:$.UpdataRecords(e, records, period)

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

Das nächste ist die Implementierung dieser Interface-Funktionen.

/**
 * 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 haben wir nur die Unterstützung für die Binance-Kontrakt-K-Linie-Schnittstelle implementiert, alsogetRecordsForFuturesBinanceDie Funktion kann auch die K-Line-Interface erweitern, die andere Kryptowährungsbörsen unterstützt.

Testschritte

Man sieht, dass es in der Vorlage nicht viel Code gibt, der diese Funktionen umsetzt, wahrscheinlich weniger als 200 Zeilen. Nachdem die Vorlage fertig geschrieben ist, gibt es absolut keinen Mangel an Tests.

Der Test erfordert die Kopie der Template "JavaScript-Version-Seitenbestimmungen für die Abfrage von K-Linien-Geschichtsdaten" und der Template "Draw Line Library" in die eigene Policy-Library.Das StrategieplatzWir haben dann eine neue Strategie erstellt, in der wir diese beiden Vorlagen anzeigen:

img

img

img

Wir verwenden "Draw Line Library", weil wir die gewonnenen K-Line-Daten anzeigen und beobachten 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 benutzen wirvar testPeriod = PERIOD_M5Das bedeutet, dass man die 5-minütige K-Linien-Zyklus einstellt, die Auswahl von 8000 Bars angibt.var r = $.GetRecordsByLength(exchange, testPeriod, 8000)Die langen K-Daten, die von der Schnittstelle zurückgegeben werden, werden für die Diagrammprüfung verwendet:

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

Das ist eine sehr lange K-Strang-Datenreihe, die man dann untersuchen kann:

    // 检测数据
    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üft, ob sich K-LineBar wiederholt. 2. Überprüfen Sie die Konsistenz der K-Linie Bar (ob die Zeitdifferenz der benachbarten Bar gleich ist)

Nach Ablauf dieser Prüfungen wird die Schnittstelle für die Aktualisierung der K-Leitung überprüft.$.UpdataRecords(exchange, r, testPeriod)Ist es normal:

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

Dieser Code wird während der Festplattendurchführung fortlaufend K-Linien auf dem Strategie-Chart ausführen, um zu überprüfen, ob die K-LineBar-Daten aktualisiert und hinzugefügt werden.

img

img

Mit dem Zugriff auf die K-Tage-Linie, die Einstellung zum Zugriff auf 8000 Roots (mit klarem Wissen, dass vor 8000 Tagen keine Marktdaten vorhanden waren) und der Gewalt-Test:

img

Die Tageszeile ist nur 1309 Punkte, verglichen mit den Zahlen auf den Charts der Börsen:

img

img

Sie sehen, dass die Daten übereinstimmen.

Ende

Die Adresse des Templates:"Javascript-Version zur Abfrage von K-Linien-Historie-Datenvorlagen"Die Adresse des Templates:"Draw Line Klassenbuch"

Die vorstehenden Vorlagen, Strategien und Codes sind nur für den Lehr- und Lernzweck bestimmt. Bitte optimieren oder ändern Sie sie nach Bedarf.


Mehr