Te enseñará a diseñar una biblioteca de modelos para obtener datos de líneas de K longitud especificadas.

El autor:Un sueño pequeño., Creado: 2023-06-27 13:37:01, Actualizado: 2023-09-18 19:34:23

img

Te enseñará a diseñar una biblioteca de modelos para obtener datos de líneas de K longitud especificadas.

Cuando se diseñan algunas estrategias de tendencia, los indicadores de cálculo a menudo requieren una cantidad suficiente de K-line Bar.exchange.GetRecords()La cantidad de datos que da la función.exchange.GetRecords()La interfaz K-line de los intercambios no incluía consultas de partición de página en los primeros diseños de la API de los intercambios de criptomonedas, y las interfaces K-line de los intercambios solo ofrecían una cantidad limitada de datos, por lo que algunos desarrolladores no podían satisfacer las necesidades de cálculo de indicadores de parámetros más grandes.

Si la interfaz de línea K de la API de contratos de Binance admite consultas de partición de páginas, este artículo le enseñará cómo implementar una consulta de partición de páginas con la interfaz de línea K de Binance y especificar el número de bares de acceso a la biblioteca de modelos de la plataforma FMZ.

Interfaz K de Binance

img

Primero, hay que ver la documentación de la API de la bolsa para ver los parámetros específicos de la interfaz. Podemos ver que esta interfaz de línea K requiere una variedad, un ciclo de línea K, un rango de datos (tiempo de inicio, tiempo de finalización), un número de páginas, etc.

Dado que nuestro requisito de diseño es consultar una cantidad determinada de datos de la línea K, por ejemplo, consultar la línea K de 1 hora, desde el momento actual hasta el momento pasado, con un número de 5.000 bares. Así que si solo llama una consulta a la interfaz API del exchange, obviamente no obtendrá los datos que desea.

Entonces hacemos una consulta de página, y procesamos los fragmentos desde el momento actual hasta un momento histórico. El ciclo de datos de K-line que sabemos que necesitamos calcula bien el comienzo y el final de cada segmento. Solo hagamos consultas en la dirección del momento histórico de cada segmento hasta que hagamos una consulta con el número suficiente de Bar.

Diseño de la plantilla de datos históricos de la línea K de búsqueda de páginas en JavaScript

Función de interfaz de diseño de la plantilla:$.GetRecordsByLength(e, period, length)

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

Diseño$.GetRecordsByLengthEsta función, que normalmente requiere una línea K larga para calcular los indicadores en el inicio de la ejecución de la estrategia. Una vez que se obtienen datos lo suficientemente largos, solo se necesita actualizar los nuevos datos de la línea K. No es necesario volver a llamar a esta función para obtener datos de línea K muy largos, lo que causa llamadas de interfaz innecesarias.

Por lo tanto, también se necesita diseñar una interfaz para actualizar los datos posteriores:$.UpdataRecords(e, records, period)

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

El siguiente paso es implementar estas funciones de interfaz.

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

En la plantilla, implementamos solo el soporte para la interfaz de línea K del contrato de Binance, que es la interfaz de línea K de Binance.getRecordsForFuturesBinanceLa función también puede extender la interfaz de K-Line que admite otros intercambios de criptomonedas.

Enlace de prueba

Se puede ver que no hay mucho código para implementar estas funciones en la plantilla, probablemente menos de 200 líneas. Una vez que se ha escrito el código de la plantilla, las pruebas son absolutamente innumerables. Y para obtener este tipo de datos, también necesitamos pruebas lo más estrictas posible.

La prueba requiere copiar esta "JavaScript version page split query K line history template" y "Draw line library" a su propia librería de políticas (en inglés).Plaza de la EstrategiaDespués de eso, creamos una nueva política para seleccionar estas dos plantillas:

img

img

img

El uso de la biblioteca de clases de líneas de dibujo se debe a que necesitamos dibujar los datos de líneas de K obtenidos para observarlos.

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

Aquí usamosvar testPeriod = PERIOD_M5Esta frase, establece un ciclo de línea K de 5 minutos, especifica obtener 8000 bares.var r = $.GetRecordsByLength(exchange, testPeriod, 8000)La interfaz devuelve datos de K-lineas largas para realizar pruebas gráficas:

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

Ahora, para hacer una prueba de este largo K-line de datos:

    // 检测数据
    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, para comprobar si hay una repetición en la línea KBar. 2, comprobar la coherencia de la línea KBar (si los valores de los intervalos de tiempo de las barras adyacentes son iguales)

Una vez que estos controles pasan, se inspecciona la interfaz para actualizar la línea K.$.UpdataRecords(exchange, r, testPeriod)¿Qué es lo normal?

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

Este código se ejecuta en el disco físico y se sigue produciendo K-line en el gráfico de políticas, con lo que se comprueba si los datos de K-lineBar se actualizan o se agregan correctamente.

img

img

Utilizando la línea K de acceso diario, configure el acceso a 8000 raíces (conociendo claramente que no hay datos de mercado antes de los 8000 días), así:

img

En el caso de los datos de los gráficos de las bolsas de valores, vemos que la línea de día tiene sólo 1309 raíces:

img

img

Se puede ver que los datos también coinciden.

Enlace a la sección

La dirección de la plantilla:"La versión de JavaScript para hacer una búsqueda de página de K-line Historial de Datos Template"La dirección de la plantilla:"La biblioteca de líneas de dibujo".

Las plantillas y el código de la estrategia se utilizan solo para la enseñanza y el aprendizaje.


Más.