指定された長さのK線データを取得するためにテンプレートクラスライブラリを設計することを教えます

作者: リン・ハーンリディア, 作成日:2023-06-29 17:27:59, 更新日:2023-09-18 19:33:33

img

指定された長さのK線データを取得するためにテンプレートクラスライブラリを設計することを教えます

傾向戦略を設計する際には,指標の計算のために十分な数のK線バーが必要である.指標の計算は,exchange.GetRecords()FMZプラットフォームAPIの機能は,取引所のKラインインターフェースのラッピングである.暗号通貨取引所のAPIの初期の設計では,Kラインインターフェイスでページ付けをサポートしていなかったし,取引所のKラインインターフェイスは限られた量のデータしか提供していなかった.その結果,一部の開発者は,より大きなパラメータ値を持つ指標の計算要件を満たすことができなかった.

Binanceの契約 API の K-line インターフェースはページ付けをサポートしています.この記事では,FMZ プラットフォームテンプレートライブラリを使用してページ付けを実装し,取得するバーの数を指定する方法について説明するために,Binance K-line API インターフェースを例として使用します.

バイナンスのKラインインターフェース

K線データ

K線を開ける時間GET /dapi/v1/klinesエンドポイントは 唯一的なIDとして考えられます

要求の重さは,パラメータ"LIMIT"の値に依存する.

img

パラメーター:

img

まず,K-line インターフェースの特定のパラメータを理解するために,Exchange による API ドキュメンテーションを参照する必要があります.この K-line エンドポイントを呼び出すとき,タイプ,K-line 期間,データ範囲 (開始時と終了時),ページの数などを指定する必要があります.

例えば,1時間のKラインをクエリし,1時間のKラインデータを5000バーで過去に向かってクエリするので 単一のAPIを交換に呼び出すことは 望ましいデータを取得しないことは明らかです

この目的を達成するために,ページ付けを実装し,クエリを現在の瞬間から特定の歴史的瞬間に向かってセグメントに分けることができます. 望ましいK線データの期間を知っているので,各セグメントの開始および終了時間を容易に計算できます. その後,十分なバーが回収されるまで,歴史的な瞬間に向かって各セグメントを順番にクエリすることができます.アプローチはシンプルに聞こえますので,実行してみましょう!

デザイン ページ化されたクエリのJavaScriptバージョン K線履歴データテンプレート

設計テンプレートのインターフェース機能:$.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
 */

機能を設計する$.GetRecordsByLength,この関数は通常,戦略実行の初期段階で,長い期間K線データに基づいて指標を計算するために使用されます.この関数が実行され,十分なデータが得られたら,新しいK線データのみが更新する必要があります.不要なAPI呼び出しを引き起こすため,過剰に長いK線データを取得するために,この関数を再び呼び出す必要はありません.

したがって,次のデータ更新のためのインターフェースも設計する必要があります.$.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
 */

次のステップはこれらのインターフェース機能を実装することです

/**
 * 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
}

テンプレートでは,我々はBinance先物契約のK-ラインインターフェースのみのサポートを実装しました.getRecordsForFuturesBinanceまた,他の仮想通貨取引所のKラインインターフェースをサポートするために拡張することもできます.

テストセッション

テンプレートでこれらの機能を実装するためのコードは,合計で200行未満で,広範ではありません.テンプレートコードを書いた後,テストは重要です.また,このようなデータ復元のために,徹底的なテストを行うことが重要です.

テストするには,ページナレーションクエリ K-Line 歴史データテンプレート の JavaScript バージョン Plot Library のテンプレート を,戦略ライブラリ にコピーする必要があります (このテンプレートは,ページナレーションクエリ K-Line 歴史データテンプレート の JavaScript バージョン Plot Library の テンプレート を戦略広場) 次に,新しい戦略を作成し,この2つのテンプレートを選択します.

img

img

プロットライブラリを使用します. 観測のために得られたK線データを描く必要があるからです.

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)
    }
}

この線はvar testPeriod = PERIOD_M58000バーを取得する指定します. その後,我々は,長いK線データでプロットテストを実行することができますvar r = $.GetRecordsByLength(exchange, testPeriod, 8000) interface.

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

長い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")
  1. K線データに 複製棒がないか確認します
  2. K線データの一貫性 (隣接する棒間のタイムスタンプの差が等しいかどうか) を確認する.

このチェックを完了した後,K線データを更新するために使用されたインターフェースが,$.UpdateRecords(exchange, r, testPeriod)正常に機能しています.

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

このコードは,ライブ取引中に戦略チャートに K線データを継続的に出力し,K線データの更新と追加が正しく機能しているかどうかを確認することができます.

img

img

日々のK線データを利用して,それを8000バーを取得するように設定します (8000日前の市場データが利用できないことを知っています). これはブルートフォーステストとして機能します:

img

日々のK線が1309本しかないので 交換チャート上のデータを比較してみてください

img

img

データも一致しているのがわかります

エンド

模様の住所:JavaScriptバージョンのページナレーションクエリ K-Line 歴史データテンプレート模様の住所:プロットライブラリ

上記のテンプレートと戦略コードは,教育および学習用のみであり,ライブ取引の特定のニーズに応じて最適化および変更してください.


関連性

もっと