K 길이의 특정 줄의 데이터를 얻을 수 있는 템플릿 클래스 라이브러리를 디자인하는 방법을 알려줍니다.

저자:작은 꿈, 창작: 2023-06-27 13:37:01, 업데이트: 2023-09-18 19:34:23

img

K 길이의 특정 줄의 데이터를 얻을 수 있는 템플릿 클래스 라이브러리를 디자인하는 방법을 알려줍니다.

트렌드 전략을 설계할 때, 계산 지표는 종종 충분한 양의 K 라인 바를 필요로 한다. FMZ 플랫폼 API에 의존한다:exchange.GetRecords()이 함수들은exchange.GetRecords()초기 암호화폐 거래소 API 설계에는 페이지 분할 쿼리가 없었고, 거래소의 K 라인 인터페이스는 제한된 양의 데이터에만 제공되었기 때문에 일부 개발자는 더 큰 매개 변수 지표 계산에 대한 요구를 충족시킬 수 없었습니다.

Binance 계약 API의 K 라인 인터페이스는 분화 질의를 지원하기 때문에 이 문서는 Binance K 라인 API의 예를 통해 분화 질의를 구현하고 FMZ 플랫폼 템플릿 라이브러리에 바의 수를 지정할 수 있도록 가르칩니다.

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

img

먼저 거래소 API 문서를 살펴보고 인터페이스의 특정 매개 변수를 참조하십시오. 우리는 이 K선 인터페이스 호출에서 종류, K선 주기, 데이터 범위 (시작, 종료 시간), 페이지 분할 수 등을 지정해야한다는 것을 볼 수 있습니다.

우리가 설계한 요구사항은 지정된 양의 K선 데이터에 대한 쿼리이기 때문에, 예를 들어 1시간 K선에 대한 쿼리를 현재 시점에서 과거 시점 방향으로 밀고, 5000바르의 쿼리를 합니다.

그러면 우리는 페이지별로 쿼리를 하고, 현재 순간부터 역사의 어떤 순간까지 분기 처리한다. 우리가 필요로 하는 K선 데이터의 주기는 각 분기 시작 및 종료 시간을 계산하는 것이 좋습니다. 충분한 바 수를 쿼리할 때까지 분기 방향으로만 쿼리를 합니다. 아이디어가 듣기 쉽지 않다면, 직접 실행하세요!

"자바스크립트 버전의 K 라인 역사 데이터 템플릿 페이지 쿼리"를 디자인

디자인 템플릿의 인터페이스 함수:$.GetRecordsByLength(e, period, length)

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

디자인$.GetRecordsByLength이 함수는 일반적으로 전략 실행 초기에는 긴 K 라인을 필요로 하는 용도 시나리오에서 계산 지표를 수행한다. 이 함수가 실행되면 충분한 양의 데이터를 얻으면 새로운 K 라인 데이터를 업데이트할 필요가 있다. 이 함수를 더 이상 호출할 필요가 없다. 이는 불필요한 인터페이스 호출을 초래한다.

그래서 후속 데이터 업데이트를 위한 인터페이스를 설계해야 합니다.$.UpdataRecords(e, records, period)

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

다음으로 이러한 인터페이스 함수를 구현하는 것입니다.

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

이 템플릿에서는 K 라인 Binance 계약 인터페이스만 지원합니다.getRecordsForFuturesBinance이 기능은 다른 암호화폐 거래소를 지원하는 K 라인 인터페이스를 확장할 수 있습니다.

테스트 링크

템플릿에서 이러한 기능을 구현하는 코드가 많지 않은 것을 볼 수 있습니다. 아마 200줄 이하입니다. 템플릿 코드가 작성된 후에 테스트는 절대적으로 적지 않습니다. 그리고 이러한 데이터를 얻기 위해 우리는 가능한 한 엄격한 테스트를 필요로합니다.

이 테스트는 "JavaScript 버전의 K줄 역사 데이터 템플릿을 검색"과 "줄 라이브러리 그림을 그리기" 템플릿을 자신의 정책 라이브러리에 복사해야 합니다.전략 광장이 두 가지 템플릿을 선택하여 새로운 정책을 만들었습니다.

img

img

img

"그림줄 클래스 라이브러리"를 사용하는 이유는 우리가 얻은 K줄 데이터를 관찰하기 위해 그려야 하기 때문입니다.

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

여기 우리가 사용하는var testPeriod = PERIOD_M5이 문장은 5분 K 라인 주기를 설정하고 8000 바르를 얻도록 지정합니다.var r = $.GetRecordsByLength(exchange, testPeriod, 8000)인터페이스에서 돌아온 긴 K선 데이터의 그림 테스트를 위해:

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

이 긴 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("检测通过")

1, K 라인Bar에서 반복되는 것이 있는지 확인합니다. 2, K선Bar의 연속성을 검사한다 (동접한Bar의 시간각차가 같는지)

이 검사들이 통과된 후, K선을 업데이트하는 인터페이스를 검사합니다.$.UpdataRecords(exchange, r, testPeriod)이 사진이 어떻게 생겼는지

    // 更新数据
    while (true) {
        $.UpdataRecords(exchange, r, testPeriod)
        LogStatus(_D(), "r.length:", r.length)
        $.PlotRecords(r, "k")
        Sleep(5000)
    }

이 코드는 리얼 디스크에서 실행되는 동안 정책 차트에 K줄을 지속적으로 출력합니다. 이를 통해 K줄 바 데이터 업데이트와 추가가 정상인지 확인합니다.

img

img

K 라인을 사용 하 여 8000 루트를 사용 하 여 (이전 8000 일, 시장 데이터 가 없 는 것을 알고) 이렇게 폭력 테스트:

img

유동인력거래소 차트와 비교해 볼 때 일선은 1309개에 불과합니다.

img

img

이 자료들은 서로 일치하는 것을 볼 수 있습니다.

END

템플릿 주소:"자바스크립트 버전의 K줄 역사 데이터 템플릿 검색 페이지"템플릿 주소:"그림자리 클래식 라이브러리"

위의 템플릿과 전략 코드는 교육용, 학습용으로만 사용되며 실제 디스크는 필요에 따라 최적화 또는 수정하십시오.


더 많은