Apabila merancang strategi trend, sering kali perlu mempunyai bilangan bar K-line yang mencukupi untuk mengira penunjuk.exchange.GetRecords()
fungsi dalam API platform FMZ, yang merupakan bungkus untuk antara muka K-line pertukaran. Dalam reka bentuk awal API pertukaran mata wang kripto, tidak ada sokongan untuk paginasi dalam antara muka K-line, dan antara muka K-line pertukaran hanya menyediakan sejumlah data yang terhad. Akibatnya, beberapa pemaju tidak dapat memenuhi keperluan untuk mengira penunjuk dengan nilai parameter yang lebih besar.
Antara muka K-line API kontrak Binance
Data garis K
Waktu pembukaan setiap K-garis dalamGET /dapi/v1/klines
Titik akhir boleh dianggap sebagai ID unik.
Berat permintaan bergantung kepada nilai parameter
Parameter:
Pertama, kita perlu merujuk kepada dokumentasi API pertukaran untuk memahami parameter khusus antara muka K-line. Kita dapat melihat bahawa ketika memanggil titik akhir K-line ini, kita perlu menentukan jenis, tempoh K-line, julat data (waktu permulaan dan akhir), dan bilangan halaman, dll.
Oleh kerana keperluan reka bentuk kami adalah untuk menyoal sejumlah data K-line tertentu, sebagai contoh, untuk menyoal data K-line 1 jam, 5000 bar data K-line 1 jam dari masa kini ke masa lalu, jelas bahawa membuat panggilan API tunggal ke pertukaran tidak akan mendapatkan data yang dikehendaki.
Untuk mencapai ini, kita boleh melaksanakan pagination dan membahagikan pertanyaan ke dalam segmen dari masa kini ke masa sejarah tertentu. Oleh kerana kita tahu tempoh data K-line yang dikehendaki, kita boleh dengan mudah mengira masa permulaan dan akhir untuk setiap segmen. Kita kemudian boleh menanyakan setiap segmen secara berurutan ke arah masa sejarah sehingga kita mendapatkan bar yang cukup. Pendekatan terdengar mudah, jadi mari kita teruskan dan pelaksanaannya!
Fungsi antara muka untuk templat reka bentuk:$.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
*/
Reka bentuk fungsi$.GetRecordsByLength
, yang biasanya digunakan pada peringkat awal pelaksanaan strategi untuk mengira penunjuk berdasarkan data K-line yang panjang. Setelah fungsi ini dijalankan dan data yang mencukupi diperoleh, hanya data K-line baru yang perlu dikemas kini. Tidak perlu memanggil fungsi ini lagi untuk mendapatkan data K-line yang terlalu panjang, kerana akan mengakibatkan panggilan API yang tidak perlu.
Oleh itu, ia juga perlu untuk merancang antara muka untuk kemas kini 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 seterusnya adalah untuk melaksanakan fungsi antara muka 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, kita hanya melaksanakan sokongan untuk kontrak niaga hadapan Binance antara muka K-garis, iaitu,getRecordsForFuturesBinance
Ia juga boleh diperluaskan untuk menyokong antara muka K-line pertukaran cryptocurrency lain.
Seperti yang anda lihat, kod untuk melaksanakan fungsi ini dalam templat tidak luas, berjumlah kurang daripada 200 baris. Selepas menulis kod templat, ujian adalah penting dan tidak boleh diabaikan.
Untuk mengujinya, anda perlu menyalin kedua-dua
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 gunakan garisvar testPeriod = PERIOD_M5
untuk menetapkan tempoh K-garis 5 minit dan tentukan untuk mendapatkan 8000 bar. kemudian kita boleh melakukan ujian plot pada data K-garis panjang dikembalikan olehvar r = $.GetRecordsByLength(exchange, testPeriod, 8000)
interface.
// Use the plot test for easy observation
$.PlotRecords(r, "k")
Ujian seterusnya untuk data garis K panjang 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")
Selepas lulus pemeriksaan ini, mengesahkan sama ada antara muka yang digunakan untuk mengemas kini data K-garis,$.UpdateRecords(exchange, r, testPeriod)
, berfungsi dengan betul.
// Update data
while (true) {
$.UpdataRecords(exchange, r, testPeriod)
LogStatus(_D(), "r.length:", r.length)
$.PlotRecords(r, "k")
Sleep(5000)
}
Kod ini akan terus mengeluarkan data K-line pada carta strategi semasa perdagangan langsung, yang membolehkan kita memeriksa sama ada kemas kini dan penambahan data K-line berfungsi dengan betul.
Menggunakan data K-line harian, kami menetapkannya untuk mendapatkan 8000 bar (mengetahui bahawa tidak ada data pasaran yang tersedia untuk 8000 hari yang lalu).
Memandangkan terdapat hanya 1309 K-line harian, bandingkan data pada carta pertukaran:
Anda boleh lihat bahawa data juga sepadan.
Alamat templat:
Templat dan kod strategi di atas hanya untuk penggunaan pengajaran dan pembelajaran, sila optimumkan dan ubahsuai mengikut keperluan khusus perdagangan langsung.