Dạy bạn thiết kế thư viện lớp mẫu để có được dữ liệu đường K có chiều dài xác định

Tác giả:Lydia., Tạo: 2023-06-29 17:27:59, Cập nhật: 2023-09-18 19:33:33

img

Dạy bạn thiết kế thư viện lớp mẫu để có được dữ liệu đường K có chiều dài xác định

Khi thiết kế các chiến lược xu hướng, thường cần có một số lượng đủ các thanh K-line để tính toán các chỉ số.exchange.GetRecords()Trong thiết kế ban đầu của các API trao đổi tiền điện tử, không có hỗ trợ để trang trong giao diện K-line, và giao diện K-line của trao đổi chỉ cung cấp một lượng dữ liệu hạn chế. Kết quả là, một số nhà phát triển không thể đáp ứng các yêu cầu để tính toán các chỉ số với giá trị tham số lớn hơn.

Giao diện K-line của API hợp đồng của Binance hỗ trợ pagination. Trong bài viết này, chúng tôi sẽ sử dụng giao diện Binance K-line API làm ví dụ để dạy bạn cách thực hiện pagination và chỉ định số thanh để lấy bằng thư viện mẫu nền tảng FMZ.

Giao diện K-line của Binance

Dữ liệu đường K

Thời gian mở của mỗi đường K trongGET /dapi/v1/klinesđiểm cuối có thể được coi là một ID duy nhất.

Trọng lượng của yêu cầu phụ thuộc vào giá trị của tham số LIMIT.

img

Các thông số:

img

Đầu tiên, chúng ta cần tham khảo tài liệu API của Exchange để hiểu các thông số cụ thể của giao diện K-line. Chúng ta có thể thấy rằng khi gọi điểm cuối K-line này, chúng ta cần xác định loại, khoảng thời gian K-line, phạm vi dữ liệu (thời gian bắt đầu và kết thúc), và số trang, v.v.

Vì yêu cầu thiết kế của chúng tôi là truy vấn một số lượng cụ thể dữ liệu đường K, ví dụ, truy vấn đường K 1 giờ, 5000 thanh dữ liệu đường K 1 giờ từ thời điểm hiện tại sang quá khứ, rõ ràng rằng thực hiện một cuộc gọi API duy nhất đến trao đổi sẽ không lấy lại dữ liệu mong muốn.

Để đạt được điều này, chúng ta có thể thực hiện pagination và chia truy vấn thành các phân đoạn từ thời điểm hiện tại đến một thời điểm lịch sử cụ thể. Vì chúng ta biết khoảng thời gian dữ liệu K-line mong muốn, chúng ta có thể dễ dàng tính toán thời gian bắt đầu và kết thúc cho mỗi phân đoạn. Sau đó chúng ta có thể truy vấn từng phân đoạn theo trình tự hướng tới thời điểm lịch sử cho đến khi chúng ta lấy đủ thanh. Cách tiếp cận nghe có vẻ đơn giản, vì vậy hãy tiếp tục và thực hiện nó!

Thiết kế Phiên bản JavaScript của mẫu dữ liệu lịch sử truy vấn K-line

Chức năng giao diện cho mẫu thiết kế:$.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
 */

Thiết kế chức năng$.GetRecordsByLength, thường được sử dụng trong giai đoạn đầu của việc thực hiện chiến lược để tính toán các chỉ số dựa trên một khoảng thời gian dài dữ liệu đường K. Một khi chức năng này được thực hiện và có đủ dữ liệu, chỉ cần cập nhật dữ liệu đường K mới. Không cần gọi chức năng này một lần nữa để lấy dữ liệu đường K quá dài, vì nó sẽ dẫn đến các cuộc gọi API không cần thiết.

Do đó, cũng cần thiết phải thiết kế một giao diện cho các cập nhật dữ liệu tiếp theo:$.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
 */

Bước tiếp theo là thực hiện các chức năng giao diện này.

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

Trong mẫu, chúng tôi đã thực hiện hỗ trợ cho Binance hợp đồng tương lai giao diện K-line, tức là,getRecordsForFuturesBinanceNó cũng có thể được mở rộng để hỗ trợ giao diện K-line của các sàn giao dịch tiền điện tử khác.

Phiên thi thử

Như bạn có thể thấy, mã để thực hiện các chức năng này trong mẫu không rộng rãi, tổng cộng ít hơn 200 dòng. Sau khi viết mã mẫu, kiểm tra là rất quan trọng và không nên bỏ qua. Hơn nữa, để lấy dữ liệu như thế này, điều quan trọng là phải tiến hành kiểm tra kỹ lưỡng.

Để kiểm tra nó, bạn cần phải sao chép cả JavaScript Version of Pagination Query K-Line Historical Data TemplatePlot Library mẫu vào thư viện chiến lược của bạn (có thể được tìm thấy trongQuảng trường chiến lượcSau đó, tạo một chiến lược mới và chọn hai mẫu này.

img

img

Thư viện được sử dụng, bởi vì chúng ta cần vẽ dữ liệu đường K để quan sát.

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

Ở đây, chúng ta sử dụng đườngvar testPeriod = PERIOD_M5sau đó chúng ta có thể thực hiện một thử nghiệm phác thảo trên các dữ liệu K-line dài được trả về bởi cácvar r = $.GetRecordsByLength(exchange, testPeriod, 8000) interface.

    // Use the plot test for easy observation
    $.PlotRecords(r, "k")

Thử nghiệm tiếp theo cho dữ liệu đường K dài là:

    // 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")
  1. Kiểm tra xem có bất kỳ thanh trùng lặp nào trong dữ liệu K-line không.
  2. Kiểm tra sự nhất quán của dữ liệu đường K (liệu sự khác biệt dấu thời gian giữa các thanh liền kề là bằng nhau hay không).

Sau khi vượt qua các kiểm tra này, kiểm tra xem giao diện được sử dụng để cập nhật dữ liệu đường K,$.UpdateRecords(exchange, r, testPeriod), đang hoạt động chính xác.

    // Update data
    while (true) {
        $.UpdataRecords(exchange, r, testPeriod)
        LogStatus(_D(), "r.length:", r.length)
        $.PlotRecords(r, "k")
        Sleep(5000)
    }

Mã này sẽ liên tục xuất dữ liệu đường K trên biểu đồ chiến lược trong giao dịch trực tiếp, cho phép chúng tôi kiểm tra xem các cập nhật và bổ sung dữ liệu đường K có hoạt động đúng không.

img

img

Sử dụng dữ liệu K-line hàng ngày, chúng tôi thiết lập nó để lấy 8000 thanh (biết rằng không có dữ liệu thị trường có sẵn cho 8000 ngày trước đây).

img

Nhìn thấy rằng chỉ có 1309 dòng K hàng ngày, so sánh dữ liệu trên biểu đồ trao đổi:

img

img

Bạn có thể thấy rằng dữ liệu cũng phù hợp.

Kết thúc

Địa chỉ mẫu: Phiên bản JavaScript của Query Query K-Line Template Dữ liệu Lịch sửĐịa chỉ mẫu:Bộ Thư Ký

Mô hình và mã chiến lược ở trên chỉ dành cho việc giảng dạy và học tập, vui lòng tối ưu hóa và sửa đổi theo nhu cầu cụ thể của giao dịch trực tiếp.


Có liên quan

Thêm nữa