प्रवृत्ति रणनीतियों को तैयार करते समय अक्सर संकेतकों की गणना के लिए पर्याप्त संख्या में के-लाइन बार होना आवश्यक होता है।exchange.GetRecords()
एफएमजेड प्लेटफॉर्म एपीआई में फ़ंक्शन, जो एक्सचेंज के के-लाइन इंटरफ़ेस के लिए एक रैपर है। क्रिप्टोक्यूरेंसी एक्सचेंज एपीआई के शुरुआती डिजाइन में, के-लाइन इंटरफ़ेस में पेजिंग के लिए कोई समर्थन नहीं था, और एक्सचेंज के के-लाइन इंटरफ़ेस ने केवल सीमित मात्रा में डेटा प्रदान किया। परिणामस्वरूप, कुछ डेवलपर्स बड़े पैरामीटर मूल्यों के साथ संकेतकों की गणना के लिए आवश्यकताओं को पूरा करने में असमर्थ थे।
Binance
के-लाइन डेटा
में प्रत्येक K-लाइन के उद्घाटन का समयGET /dapi/v1/klines
अंत बिंदु को एक अद्वितीय आईडी माना जा सकता है।
अनुरोध का भार
पैरामीटर:
सबसे पहले, हमें एक्सचेंज के एपीआई दस्तावेज़ीकरण का संदर्भ लेने की आवश्यकता है ताकि के-लाइन इंटरफ़ेस के विशिष्ट मापदंडों को समझा जा सके। हम देख सकते हैं कि इस के-लाइन एंडपॉइंट को कॉल करते समय, हमें प्रकार, के-लाइन अवधि, डेटा रेंज (शुरू और अंत समय), और पृष्ठों की संख्या आदि निर्दिष्ट करने की आवश्यकता होती है।
चूंकि हमारे डिजाइन की आवश्यकता है के-लाइन डेटा की एक विशिष्ट संख्या की क्वेरी करने के लिए, उदाहरण के लिए, वर्तमान क्षण से अतीत की ओर 1 घंटे के-लाइन डेटा के 5000 बार की क्वेरी करने के लिए, यह स्पष्ट है कि एक्सचेंज के लिए एक एकल एपीआई कॉल करने से वांछित डेटा प्राप्त नहीं होगा।
इसे प्राप्त करने के लिए, हम पृष्ठीकरण को लागू कर सकते हैं और क्वेरी को वर्तमान क्षण से एक विशिष्ट ऐतिहासिक क्षण की ओर खंडों में विभाजित कर सकते हैं। चूंकि हम वांछित के-लाइन डेटा की अवधि जानते हैं, इसलिए हम प्रत्येक खंड के लिए प्रारंभ और अंत समय की गणना आसानी से कर सकते हैं। फिर हम प्रत्येक खंड को ऐतिहासिक क्षण की ओर अनुक्रम में क्वेरी कर सकते हैं जब तक कि हम पर्याप्त बार प्राप्त नहीं करते। दृष्टिकोण सरल लगता है, इसलिए चलो इसे लागू करते हैं!
डिजाइन टेम्पलेट्स के लिए इंटरफेस फ़ंक्शनः$.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
*/
फ़ंक्शन डिजाइन करें$.GetRecordsByLength
, जो आमतौर पर रणनीति निष्पादन के प्रारंभिक चरण में K-लाइन डेटा की एक लंबी अवधि के आधार पर संकेतकों की गणना करने के लिए उपयोग किया जाता है। एक बार जब यह फ़ंक्शन निष्पादित हो जाता है और पर्याप्त डेटा प्राप्त हो जाता है, तो केवल नए K-लाइन डेटा को अपडेट करने की आवश्यकता होती है। अत्यधिक लंबे K-लाइन डेटा को पुनर्प्राप्त करने के लिए इस फ़ंक्शन को फिर से कॉल करने की आवश्यकता नहीं है, क्योंकि इससे अनावश्यक एपीआई कॉल होंगे।
इसलिए बाद के डेटा अपडेट के लिए एक इंटरफेस डिजाइन करना भी आवश्यक हैः$.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
*/
अगला कदम इन इंटरफ़ेस कार्यों को लागू करना है।
/**
* 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
}
टेम्पलेट में, हम केवल बिनेंस वायदा अनुबंध के लाइन इंटरफ़ेस के लिए समर्थन लागू किया है, यानी,getRecordsForFuturesBinance
यह अन्य क्रिप्टोक्यूरेंसी एक्सचेंजों के के-लाइन इंटरफेस का समर्थन करने के लिए भी विस्तारित किया जा सकता है।
जैसा कि आप देख सकते हैं, टेम्पलेट में इन कार्यक्षमताओं को लागू करने के लिए कोड व्यापक नहीं है, कुल मिलाकर 200 पंक्तियों से कम है। टेम्पलेट कोड लिखने के बाद, परीक्षण महत्वपूर्ण है और इसे अनदेखा नहीं किया जाना चाहिए। इसके अलावा, इस तरह के डेटा पुनर्प्राप्ति के लिए, गहन परीक्षण करना महत्वपूर्ण है।
इसका परीक्षण करने के लिए, आपको अपने रणनीति पुस्तकालय में
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)
}
}
यहाँ, हम लाइन का उपयोगvar testPeriod = PERIOD_M5
5 मिनट के-लाइन अवधि सेट करने के लिए और 8000 बार पुनर्प्राप्त करने के लिए निर्दिष्ट करें. तो हम लंबे के-लाइन डेटा द्वारा लौटाया पर एक भूखंड परीक्षण कर सकते हैंvar r = $.GetRecordsByLength(exchange, testPeriod, 8000)
interface.
// 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")
इन जाँचों को पारित करने के बाद, सत्यापित करें कि क्या K-लाइन डेटा को अद्यतन करने के लिए उपयोग किया गया इंटरफ़ेस,$.UpdateRecords(exchange, r, testPeriod)
, ठीक से काम कर रहा है।
// Update data
while (true) {
$.UpdataRecords(exchange, r, testPeriod)
LogStatus(_D(), "r.length:", r.length)
$.PlotRecords(r, "k")
Sleep(5000)
}
यह कोड लाइव ट्रेडिंग के दौरान रणनीति चार्ट पर लगातार K-लाइन डेटा आउटपुट करेगा, जिससे हमें यह जांचने की अनुमति मिलती है कि K-लाइन डेटा अपडेट और जोड़ सही ढंग से काम कर रहे हैं या नहीं।
दैनिक के-लाइन डेटा का उपयोग करके, हम इसे 8000 बार पुनर्प्राप्त करने के लिए सेट करते हैं (यह जानते हुए कि 8000 दिन पहले के लिए कोई बाजार डेटा उपलब्ध नहीं है) । यह एक क्रूर बल परीक्षण के रूप में कार्य करता हैः
चूंकि केवल 1309 दैनिक K-लाइनें हैं, इसलिए विनिमय चार्ट के आंकड़ों की तुलना करें:
आप देख सकते हैं कि डेटा भी मेल खाता है।
टेम्पलेट का पताः
उपरोक्त टेम्पलेट और रणनीति कोड केवल शिक्षण और सीखने के उपयोग के लिए हैं, कृपया लाइव ट्रेडिंग की विशिष्ट आवश्यकताओं के अनुसार अनुकूलित और संशोधित करें।