리소스 로딩... 로딩...

지정된 길이의 K-라인 데이터를 얻기 위해 템플릿 클래스 라이브러리를 설계하는 것을 가르쳐

저자:FMZ~리디아, 창작: 2023-06-29 17:27:59, 업데이트: 2023-09-18 19:33:33

img

지정된 길이의 K-라인 데이터를 얻기 위해 템플릿 클래스 라이브러리를 설계하는 것을 가르쳐

트렌드 전략을 설계할 때, 지표를 계산하기 위해 충분한 수의 K-라인 바가 필요합니다.exchange.GetRecords()FMZ 플랫폼 API에서 기능, 이는 거래소의 K-라인 인터페이스에 대한 래퍼입니다. 암호화폐 거래소 API의 초기 설계에서 K-라인 인터페이스에서 페이지링에 대한 지원이 없었으며 거래소의 K-라인 인터페이스는 제한된 양의 데이터만을 제공했습니다. 결과적으로 일부 개발자는 더 큰 매개 변수 값으로 지표를 계산하는 요구 사항을 충족할 수 없었습니다.

바이낸스 계약 API의 K-라인 인터페이스는 페이징을 지원합니다. 이 기사에서는 바이낸스 K-라인 API 인터페이스를 예로 사용하여 페이징을 구현하고 FMZ 플랫폼 템플릿 라이브러리를 사용하여 검색해야하는 바 수를 지정하는 방법을 알려 드리겠습니다.

바이낸스의 K-라인 인터페이스

K선 데이터

각 K 라인의 열 시간GET /dapi/v1/klines엔드포인트는 고유의 ID로 간주 될 수 있습니다.

요청의 무게는 LIMIT 매개 변수의 값에 달려 있습니다.

img

매개 변수

img

먼저, 우리는 K-라인 인터페이스의 특정 매개 변수를 이해하기 위해 교환의 API 문서를 참조해야합니다. 우리는이 K-라인 엔드포인트를 호출 할 때 유형, K-라인 기간, 데이터 범위 (시작 및 종료 시간) 및 페이지 수 등을 지정해야합니다.

우리의 설계 요구 사항은 특정 수의 K-라인 데이터를 검색하기 때문에, 예를 들어, 1시간 K-라인, 5000 바의 1시간 K-라인 데이터를 현재 순간부터 과거로 검색하기 위해, 교환에 단일 API 호출을 하는 것은 원하는 데이터를 검색하지 않을 것이 분명합니다.

이를 달성하기 위해, 우리는 페이지링을 구현하고 현재 순간부터 특정 역사적 시점까지 쿼리를 세그먼트로 나눌 수 있습니다. 원하는 K-라인 데이터의 기간을 알고 있기 때문에 각 세그먼트의 시작 및 종료 시간을 쉽게 계산 할 수 있습니다. 우리는 충분한 바를 검색 할 때까지 역사적 시점으로 순차적으로 각 세그먼트를 쿼리 할 수 있습니다. 접근 방식은 간단합니다. 그래서 그것을 실행하도록 합시다!

디자인 페이지화된 질의 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
 */

함수를 설계$.GetRecordsByLength, 일반적으로 전략 실행의 초기 단계에서 K-라인 데이터의 긴 기간에 기반한 지표를 계산하는 데 사용됩니다. 이 함수가 실행되고 충분한 데이터가 획득되면 새로운 K-라인 데이터만 업데이트해야합니다. 불필요한 API 호출을 초래하기 때문에 과도하게 긴 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
}

템플릿에서, 우리는 단지 바이낸스 선물 계약 K-라인 인터페이스에 대한 지원을 구현, 즉,getRecordsForFuturesBinance또한 다른 암호화폐 거래소의 K-라인 인터페이스를 지원하기 위해 확장될 수 있습니다.

테스트 세션

보시다시피, 템플릿에 이러한 기능을 구현하는 코드는 200줄 미만으로 광범위하지 않습니다. 템플릿 코드를 작성한 후 테스트는 매우 중요하며 간과해서는 안됩니다. 또한, 이와 같은 데이터 검색을 위해 철저한 테스트를 수행하는 것이 중요합니다.

그것을 테스트하기 위해, 당신은 당신의 전략 라이브러리 (가 찾을 수 있는) 에 페이지화 질의 K-라인 역사 데이터 템플릿의 자바스크립트 버전과 플롯 라이브러리 템플릿을 복사해야합니다전략 광장) 다음, 새로운 전략을 만들고 이 두 가지 템플릿을 선택.

img

img

플로트 라이브러리을 사용하는데, 우리는 관찰을 위해 얻은 K-라인 데이터를 그려야 하기 때문입니다.

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_M55분 K-라인 기간을 설정하고 8000바를 검색하도록 지정합니다.var r = $.GetRecordsByLength(exchange, testPeriod, 8000) interface.

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

긴 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")
  1. K-라인 데이터에 복제된 바가 있는지 확인하십시오.
  2. K선 데이터의 일관성을 확인합니다 (접근 바 사이의 시간표차가 같는지 여부).

이 검사를 통과한 후, 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-라인 데이터 업데이트와 추가가 올바르게 작동하는지 확인할 수 있습니다.

img

img

매일 K-라인 데이터를 사용하여 8000 바를 검색하도록 설정합니다.

img

매일 1309개의 K-라인만 있는 것을 보면, 교환 차트의 데이터를 비교해보세요.

img

img

데이터도 일치한다는 것을 알 수 있습니다.

END

템플릿 주소:파그니케이션 쿼리 K-라인 역사 데이터 템플릿의 자바스크립트 버전템플릿 주소:플롯 라이브러리

위의 템플릿과 전략 코드는 교육 및 학습 용도로만 제공되며 라이브 거래의 특정 필요에 따라 최적화 및 수정하십시오.


관련

더 많은