La API Info de Hyperliquid expone un método candleSnapshot que devuelve un arreglo de objetos de vela para una moneda y un intervalo, acotado por una ventana startTime/endTime. Dado que cada solicitud está acotada, un historial OHLCV continuo se construye avanzando un cursor a través de ventanas ordenadas, deduplicando por el tiempo de apertura de la vela t y verificando explícitamente los intervalos faltantes. Obtener los datos en el intervalo nativo que se pretende almacenar evita los errores de redondeo y de atribución de volumen que se acumulan al remuestrear velas más gruesas. Las velas históricas deben luego conciliarse con el canal WebSocket de velas en vivo para que la vela final del archivo no quede congelada en el momento en que se ejecutó el sondeo. Esta guía documenta el contrato de solicitud, la semántica de intervalos, la paginación por ventanas, un recolector Node.js ejecutable, una tabla de resultados que el lector completa, los modos de fallo y las compensaciones entre profundidad histórica y costo de solicitudes.
El contrato de solicitud candleSnapshot y la forma de la respuesta
El endpoint Info de Hyperliquid documenta candleSnapshot como una solicitud POST cuyo cuerpo lleva un type de candleSnapshot, una coin, un interval y una ventana startTime/endTime. La respuesta es un arreglo de objetos de vela en lugar de un único objeto, y ese es el detalle que determina cada decisión de paginación a lo largo de esta guía. Considera la documentación de Hyperliquid, endpoint Info como la fuente autoritativa para los nombres exactos de los campos y las cadenas de intervalo aceptadas, porque las copias del proveedor de la referencia del método pueden desviarse.
Cada objeto de vela lleva t (tiempo de apertura), T (tiempo de cierre), s (símbolo), i (intervalo), o/h/l/c (apertura, máximo, mínimo, cierre), v (volumen) y n (número de operaciones). El tiempo de apertura t es la clave primaria natural para un archivo: es estable entre solicitudes, por lo que es el campo correcto para deduplicar cuando las ventanas se superponen. El tiempo de cierre T se deriva del intervalo, así que es útil para la detección de huecos pero no para la identidad.
La solicitud está acotada por la ventana que proporciones, y el servidor devuelve como máximo las velas que devolverá en una sola respuesta. Esa única frase es la razón por la que una llamada única ingenua no puede producir un historial de varios años, y es el mecanismo sobre el que se construye el resto de este artículo. Para el conjunto más amplio de superficies disponibles para datos de mercado, consulta Superficies de la API de datos de mercado históricos de Hyperliquid.
- Campos de la solicitud: type, coin, interval, startTime, endTime.
- Respuesta: un arreglo de objetos de vela, no un objeto contenedor.
- Campo de identidad: t (tiempo de apertura); campo derivado: T (tiempo de cierre).
- Volumen y número de operaciones: v y n, atribuidos al propio intervalo de la vela.
Semántica de intervalos y por qué los intervalos nativos superan al remuestreo
El campo interval selecciona el ancho de la vela, y las cadenas de intervalo documentadas se corresponden con anchos fijos en milisegundos. Cuando solicitas un intervalo más grueso y luego lo remuestreas a uno más fino, estás inventando valores de apertura, máximo, mínimo y cierre que el mercado nunca publicó. El máximo de una vela de 1h no es el máximo de ninguna vela de 1m en particular dentro de ella, por lo que una serie de 1m remuestreada discrepará de la serie de 1m del propio mercado exactamente en los puntos que le importan a un backtest.
La atribución de volumen es la segunda víctima del remuestreo. El v de una vela de 1h es el volumen total de la hora, y dividirlo entre doce velas de 1m requiere una suposición que los datos no contienen. Si tu estrategia dimensiona posiciones según el volumen por minuto, esa suposición se convierte en una fuente silenciosa de error. Obtén los datos en el intervalo nativo que pretendes almacenar, y guarda la cadena de intervalo junto a cada vela para que la procedencia sea inequívoca.
El mismo razonamiento se aplica al número de operaciones n. Es un conteo sobre la propia ventana de la vela, y no puede descomponerse en ventanas más finas sin las operaciones subyacentes. Si realmente necesitas varias granularidades, obtén cada una de forma nativa en lugar de derivar una de otra. La página Mecánica de las tasas de financiación de Hyperliquid es un complemento útil cuando tu estrategia también consume financiación, porque la financiación también se publica según su propio calendario en lugar de derivarse de las velas.
Paginación por ventanas, avance del cursor y verificación de huecos
Dado que la solicitud está acotada, el historial continuo se construye emitiendo solicitudes ordenadas por ventanas y avanzando un cursor según el ancho del intervalo en milisegundos. Comienza el cursor en el startTime deseado, solicita una ventana, añade las velas devueltas y luego establece el startTime de la siguiente ventana en el t de la última vela más un intervalo. Este orden garantiza que nunca solicites la misma ventana dos veces en el camino feliz, y hace que el bucle sea trivialmente reanudable si el proceso muere a mitad de ejecución.
Deduplica por el tiempo de apertura de la vela t en lugar de por la posición en el arreglo. Las ventanas superpuestas son comunes cuando reanudas desde un punto de control o cuando vuelves a solicitar deliberadamente una ventana límite para confirmar que está completa, y un Map con clave t colapsa esos duplicados de forma determinista. Conserva la última escritura para un t dado, porque una vela límite vuelta a solicitar puede haber estado en curso cuando se obtuvo por primera vez.
La verificación de huecos es el paso que la mayoría de las implementaciones omite. Tras la deduplicación, ordena por t y recorre la serie, comprobando que cada par consecutivo difiere exactamente en un ancho de intervalo. Cualquier par que difiera en más de un intervalo es un hueco, y normalmente es una ventana sin operaciones en lugar de un fallo de transporte. Registra los huecos explícitamente en lugar de interpolarlos en silencio, porque un backtest que rellena un hueco con una vela sintética está probando datos que nunca existieron.
- Avanza el cursor según los milisegundos del intervalo, no según un número fijo de velas.
- Deduplica por t, conservando la vela obtenida más recientemente para ese t.
- Ordena por t y luego comprueba que los deltas consecutivos equivalen a un ancho de intervalo.
- Registra los huecos como datos, nunca los interpoles en silencio.
Conciliar las velas históricas con el WebSocket de velas en vivo
Un backfill que se detiene en el límite actual deja la vela final del archivo congelada en el momento en que se ejecutó el sondeo. La documentación de suscripciones WebSocket de Hyperliquid describe un canal de velas que envía actualizaciones de la vela en curso a medida que llegan las operaciones, que es exactamente el mecanismo necesario para mantener esa vela final al día. La página Suscripciones WebSocket de Hyperliquid y ciclo de vida de la conexión cubre el ciclo de vida de la conexión con más profundidad.
La regla de conciliación es simple: haz backfill mediante candleSnapshot hasta el límite actual, luego suscríbete al canal de velas para la misma moneda e intervalo, y reemplaza la última vela en curso en cada actualización usando como clave su tiempo de apertura t. Cuando la vela en curso se cierra y se abre una nueva, la vela cerrada ya está en tu archivo bajo su t, y la nueva vela llega bajo un nuevo t. Por eso importa deduplicar por t: la actualización del WebSocket y la obtención histórica describen la misma vela, y el archivo debe contener una sola fila para ella.
El límite en sí es la parte sutil. Si obtienes una ventana cuyo endTime está en el futuro respecto al reloj del mercado, la vela final puede ser parcial. Obtén datos solo hasta un límite que estés seguro de que está cerrado, y luego deja que el WebSocket se encargue de todo lo posterior. Esta división es el mismo límite entre en vivo e histórico con el que debe conciliar cualquier historial rellenado, y es un comportamiento documentado, no una peculiaridad del proveedor.
Un recolector Node.js ejecutable para la paginación de candleSnapshot por ventanas
El recolector de abajo pagina candleSnapshot a lo largo de un rango de fechas, deduplica por tiempo de apertura e informa de los intervalos faltantes. Usa el fetch global disponible en Node.js moderno y un endpoint configurable para que puedas apuntarlo a tu propio proveedor. Reemplaza el endpoint por el que uses; la página Endpoints RPC de Hyperliquid (RPC Assistant) enumera opciones, y Precios de RPC explica cómo el volumen de solicitudes se traduce en costo.
La tabla de anchos de intervalo es el único lugar donde se codifica la semántica de intervalos, así que mantenla sincronizada con las cadenas de intervalo documentadas. El informe de huecos es intencionadamente detallado: imprime los tiempos de apertura faltantes para que puedas decidir si cada hueco es una ventana sin operaciones o un fallo de transporte que merece reintentarse.
const ENDPOINT = process.env.HL_INFO_ENDPOINT || 'https://api.hyperliquid.xyz/info';
const INTERVAL_MS = { '1m': 60000, '5m': 300000, '15m': 900000, '1h': 3600000, '4h': 14400000, '1d': 86400000 };
async function candleSnapshot({ coin, interval, startTime, endTime }) {
const res = await fetch(ENDPOINT, {
method: 'POST',
headers: { 'content-type': 'application/json' },
body: JSON.stringify({ type: 'candleSnapshot', req: { coin, interval, startTime, endTime } })
});
if (!res.ok) throw new Error('HTTP ' + res.status);
const body = await res.json();
if (!Array.isArray(body)) throw new Error('Unexpected response: ' + JSON.stringify(body));
return body;
}
async function collect({ coin, interval, startTime, endTime, windowMs }) {
const step = INTERVAL_MS[interval];
if (!step) throw new Error('Unknown interval: ' + interval);
const byOpenTime = new Map();
let requests = 0;
let cursor = startTime;
while (cursor < endTime) {
const windowEnd = Math.min(cursor + windowMs, endTime);
const batch = await candleSnapshot({ coin, interval, startTime: cursor, endTime: windowEnd });
requests += 1;
for (const c of batch) byOpenTime.set(c.t, c);
const last = batch.length ? batch[batch.length - 1].t : cursor;
cursor = Math.max(last + step, cursor + step);
}
const candles = [...byOpenTime.values()].sort((a, b) => a.t - b.t);
const gaps = [];
for (let i = 1; i < candles.length; i += 1) {
const delta = candles[i].t - candles[i - 1].t;
if (delta !== step) gaps.push({ after: candles[i - 1].t, before: candles[i].t, delta });
}
return { candles, gaps, requests };
}
collect({
coin: 'BTC',
interval: '1m',
startTime: Date.parse('2026-09-01T00:00:00Z'),
endTime: Date.parse('2026-09-08T00:00:00Z'),
windowMs: 6 * 3600000
}).then((r) => {
console.log('candles', r.candles.length, 'requests', r.requests, 'gaps', r.gaps.length);
if (r.candles.length) console.log('first', r.candles[0].t, 'last', r.candles[r.candles.length - 1].t);
for (const g of r.gaps.slice(0, 20)) console.log('gap', new Date(g.after).toISOString(), '->', new Date(g.before).toISOString());
}).catch((e) => { console.error(e); process.exit(1); });Una tabla de resultados para completar con tu propio endpoint
El comportamiento del proveedor varía, así que la única forma honesta de caracterizar tu endpoint es medirlo. Ejecuta el recolector de arriba contra tu propio endpoint y registra los valores de abajo. No trates ningún número de aquí como una afirmación sobre un proveedor concreto; la tabla es una plantilla para tus propias observaciones.
Registra la ventana de obtención por ejecución para que los números sean reproducibles. Si cambias el tamaño de la ventana, la columna de solicitudes emitidas cambiará, y ese es el punto: muestra directamente la compensación de costo.
- Primera vela devuelta (marca de tiempo ISO de t).
- Última vela devuelta (marca de tiempo ISO de t).
- Velas por solicitud (mínimo, mediana, máximo entre ventanas).
- Huecos detectados (recuento y los tiempos de apertura).
- Solicitudes emitidas para el rango completo.
- Duración en tiempo real y cualquier respuesta de límite de tasa observada.
Modos de fallo y solución de problemas
Un arreglo vacío para una ventana normalmente significa que no ocurrieron operaciones en esa ventana, no que la solicitud falló. Confírmalo comprobando si la ventana cae en un periodo de baja liquidez y volviendo a solicitar una ventana vecina que sabes que tiene operaciones. Si la ventana vecina devuelve velas y la ventana vacía es genuinamente tranquila, regístrala como un hueco en lugar de reintentar indefinidamente.
Un error de límite de tasa cuando las ventanas se solicitan demasiado rápido es el fallo operativo más común. La API Info devuelve un objeto de error, y la Especificación JSON-RPC 2.0 es la referencia autoritativa para la forma del envoltorio del objeto de error que siguen tales respuestas. Retrocede y reintenta en lugar de martillar el endpoint; la página Límites de tasa de la API de Hyperliquid: Info vs Exchange separa las dos superficies, lo cual importa porque se presupuestan de forma diferente.
Un desajuste de mayúsculas o de nomenclatura en el nombre de la moneda devuelve un resultado vacío que parece idéntico a una ventana sin operaciones. Los identificadores de moneda distinguen mayúsculas y minúsculas en la práctica, así que normaliza tu entrada y verifícala con una solicitud que sabes que funciona antes de concluir que la ventana está vacía. Una vela final que parece ir con retraso suele ser una vela obtenida a mitad de intervalo: su cierre, máximo, mínimo y volumen aún se están moviendo. La solución es el paso de conciliación de arriba, no un reintento.
- Arreglo vacío: comprueba si es una ventana sin operaciones antes de asumir un fallo.
- Error de límite de tasa: retrocede y luego reintenta; no paralelices a ciegas.
- Desajuste de nomenclatura: normaliza las mayúsculas de la moneda y verifica con una solicitud que sabes que funciona.
- Vela final con retraso: se obtuvo a mitad de intervalo; deja que el WebSocket se encargue de ella.
Profundidad histórica, costo de solicitudes y compensaciones de procedencia
La profundidad histórica es una restricción documentada que deberías descubrir empíricamente en lugar de asumir. El techo práctico de hasta dónde atrás servirá datos candleSnapshot se descubre por prueba, como ilustra el issue de GitHub de ccxt sobre los límites de fetch_ohlcv, y puede diferir de la profundidad disponible a través de otras superficies. Sondea hacia atrás con una sola ventana antes de comprometerte con un plan de backfill de varios años.
El costo de solicitudes escala de forma inversa al tamaño de la ventana. Muchas ventanas pequeñas te dan un control más fino sobre los reintentos y la reanudación, pero multiplican el número de solicitudes, lo que interactúa con los límites de tasa y con lo que tu proveedor mida. Las ventanas grandes reducen el número de solicitudes, pero hacen que un único fallo sea más costoso de reintentar. El tamaño de ventana correcto es el más grande que aún devuelve datos completos para tu intervalo, que es exactamente lo que mide la tabla de resultados de arriba.
Registra la ventana de obtención por vela en tu archivo. Una vela obtenida en una ventana que terminó a mitad de intervalo puede haber sido parcial en el momento de la obtención, y sin los metadatos de la ventana no puedes saber después si una cifra de volumen baja era real o un artefacto de cuándo preguntaste. La procedencia es barata de almacenar y costosa de reconstruir. Para la decisión más amplia de qué superficie de datos usar, consulta el centro de aprendizaje de OnFinality y la descripción general del servicio de API.
Próximos pasos para un archivo OHLCV en producción
Pasa de un script de una sola ejecución a un backfill programado más una cola en vivo. Ejecuta el recolector por ventanas de forma programada para extender el historial, y ejecuta la conciliación por WebSocket de forma continua para que la vela límite se mantenga al día. Persiste el cursor y el t de la última vela cerrada para que un reinicio se reanude sin volver a obtener todo el rango.
Añade una pasada de reparación de huecos que vuelva a solicitar solo las ventanas que rodean los huecos registrados, y mantén el informe de huecos como un artefacto de primera clase en lugar de una línea de registro. Si tu estrategia consume financiación o precios de oráculo junto con las velas, la página Precios de oráculo de Hyperliquid y la subasta del builder cubre esas superficies de la API Info. Por último, revisa Precios de RPC antes de escalar el volumen de solicitudes, y confirma tu elección de endpoint con Endpoints RPC de Hyperliquid (RPC Assistant).
- Programa el backfill; ejecuta la cola del WebSocket de forma continua.
- Persiste el cursor y el último t cerrado para reinicios reanudables.
- Repara los huecos volviendo a solicitar solo las ventanas afectadas.
- Almacena la ventana de obtención por vela para la procedencia.