Lección 5.8.1 · 60 min
Modelos fundacionales de series: preentrenar una vez, prever sin entrenar
Un modelo fundacional de series se entrena una sola vez con decenas de miles de millones de observaciones de dominios muy distintos y después se usa, sin reentrenar, sobre una serie que nunca ha visto. Esta lección explica qué se preentrena, cómo se convierte una serie en tokens o en parches y qué significa «zero-shot», y hace la primera previsión con Chronos-Bolt sobre la volatilidad realizada del nivel 5, con dos referencias ingenuas al lado.
- Módulo
- 5.8 · Modelos fundacionales de series temporales
- Duración
- 60 min
Lecciones del nivel 5
5.1 · Fundamentos de ML aplicados a finanzas
5.2 · Ingeniería de características
5.3 · Etiquetado y muestreo
- 5.3.1 Etiquetado de horizonte fijo y sus problemas
- 5.3.2 Método de la triple barrera: etiquetas que imitan una operación
- 5.3.3 Meta-labeling: un modelo para el lado y otro para el tamaño
- 5.3.4 Unicidad de las etiquetas, pesos por solapamiento y bootstrap secuencial
- 5.3.5 Muestreo por eventos: el filtro CUSUM simétrico
5.4 · Validación para series financieras
5.5 · Modelos clásicos
- 5.5.1 Regresiones regularizadas: Ridge, Lasso, Elastic Net y logística
- 5.5.2 Árboles de decisión, Random Forest y bagging
- 5.5.3 Gradient boosting: XGBoost, LightGBM y CatBoost
- 5.5.4 Optuna y el riesgo de sobreajustar la validación
- 5.5.5 Aprendizaje no supervisado: PCA, clustering y autoencoders
- 5.5.6 Learning to rank para la selección de acciones
5.6 · Deep learning con Keras 3
5.7 · Deep learning con PyTorch
- 5.7.1 PyTorch: tensores, autograd y el bucle de entrenamiento
- 5.7.2 Arquitecturas de series: TCN, N-BEATS, PatchTST e iTransformer
- 5.7.3 Modelos probabilísticos: pérdida cuantílica, DeepAR e intervalos
- 5.7.4 Redes de grafos para relaciones entre activos
- 5.7.5 Optimización de carteras end-to-end: capas diferenciables y pérdida de Sharpe
5.8 · Modelos fundacionales de series temporales
- 5.8.1 Modelos fundacionales de series: preentrenar una vez, prever sin entrenar
- 5.8.2 Las familias de modelos fundacionales: arquitectura, datos y licencia
- 5.8.3 Uso práctico: contexto, cuantiles, covariables y ajuste fino
- 5.8.4 Modelos fundacionales en finanzas: qué dice la evidencia
- 5.8.5 Laboratorio: modelos fundacionales frente a GARCH, HAR y LightGBM
5.9 · Aprendizaje por refuerzo
5.10 · Interpretabilidad, robustez y riesgo de modelo
De un modelo por serie a un modelo para todas
Hasta aquí, cada modelo del curso se ha estimado con los datos de su problema: un GARCH con los rendimientos de un activo (lección 2.1.4), un HAR o una red con la volatilidad de seis activos (lección 5.7.2). Un modelo fundacional de series invierte el orden. Alguien lo entrena una vez, con un corpus enorme de series de dominios muy distintos (energía, tráfico, ventas, tiempo, visitas a webs, finanzas, series sintéticas), publica los pesos y cualquiera los usa después sobre una serie que el modelo nunca ha visto, sin reentrenar. A eso se le llama previsión zero-shot: la serie nueva entra solo como contexto, en la pasada hacia delante, y los pesos no cambian.
Fuente Mermaid
flowchart TB A[Corpus masivo] --> B[Preentrenamiento] B --> C[Pesos publicados] C --> D[Contexto] D --> E[Zero-shot] E --> F[Ajuste fino]
La idea viene de los modelos de lenguaje: un transformer que ha visto suficientes textos completa uno nuevo sin que nadie lo entrene para ese texto. En series, la apuesta es que hay regularidades comunes a casi todas (tendencias, estacionalidades, persistencia, escalones, ruido con estructura) y que un modelo grande puede aprenderlas y reconocerlas en el contexto que recibe. Las cifras de los corpus lo dicen todo:
| Modelo | Corpus de preentrenamiento (según sus autores) |
|---|---|
| Chronos (Amazon, 2024) | 28 conjuntos públicos, unos 890 000 series y unos 84 000 millones de observaciones, más 10 millones de series aumentadas con TSMixup y 1 millón de series sintéticas de procesos gaussianos (KernelSynth) |
| Chronos-Bolt (Amazon, 2024) | «casi 100 000 millones de observaciones» |
| TimesFM (Google, 2024) | del orden de 100 000 millones de puntos: Google Trends, visitas de Wikipedia y series sintéticas |
En la lección 5.8.2 están las familias con sus arquitecturas, tamaños y licencias. Esta lección se queda en lo que tienen en común: cómo convierten una serie en algo que un transformer pueda leer y qué se obtiene al usarlas sin entrenar.
La serie: la varianza realizada del índice
El banco de pruebas es el de las lecciones 5.7.2 y 5.7.3: el activo indice de vol5_diario.parquet, 4 529 sesiones
de 2008 a 2025, con su varianza realizada de cada día (rv_5min, en rendimiento al cuadrado). Se prevé su logaritmo,
que es casi gaussiano y es la escala en la que trabaja el generador.
import numpy as np
import pandas as pd
vol = pd.read_parquet("vol5_diario.parquet")
ind = vol[vol["activo"] == "indice"].set_index("fecha")
log_rv = np.log(ind["rv_5min"].to_numpy())
vol_anual = np.sqrt(252 * ind["rv_5min"].to_numpy())
fechas = pd.DatetimeIndex(ind.index)
print(f"{len(log_rv)} sesiones, {fechas[0].date()} a "
f"{fechas[-1].date()}")
print(f"log RV: media {log_rv.mean():.2f}, desv. {log_rv.std():.2f}")
print(f"vol. anual: mediana {np.median(vol_anual):.1%}, "
f"p99 {np.quantile(vol_anual, 0.99):.1%}")4529 sesiones, 2008-01-02 a 2025-12-31
log RV: media -9.75, desv. 0.64
vol. anual: mediana 12.1%, p99 25.6%La log RV vale en torno a −9,75 con una desviación de 0,64: una serie lejos del cero y con poca variación relativa. Ese detalle importa enseguida.
De números a tokens: la receta de Chronos
Un transformer de lenguaje trabaja con un vocabulario finito. Chronos (Ansari et al., 2024) hace lo mínimo para que una serie lo parezca: escala el contexto dividiéndolo por la media de sus valores absolutos y cuantiza el resultado en cajones uniformes. Con un contexto :
Según el artículo y el config.json de los modelos, los cajones son 4 093 centros equiespaciados entre −15 y +15 (un
vocabulario de 4 096 con los tokens especiales de relleno y de fin), el contexto es de 512 observaciones y el
horizonte, de 64. El modelo (un T5 de 20 a 710 millones de parámetros) se entrena con entropía cruzada para predecir el
token siguiente, como un modelo de lenguaje, y la previsión probabilística sale de muestrear trayectorias de
tokens y deshacer la escala. Cada cajón mide en unidades escaladas.
La librería chronos-forecasting trae el tokenizador, que no necesita pesos: basta con la configuración de
amazon/chronos-t5-small. La celda lo reproduce a mano y lo aplica a dos versiones de la misma información, la
volatilidad anual y el logaritmo de la varianza:
import torch
from chronos import ChronosConfig
# La configuración de amazon/chronos-t5-small (config.json del repo)
cfg = ChronosConfig(
tokenizer_class="MeanScaleUniformBins",
tokenizer_kwargs={"low_limit": -15.0, "high_limit": 15.0},
n_tokens=4096, n_special_tokens=2, pad_token_id=0,
eos_token_id=1, use_eos_token=True, model_type="seq2seq",
context_length=512, prediction_length=64, num_samples=20,
temperature=1.0, top_k=50, top_p=1.0)
tok = cfg.create_tokenizer()
centros = np.linspace(-15, 15, 4096 - 2 - 1)
def tokens_a_mano(x):
"""Escala por la media de |x| y redondea al centro más cercano.
Los ids 0 y 1 son PAD y EOS; los cajones empiezan en el 3."""
escala = np.abs(x).mean()
ids = np.abs(x[:, None] / escala - centros).argmin(1) + 3
return ids, centros[ids - 3] * escala
for nombre, x in (("vol. anual", vol_anual[-512:]),
("log RV", log_rv[-512:])):
ids, x_rec = tokens_a_mano(x)
ids_chr, _, escala = tok.context_input_transform(
torch.tensor(x[None, :], dtype=torch.float32))
igual = (ids == ids_chr[0, :512].numpy()).mean()
print(f"{nombre:<10} escala {escala.item():8.4f} "
f"tokens distintos {len(np.unique(ids)):4d} "
f"error máx. {np.abs(x - x_rec).max():.4f} "
f"igual que chronos {igual:.0%}")vol. anual escala 0.1405 tokens distintos 168 error máx. 0.0005 igual que chronos 100%
log RV escala 9.5590 tokens distintos 46 error máx. 0.0350 igual que chronos 100%El tokenizador de la librería y el de la celda coinciden. La comparación entre las dos series enseña la debilidad de la escala media. La volatilidad anual (positiva, con una media de 0,14) usa 168 cajones distintos y el redondeo cuesta como mucho 0,0005, cinco centésimas de punto de volatilidad. El logaritmo de la varianza, en cambio, vale siempre en torno a −9,6: dividido por su media absoluta queda casi siempre cerca de −1, solo usa 46 cajones y el redondeo llega a 0,035 en log, un 3,6 % de la varianza. La escala media no resta la media, así que una serie lejos del cero pierde resolución. El ejercicio 2 lo mide con la serie tipificada.
Parches: lo que hacen Chronos-Bolt y TimesFM
La segunda generación abandona el token por dato. Chronos-Bolt tipifica el contexto (resta la media y divide por
la desviación típica, lo que el código llama InstanceNorm), lo corta en parches de 16 observaciones y proyecta
cada parche a un vector con una red pequeña; al final añade un token de regresión. El codificador T5 lee esos vectores y
el decodificador produce de una vez los cuantiles 0,1…0,9 de los 64 pasos siguientes (previsión directa
multipaso), sin muestrear. TimesFM hace algo parecido con parches de 32 y un transformer solo decodificador (lección
5.8.2). Es la misma idea que PatchTST en la lección 5.7.2, a escala de preentrenamiento.
Fuente Mermaid
flowchart LR S[Contexto] --> M[Escala media] M --> Q[Un token por dato] S --> N[Tipificar] N --> P[Parches de 16] Q --> T[Transformer] P --> T
La consecuencia es de coste. La atención compara cada token con todos los demás, así que su coste crece con el cuadrado del número de tokens:
Los pesos de Chronos-Bolt-small están en la caché del entorno ml, fijados por commit (README del entorno). La celda
los carga sin red y comprueba los parches a mano contra los del modelo:
from chronos import BaseChronosPipeline
torch.manual_seed(0)
torch.use_deterministic_algorithms(True)
bolt = BaseChronosPipeline.from_pretrained(
"amazon/chronos-bolt-small", device_map="cpu",
dtype=torch.float32)
cc = bolt.model.chronos_config
print(f"contexto máx. {cc.context_length}, "
f"parche {cc.input_patch_size}, "
f"horizonte {cc.prediction_length}, cuantiles {cc.quantiles}")
x = torch.tensor(log_rv[-512:], dtype=torch.float32)[None, :]
z = (x - x.mean()) / x.std(correction=0) # tipificar
parches = z.unfold(-1, 16, 16) # (1, 32, 16)
z_bolt, _ = bolt.model.instance_norm(x)
print("parches:", tuple(parches.shape),
"| iguales a los del modelo:",
torch.allclose(parches, bolt.model.patch(z_bolt), atol=1e-5))
print(f"valores tipificados: de {z.min():.2f} a {z.max():.2f}")contexto máx. 2048, parche 16, horizonte 64, cuantiles [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9]
parches: (1, 32, 16) | iguales a los del modelo: True
valores tipificados: de -2.45 a 2.57Contexto máximo de 2 048 observaciones, parches de 16, horizonte de 64 pasos y nueve cuantiles. Tipificada, la log RV ocupa de −2,45 a 2,57: el problema de resolución de la escala media desaparece, porque aquí no hay redondeo (cada parche entra con sus valores reales) y la media se resta antes.
Una primera previsión
Con el modelo cargado, prever es una llamada: se le da el contexto (las últimas 512 sesiones) y el horizonte. El origen elegido es el viernes 6 de marzo de 2020, la víspera de uno de los choques plantados en los datos (el README documenta +1,8 en log-varianza el 9 de marzo). La salida se pasa a volatilidad anual para leerla mejor:
i0 = fechas.get_loc(pd.Timestamp("2020-03-06")) + 1
q, _ = bolt.predict_quantiles(
inputs=torch.tensor(log_rv[i0 - 512:i0], dtype=torch.float32),
prediction_length=5, quantile_levels=[0.1, 0.5, 0.9])
a_vol = lambda l: np.sqrt(252 * np.exp(l)) # log RV a vol. anual
tabla = pd.DataFrame(
a_vol(q[0].numpy().astype(float)) * 100,
index=fechas[i0:i0 + 5].date, columns=["q10", "q50", "q90"])
tabla["realizada"] = vol_anual[i0:i0 + 5] * 100
tabla.round(1) q10 q50 q90 realizada
2020-03-09 12.0 15.5 20.2 52.8
2020-03-10 12.0 16.0 21.4 28.6
2020-03-11 12.2 16.5 22.1 31.0
2020-03-12 12.4 16.9 22.6 24.9
2020-03-13 12.5 17.1 22.9 23.3El modelo prevé una volatilidad mediana del 15,5 % para el lunes, con una banda del 10 al 90 % de 12,0 a 20,2 %, y una ligera subida en los días siguientes. La realizada del lunes es del 52,8 %: el choque no estaba en el pasado de la serie y nadie podía preverlo con ella. A partir del martes la realizada (28,6 %, 31,0 %…) sigue por encima de la banda, porque esta previsión es a cinco días desde el viernes y no se actualiza. La figura de la cabecera muestra lo que pasa cuando se vuelve a prever cada día con el dato nuevo: la banda salta tras el choque y persigue a la realizada.
Zero-shot a un día con origen móvil
Una previsión suelta no evalúa nada. La evaluación honesta es la de la lección 5.4.3 sin el reentrenamiento: para cada sesión de 2018 a 2025, se prevé el día siguiente con las 512 sesiones anteriores y se compara con lo que pasó. El modelo no se ajusta nunca, así que no hay fuga posible por entrenamiento; la única regla es que el contexto acabe en la víspera. Las referencias son la previsión ingenua (la log RV de ayer) y la media de los últimos 22 días.
prueba = np.flatnonzero(fechas.year >= 2018)
C = 512
def zero_shot(serie, origenes, contexto=C, lote=256):
"""Cuantiles 0,1…0,9 de mañana para cada origen (sin reentrenar)."""
salida = []
for k in range(0, len(origenes), lote):
ventanas = np.stack([serie[i - contexto:i]
for i in origenes[k:k + lote]])
q, _ = bolt.predict_quantiles(
inputs=torch.tensor(ventanas, dtype=torch.float32),
prediction_length=1)
salida.append(q[:, 0, :].numpy().astype(float))
return np.concatenate(salida)
q_bolt = zero_shot(log_rv, prueba)
real = log_rv[prueba]
previsiones = {
"ingenua (ayer)": log_rv[prueba - 1],
"media de 22 días": np.array([log_rv[i - 22:i].mean()
for i in prueba]),
"Chronos-Bolt (mediana)": q_bolt[:, 4],
}
def metricas(f):
e2 = (real - f) ** 2
return {"ECM": e2.mean(), "R²": np.corrcoef(real, f)[0, 1] ** 2}
tabla = pd.DataFrame({k: metricas(f) for k, f in previsiones.items()})
tabla.T.round(3) ECM R²
ingenua (ayer) 0.233 0.503
media de 22 días 0.237 0.418
Chronos-Bolt (mediana) 0.181 0.551Chronos-Bolt, sin haber visto nunca la serie, da un error cuadrático medio de 0,181 frente a 0,233 de la ingenua y 0,237 de la media de 22 días, y un R² de 0,551 (el R² es el de la regresión de la log RV sobre la previsión, la misma medida que el README). Para situarlo: el README publica, en el mismo periodo, un R² de 0,57 para un HAR reestimado cada enero y de 0,61 para el oráculo, la esperanza exacta de la varianza con la información de la víspera. El modelo fundacional queda entre la referencia ingenua y el HAR, más cerca del HAR. Si eso basta o no lo decide el laboratorio de la lección 5.8.5, con GARCH y LightGBM en la misma prueba.
La previsión que se compara es la mediana (el cuantil 0,5), no la media. En log da igual porque la distribución es casi simétrica; en varianza no daría igual (la exponencial de la mediana del log infravalora la media de la varianza), y la lección 5.8.3 lo trata.
¿Es la mejora más grande que el ruido?
Las diferencias de error se leen con la diferencia pareada día a día, como en la lección 5.4.3: los días difíciles lo son para todos los modelos, y la diferencia elimina ese ruido común.
def pareada(a, b):
"""Diferencia media de errores cuadráticos (a − b) y su t."""
d = (real - previsiones[a]) ** 2 - (real - previsiones[b]) ** 2
return d.mean(), d.mean() / (d.std(ddof=1) / np.sqrt(len(d)))
for ref in ("ingenua (ayer)", "media de 22 días"):
dif, t = pareada("Chronos-Bolt (mediana)", ref)
print(f"Bolt − {ref:<16} {dif:+.4f} t = {t:+.1f}")
dentro = (real >= q_bolt[:, 0]) & (real <= q_bolt[:, 8])
print(f"cobertura del intervalo 10-90 %: {dentro.mean():.1%} "
f"({len(real)} días)")Bolt − ingenua (ayer) -0.0516 t = -9.8
Bolt − media de 22 días -0.0557 t = -10.4
cobertura del intervalo 10-90 %: 76.4% (2011 días)Las dos mejoras están muy por encima del ruido: t = −9,8 frente a la ingenua y −10,4 frente a la media de 22 días. Los días de prueba se solapan en el contexto pero no en el error que se mide (cada día se prevé una vez), así que el error típico de la diferencia es razonable; si los errores tuvieran autocorrelación habría que corregirlo (Newey-West), pero con un t de −10 haría falta una autocorrelación muy fuerte para cambiar la conclusión. El intervalo del 10 al 90 % cubre el 76,4 % de los días, no el 80 %: los cuantiles son algo estrechos. La lección 5.8.3 mide la calibración cuantil a cuantil y la corrige.
El resultado se mantiene año a año:
anio = fechas.year[prueba]
por_anio = pd.DataFrame({k: (real - f) ** 2 for k, f in
previsiones.items()}).groupby(anio).mean()
por_anio.round(3) ingenua (ayer) media de 22 días Chronos-Bolt (mediana)
fecha
2018 0.202 0.163 0.147
2019 0.229 0.194 0.166
2020 0.288 0.285 0.224
2021 0.214 0.301 0.181
2022 0.247 0.261 0.197
2023 0.201 0.216 0.159
2024 0.233 0.224 0.182
2025 0.249 0.251 0.194Chronos-Bolt tiene el error más bajo los ocho años. El peor es 2020 para todos (el año de los choques de marzo). La media de 22 días sufre más en 2021: arrastra durante semanas los días de volatilidad extrema del año anterior, que el modelo fundacional descuenta antes.
Lo que el zero-shot no hace
Una previsión zero-shot buena sobre la volatilidad no dice nada de otras cosas, y conviene tenerlo claro antes de seguir:
| El modelo hace | El modelo no hace |
|---|---|
| Extraer de la historia reciente persistencia, nivel y dispersión | Conocer el activo, el calendario de eventos ni las noticias |
| Dar cuantiles sin entrenar nada | Garantizar que esos cuantiles están calibrados (aquí, 76,4 % frente a 80 %) |
| Funcionar en series con estructura (la volatilidad tiene mucha) | Predecir lo que no tiene estructura: los rendimientos de vol5 son impredecibles por construcción |
| Ahorrar el trabajo de estimar un modelo por serie | Superar al proceso generador: el oráculo es el suelo |
La lección 5.8.2 compara las familias (Chronos, Chronos-Bolt, Chronos-2, TimesFM-2.5, Moirai-2.0, TiRex, TimeGPT y Kronos) y pone a TimesFM-2.5 al lado de Chronos-Bolt; la 5.8.3 entra en las decisiones prácticas (longitud del contexto, cuantiles, covariables y ajuste fino).
Ejercicios
- Repite la evaluación zero-shot con el activo
cripto(usa un origen de cada cuatro para que sea rápido). ¿Mejora Chronos-Bolt a las dos referencias? Compara su R² con el del HAR del README para ese activo (0,40).
Solución
vc = vol[vol["activo"] == "cripto"].set_index("fecha")
log_rv_c = np.log(vc["rv_5min"].to_numpy())
orig = prueba[::4]
q_c = zero_shot(log_rv_c, orig)
real_c = log_rv_c[orig]
for nombre, f in (("ingenua", log_rv_c[orig - 1]),
("media 22", np.array([log_rv_c[i - 22:i].mean()
for i in orig])),
("Bolt", q_c[:, 4])):
print(f"{nombre:<9} ECM {np.mean((real_c - f) ** 2):.3f} "
f"R² {np.corrcoef(real_c, f)[0, 1] ** 2:.3f}")ingenua ECM 0.652 R² 0.252
media 22 ECM 0.427 R² 0.328
Bolt ECM 0.395 R² 0.393En cripto la ingenua es mucho peor (ECM 0,652): la RV diaria de un activo con saltos frecuentes es muy ruidosa y el dato de ayer es mala previsión. Chronos-Bolt baja a 0,395, mejor que la media de 22 días (0,427), y su R² de 0,393 queda casi en el del HAR del README (0,40), con el oráculo en 0,46. Con 503 orígenes el R² tiene un error de unas centésimas: la comparación con el HAR se lee como «parecido», no como una ordenación.
- Tipifica el contexto de log RV (resta la media y divide por la desviación típica) antes de tokenizarlo con la receta de Chronos. ¿Cuántos cajones usa ahora? ¿Qué te dice sobre la escala media del Chronos original?
Solución
x = log_rv[-512:]
z = (x - x.mean()) / x.std()
for nombre, serie in (("log RV tal cual", x), ("log RV tipificada", z)):
ids, rec = tokens_a_mano(serie)
print(f"{nombre:<18} tokens distintos {len(np.unique(ids)):4d}")log RV tal cual tokens distintos 46
log RV tipificada tokens distintos 353Tipificada, la misma información usa 353 cajones en lugar de 46: casi ocho veces más resolución. La escala media del Chronos original está pensada para series positivas cerca de su nivel típico (ventas, demanda, visitas), donde dividir por la media es natural. Para series lejos del cero o con signo, la segunda generación (Chronos-Bolt, Chronos-2) pasó a tipificar, y además no cuantiza. Si usas un modelo que cuantiza, la transformación previa de la serie forma parte del modelo.
- Un artículo evalúa en 2025 un modelo fundacional sobre rentabilidades diarias de acciones del S&P 500 de 2015 a 2023, y el modelo se preentrenó con un corpus publicado en 2024 que incluye series financieras públicas. ¿Qué problema tiene la evaluación? ¿Por qué los datos del curso no lo tienen?
Solución
El riesgo es la contaminación del preentrenamiento: si las series de prueba (o series muy correlacionadas con ellas, como otras acciones del mismo índice en las mismas fechas) estaban en el corpus, el modelo puede haber memorizado parte de lo que luego «prevé», y la evaluación ya no es fuera de muestra. Es la misma fuga de la lección 5.2.2, pero escondida en los pesos de otro. Los autores serios lo controlan: la ficha de Chronos-2 dice que excluye las partes de prueba de los conjuntos que solapan con el benchmark GIFT-Eval, y la de Moirai-2.0 habla de subconjuntos «non-leaking». Para una evaluación propia, lo seguro es probar con datos posteriores a la fecha de corte del corpus o con datos que no pueden estar en él, como los sintéticos de este curso, generados después de publicarse los modelos.
Respuesta plegada en cada pregunta
Autoevaluación
¿Qué significa que una previsión de Chronos-Bolt sobre
vol5es zero-shot?- AQue el modelo no tiene parámetros
- BQue la previsión no tiene error en el primer día
- CQue el modelo no se ha entrenado ni ajustado con esa serie: los pesos son los del preentrenamiento y la serie solo entra como contexto
- DQue el modelo se reentrena desde cero con cada serie
Ver respuesta
Respuesta C. Que el modelo no se ha entrenado ni ajustado con esa serie: los pesos son los del preentrenamiento y la serie solo entra como contexto
El modelo aprende una vez, con su corpus, y después recibe la historia reciente de la serie como contexto. Lo que «aprende» de la serie nueva lo hace en la pasada hacia delante, sin tocar ningún peso.
Chronos tokeniza el logaritmo de la varianza realizada del índice (valores en torno a −9,8 con una desviación de 0,6) con escala media y 4 093 cajones uniformes en [−15, 15]. ¿Qué pasa?
- ALa serie escalada vale casi siempre en torno a −1, así que solo usa unos 46 cajones y el redondeo llega a 0,035 en log (un 3,6 % de la varianza)
- BNada: la escala media es invariante a cualquier transformación
- CSe sale del rango [−15, 15] y el modelo falla
- DUsa todos los cajones por igual
Ver respuesta
Respuesta A. La serie escalada vale casi siempre en torno a −1, así que solo usa unos 46 cajones y el redondeo llega a 0,035 en log (un 3,6 % de la varianza)
La escala media divide por la media de |x| pero no resta la media. En una serie lejos del cero y con poca variación relativa, todos los valores escalados caen en una franja estrecha. Tipificada (restando la media), la misma serie usa 353 cajones.
¿Por qué Chronos-Bolt es mucho más rápido que el Chronos original del mismo tamaño?
- APorque tiene menos capas
- BPorque no usa atención
- CPorque solo predice la media
- DPorque agrupa 16 observaciones en cada token (512 datos son 33 tokens en vez de 513) y predice todos los cuantiles del horizonte de una vez, en lugar de muestrear token a token
Ver respuesta
Respuesta D. Porque agrupa 16 observaciones en cada token (512 datos son 33 tokens en vez de 513) y predice todos los cuantiles del horizonte de una vez, en lugar de muestrear token a token
Menos tokens abaratan la atención, cuyo coste crece con el cuadrado de su número, y la salida directa de cuantiles evita generar muchas trayectorias autorregresivas. Amazon cifra la ganancia en hasta 250 veces en velocidad.
Chronos-Bolt zero-shot da un ECM de 0,181 en log RV frente a 0,233 de la previsión ingenua, con t = −9,8 en la diferencia pareada. ¿Qué se puede concluir?
- AQue Chronos-Bolt es el mejor modelo de volatilidad posible
- BQue mejora con claridad a la ingenua en estos datos, pero queda por debajo del HAR del README (R² 0,551 frente a 0,57) y lejos del oráculo (0,61): falta compararlo con modelos estimados sobre la serie (lección 5.8.5)
- CQue también predecirá bien los rendimientos
- DNada: 2 011 días son pocos
Ver respuesta
Respuesta B. Que mejora con claridad a la ingenua en estos datos, pero queda por debajo del HAR del README (R² 0,551 frente a 0,57) y lejos del oráculo (0,61): falta compararlo con modelos estimados sobre la serie (lección 5.8.5)
La referencia ingenua es fácil de batir. El listón serio es un HAR, un GARCH o un LightGBM estimados con la propia serie, y el suelo es el oráculo. Y la volatilidad tiene estructura; los rendimientos de
vol5, por construcción, no.El 9 de marzo de 2020 la volatilidad realizada del índice sintético salta al 52,8 % y la banda 10-90 % prevista la víspera va de 12,0 a 20,2 %. ¿Qué indica?
- AQue el modelo está roto
- BQue hay que entrenar más el modelo
- CQue el choque es una innovación sin aviso en los datos: ningún modelo que solo vea el pasado de la serie podía preverlo, y la banda reacciona después
- DQue el contexto era demasiado corto
Ver respuesta
Respuesta C. Que el choque es una innovación sin aviso en los datos: ningún modelo que solo vea el pasado de la serie podía preverlo, y la banda reacciona después
El README del nivel lo documenta como un choque de +1,8 en log-varianza ese día. Un modelo de series, fundacional o no, solo puede anticipar lo que el pasado contiene; los saltos se gestionan con riesgo, no con previsión.
Ideas clave
- Un modelo fundacional se preentrena una vez con un corpus enorme y variado (Chronos: unos 84 000 millones de observaciones de 28 conjuntos, más datos aumentados y sintéticos) y se usa zero-shot: la serie nueva entra como contexto, sin tocar los pesos.
- Chronos convierte cada dato en un token: lo divide por la media de |x| y lo redondea a uno de 4 093 cajones en [−15, 15]. En una serie lejos del cero, como el log de la varianza, eso deja pocos cajones útiles.
- Chronos-Bolt y TimesFM tipifican la serie y la cortan en parches (16 y 32 datos): 512 observaciones son 33 o 16 tokens, y la atención cuesta mucho menos.
- Sobre la log RV del índice, 2018-2025, Chronos-Bolt-small zero-shot da un ECM de 0,181 frente a 0,233 de la ingenua (t = −9,8) y un R² de 0,551, por debajo del HAR del README (0,57) y del oráculo (0,61).
- Sus cuantiles son útiles pero no exactos: el intervalo 10-90 % cubre el 76,4 % de los días. Los choques, como el del 9 de marzo de 2020, no se prevén.