Type/to search
8
Follow
1363
Followers
Una breve discusión sobre el procesamiento de datos de la línea K en el comercio programado
Discussions
Created 2019-08-13 11:11:38  Updated 2023-10-20 20:06:13
 8
 4970

img

Una breve discusión sobre el procesamiento de datos de la línea K en el comercio programado

Al escribir estrategias de negociación programática, utilizando datos de la línea K, a menudo es necesario utilizar algunos datos de la línea K de período no estándar, como datos de la línea K de período de 12 minutos, datos de la línea K de período de 4 horas, generalmente Este tipo de período no estándar no se puede obtener directamente. ¿Cómo respondemos entonces a tales demandas?
La respuesta es definitivamente que hay una manera.
Los ciclos no estándar se pueden obtener fusionando y sintetizando datos de ciclos más pequeños. Puede imaginar que el precio más alto en varios ciclos se cuenta como el precio más alto después de la síntesis, y el precio más bajo se cuenta como el precio más bajo después de la síntesis. El precio no cambiará. Se utiliza el primer precio de apertura de los datos de materia prima de la línea K sintetizada, el precio de cierre corresponde al último precio de cierre de los datos de materia prima de la línea K sintetizada, el tiempo es el tiempo del precio de apertura y el volumen de negociación se calcula sumando los volúmenes de transacción de los datos de la materia prima.
Como se muestra en la imagen:

  • Ideas

    Tomamos el mercado de activos blockchain BTC_USDT como ejemplo y sintetizamos 1 hora en 4 horas.

    img

    img

    img

    img

    HoraAltoAperturaBajoCierre
    2019.8.12 00:0011447.0711382.5711367.211406.92
    2019.8.12 01:001142011405.6511366.611373.83
    2019.8.12 02:0011419.2411374.6811365.5111398.19
    2019.8.12 03:0011407.8811398.5911369.711384.71

    Los datos de estos cuatro ciclos de 1 hora se combinan en un ciclo de 4 horas. El precio de apertura es el precio de apertura de las primeras 00:00: 11382,57
    El precio de cierre es el último, es decir, el precio de cierre a las 03:00: 11384.71
    El precio más alto es el precio más alto aquí: 11447.07
    El precio más bajo está aquí: 11365.51
    La hora de inicio del ciclo de 4 horas es 00:00, la hora de inicio de la línea K de 1 hora, es decir, 2019.8.12 00:00
    El volumen de operaciones se puede sumar cada 1 hora (principalmente para observar cómo se sintetiza el precio, lo que no se muestra en los datos del volumen de operaciones). No entraré en detalles aquí.

    La línea K de 4 horas sintetizada es:
    Alto: 11447.07
    Abierto: 11382.57
    Mínimo: 11365,51
    Recibidos: 11384.71
    Hora: 2019.8.12 00:00

    img

    Se puede ver que los datos son consistentes.

  • Escribe código para implementar

    Después de verificar las ideas preliminares, puede comenzar a escribir código para implementar preliminarmente este requisito.

    Libere el código directamente, el código es solo para referencia:

    function GetNewCycleRecords (sourceRecords, targetCycle) { // K线合成函数 var ret = [] // 首先获取源K线数据的周期 if (!sourceRecords || sourceRecords.length < 2) { return null } var sourceLen = sourceRecords.length var sourceCycle = sourceRecords[sourceLen - 1].Time - sourceRecords[sourceLen - 2].Time if (targetCycle % sourceCycle != 0) { Log("targetCycle:", targetCycle) Log("sourceCycle:", sourceCycle) throw "targetCycle is not an integral multiple of sourceCycle." } if ((1000 * 60 * 60) % targetCycle != 0 && (1000 * 60 * 60 * 24) % targetCycle != 0) { Log("targetCycle:", targetCycle) Log("sourceCycle:", sourceCycle) Log((1000 * 60 * 60) % targetCycle, (1000 * 60 * 60 * 24) % targetCycle) throw "targetCycle cannot complete the cycle." } var multiple = targetCycle / sourceCycle var isBegin = false var count = 0 var high = 0 var low = 0 var open = 0 var close = 0 var time = 0 var vol = 0 for (var i = 0 ; i < sourceLen ; i++) { // 获取 时区偏移数值 var d = new Date() var n = d.getTimezoneOffset() if (((1000 * 60 * 60 * 24) - sourceRecords[i].Time % (1000 * 60 * 60 * 24) + (n * 1000 * 60)) % targetCycle == 0) { isBegin = true } if (isBegin) { if (count == 0) { high = sourceRecords[i].High low = sourceRecords[i].Low open = sourceRecords[i].Open close = sourceRecords[i].Close time = sourceRecords[i].Time vol = sourceRecords[i].Volume count++ } else if (count < multiple) { high = Math.max(high, sourceRecords[i].High) low = Math.min(low, sourceRecords[i].Low) close = sourceRecords[i].Close vol += sourceRecords[i].Volume count++ } if (count == multiple || i == sourceLen - 1) { ret.push({ High : high, Low : low, Open : open, Close : close, Time : time, Volume : vol, }) count = 0 } } } return ret } // 测试 function main () { while (true) { var r = exchange.GetRecords() // 原始数据,作为合成K线的基础K线数据,例如要合成4小时K线,可以用1小时K线作为原始数据。 var r2 = GetNewCycleRecords(r, 1000 * 60 * 60 * 4) // 通过 GetNewCycleRecords 函数 传入 原始K线数据 r , 和目标周期, 1000 * 60 * 60 * 4 即 目标合成的周期 是4小时K线数据。 $.PlotRecords(r2, "r2") // 策略类库栏 可以勾选画线类库,调用 $.PlotRecords 画线类库 导出函数 画图。 Sleep(1000) // 每次循环间隔 1000 毫秒,防止访问K线接口获取数据过于频繁,导致交易所限制。 } }

    De hecho, para sintetizar la línea K se necesitan dos cosas: la primera son los datos de la materia prima, es decir, los datos de la línea K de un período pequeño.var r = exchange.GetRecords()
    Datos de la línea K de período pequeño obtenidos. El segundo es definir claramente el período de síntesis, es decir, el período objetivo para la síntesis de datos de la línea K.
    Luego, a través del algoritmo de la función GetNewCycleRecords, se pueden devolver finalmente los datos de una estructura de matriz de K líneas sintetizada.
    Cabe señalar que:

      1. El ciclo de destino no puede ser menor que el ciclo de la línea K que pasa a la función GetNewCycleRecords como materia prima de datos.
        Esto se debe a que es imposible utilizar un ciclo pequeño para sintetizar datos de un ciclo más pequeño.
      1. El período objetivo que se establezca debe ser un período cerrado.
        ¿Qué es el cierre de ciclo?
        En pocas palabras, en el plazo de una hora o un día, los rangos de tiempo del ciclo objetivo se combinan para formar un circuito cerrado.
        Ejemplo:
        Por ejemplo, la línea K de un ciclo de 12 minutos comienza en 0:00 de cada hora (tome 0:00 como ejemplo), y el primer ciclo es00:00:00 ~ 00:12:00, el segundo ciclo es00:12:00 ~ 00:24:00, el tercer ciclo es00:24:00 ~ 00:36:00, el cuarto ciclo es00:36:00 ~ 00:48:00, el quinto ciclo es00:48:00 ~ 01:00:00 , lo que supone una hora completa.

      Si se trata de un ciclo de 13 minutos, es un ciclo abierto y los datos calculados en dicho ciclo no son únicos, porque los datos sintetizados diferirán dependiendo del punto de inicio de los datos sintetizados.

    El disco real se ejecutó:
    img

    Comparar gráficos de cambio
    img

  • Utilice datos de la línea K para construir la estructura de datos requerida

    Los miembros del grupo a menudo hacen preguntas: Quiero calcular el promedio móvil del precio más alto de cada línea K, ¿qué debo hacer?

    Generalmente, calculamos la media móvil calculando el promedio de los precios de cierre para formar la media móvil, pero a veces es necesario calcular el precio más alto, el precio más bajo, el precio de apertura, etc.
    En este momento, no puedes simplementeexchange.GetRecords() Los datos de la línea K devueltos por la función se pasan directamente a la función de cálculo del indicador.

    Por ejemplo:
    La función de cálculo del indicador de media móvil talib.MA tiene dos parámetros. El primer parámetro son los datos que se deben introducir y el segundo parámetro es el parámetro del período del indicador.
    Por ejemplo, queremos calcular los siguientes indicadores
    img

    El ciclo de la línea K es de 4 horas.
    En el gráfico de intercambio, se ha establecido una media móvil con un parámetro de período de media móvil de 9.
    Y la fuente de datos para el cálculo se establece en el precio más alto de cada barra.
    img
    Es decir, esta media móvil es el promedio de los precios más altos de 9 barras de la línea K de 4 horas, que constituyen la media móvil del indicador.

    Construyamos algunos datos nosotros mismos y veamos si son los mismos que los calculados por el gráfico del exchange.

    var highs = [] for (var i = 0 ; i < r2.length ; i++) { highs.push(r2[i].High) }

    Dado que necesitamos calcular el promedio de los precios más altos de cada barra para derivar el indicador de promedio móvil.
    Luego primero debes construir una matriz, en la que cada elemento de datos corresponde al precio más alto de cada barra.
    Puedes ver que la variable highs es inicialmente una matriz vacía, y luego recorremos la variable de datos de la vela r2 (¿no recuerdas r2? Mira el código en la función principal de síntesis de la vela de 4 horas anterior).
    Leer el precio más alto de cada barra de r2 (es decir, r2[i].High , i varía de 0 a r2.length - 1 ), y luego lo empuja hacia los máximos. De esta manera se construye una estructura de datos que se corresponde uno a uno con los datos de la línea K Bar.

    En este punto, los máximos se pueden pasar a la función talib.MA para calcular el promedio móvil.

    Ejemplo completo:

    function main () { while (true) { var r = exchange.GetRecords() var r2 = GetNewCycleRecords(r, 1000 * 60 * 60 * 4) if (!r2) { continue } $.PlotRecords(r2, "r2") // 画出K线 var highs = [] for (var i = 0 ; i < r2.length ; i++) { highs.push(r2[i].High) } var ma = talib.MA(highs, 9) // 用均线指标函数 talib.MA 计算 均线指标 $.PlotLine("high_MA9", ma[ma.length - 2], r2[r2.length - 2].Time) // 使用画线类库把均线指标画在图表上 Sleep(1000) } }

    Ejecución de backtest:

    img

    Puede ver que los valores del indicador de promedio móvil en la posición del mouse en la figura son11466.9289

    El código anterior se puede copiar en la estrategia para ejecutar la prueba. ¡Recuerde marcar "Biblioteca de dibujo de líneas" y guardarlo!

  • Cómo obtener datos de la línea K en el mercado de divisas digitales

    La plataforma de comercio cuantitativo Inventor ya tiene una interfaz empaquetada, concretamente la función exchange.GetRecords, que puede obtener datos de la línea K.
    Lo siguiente se centra en el acceso directo a la interfaz de datos de la línea K de intercambio para obtener datos, porque a veces es necesario especificar parámetros para obtener más líneas K, interfaz GetRecords encapsulada
    Generalmente se devuelven 100. Si la estrategia requiere inicialmente más de 100 líneas K, es necesario recolectar y esperar.
    Para que la estrategia se ejecute lo más rápido posible, puede encapsular una función usted mismo, acceder directamente a la interfaz de intercambio de K-line y especificar parámetros para obtener más datos de K-line.

    Tomando como ejemplo el par comercial BTC_USDT de Huobi, implementamos este requisito:

    Encuentre el documento API del exchange y vea la descripción de la interfaz K-line:
    img

    https://api.huobi.pro/market/history/kline?period=1day&size=200&symbol=btcusdt

    parámetro:

    Nombre del parámetroTipoObligatorioDescripciónValor
    símbolocadenaverdaderoPar comercialbtcusdt, ethbtc...
    periodstringtrueDevuelve la granularidad del tiempo de los datos, es decir, el intervalo de tiempo de cada vela1min, 5min, 15min, 30min, 60min, 1day, 1mon, 1week, 1year
    sizeintegerfalseDevuelve el número de datos de la línea K[1, 2000]

    Código de prueba:

    function GetRecords_Huobi (period, size, symbol) { var url = "https://api.huobi.pro/market/history/kline?" + "period=" + period + "&size=" + size + "&symbol=" + symbol var ret = HttpQuery(url) try { var jsonData = JSON.parse(ret) var records = [] for (var i = jsonData.data.length - 1; i >= 0 ; i--) { records.push({ Time : jsonData.data[i].id * 1000, High : jsonData.data[i].high, Open : jsonData.data[i].open, Low : jsonData.data[i].low, Close : jsonData.data[i].close, Volume : jsonData.data[i].vol, }) } return records } catch (e) { Log(e) } } function main() { var records = GetRecords_Huobi("1day", "300", "btcusdt") Log(records.length) $.PlotRecords(records, "K") }

    Versión Python, ejemplo de acceso a la interfaz de intercambio de Huobi:

#!python3 import json import urllib2 def GetRecords_Huobi(period, size, symbol): headers = {'User-Agent':'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6'} url = "https://api.huobi.pro/market/history/kline?" + "period=" + period + "&size=" + size + "&symbol=" + symbol request = urllib2.Request(url) request.add_header('User-Agent','Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6') opener = urllib2.build_opener() f= opener.open(request) ret = f.read().decode('utf-8') try : jsonData = json.loads(ret) records = [] for i in range(len(jsonData["data"]) - 1, -1, -1): records.append({ "Time" : jsonData["data"][i]["id"] * 1000, "High" : jsonData["data"][i]["high"], "Open" : jsonData["data"][i]["open"], "Low" : jsonData["data"][i]["low"], "Close" : jsonData["data"][i]["close"], "Volume" : jsonData["data"][i]["vol"], }) return records except Exception as e: Log(e) def main(): r = GetRecords_Huobi("1day", "300", "btcusdt") Log(len(r)) ext.PlotRecords(r, "K") # 需要引用Python画线类库

Versión Python, un ejemplo de acceso a la interfaz K-line de Binance Exchange:

#!python3 import json import urllib2 def GetRecords_Huobi(period, size, symbol): headers = {'User-Agent':'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6'} url = "https://api.binance.com/api/v3/klines?symbol=" + symbol + "&interval=" + period request = urllib2.Request(url) request.add_header('User-Agent','Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6') opener = urllib2.build_opener() f= opener.open(request) ret = f.read().decode('utf-8') try : jsonData = json.loads(ret) records = [] for i in range(len(jsonData)): records.append({ "Time" : float(jsonData[i][0]), "High" : float(jsonData[i][2]), "Open" : float(jsonData[i][1]), "Low" : float(jsonData[i][3]), "Close" : float(jsonData[i][4]), "Volume" : float(jsonData[i][5]), }) return records except Exception as e: Log(e) def main(): r = GetRecords_Huobi("1m", "300", "BTCUSDT") Log(len(r)) ext.PlotRecords(r, "K") # 需要引用Python画线类库

img

img

Podemos ver en el registro que records.length es 300, lo que significa que hay 300 barras de datos de la línea K de registros.
img

Related Recommendations
Comment
All comments (8)

    贴主能修复一下问题么?无法用3小时或6小时k合成日k

    6 years ago

    好的,抽时间改改。

    6 years ago

    if (((1000 * 60 * 60 * 24) - sourceRecords[i].Time % (1000 * 60 * 60 * 24) + (n * 1000 * 60)) % targetCycle == 0) {
    isBegin = true
    }

    这一句有问题,无法用3小时或6小时k合成日k,只能用1小时,2小时,4小时的k线合成日k

    6 years ago

    如果要爬某品种全部的历史数据也能爬么?

    6 years ago

    这是访问交易所接口数据的,交易所给你多少数据就是多少。也就是最近的几百根吧一般来说。

    6 years ago

    感谢回复

    7 years ago

    请问,如果想要超过300根,怎么处理比较好呢?比如1000根K线数据。交易所单次好像支持每次300根。多谢

    7 years ago

    如果 超过交易所接口支持的最大返回数量,这样只能收集数据,等足够K线数据量。

    7 years ago
  • 1
iPhone Download
Forums
PINE Language
© 2015 - ∞ INVENTOR PTE LTD (SG)