Mempelajari cara membuat koleksi template untuk mendapatkan data garis dengan panjang K tertentu

Penulis:Mimpi kecil, Dibuat: 2023-06-27 13:37:01, Diperbarui: 2023-09-18 19:34:23

img

Mempelajari cara membuat koleksi template untuk mendapatkan data garis dengan panjang K tertentu

Dalam mendesain beberapa strategi tren, indikator penghitungan sering membutuhkan jumlah K-line Bar yang cukup; bergantung pada API platform FMZ:exchange.GetRecords()Jadi kita bisa melihat bahwa fungsi ini memiliki jumlah data yangexchange.GetRecords()Ini adalah pembungkus untuk antarmuka K-line pertukaran. Pada desain antarmuka API pertukaran cryptocurrency awal tidak ada pertanyaan split-page, dan antarmuka K-line pertukaran hanya tersedia untuk jumlah data yang terbatas, sehingga beberapa pengembang tidak dapat memenuhi kebutuhan untuk perhitungan indikator parameter yang lebih besar.

Jika antarmuka K-line dari Binance Contract API mendukung query split, maka artikel ini akan mengajarkan Anda bagaimana melakukan query split dengan menggunakan Binance K-line API sebagai contoh.

Interface K-line dari Binance

img

Pertama-tama kita harus melihat dokumen API pertukaran untuk melihat parameter spesifik antarmuka. Kita dapat melihat bahwa panggilan antarmuka K-line ini memerlukan spesifikasi jenis, siklus K-line, ruang lingkup data (waktu awal, akhir), jumlah halaman, dll.

Karena kebutuhan desain kami adalah untuk menanyakan sejumlah data K-line yang ditentukan, misalnya untuk menanyakan K-line 1 jam, bergerak dari saat ini ke saat lalu, jumlahnya 5000 Bar. Jadi Anda hanya memanggil permintaan API pertukaran sekali dan jelas tidak mendapatkan data yang Anda inginkan.

Kemudian kita akan membagi halaman untuk menanyakan dan memproses segmen dari saat ini ke momen tertentu dalam sejarah. Kita tahu bahwa siklus data K-line yang kita butuhkan akan sangat baik untuk menghitung awal dan akhir setiap segmen. Hanya menggunakan segmen ke arah momen sejarah untuk menanyakan hingga jumlah Bar yang cukup.

Mendesain "K-line template data riwayat pencarian versi JavaScript"

Fungsi antarmuka untuk desain template:$.GetRecordsByLength(e, period, length)

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

Desain$.GetRecordsByLengthFungsi ini biasanya membutuhkan panjang K-line untuk menghitung indikator pada tahap awal dari operasi strategi. Setelah fungsi ini dijalankan, data yang cukup panjang diperoleh, maka hanya perlu memperbarui data K-line baru. Tidak perlu lagi memanggil fungsi ini untuk mendapatkan data K-line yang sangat panjang, yang menyebabkan panggilan antarmuka yang tidak perlu.

Jadi, kita juga perlu merancang antarmuka untuk memperbarui data berikutnya:$.UpdataRecords(e, records, period)

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

Setelah itu, kita akan mengimplementasikan fungsi-fungsi antarmuka tersebut.

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

Di template ini kami hanya mengimplementasikan dukungan untuk Binance Contract K-Line Interface, yaitugetRecordsForFuturesBinanceFungsi ini juga dapat memperluas antarmuka K-line yang mendukung pertukaran cryptocurrency lainnya.

Bagian Uji

Anda dapat melihat bahwa tidak ada banyak kode untuk mengimplementasikan fungsi-fungsi ini dalam template, mungkin kurang dari 200 baris. Setelah kode template ditulis, pengujian sangat banyak. Dan untuk mendapatkan data seperti itu, kita juga perlu pengujian yang paling ketat.

Percobaan ini membutuhkan salinan template "JavaScript versi periksa halaman K-line History Data Template" dan "Drawing Line Library" ke dalam policy library sendiri (dalam bahasa Inggris).Praja StrategiKemudian kami membuat kebijakan baru untuk memilih dua template ini:

img

img

img

Menggunakan "Draw Line Library" adalah karena kita perlu menggambar data K-line yang diperoleh untuk observasi.

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

Di sini kita menggunakanvar testPeriod = PERIOD_M5Jika Anda mengklik pada bagian ini, Anda akan melihat bahwa Anda telah mengklik pada bagian yang lain.var r = $.GetRecordsByLength(exchange, testPeriod, 8000)Data panjang K-line yang dikembalikan oleh antarmuka untuk pengujian gambar:

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

Setelah itu, kita melakukan tes pada data K-line yang panjang ini:

    // 检测数据
    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, memeriksa apakah ada pengulangan di garis KBar. 2, periksa keseragaman garis KBar (apakah perbedaan selang waktu Bar yang berdekatan sama)

Setelah pemeriksaan ini selesai, memeriksa antarmuka yang digunakan untuk memperbarui garis K.$.UpdataRecords(exchange, r, testPeriod)Apakah itu normal:

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

K-line akan terus keluar pada grafik kebijakan saat berjalan pada hard disk, sehingga kita dapat memeriksa apakah data K-lineBar diperbarui atau ditambahkan dengan baik.

img

img

Dengan menggunakan K-line untuk mengakses hari, atur untuk mengakses 8000 root (dengan mengetahui bahwa tidak ada data pasar sebelum 8000 hari), seperti ini:

img

Di sini kita melihat bahwa hanya ada 1309 root di sini, dibandingkan dengan data yang ada di grafik bursa:

img

img

Anda dapat melihat bahwa data juga cocok.

Penghentian

Alamat templat:"Penggunaan JavaScript untuk mencari template riwayat K-line"Alamat templat:"Layanan Kelas Gambar"

Templat, kode strategi di atas hanya untuk pengajaran, pembelajaran dan penggunaan, dan perlengkapan yang dapat dioptimalkan sesuai kebutuhan.


Lebih banyak