Dạy bạn thiết kế thư viện mẫu để lấy dữ liệu đường dài K

Tác giả:Giấc mơ nhỏ, Tạo: 2023-06-27 13:37:01, Cập nhật: 2023-09-18 19:34:23

img

Dạy bạn thiết kế thư viện mẫu để lấy dữ liệu đường dài K

Khi thiết kế một số chiến lược xu hướng, các chỉ số tính toán thường cần một số lượng K-line Bar đầy đủ.exchange.GetRecords()Số lượng dữ liệu mà hàm cung cấp.exchange.GetRecords()Các giao dịch đầu tiên không có truy vấn phân trang trong thiết kế giao diện API cryptocurrency, và giao dịch chỉ cung cấp một lượng dữ liệu hạn chế, vì vậy một số nhà phát triển không thể đáp ứng nhu cầu tính toán chỉ số lớn hơn.

Nếu giao diện K-Line của Binance Contract API hỗ trợ truy vấn phân trang, bài viết này sẽ hướng dẫn bạn thực hiện một truy vấn phân trang bằng giao diện Binance K-Line API và có thể chỉ định số lượng Bar truy cập vào thư viện mẫu nền tảng FMZ.

K-Line của Binance

img

Trước tiên, hãy xem tài liệu API của sàn giao dịch để xem các tham số cụ thể của giao diện. Chúng ta có thể thấy rằng khi gọi giao diện K-line này, cần phải chỉ định giống, chu kỳ K-line, phạm vi dữ liệu (thời gian bắt đầu, kết thúc), số lượng phân đoạn, v.v.

Vì nhu cầu thiết kế của chúng tôi là truy vấn một số lượng dữ liệu K-line được chỉ định, ví dụ như truy vấn K-line 1 giờ, đẩy từ thời điểm hiện tại sang thời điểm quá khứ, với số lượng 5000 Bar. Vì vậy, bạn chỉ gọi một lần truy vấn API giao dịch rõ ràng sẽ không lấy dữ liệu bạn muốn.

Sau đó, chúng ta chia các trang truy vấn và xử lý các đoạn từ thời điểm hiện tại đến một thời điểm trong lịch sử. Chúng ta biết rằng các chu kỳ dữ liệu K-line cần thiết sẽ tính toán tốt thời gian bắt đầu và kết thúc của mỗi đoạn. Chỉ cần truy vấn theo hướng thời điểm lịch sử cho đến khi truy vấn đủ số Bar.

Thiết kế "Mẫu dữ liệu lịch sử truy vấn K-line JavaScript"

Các chức năng giao diện thiết kế mẫu:$.GetRecordsByLength(e, period, length)

/**
 * desc: $.GetRecordsByLength 是该模板类库的接口函数,该函数用于获取指定K线长度的K线数据
 * @param {Object} e - 交易所对象
 * @param {Int} period - K线周期,秒数为单位
 * @param {Int} length - 指定获取的K线数据的长度,具体和交易所接口限制有关
 * @returns {Array<Object>} - K线数据
 */

Thiết kế$.GetRecordsByLengthChức năng này thường được sử dụng trong trường hợp cần một K-lợi dài để tính toán các chỉ số trong quá trình chạy chính sách ban đầu. Sau khi thực hiện, chỉ cần cập nhật dữ liệu K-lợi mới. Không cần phải gọi lại chức năng này để lấy dữ liệu K-lợi quá dài, do đó sẽ tạo ra các cuộc gọi giao diện không cần thiết.

Vì vậy, cần thiết phải thiết kế một giao diện để cập nhật dữ liệu sau đó:$.UpdataRecords(e, records, period)

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

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

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

Trong mẫu, chúng tôi chỉ thực hiện hỗ trợ giao diện Binance Contract K-Line.getRecordsForFuturesBinanceChức năng này cũng có thể mở rộng các giao diện K-Line hỗ trợ các sàn giao dịch tiền điện tử khác.

Khung thử nghiệm

Bạn có thể thấy rằng không có nhiều mã để thực hiện các chức năng này trong mẫu, ít hơn 200 dòng. Khi mã mẫu được viết xong, kiểm tra là hoàn toàn không thể thiếu. Và để có được dữ liệu như vậy, chúng ta cũng cần kiểm tra nghiêm ngặt nhất có thể.

Thử nghiệm này đòi hỏi phải sao chép cả "JavaScript phiên bản tìm kiếm trang K-line History Template" và "Draw Line Library" template vào thư mục chính sách của riêng bạn ((Quảng trường Chiến lượcSau đó, chúng tôi tạo ra một chính sách mới để chọn hai mẫu:

img

img

img

Sử dụng thư viện lớp vạch là vì chúng ta cần vẽ dữ liệu vạch K được lấy ra để quan sát.

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

Chúng tôi sử dụngvar testPeriod = PERIOD_M5Câu này, đặt 5 phút K dòng chu kỳ, chỉ định lấy 8000 Bar;; và sau đó chovar r = $.GetRecordsByLength(exchange, testPeriod, 8000)Một số người dùng đã sử dụng các giao diện này để kiểm tra hình ảnh của các dữ liệu dài K-line được trả về:

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

Sau đó, chúng ta kiểm tra dữ liệu dài K-line này:

    // 检测数据
    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, kiểm tra xem có lặp lại trong K-lineBar không. 2, kiểm tra tính nhất quán của K-line Bar (nếu giá trị chênh lệch thời gian của Bar lân cận bằng nhau)

Sau khi các kiểm tra này được thông qua, kiểm tra giao diện để cập nhật đường K.$.UpdataRecords(exchange, r, testPeriod)Có bình thường không:

    // 更新数据
    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 các đường K trên biểu đồ chính sách khi chạy trên ổ đĩa thực, để kiểm tra xem các dữ liệu K-Bar được cập nhật hoặc thêm vào có ổn không.

img

img

Sử dụng truy cập ngày K-Line, cài đặt truy cập 8000 root (đã biết rõ 8000 ngày trước, không có dữ liệu thị trường), như thế này:

img

Trong khi đó, các nhà đầu tư khác cũng cho rằng chỉ có 1309 con số của đường dây ngày, so với các biểu đồ trên sàn giao dịch:

img

img

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

Kết thúc

Địa chỉ mẫu:"Sửa trang JavaScript để truy vấn mẫu dữ liệu lịch sử K-line"Địa chỉ mẫu:"Bộ thư viện đường vẽ"

Các mẫu trên, mã chiến lược chỉ dành cho việc giảng dạy, học tập sử dụng, thực tế, xin vui lòng tối ưu hóa hoặc sửa đổi theo nhu cầu cụ thể.


Thêm nữa