avatar of 发明者量化-小小梦 发明者量化-小小梦
フォロー ダイレクトメッセージ
4
フォロー
1271
フォロワー

指定された長さのKラインデータを取得するためのテンプレートライブラリの設計方法を教えます

作成日:: 2023-06-27 13:37:01, 更新日:: 2023-09-18 19:34:23
comments   0
hits   1285

指定された長さのKラインデータを取得するためのテンプレートライブラリの設計方法を教えます

指定された長さのKラインデータを取得するためのテンプレートライブラリの設計方法を教えます

いくつかのトレンド戦略を設計する場合、インジケーターを計算するには十分な数の K ライン バーが必要になることがよくあります。 FMZ プラットフォーム API に依存:exchange.GetRecords()関数によって与えられたデータの量、およびexchange.GetRecords()これは、交換 K ライン インターフェイスのカプセル化です。暗号通貨取引所の API インターフェースの初期の設計では、ページング クエリがなく、取引所の K ライン インターフェースは限られた量のデータしか提供しなかったため、より大きなパラメータを使用した指標計算に対する一部の開発者のニーズを満たすことができませんでした。

Binance コントラクト API の K ライン インターフェースは、ページ分割されたクエリをサポートしています。この記事では、Binance K ライン API インターフェースを例に、ページ分割されたクエリを実装し、FMZ プラットフォーム テンプレート ライブラリを指定してバーの数を取得する方法を説明します。

Binance Kラインインターフェース

指定された長さのKラインデータを取得するためのテンプレートライブラリの設計方法を教えます

まず、インターフェースの特定のパラメータを確認するには、Exchange API ドキュメントを読む必要があります。この K ライン インターフェイスを呼び出すときは、製品、K ライン期間、データ範囲 (開始時刻と終了時刻)、ページ数などを指定する必要があることがわかります。

私たちの設計要件は、指定された数の K ライン データを照会することであるため、たとえば、1 時間の K ラインを照会し、現在の時刻から過去の時刻にプッシュする場合、その数は 5,000 バーになります。この方法では、交換 API インターフェース クエリを 1 回だけ呼び出すだけでは、必要なデータを取得できないことは明らかです。

次に、ページ単位でクエリを実行し、現在の瞬間から履歴の特定の瞬間までのセグメント単位で処理します。必要な K ライン データの期間がわかっていれば、各セグメントの開始時間と終了時間を計算するのは簡単です。十分な数のバーが見つかるまで、歴史的な瞬間の方向に順番にクエリを実行します。アイデアはシンプルですね。実装してみましょう。

「ページングクエリ K ライン履歴データ テンプレートの JavaScript バージョン」を設計する

デザインテンプレートインターフェース機能:$.GetRecordsByLength(e, period, length)

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

デザイン$.GetRecordsByLengthこの関数は通常、インジケーターを計算するために長い K ラインが必要な戦略操作の初期段階で使用されます。この関数を実行すると、十分に長いデータが取得され、その後は新しい K ライン データを更新するだけで済みます。非常に長い K ライン データを取得するためにこの関数を呼び出す必要はありません。これにより、不要なインターフェイス呼び出しが発生します。

したがって、後続のデータ更新のためのインターフェースも設計する必要があります。$.UpdataRecords(e, records, period)

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

次のステップは、これらのインターフェース関数を実装することです。

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

テンプレートでは、BinanceコントラクトKラインインターフェースのサポートのみを実装しています。getRecordsForFuturesBinance機能拡張により、他の暗号通貨取引所のKラインインターフェースもサポートできます。

テスト

テンプレートにはこれらの関数を実装するためのコードがほとんどなく、おそらく 200 行未満であることがわかります。テンプレートコードが記述された後は、テストが絶対に必要です。そして、そのようなデータの取得については、できるだけ厳密にテストする必要もあります。

テストでは、この「ページクエリKライン履歴データテンプレートのJavaScriptバージョン」と「線描画ライブラリ」テンプレートを独自の戦略ライブラリ(戦略スクエアで検索できます。次に、新しい戦略を作成し、次の 2 つのテンプレートを確認します。

指定された長さのKラインデータを取得するためのテンプレートライブラリの設計方法を教えます

指定された長さのKラインデータを取得するためのテンプレートライブラリの設計方法を教えます

指定された長さのKラインデータを取得するためのテンプレートライブラリの設計方法を教えます

得られたK線データを観測用に描画する必要があるため、「線描画ライブラリ」を使用します。

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

ここではvar testPeriod = PERIOD_M5この文は、K ライン期間を 5 分に設定し、8000 バーを取得するように指定します。そしてvar r = $.GetRecordsByLength(exchange, testPeriod, 8000)インターフェースは描画テスト用の長い K ライン データを返します。

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

次に、この非常に長い 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("检测通过")
  1. K ライン バーに重複がないか確認します。
  2. Kラインバーの連続性を確認します(隣接するバーのタイムスタンプの差が等しいかどうか)

これらのチェックに合格したら、Kラインの更新に使用されるインターフェースをチェックします。$.UpdataRecords(exchange, r, testPeriod)普通:

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

このコードは、実際の取引で実行されているときに戦略チャートに K ラインを継続的に出力し、K ライン バー データが正常に更新および追加されているかどうかを確認できます。

指定された長さのKラインデータを取得するためのテンプレートライブラリの設計方法を教えます

指定された長さのKラインデータを取得するためのテンプレートライブラリの設計方法を教えます

日次 K ライン取得関数を使用し、取得を 8,000 に設定し (8,000 日前には市場データがないことを認識)、次のようなブルー​​ト フォース テストを実行します。

指定された長さのKラインデータを取得するためのテンプレートライブラリの設計方法を教えます

為替チャートのデータと比較すると、日足線は 1309 本しかありません。

指定された長さのKラインデータを取得するためのテンプレートライブラリの設計方法を教えます

指定された長さのKラインデータを取得するためのテンプレートライブラリの設計方法を教えます

データが一貫していることがわかります。

END

テンプレートアドレス:「ページクエリ K ライン履歴データ テンプレートの JavaScript バージョン」 テンプレートアドレス:線画ライブラリ

上記のテンプレートと戦略コードは、教育と学習の目的のみに使用されます。実際のニーズに合わせて最適化および変更してください。