Ketika merancang strategi tren, seringkali perlu memiliki jumlah batang garis K yang cukup untuk perhitungan indikator.exchange.GetRecords()
Pada awal desain API pertukaran cryptocurrency, tidak ada dukungan untuk paginasi di antarmuka K-line, dan antarmuka K-line exchange hanya menyediakan sejumlah data terbatas. Akibatnya, beberapa pengembang tidak dapat memenuhi persyaratan untuk menghitung indikator dengan nilai parameter yang lebih besar.
Antarmuka K-line dari API kontrak Binance
Data garis K
Waktu pembukaan setiap K-line diGET /dapi/v1/klines
titik akhir dapat dianggap sebagai ID unik.
Berat permintaan tergantung pada nilai parameter
Parameter:
Pertama, kita perlu merujuk ke dokumentasi API exchange
Karena persyaratan desain kami adalah untuk menanyakan sejumlah data K-line tertentu, misalnya, untuk menanyakan data K-line 1 jam, 5000 bar data K-line 1 jam dari saat ini ke masa lalu, jelas bahwa melakukan panggilan API tunggal ke pertukaran tidak akan mengambil data yang diinginkan.
Untuk mencapai hal ini, kita dapat menerapkan pagination dan membagi query menjadi segmen dari saat ini menuju momen historis tertentu. Karena kita tahu periode data K-line yang diinginkan, kita dapat dengan mudah menghitung waktu awal dan akhir untuk setiap segmen. Kita kemudian dapat menanyakan setiap segmen secara berurutan menuju momen historis sampai kita mendapatkan cukup batang. Pendekatan terdengar sederhana, jadi mari kita lanjutkan dan terapkan!
Fungsi antarmuka untuk template desain:$.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
*/
Desain fungsi$.GetRecordsByLength
, yang biasanya digunakan pada tahap awal pelaksanaan strategi untuk menghitung indikator berdasarkan periode panjang data K-line. Setelah fungsi ini dieksekusi dan data yang cukup diperoleh, hanya data K-line baru yang perlu diperbarui. Tidak perlu memanggil fungsi ini lagi untuk mengambil data K-line yang terlalu panjang, karena akan menghasilkan panggilan API yang tidak perlu.
Oleh karena itu, juga perlu merancang antarmuka untuk pembaruan data berikutnya:$.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
*/
Langkah selanjutnya adalah menerapkan fungsi antarmuka ini.
/**
* 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
}
Dalam templat, kami hanya menerapkan dukungan untuk Binance kontrak berjangka K-line antarmuka, yaitu,getRecordsForFuturesBinance
Ini juga dapat diperluas untuk mendukung antarmuka K-line dari pertukaran cryptocurrency lainnya.
Seperti yang Anda lihat, kode untuk menerapkan fungsionalitas ini dalam template tidak luas, total kurang dari 200 baris. Setelah menulis kode template, pengujian sangat penting dan tidak boleh diabaikan.
Untuk mengujinya, Anda perlu menyalin kedua
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)
}
}
Di sini, kita menggunakan garisvar testPeriod = PERIOD_M5
untuk mengatur periode K-line 5 menit dan menentukan untuk mengambil 8000 bar. kemudian kita dapat melakukan tes plot pada data K-line panjang dikembalikan olehvar r = $.GetRecordsByLength(exchange, testPeriod, 8000)
interface.
// Use the plot test for easy observation
$.PlotRecords(r, "k")
Tes berikutnya untuk data garis panjang K adalah:
// 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")
Setelah melewati pemeriksaan ini, periksa apakah antarmuka yang digunakan untuk memperbarui data K-line,$.UpdateRecords(exchange, r, testPeriod)
, berfungsi dengan baik.
// Update data
while (true) {
$.UpdataRecords(exchange, r, testPeriod)
LogStatus(_D(), "r.length:", r.length)
$.PlotRecords(r, "k")
Sleep(5000)
}
Kode ini akan terus menghasilkan data K-line pada grafik strategi selama perdagangan langsung, memungkinkan kita untuk memeriksa apakah pembaruan dan penambahan data K-line berfungsi dengan benar.
Menggunakan data K-line harian, kami mengaturnya untuk mengambil 8000 bar (mengetahui bahwa tidak ada data pasar yang tersedia untuk 8000 hari yang lalu).
Mengingat hanya ada 1309 K-line harian, bandingkan data pada grafik pertukaran:
Anda dapat melihat bahwa data juga cocok.
Alamat templat:
Templat dan kode strategi di atas hanya untuk penggunaan pengajaran dan pembelajaran, silahkan dioptimalkan dan dimodifikasi sesuai dengan kebutuhan khusus perdagangan langsung.