avatar of 发明者量化-小小梦 发明者量化-小小梦
fokus pada Pesan pribadi
4
fokus pada
1271
Pengikut

Mengajarkan Anda untuk mendesain pustaka template untuk mendapatkan data K-line dengan panjang yang ditentukan

Dibuat di: 2023-06-27 13:37:01, diperbarui pada: 2023-09-18 19:34:23
comments   0
hits   1285

Mengajarkan Anda untuk mendesain pustaka template untuk mendapatkan data K-line dengan panjang yang ditentukan

Mengajarkan Anda untuk mendesain pustaka template untuk mendapatkan data K-line dengan panjang yang ditentukan

Saat merancang beberapa strategi tren, perhitungan indikator sering kali memerlukan jumlah batang K-line yang memadai. Tergantung pada API platform FMZ:exchange.GetRecords()Jumlah data yang diberikan oleh fungsi, danexchange.GetRecords()Ini adalah enkapsulasi antarmuka pertukaran K-line. Dalam desain awal antarmuka API pertukaran mata uang kripto, tidak ada kueri paging, dan antarmuka K-line pertukaran hanya menyediakan data dalam jumlah terbatas, sehingga kebutuhan beberapa pengembang untuk kalkulasi indikator dengan parameter yang lebih besar tidak dapat dipenuhi.

Antarmuka K-line dari API kontrak Binance mendukung kueri berhalaman. Artikel ini mengambil antarmuka API K-line Binance sebagai contoh untuk mengajarkan Anda cara mengimplementasikan kueri berhalaman dan menentukan pustaka templat platform FMZ untuk memperoleh jumlah Bar.

Antarmuka K-line Binance

Mengajarkan Anda untuk mendesain pustaka template untuk mendapatkan data K-line dengan panjang yang ditentukan

Pertama, Anda perlu membaca dokumentasi API pertukaran untuk melihat parameter antarmuka yang spesifik. Kita dapat melihat bahwa saat memanggil antarmuka K-line ini, perlu menentukan produk, periode K-line, rentang data (waktu mulai dan berakhir), jumlah halaman, dll.

Karena persyaratan desain kami adalah untuk menanyakan sejumlah data K-line yang ditentukan, misalnya, untuk menanyakan K-line 1 jam, mendorong dari waktu saat ini ke waktu lampau, jumlahnya adalah 5.000 bar. Dengan cara ini, Anda jelas tidak bisa mendapatkan data yang Anda inginkan dengan memanggil kueri antarmuka API pertukaran satu kali saja.

Kemudian, kami akan melakukan kueri dalam beberapa halaman, memproses dalam beberapa segmen dari momen saat ini hingga momen tertentu dalam sejarah. Selama kita mengetahui periode data K-line yang dibutuhkan, mudah untuk menghitung waktu mulai dan berakhirnya setiap segmen. Cukup cari arah momen bersejarah secara berurutan hingga Anda menemukan bar yang cukup. Idenya terdengar sederhana, bukan? Mari kita terapkan!

Desain “Versi JavaScript dari templat data historis K-line kueri berhalaman”

Fungsi antarmuka template desain:$.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 digunakan pada tahap awal operasi strategi ketika garis K yang panjang diperlukan untuk menghitung indikator. Setelah fungsi ini dijalankan, ia memperoleh data yang cukup panjang, dan selanjutnya hanya perlu memperbarui data K-line yang baru. Tidak perlu memanggil fungsi ini untuk memperoleh data K-line yang sangat panjang, yang akan menyebabkan panggilan antarmuka yang tidak perlu.

Oleh karena itu, perlu juga merancang antarmuka untuk pembaruan data selanjutnya:$.UpdataRecords(e, records, period)

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

Langkah berikutnya adalah mengimplementasikan fungsi antarmuka ini.

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

Dalam template, kami hanya menerapkan dukungan antarmuka K-line kontrak Binance, yaitu,getRecordsForFuturesBinanceFungsinya juga dapat diperluas untuk mendukung antarmuka K-line pada bursa mata uang kripto lainnya.

Pengujian

Anda dapat melihat bahwa tidak banyak kode dalam templat untuk mengimplementasikan fungsi ini, mungkin kurang dari 200 baris. Setelah kode templat ditulis, pengujian mutlak diperlukan. Dan untuk perolehan data tersebut, kita juga perlu mengujinya seketat mungkin.

Pengujian ini memerlukan penyalinan “versi JavaScript dari templat data historis K-line kueri halaman” dan templat “perpustakaan gambar garis” ini ke pustaka strategi Anda sendiri (dalamStrategi Persegidapat dicari di ). Kemudian kami membuat strategi baru dan memeriksa dua templat ini:

Mengajarkan Anda untuk mendesain pustaka template untuk mendapatkan data K-line dengan panjang yang ditentukan

Mengajarkan Anda untuk mendesain pustaka template untuk mendapatkan data K-line dengan panjang yang ditentukan

Mengajarkan Anda untuk mendesain pustaka template untuk mendapatkan data K-line dengan panjang yang ditentukan

“Perpustakaan gambar garis” digunakan karena kita perlu menggambar data garis K 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_M5Kalimat ini menetapkan periode K-line menjadi 5 menit dan menentukan untuk memperoleh 8000 bar. Kemudian untukvar r = $.GetRecordsByLength(exchange, testPeriod, 8000)Antarmuka mengembalikan data K-line panjang untuk pengujian gambar:

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

Selanjutnya, kita akan menguji data K-line yang sangat 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. Periksa apakah ada duplikat pada K-line Bar.
  2. Periksa kontinuitas Bar K-line (apakah perbedaan cap waktu Bar yang berdekatan sama)

Setelah pemeriksaan ini lulus, periksa antarmuka yang digunakan untuk memperbarui jalur K$.UpdataRecords(exchange, r, testPeriod)Normal:

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

Kode ini akan terus menerus mengeluarkan K-line pada grafik strategi saat dijalankan dalam perdagangan nyata, sehingga kita dapat memeriksa apakah data K-line Bar diperbarui dan ditambahkan secara normal.

Mengajarkan Anda untuk mendesain pustaka template untuk mendapatkan data K-line dengan panjang yang ditentukan

Mengajarkan Anda untuk mendesain pustaka template untuk mendapatkan data K-line dengan panjang yang ditentukan

Gunakan fungsi akuisisi K-line harian dan atur akuisisi ke 8.000 (dengan mengetahui bahwa tidak ada data pasar sebelum 8.000 hari), dan lakukan uji kekuatan kasar seperti ini:

Mengajarkan Anda untuk mendesain pustaka template untuk mendapatkan data K-line dengan panjang yang ditentukan

Hanya ada 1309 garis harian, dibandingkan dengan data pada grafik bursa:

Mengajarkan Anda untuk mendesain pustaka template untuk mendapatkan data K-line dengan panjang yang ditentukan

Mengajarkan Anda untuk mendesain pustaka template untuk mendapatkan data K-line dengan panjang yang ditentukan

Anda dapat melihat bahwa datanya konsisten.

END

Alamat templat:「Versi JavaScript dari templat data historis K-line kueri berhalaman」 Alamat templat:Perpustakaan gambar garis

Template dan kode strategi di atas hanya untuk tujuan pengajaran dan pembelajaran. Harap optimalkan dan modifikasi sesuai dengan kebutuhan Anda yang sebenarnya.