Cuando se escribe una estrategia comercial cuantitativa, utilizando los datos de la línea K, a menudo hay casos en los que se requieren datos de la línea K de ciclo no estándar. por ejemplo, se requieren datos de la línea K de ciclo de 12 minutos y datos de ciclo de línea K de 4 horas. Por lo general, tales ciclos no estándar no están directamente disponibles. Entonces, ¿cómo lidiar con tales necesidades?
Los datos de la línea K del ciclo no estándar se pueden obtener combinando los datos del ciclo más pequeño. Imagínese esto, el precio más alto en múltiples ciclos se cuenta como el precio más alto después de la síntesis de la línea K del ciclo múltiple, y el precio más bajo se calcula como el precio más bajo después de la síntesis, y el precio de apertura no cambia. Se sintetiza el primer precio de apertura de los datos de materia prima de la línea K. El precio de cierre corresponde al precio de cierre de los últimos datos de materia prima de la línea K. El tiempo utiliza el tiempo de la línea de precio de apertura k. El volumen de transacción utiliza los datos de materia prima que se suman y calculan.
Como se muestra en la figura:
Tomemos el activo blockchain BTC_USDT como ejemplo y sintetizemos 1 hora en 4 horas.
El tiempo | El más alto | Abierto. | El más bajo | Muy cerca. |
---|---|---|---|---|
2019.8.12 00:00 | 11447.07 | 11382.57 | 11367.2 | 11406.92 |
2019.8.12 01:00 | 11420 | 11405.65 | 11366.6 | 11373.83 |
2019.8.12 02:00 | 11419.24 | 11374.68 | 11365.51 | 11398.19 |
2019.8.12 03:00 | 11407.88 | 11398.59 | 11369.7 | 11384.71 |
Los datos de cuatro ciclos de una hora se combinan en un solo ciclo de cuatro horas.
El precio de apertura es el precio de apertura de la primera línea K a las 00:00 hora: 11382.57 El precio de cierre es el precio de cierre de la última línea k a las 03:00: 11384.71 El precio más alto es encontrar el precio más alto entre ellos: 11447.07 El precio más bajo es encontrar el precio más bajo entre ellos: 11365.51
Nota: El mercado de futuros de materias primas de China cerró a las 15:00 horas en un día de negociación normal
La hora de inicio del ciclo de 4 horas es la hora de inicio de la primera línea K de 1 hora, es decir, 2019.8.12 00:00
La suma del volumen de todas las líneas k de 1 hora se utiliza como este volumen de líneas k de 4 horas.
Se sintetiza una línea K de 4 horas:
High: 11447.07
Open: 11382.57
Low: 11365.51
Close: 11384.71
Time: 209.8.12 00:00
Se puede ver que los datos son consistentes.
Después de entender las ideas iniciales, se puede escribir manualmente el código para realizar los requisitos.
Estos códigos son únicamente de referencia:
function GetNewCycleRecords (sourceRecords, targetCycle) { // K line synthesis function
var ret = []
// First get the source K line data cycle
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++) {
// Get the time zone offset value
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
}
// test
function main () {
while (true) {
var r = exchange.GetRecords() // Raw data, as the basic K-line data of the synthesize K line. for example, to synthesize a 4-hour K-line, you can use the 1-hour K-line as the raw data.
var r2 = GetNewCycleRecords(r, 1000 * 60 * 60 * 4) // Pass the original K-line data r through the GetNewCycleRecords function, and the target cycles, 1000 * 60 * 60 * 4, ie the target synthesis cycle is 4 hours K-line data .
$.PlotRecords(r2, "r2") // The strategy class library bar can be selected by check the line class library, and calling the $.PlotRecords line drawing class library to export the function drawing.
Sleep(1000) // Each cycle is separated by 1000 milliseconds, preventing access to the K-line interface too much, resulting in transaction restrictions.
}
}
En realidad, para sintetizar la línea K, se necesitan dos cosas. El primero son los datos de la materia prima, es decir, los datos de la línea K de un ciclo más pequeño.var r = exchange.GetRecords()
para obtener los datos de la línea K del ciclo más pequeño.
La segunda es calcular el tamaño del ciclo de síntesis, usamos el algoritmo de función GetNewCycleRecords para hacer esto, entonces finalmente se puede devolver los datos de una estructura de matriz de K-línea sintetizada.
Tenga en cuenta:
El ciclo objetivo no puede ser menor que el ciclo de la línea K que pasó en la función GetNewCycleRecords como materia prima para los datos.
El ciclo objetivo debe ser establecido en
Por ejemplo:
La línea K del ciclo de 12 minutos comienza a partir de 0:0 cada hora, el primer ciclo es 00:00:00 ~ 00:12:00, y el segundo ciclo es 00:12: 00 ~ 00: 24:00, el tercer ciclo es 00:24: 00 ~ 00:36:00, el cuarto ciclo es 00:36:00 ~ 00:48:00, el quinto ciclo es 00:48 :00 ~ 01:00:00, que son exactamente una hora completa.
Si se trata de un ciclo de 13 minutos, será un ciclo que no está cerrado. Los datos calculados por dicho ciclo no son únicos porque los datos sintetizados difieren según el punto de partida de los datos sintetizados.
Lo ejecutamos en el mercado real:
Gráfico de cambio de contraste
Quiero calcular la media móvil del precio más alto para todas las líneas K. ¿Qué debo hacer?
Por lo general, calculamos los promedios móviles utilizando el promedio de los precios de cierre, pero a veces hay demanda para utilizar el precio más alto, el precio más bajo, el precio de apertura y así sucesivamente.
para estas demandas adicionales, los datos de línea K devueltos por la función exchange.GetRecords() no se pueden pasar directamente a la función de cálculo del indicador.
Por ejemplo:
Eltalib.MA
La función de cálculo del indicador de media móvil tiene dos parámetros, el primero es el de los datos que se deben transmitir y el segundo es el parámetro del ciclo del indicador.
Por ejemplo, debemos calcular los indicadores que se muestran a continuación.
El ciclo de la línea K es de 4 horas.
En el gráfico de cotizaciones del mercado de divisas, se ha establecido una línea media con el parámetro del ciclo de 9.
La fuente de datos calculada utiliza el precio más alto por barra.
Es decir, esta línea media móvil consiste en el promedio del precio promedio más alto de nueve ciclos de 4 horas K-line Bar.
Vamos a construir un dato nosotros mismos para ver si es lo mismo con los datos del intercambio.
var highs = []
for (var i = 0 ; i < r2.length ; i++) {
highs.push(r2[i].High)
}
Dado que necesitamos calcular el precio más alto de cada barra para obtener el valor del indicador de la media móvil, necesitamos construir una matriz en la que cada elemento de datos tiene el precio más alto para cada barra.
Se puede ver que elhighs
La variable es inicialmente una matriz vacía, luego atravesamos la variable de datos de línea k r2 (no recuerden la r2?
Leer el precio más alto de cada Bar de r2 (es decir, r2 [i].Alto, i oscila entre 0 y r2. longitud - 1), luego presionar enhighs
De esta manera sólo construimos una estructura de datos que corresponde uno a uno con la K-línea de datos Bar.
En este momento,highs
¿Puede pasar eltalib.MA
función para calcular la media 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") // Draw the K line
var highs = []
for (var i = 0 ; i < r2.length ; i++) {
Highs.push(r2[i].High)
}
var ma = talib.MA(highs, 9) // use the moving average function "talib.MA" to calculate the moving average indicator
$.PlotLine("high_MA9", ma[ma.length - 2], r2[r2.length - 2].Time) // Use the line drawing library to draw the moving average indicator on the chart
Sleep(1000)
}
}
Prueba posterior:
Puede ver que el valor promedio del indicador de la posición del punto del ratón en la figura es 11466.9289
El código anterior se puede copiar a la estrategia para ejecutar la prueba, recuerde revisar la
La plataforma FMZ Quant cuenta ya con una interfaz empaquetada, a saber, el
exchange.GetRecords
Función, para obtener datos de línea K.
Lo siguiente se centra en el acceso directo a la interfaz de datos de línea K del intercambio para obtener datos, porque a veces se necesitan especificar parámetros para obtener más líneas K, el paqueteGetRecords
La interfaz generalmente devuelve 100 k líneas. si te encuentras con una estrategia que inicialmente requiere más de 100 K-líneas, necesitas esperar el proceso de recopilación.
Para hacer que la estrategia funcione lo antes posible, puede encapsular una función, acceder directamente a la interfaz de línea K del intercambio y especificar parámetros para obtener más datos de línea K.
Utilizando el par de operaciones BTC_USDT en el exchange Huobi como ejemplo, implementamos este requisito:
Encuentra la documentación de la API del exchange
https://huobiapi.github.io/docs/spot/v1/en/#get-klines-candles
Parámetros:
Nombre | Tipo de producto | ¿Es necesario? | Descripción | Valor |
---|---|---|---|---|
el símbolo | la cuerda | Es cierto | Pares de negociación | ¿Qué es eso? |
el período | la cuerda | Es cierto | Devuelve la granularidad de tiempo de los datos, que es el intervalo de tiempo de cada línea k | 1 minuto, 5 minutos, 15 minutos, 30 minutos, 60 minutos, 1 día, 1 mes, 1 semana, 1 año |
tamaño | número entero | - No es cierto. | Devuelve el número de K líneas de datos | [1, 2000] |
Código de ensayo:
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")
}
Se puede ver que en el registro, impresiónrecords.length
es 300, es decir, el número derecords
La barra de datos de la línea K es 300.