Mercado y barras¶
Qué vas a aprender¶
- Qué es una barra OHLCV y por qué es la unidad básica del banco.
- Qué es un timeframe (1min, 5min, 1h, 1d…) y cómo se derivan unos de otros.
- Qué significa que un precio esté ajustado por splits y dividendos (
adjclose,price_basis) y por qué mezclar series ajustadas y sin ajustar es un error grave. - Qué son el tick y el redondeo al tick.
La barra: una foto resumida del mercado¶
Un mercado produce miles de operaciones por minuto. Guardarlas todas sería caro y, para la mayoría de estrategias, innecesario. Lo que se hace es resumir un intervalo de tiempo en cinco números:
| Campo | Qué es | Analogía |
|---|---|---|
open |
Primer precio del intervalo | La temperatura al abrir la ventana |
high |
Precio máximo | La máxima del día |
low |
Precio mínimo | La mínima del día |
close |
Último precio del intervalo | La temperatura al cerrar la ventana |
volume |
Cantidad negociada | Cuánta gente pasó por la calle |
A esa foto se le llama barra OHLCV (o vela). Tiene una propiedad que el banco
comprueba siempre: low ≤ open, close ≤ high. Si una barra la viola, el dato está
roto y la política de limpieza clean.v1 lo repara y lo marca (is_synthetic),
en vez de esconderlo.
Figura 1. La trayectoria real del precio durante un minuto (izquierda) se resume en cuatro números: open, high, low y close (derecha).
Figura 2. La vela japonesa dibuja los mismos cuatro precios; el color y el cuerpo dicen de un vistazo si la barra subió o bajó.
flowchart LR
T["Operaciones individuales<br/>(ticks)"] -->|resumir intervalo| B["Barra OHLCV<br/>open · high · low · close · volume"]
B --> V{"¿low ≤ open,close ≤ high?"}
V -->|sí| OK["Barra canónica"]
V -->|no| R["Reparar + marcar is_synthetic"]
El intervalo es semiabierto¶
Una barra de 1 minuto que empieza a las 09:30 cubre [09:30, 09:31): incluye el
instante 09:30 y excluye el 09:31. Así ninguna operación puede caer en dos barras
a la vez. El esquema canónico lo guarda con tres relojes en nanosegundos UTC:
| Columna | Significado |
|---|---|
market_open_ns |
Apertura económica del intervalo |
market_close_ns |
Fin del intervalo |
data_available_ns |
Desde cuándo se puede usar el dato |
Por qué hay un tercer reloj
En el banco, data_available_ns = market_close_ns por supuesto declarado de
latencia de publicación cero. Es un supuesto sintético (el proveedor no documenta
su latencia real) y está escrito en el manifiesto. Ese supuesto es lo que hace
posible el carril SIM-S next-open idealizado (ver
Backtesting causal). El lector filtra siempre por
data_available_ns, nunca por la apertura.
Timeframes: la misma película a distintas velocidades¶
El timeframe (o marco) es la duración de cada barra. El banco trabaja con
1min, 2min, 5min, 15min, 30min, 1h, 1d para NVDA y KO (fuente twelvedata) y con
1d para el universo de Yahoo.
Figura 3. Agregar barras: open de la primera, máximo de los high, mínimo de los low, close de la última y suma de volúmenes.
Los marcos superiores se derivan de las barras de 1 minuto con una única
implementación (finazbench/data/resample.py):
open= primero,high= máximo,low= mínimo,close= último,volume= suma.- Los cubos se anclan a la apertura de sesión que dice el calendario (no a medianoche ni a la primera barra presente).
- Ningún cubo cruza el límite de sesión: la barra de las 15:59 del lunes y la de las 09:30 del martes nunca se mezclan.
El error que se corrigió (DEV-01B-09)
Anclar los cubos a la primera barra presente parece equivalente, pero cuando una sesión empieza con hueco desplaza toda la rejilla. Se midieron 7 sesiones afectadas, con desfases de 6 min en NVDA y 241 min en KO, que producían barras «horarias» empezando a las 09:36 o a las 13:31. Tras la corrección cambiaron de límites 37 barras de 1 h, 75 de 30 min, 156 de 15 min, 479 de 5 min y 1.016 de 2 min.
1d no es 1d_long
freq=1d se deriva del minuto (desde 2020); freq=1d_long viene del CSV diario del
proveedor (desde 1999 en NVDA, 1970 en KO). Se guardan separados a propósito:
mezclarlos daría dos valores distintos para la misma sesión.
Ajustes: splits y dividendos¶
Cuando una empresa hace un split 4×1, su precio se divide entre cuatro de un día para otro sin que nadie haya perdido dinero. Si no se ajusta la serie histórica, un indicador vería una «caída» del 75 % que nunca ocurrió. Por eso las series se ajustan:
- Ajuste por splits: el OHLC de Yahoo y el de twelvedata ya vienen ajustados por splits.
- Ajuste por dividendos (total return):
adjcloseañade el efecto de los dividendos. Es otra serie, no «la misma más precisa».
El banco guarda siempre el OHLC del proveedor más adj_close y
adj_factor = adj_close / close, y decide al leer con price_basis:
price_basis |
Qué devuelve |
|---|---|
raw_split_adjusted (por defecto) |
El OHLC tal cual (ajustado solo por splits) |
total_return_adjusted |
open, high, low y close escalados por adj_factor |
¿Por qué escalar los cuatro precios y no solo el cierre?
Porque el factor es un escalar positivo por barra: multiplicar los cuatro conserva
low ≤ close ≤ high. Escalar solo close fabricaría barras imposibles, y un ATR
leería volatilidad inventada.
Regla de oro: adj_close para features, close para ejecutar
Nunca se sobrescribe close. Pedir total_return_adjusted a un instrumento sin
adj_close (NVDA y KO de twelvedata, o los pares FX) lanza un error: devolver
una serie sin dividendos cuando se pidió con dividendos sería una sustitución
silenciosa.
Factores medidos (valor inicial de adj_factor y número de saltos de dividendo):
| Serie | adj_factor inicial |
Saltos |
|---|---|---|
| AMZN, TSLA | 1,000000 | 0 |
| INTC | 0,767229 | 39 |
| MSFT | 0,847031 | 47 |
| BBVA.MC | 0,541159 | 26 |
| SAN.MC | 0,645629 | 30 |
| TEF.MC | 0,443214 | 23 |
El tick: la rejilla de precios¶
Un precio no puede ser cualquier número: se mueve en múltiplos de un tick (0,01 USD en las acciones de EE. UU., por ejemplo). El ledger trabaja con precios en ticks enteros para que la contabilidad sea exacta (lo verás en Ledger SIM-S).
El tick se aplica al precio crudo (DEV-01B-08)
Una serie ajustada por dividendos deja de caer en la rejilla (5,02 EUR × 0,6845 = 3,4362 EUR, que no es múltiplo de 0,001). Es una aproximación declarada: re-redondear la serie ajustada destruiría lo único que la hace útil, que los retornos sean exactos.
Resumen¶
- La barra OHLCV resume un intervalo semiabierto
[inicio, fin); el banco guarda tres relojes y filtra pordata_available_ns. - Los timeframes superiores se derivan del minuto, anclados a la sesión y sin cruzarla.
price_basiselige entre precios ajustados solo por splits o también por dividendos; nunca se mezclan ni se sustituyen en silencio.- Los precios viven en una rejilla de ticks; el ledger opera en enteros.
Para practicar¶
- Una barra tiene
open=10,high=12,low=9,close=12,5. ¿Qué dice el banco de ella? - ¿Por qué un cubo de 1 h anclado a medianoche daría barras incorrectas en XNYS?
- Pide mentalmente
total_return_adjustedpara KO de twelvedata. ¿Qué ocurre y por qué es lo correcto?