34. Chronos forecasting#

The paper behind this approach is here: https://arxiv.org/pdf/2403.07815 (univariate models)

The paper introduces Chronos, a framework that adapts language model architectures for time series forecasting. The key aspects are:

  1. Approach:

  • Converts time series data into tokens through scaling and quantization

  • Uses existing transformer language model architectures with minimal modifications

  • Trains models on both real and synthetic time series data

  1. Key Components:

  • TSMixup: Data augmentation technique that combines patterns from different time series

  • KernelSynth: Synthetic data generation using Gaussian processes

  • Based on T5 transformer architecture, with models ranging from 20M to 710M parameters

  1. Main Results:

  • Significantly outperforms traditional statistical models and task-specific deep learning models on in-domain datasets

  • Achieves competitive zero-shot performance on unseen datasets compared to models specifically trained on those datasets

  • Fine-tuning further improves performance on new datasets

  1. Key Benefits:

  • Eliminates need for task-specific training

  • Simplifies forecasting pipelines

  • Shows language model architectures can handle time series without specialized modifications

  • Provides strong zero-shot forecasting capabilities

  1. Limitations:

  • Inference speed slower than some specialized models

  • Edge cases with very sparse or high-variance time series

  • Limited by available high-quality public time series data

The paper demonstrates that language model architectures can be effectively adapted for time series forecasting with minimal modifications, potentially simplifying real-world forecasting applications.

Chronos-2 was released in October 2025: https://www.amazon.science/blog/introducing-chronos-2-from-univariate-to-universal-forecasting. It now supports multivariate forecasting.

  1. See Chronos: amazon-science/chronos-forecasting

  2. Docs: https://auto.gluon.ai/stable/tutorials/timeseries/forecasting-chronos.html

%%time
!pip install chronos-forecasting
Collecting chronos-forecasting
  Downloading chronos_forecasting-2.3.2-py3-none-any.whl.metadata (24 kB)
Requirement already satisfied: accelerate<2,>=1.1.0 in /usr/local/lib/python3.13/dist-packages (from chronos-forecasting) (1.14.0)
Requirement already satisfied: einops<1,>=0.7.0 in /usr/local/lib/python3.13/dist-packages (from chronos-forecasting) (0.8.2)
Requirement already satisfied: numpy<3,>=1.21 in /usr/local/lib/python3.13/dist-packages (from chronos-forecasting) (2.1.3)
Requirement already satisfied: pandas<4,>=2.0 in /usr/local/lib/python3.13/dist-packages (from chronos-forecasting) (2.2.3)
Requirement already satisfied: torch<3,>=2.2 in /usr/local/lib/python3.13/dist-packages (from chronos-forecasting) (2.11.0+cu128)
Requirement already satisfied: transformers<6,>=4.41 in /usr/local/lib/python3.13/dist-packages (from chronos-forecasting) (5.16.1)
Requirement already satisfied: packaging>=20.0 in /usr/local/lib/python3.13/dist-packages (from accelerate<2,>=1.1.0->chronos-forecasting) (26.3)
Requirement already satisfied: psutil in /usr/local/lib/python3.13/dist-packages (from accelerate<2,>=1.1.0->chronos-forecasting) (5.9.5)
Requirement already satisfied: pyyaml in /usr/local/lib/python3.13/dist-packages (from accelerate<2,>=1.1.0->chronos-forecasting) (6.0.3)
Requirement already satisfied: huggingface_hub>=0.21.0 in /usr/local/lib/python3.13/dist-packages (from accelerate<2,>=1.1.0->chronos-forecasting) (1.29.0)
Requirement already satisfied: safetensors>=0.4.3 in /usr/local/lib/python3.13/dist-packages (from accelerate<2,>=1.1.0->chronos-forecasting) (0.8.0)
Requirement already satisfied: python-dateutil>=2.8.2 in /usr/local/lib/python3.13/dist-packages (from pandas<4,>=2.0->chronos-forecasting) (2.9.0.post0)
Requirement already satisfied: pytz>=2020.1 in /usr/local/lib/python3.13/dist-packages (from pandas<4,>=2.0->chronos-forecasting) (2025.2)
Requirement already satisfied: tzdata>=2022.7 in /usr/local/lib/python3.13/dist-packages (from pandas<4,>=2.0->chronos-forecasting) (2026.3)
Requirement already satisfied: filelock in /usr/local/lib/python3.13/dist-packages (from torch<3,>=2.2->chronos-forecasting) (3.32.5)
Requirement already satisfied: typing-extensions>=4.10.0 in /usr/local/lib/python3.13/dist-packages (from torch<3,>=2.2->chronos-forecasting) (4.16.0)
Requirement already satisfied: setuptools<82 in /usr/local/lib/python3.13/dist-packages (from torch<3,>=2.2->chronos-forecasting) (80.10.2)
Requirement already satisfied: sympy>=1.13.3 in /usr/local/lib/python3.13/dist-packages (from torch<3,>=2.2->chronos-forecasting) (1.14.0)
Requirement already satisfied: networkx>=2.5.1 in /usr/local/lib/python3.13/dist-packages (from torch<3,>=2.2->chronos-forecasting) (3.6.1)
Requirement already satisfied: jinja2 in /usr/local/lib/python3.13/dist-packages (from torch<3,>=2.2->chronos-forecasting) (3.1.6)
Requirement already satisfied: fsspec>=0.8.5 in /usr/local/lib/python3.13/dist-packages (from torch<3,>=2.2->chronos-forecasting) (2025.12.0)
Requirement already satisfied: cuda-toolkit==12.8.1 in /usr/local/lib/python3.13/dist-packages (from cuda-toolkit[cublas,cudart,cufft,cufile,cupti,curand,cusolver,cusparse,nvjitlink,nvrtc,nvtx]==12.8.1; platform_system == "Linux"->torch<3,>=2.2->chronos-forecasting) (12.8.1)
Requirement already satisfied: cuda-bindings<13,>=12.9.4 in /usr/local/lib/python3.13/dist-packages (from torch<3,>=2.2->chronos-forecasting) (12.9.7)
Requirement already satisfied: nvidia-cudnn-cu12==9.19.0.56 in /usr/local/lib/python3.13/dist-packages (from torch<3,>=2.2->chronos-forecasting) (9.19.0.56)
Requirement already satisfied: nvidia-cusparselt-cu12==0.7.1 in /usr/local/lib/python3.13/dist-packages (from torch<3,>=2.2->chronos-forecasting) (0.7.1)
Requirement already satisfied: nvidia-nccl-cu12==2.28.9 in /usr/local/lib/python3.13/dist-packages (from torch<3,>=2.2->chronos-forecasting) (2.28.9)
Requirement already satisfied: nvidia-nvshmem-cu12==3.4.5 in /usr/local/lib/python3.13/dist-packages (from torch<3,>=2.2->chronos-forecasting) (3.4.5)
Requirement already satisfied: triton==3.6.0 in /usr/local/lib/python3.13/dist-packages (from torch<3,>=2.2->chronos-forecasting) (3.6.0)
Requirement already satisfied: nvidia-cublas-cu12==12.8.4.1.* in /usr/local/lib/python3.13/dist-packages (from cuda-toolkit[cublas,cudart,cufft,cufile,cupti,curand,cusolver,cusparse,nvjitlink,nvrtc,nvtx]==12.8.1; platform_system == "Linux"->torch<3,>=2.2->chronos-forecasting) (12.8.4.1)
Requirement already satisfied: nvidia-cuda-runtime-cu12==12.8.90.* in /usr/local/lib/python3.13/dist-packages (from cuda-toolkit[cublas,cudart,cufft,cufile,cupti,curand,cusolver,cusparse,nvjitlink,nvrtc,nvtx]==12.8.1; platform_system == "Linux"->torch<3,>=2.2->chronos-forecasting) (12.8.90)
Requirement already satisfied: nvidia-cufft-cu12==11.3.3.83.* in /usr/local/lib/python3.13/dist-packages (from cuda-toolkit[cublas,cudart,cufft,cufile,cupti,curand,cusolver,cusparse,nvjitlink,nvrtc,nvtx]==12.8.1; platform_system == "Linux"->torch<3,>=2.2->chronos-forecasting) (11.3.3.83)
Requirement already satisfied: nvidia-cufile-cu12==1.13.1.3.* in /usr/local/lib/python3.13/dist-packages (from cuda-toolkit[cublas,cudart,cufft,cufile,cupti,curand,cusolver,cusparse,nvjitlink,nvrtc,nvtx]==12.8.1; platform_system == "Linux"->torch<3,>=2.2->chronos-forecasting) (1.13.1.3)
Requirement already satisfied: nvidia-cuda-cupti-cu12==12.8.90.* in /usr/local/lib/python3.13/dist-packages (from cuda-toolkit[cublas,cudart,cufft,cufile,cupti,curand,cusolver,cusparse,nvjitlink,nvrtc,nvtx]==12.8.1; platform_system == "Linux"->torch<3,>=2.2->chronos-forecasting) (12.8.90)
Requirement already satisfied: nvidia-curand-cu12==10.3.9.90.* in /usr/local/lib/python3.13/dist-packages (from cuda-toolkit[cublas,cudart,cufft,cufile,cupti,curand,cusolver,cusparse,nvjitlink,nvrtc,nvtx]==12.8.1; platform_system == "Linux"->torch<3,>=2.2->chronos-forecasting) (10.3.9.90)
Requirement already satisfied: nvidia-cusolver-cu12==11.7.3.90.* in /usr/local/lib/python3.13/dist-packages (from cuda-toolkit[cublas,cudart,cufft,cufile,cupti,curand,cusolver,cusparse,nvjitlink,nvrtc,nvtx]==12.8.1; platform_system == "Linux"->torch<3,>=2.2->chronos-forecasting) (11.7.3.90)
Requirement already satisfied: nvidia-cusparse-cu12==12.5.8.93.* in /usr/local/lib/python3.13/dist-packages (from cuda-toolkit[cublas,cudart,cufft,cufile,cupti,curand,cusolver,cusparse,nvjitlink,nvrtc,nvtx]==12.8.1; platform_system == "Linux"->torch<3,>=2.2->chronos-forecasting) (12.5.8.93)
Requirement already satisfied: nvidia-nvjitlink-cu12==12.8.93.* in /usr/local/lib/python3.13/dist-packages (from cuda-toolkit[cublas,cudart,cufft,cufile,cupti,curand,cusolver,cusparse,nvjitlink,nvrtc,nvtx]==12.8.1; platform_system == "Linux"->torch<3,>=2.2->chronos-forecasting) (12.8.93)
Requirement already satisfied: nvidia-cuda-nvrtc-cu12==12.8.93.* in /usr/local/lib/python3.13/dist-packages (from cuda-toolkit[cublas,cudart,cufft,cufile,cupti,curand,cusolver,cusparse,nvjitlink,nvrtc,nvtx]==12.8.1; platform_system == "Linux"->torch<3,>=2.2->chronos-forecasting) (12.8.93)
Requirement already satisfied: nvidia-nvtx-cu12==12.8.90.* in /usr/local/lib/python3.13/dist-packages (from cuda-toolkit[cublas,cudart,cufft,cufile,cupti,curand,cusolver,cusparse,nvjitlink,nvrtc,nvtx]==12.8.1; platform_system == "Linux"->torch<3,>=2.2->chronos-forecasting) (12.8.90)
Requirement already satisfied: regex>=2025.10.22 in /usr/local/lib/python3.13/dist-packages (from transformers<6,>=4.41->chronos-forecasting) (2025.11.3)
Requirement already satisfied: tokenizers<0.24.0,>=0.23.1 in /usr/local/lib/python3.13/dist-packages (from transformers<6,>=4.41->chronos-forecasting) (0.23.1)
Requirement already satisfied: typer in /usr/local/lib/python3.13/dist-packages (from transformers<6,>=4.41->chronos-forecasting) (0.27.2)
Requirement already satisfied: tqdm>=4.60 in /usr/local/lib/python3.13/dist-packages (from transformers<6,>=4.41->chronos-forecasting) (4.67.3)
Requirement already satisfied: cuda-pathfinder~=1.1 in /usr/local/lib/python3.13/dist-packages (from cuda-bindings<13,>=12.9.4->torch<3,>=2.2->chronos-forecasting) (1.8.0)
Requirement already satisfied: click<9.0.0,>=8.4.2 in /usr/local/lib/python3.13/dist-packages (from huggingface_hub>=0.21.0->accelerate<2,>=1.1.0->chronos-forecasting) (8.5.0)
Requirement already satisfied: hf-xet<2.0.0,>=1.5.2 in /usr/local/lib/python3.13/dist-packages (from huggingface_hub>=0.21.0->accelerate<2,>=1.1.0->chronos-forecasting) (1.6.0)
Requirement already satisfied: httpx<1,>=0.23.0 in /usr/local/lib/python3.13/dist-packages (from huggingface_hub>=0.21.0->accelerate<2,>=1.1.0->chronos-forecasting) (0.28.1)
Requirement already satisfied: six>=1.5 in /usr/local/lib/python3.13/dist-packages (from python-dateutil>=2.8.2->pandas<4,>=2.0->chronos-forecasting) (1.17.0)
Requirement already satisfied: mpmath<1.4,>=1.1.0 in /usr/local/lib/python3.13/dist-packages (from sympy>=1.13.3->torch<3,>=2.2->chronos-forecasting) (1.3.0)
Requirement already satisfied: MarkupSafe>=2.0 in /usr/local/lib/python3.13/dist-packages (from jinja2->torch<3,>=2.2->chronos-forecasting) (3.0.3)
Requirement already satisfied: shellingham>=1.3.0 in /usr/local/lib/python3.13/dist-packages (from typer->transformers<6,>=4.41->chronos-forecasting) (1.5.4)
Requirement already satisfied: rich>=13.8.0 in /usr/local/lib/python3.13/dist-packages (from typer->transformers<6,>=4.41->chronos-forecasting) (13.9.4)
Requirement already satisfied: annotated-doc>=0.0.2 in /usr/local/lib/python3.13/dist-packages (from typer->transformers<6,>=4.41->chronos-forecasting) (0.0.5)
Requirement already satisfied: anyio in /usr/local/lib/python3.13/dist-packages (from httpx<1,>=0.23.0->huggingface_hub>=0.21.0->accelerate<2,>=1.1.0->chronos-forecasting) (4.14.2)
Requirement already satisfied: certifi in /usr/local/lib/python3.13/dist-packages (from httpx<1,>=0.23.0->huggingface_hub>=0.21.0->accelerate<2,>=1.1.0->chronos-forecasting) (2026.7.22)
Requirement already satisfied: httpcore==1.* in /usr/local/lib/python3.13/dist-packages (from httpx<1,>=0.23.0->huggingface_hub>=0.21.0->accelerate<2,>=1.1.0->chronos-forecasting) (1.0.9)
Requirement already satisfied: idna in /usr/local/lib/python3.13/dist-packages (from httpx<1,>=0.23.0->huggingface_hub>=0.21.0->accelerate<2,>=1.1.0->chronos-forecasting) (3.19)
Requirement already satisfied: h11>=0.16 in /usr/local/lib/python3.13/dist-packages (from httpcore==1.*->httpx<1,>=0.23.0->huggingface_hub>=0.21.0->accelerate<2,>=1.1.0->chronos-forecasting) (0.16.0)
Requirement already satisfied: markdown-it-py>=2.2.0 in /usr/local/lib/python3.13/dist-packages (from rich>=13.8.0->typer->transformers<6,>=4.41->chronos-forecasting) (4.2.0)
Requirement already satisfied: pygments<3.0.0,>=2.13.0 in /usr/local/lib/python3.13/dist-packages (from rich>=13.8.0->typer->transformers<6,>=4.41->chronos-forecasting) (2.21.0)
Requirement already satisfied: mdurl~=0.1 in /usr/local/lib/python3.13/dist-packages (from markdown-it-py>=2.2.0->rich>=13.8.0->typer->transformers<6,>=4.41->chronos-forecasting) (0.1.2)
Downloading chronos_forecasting-2.3.2-py3-none-any.whl (80 kB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 80.8/80.8 kB 2.3 MB/s eta 0:00:00
?25hInstalling collected packages: chronos-forecasting
Successfully installed chronos-forecasting-2.3.2
CPU times: user 2.12 s, sys: 768 ms, total: 2.88 s
Wall time: 10.7 s

34.1. Set Up#

import pandas as pd  # requires: pip install pandas
import torch
from chronos import BaseChronosPipeline
import matplotlib.pyplot as plt  # requires: pip install matplotlib
import numpy as np

pipeline = BaseChronosPipeline.from_pretrained(
    "amazon/chronos-t5-small",  # use "amazon/chronos-bolt-small" for the corresponding Chronos-Bolt model
    device_map="cuda",  # use "cpu" for CPU inference
    torch_dtype=torch.bfloat16,
)

Warning: You are sending unauthenticated requests to the HF Hub. Please set a HF_TOKEN to enable higher rate limits and faster downloads.
WARNING:huggingface_hub.utils._http:Warning: You are sending unauthenticated requests to the HF Hub. Please set a HF_TOKEN to enable higher rate limits and faster downloads.

34.2. Forecasting Passenger Traffic#

df = pd.read_csv(
    "https://raw.githubusercontent.com/AileenNielsen/TimeSeriesAnalysisWithPython/master/data/AirPassengers.csv"
)

# context must be either a 1D tensor, a list of 1D tensors,
# or a left-padded 2D tensor with batch as the first dimension
# quantiles is an fp32 tensor with shape [batch_size, prediction_length, num_quantile_levels]
# mean is an fp32 tensor with shape [batch_size, prediction_length]
quantiles, mean = pipeline.predict_quantiles(
    inputs=torch.tensor(df["#Passengers"]),
    prediction_length=12,
    quantile_levels=[0.1, 0.5, 0.9],
)
df.head()
Month #Passengers
0 1949-01 112
1 1949-02 118
2 1949-03 132
3 1949-04 129
4 1949-05 121
df.tail()
Month #Passengers
139 1960-08 606
140 1960-09 508
141 1960-10 461
142 1960-11 390
143 1960-12 432
from chronos import ChronosPipeline, ChronosBoltPipeline

print(ChronosPipeline.predict.__doc__)  # for Chronos models
print(ChronosBoltPipeline.predict.__doc__)  # for Chronos-Bolt models
Get forecasts for the given time series.

Refer to the base method (``BaseChronosPipeline.predict``)
for details on shared parameters.

Additional parameters
---------------------
num_samples
    Number of sample paths to predict. Defaults to what
    specified in ``self.model.config``.
temperature
    Temperature to use for generating sample tokens.
    Defaults to what specified in ``self.model.config``.
top_k
    Top-k parameter to use for generating sample tokens.
    Defaults to what specified in ``self.model.config``.
top_p
    Top-p parameter to use for generating sample tokens.
    Defaults to what specified in ``self.model.config``.
limit_prediction_length
    Force prediction length smaller or equal than the
    built-in prediction length from the model. False by
    default. When true, fail loudly if longer predictions
    are requested, otherwise longer predictions are allowed.

Returns
-------
samples
    Tensor of sample forecasts, of shape
    (batch_size, num_samples, prediction_length).


Get forecasts for the given time series.

Refer to the base method (``BaseChronosPipeline.predict``)
for details on shared parameters.
Additional parameters
---------------------
limit_prediction_length
    Force prediction length smaller or equal than the
    built-in prediction length from the model. False by
    default. When true, fail loudly if longer predictions
    are requested, otherwise longer predictions are allowed.

Returns
-------
torch.Tensor
    Forecasts of shape (batch_size, num_quantiles, prediction_length)
    where num_quantiles is the number of quantiles the model has been
    trained to output. For official Chronos-Bolt models, the value of
    num_quantiles is 9 for [0.1, 0.2, ..., 0.9]-quantiles.

Raises
------
ValueError
    When limit_prediction_length is True and the prediction_length is
    greater than model's training prediction_length.
forecast_index = range(len(df), len(df) + 12)
low, median, high = quantiles[0, :, 0], quantiles[0, :, 1], quantiles[0, :, 2]

plt.figure(figsize=(8, 4))
plt.plot(df["#Passengers"], color="royalblue", label="historical data")
plt.plot(forecast_index, median, color="tomato", label="median forecast")
plt.fill_between(forecast_index, low, high, color="tomato", alpha=0.3, label="80% prediction interval")
plt.legend()
plt.grid()
plt.show()
_images/2f0c545476206c4b30f1004f6055932db7370e5478bfa7d0f5bfccee171fbf0f.png

34.3. Forecasting Stock Prices#

# Code to use yfinance to download bitcoin data from FRED ticker CBBTCUSD

!pip install yfinance

import yfinance as yf
Requirement already satisfied: yfinance in /usr/local/lib/python3.13/dist-packages (0.2.66)
Requirement already satisfied: pandas>=1.3.0 in /usr/local/lib/python3.13/dist-packages (from yfinance) (2.2.3)
Requirement already satisfied: numpy>=1.16.5 in /usr/local/lib/python3.13/dist-packages (from yfinance) (2.1.3)
Requirement already satisfied: requests>=2.31 in /usr/local/lib/python3.13/dist-packages (from yfinance) (2.32.4)
Requirement already satisfied: multitasking>=0.0.7 in /usr/local/lib/python3.13/dist-packages (from yfinance) (0.0.13)
Requirement already satisfied: platformdirs>=2.0.0 in /usr/local/lib/python3.13/dist-packages (from yfinance) (4.11.7)
Requirement already satisfied: pytz>=2022.5 in /usr/local/lib/python3.13/dist-packages (from yfinance) (2025.2)
Requirement already satisfied: frozendict>=2.3.4 in /usr/local/lib/python3.13/dist-packages (from yfinance) (2.4.7)
Requirement already satisfied: peewee>=3.16.2 in /usr/local/lib/python3.13/dist-packages (from yfinance) (4.4.0)
Requirement already satisfied: beautifulsoup4>=4.11.1 in /usr/local/lib/python3.13/dist-packages (from yfinance) (4.13.5)
Requirement already satisfied: curl_cffi>=0.7 in /usr/local/lib/python3.13/dist-packages (from yfinance) (0.16.2)
Requirement already satisfied: protobuf>=3.19.0 in /usr/local/lib/python3.13/dist-packages (from yfinance) (5.29.6)
Requirement already satisfied: websockets>=13.0 in /usr/local/lib/python3.13/dist-packages (from yfinance) (15.0.1)
Requirement already satisfied: soupsieve>1.2 in /usr/local/lib/python3.13/dist-packages (from beautifulsoup4>=4.11.1->yfinance) (2.9.2)
Requirement already satisfied: typing-extensions>=4.0.0 in /usr/local/lib/python3.13/dist-packages (from beautifulsoup4>=4.11.1->yfinance) (4.16.0)
Requirement already satisfied: cffi>=2.0.0 in /usr/local/lib/python3.13/dist-packages (from curl_cffi>=0.7->yfinance) (2.1.1)
Requirement already satisfied: certifi>=2024.2.2 in /usr/local/lib/python3.13/dist-packages (from curl_cffi>=0.7->yfinance) (2026.7.22)
Requirement already satisfied: python-dateutil>=2.8.2 in /usr/local/lib/python3.13/dist-packages (from pandas>=1.3.0->yfinance) (2.9.0.post0)
Requirement already satisfied: tzdata>=2022.7 in /usr/local/lib/python3.13/dist-packages (from pandas>=1.3.0->yfinance) (2026.3)
Requirement already satisfied: charset_normalizer<4,>=2 in /usr/local/lib/python3.13/dist-packages (from requests>=2.31->yfinance) (3.4.9)
Requirement already satisfied: idna<4,>=2.5 in /usr/local/lib/python3.13/dist-packages (from requests>=2.31->yfinance) (3.19)
Requirement already satisfied: urllib3<3,>=1.21.1 in /usr/local/lib/python3.13/dist-packages (from requests>=2.31->yfinance) (2.5.0)
Requirement already satisfied: pycparser in /usr/local/lib/python3.13/dist-packages (from cffi>=2.0.0->curl_cffi>=0.7->yfinance) (3.0)
Requirement already satisfied: six>=1.5 in /usr/local/lib/python3.13/dist-packages (from python-dateutil>=2.8.2->pandas>=1.3.0->yfinance) (1.17.0)
# Download Stock data
df = yf.download("GOOGL", start="2023-08-31", end="2026-12-31")

# Print the downloaded data
df.head()
/tmp/ipykernel_3292/1629859599.py:2: FutureWarning: YF.download() has changed argument auto_adjust default to True
  df = yf.download("GOOGL", start="2023-08-31", end="2026-12-31")
[*********************100%***********************]  1 of 1 completed
Price Close High Low Open Volume
Ticker GOOGL GOOGL GOOGL GOOGL GOOGL
Date
2023-08-31 134.886459 136.699212 134.510036 134.727964 30053800
2023-09-01 134.381287 136.164323 133.578924 136.164323 21543700
2023-09-05 134.490234 135.134101 133.311449 134.163343 19403100
2023-09-06 133.192612 135.243092 132.410050 134.737905 18684500
2023-09-07 133.985062 134.302053 131.696838 132.330805 18844300
f_len = 32
col_name = 'Close'

quantiles, mean = pipeline.predict_quantiles(
    inputs=torch.tensor(df[col_name].dropna().values[-126:]), # Convert the Pandas Series to a NumPy array and drop NaN values before creating the tensor
    prediction_length=f_len,
    quantile_levels=[0.1, 0.5, 0.9],
)
forecast_index = range(len(df[-126:]), len(df[-126:]) + f_len)
low, median, high = quantiles[0, :, 0], quantiles[0, :, 1], quantiles[0, :, 2]

plt.figure(figsize=(8, 4))
plt.plot(np.array(df[col_name][-126:]), color="royalblue", label="historical data")
plt.plot(forecast_index, median, color="tomato", label="median forecast")
plt.fill_between(forecast_index, low, high, color="tomato", alpha=0.3, label="80% prediction interval")
plt.legend()
plt.grid()
plt.show()
_images/736b19ee31d72fb94fdd8e217544f1e092a1d1a349d4a491253cb89dd33080f7.png

34.4. Stock Returns#

f_len = 21
col_name = 'Close'
ts = df[col_name].pct_change().dropna().values

quantiles, mean = pipeline.predict_quantiles(
    inputs=torch.tensor(ts), # Convert the Pandas Series to a NumPy array and drop NaN values before creating the tensor
    prediction_length=f_len,
    quantile_levels=[0.1, 0.5, 0.9],
)
forecast_index = range(len(ts), len(ts) + f_len)
low, median, high = quantiles[0, :, 0], quantiles[0, :, 1], quantiles[0, :, 2]

plt.figure(figsize=(8, 4))
plt.plot(np.array(ts), color="royalblue", label="historical data")
plt.plot(forecast_index, median, color="tomato", label="median forecast")
plt.fill_between(forecast_index, low, high, color="tomato", alpha=0.3, label="80% prediction interval")
plt.legend()
plt.grid()
plt.show()
_images/e2e182e33f61baa6f218cb0c4852d192e2ef21e4cccc1fcf071258633f57b6f2.png

34.5. Treasuries (10 yr)#

df = pd.read_csv('https://fred.stlouisfed.org/graph/fredgraph.csv?bgcolor=%23ebf3fb&chart_type=line&drp=0&fo=open%20sans&graph_bgcolor=%23ffffff&height=450&mode=fred&recession_bars=on&txtcolor=%23444444&ts=12&tts=12&width=1320&nt=0&thu=0&trc=0&show_legend=yes&show_axis_titles=yes&show_tooltip=yes&id=DFII10&scale=left&cosd=2020-03-20&coed=2025-03-20&line_color=%230073e6&link_values=false&line_style=solid&mark_type=none&mw=3&lw=3&ost=-99999&oet=99999&mma=0&fml=a&fq=Daily&fam=avg&fgst=lin&fgsnd=2020-02-01&line_index=1&transformation=lin&vintage_date=2025-03-21&revision_date=2025-03-21&nd=2003-01-02')
df.head()
observation_date DFII10
0 2020-03-20 0.17
1 2020-03-23 -0.04
2 2020-03-24 -0.13
3 2020-03-25 -0.19
4 2020-03-26 -0.24
f_len = 64
col_name = 'DFII10'

quantiles, mean = pipeline.predict_quantiles(
    inputs=torch.tensor(df[col_name].dropna().values), # Convert the Pandas Series to a NumPy array and drop NaN values before creating the tensor
    prediction_length=f_len,
    quantile_levels=[0.1, 0.5, 0.9],
)
forecast_index = range(len(df), len(df) + f_len)
low, median, high = quantiles[0, :, 0], quantiles[0, :, 1], quantiles[0, :, 2]

plt.figure(figsize=(8, 4))
plt.plot(np.array(df[col_name]), color="royalblue", label="historical data")
plt.plot(forecast_index, median, color="tomato", label="median forecast")
plt.fill_between(forecast_index, low, high, color="tomato", alpha=0.3, label="80% prediction interval")
plt.legend()
plt.grid()
plt.show()
_images/87a6ddb36b99f653d706f2de66b32c9e5b5d8905ea448e7fd56ceecb5add1074.png

34.6. Cryptocurrencies#

df = pd.read_csv('https://fred.stlouisfed.org/graph/fredgraph.csv?bgcolor=%23ebf3fb&chart_type=line&drp=0&fo=open%20sans&graph_bgcolor=%23ffffff&height=450&mode=fred&recession_bars=on&txtcolor=%23444444&ts=12&tts=12&width=1320&nt=0&thu=0&trc=0&show_legend=yes&show_axis_titles=yes&show_tooltip=yes&id=CBBTCUSD&scale=left&cosd=2020-03-20&coed=2025-03-20&line_color=%230073e6&link_values=false&line_style=solid&mark_type=none&mw=3&lw=3&ost=-99999&oet=99999&mma=0&fml=a&fq=Daily%2C%207-Day&fam=avg&fgst=lin&fgsnd=2020-02-01&line_index=1&transformation=lin&vintage_date=2025-03-21&revision_date=2025-03-21&nd=2014-12-01')
df.head()
observation_date CBBTCUSD
0 2020-03-20 6215.40
1 2020-03-21 6168.72
2 2020-03-22 5791.69
3 2020-03-23 6583.38
4 2020-03-24 6742.21
f_len = 64
col_name = 'CBBTCUSD'

quantiles, mean = pipeline.predict_quantiles(
    inputs=torch.tensor(df[col_name].dropna().values), # Convert the Pandas Series to a NumPy array and drop NaN values before creating the tensor
    prediction_length=f_len,
    quantile_levels=[0.1, 0.5, 0.9],
)
forecast_index = range(len(df), len(df) + f_len)
low, median, high = quantiles[0, :, 0], quantiles[0, :, 1], quantiles[0, :, 2]

plt.figure(figsize=(8, 4))
plt.plot(np.array(df[col_name]), color="royalblue", label="historical data")
plt.plot(forecast_index, median, color="tomato", label="median forecast")
plt.fill_between(forecast_index, low, high, color="tomato", alpha=0.3, label="80% prediction interval")
plt.legend()
plt.grid()
plt.show()
_images/83efdd45ab475b3545a047fb274e0ffdee798f91ef982cf1be3c082fbc5aad2b.png

34.7. Chronos-2#

This is for multivariate forecasting. See the technical paper: https://arxiv.org/abs/2510.15821

GitHub: amazon-science/chronos-forecasting

Let’s try the example provided:

import pandas as pd  # requires: pip install 'pandas[pyarrow]'
from chronos import Chronos2Pipeline

pipeline = Chronos2Pipeline.from_pretrained("amazon/chronos-2", device_map="cuda")

# Load historical target values and past values of covariates
context_df = pd.read_parquet("https://autogluon.s3.amazonaws.com/datasets/timeseries/electricity_price/train.parquet")

# (Optional) Load future values of covariates
test_df = pd.read_parquet("https://autogluon.s3.amazonaws.com/datasets/timeseries/electricity_price/test.parquet")
future_df = test_df.drop(columns="target")

# Generate predictions with covariates
pred_df = pipeline.predict_df(
    context_df,
    future_df=future_df,
    prediction_length=24,  # Number of steps to forecast
    quantile_levels=[0.1, 0.5, 0.9],  # Quantile for probabilistic forecast
    id_column="id",  # Column identifying different time series
    timestamp_column="timestamp",  # Column with datetime information
    target="target",  # Column(s) with time series values to predict
)
context_df.head()
id timestamp target Ampirion Load Forecast PV+Wind Forecast
0 DE 2012-01-09 00:00:00 34.970001 16382.00 3569.527588
1 DE 2012-01-09 01:00:00 33.430000 15410.50 3315.274902
2 DE 2012-01-09 02:00:00 32.740002 15595.00 3107.307617
3 DE 2012-01-09 03:00:00 32.459999 16521.00 2944.620117
4 DE 2012-01-09 04:00:00 32.500000 17700.75 2897.149902
import matplotlib.pyplot as plt  # requires: pip install matplotlib

ts_context = context_df.set_index("timestamp")["target"].tail(256)
ts_pred = pred_df.set_index("timestamp")
ts_ground_truth = test_df.set_index("timestamp")["target"]

ts_context.plot(label="historical data", color="xkcd:azure", figsize=(12, 3))
ts_ground_truth.plot(label="future data (ground truth)", color="xkcd:grass green")
ts_pred["predictions"].plot(label="forecast", color="xkcd:violet")
plt.fill_between(
    ts_pred.index,
    ts_pred["0.1"],
    ts_pred["0.9"],
    alpha=0.7,
    label="prediction interval",
    color="xkcd:light lavender",
)
plt.legend()
<matplotlib.legend.Legend at 0x7a840e8ad590>
_images/9fff8171cd0ab783552487c67d8c52e387ff57233be5f4572176a244be4bb507.png

34.8. Compare to univariate forecast#

Drop all additional data and only keep the target series.

context_df = context_df[["id", "timestamp", "target"]]
test_df = test_df[["id", "timestamp", "target"]]
future_df = test_df.drop(columns="target")
pred_df = pipeline.predict_df(
    context_df,
    future_df=future_df,
    prediction_length=24,  # Number of steps to forecast
    quantile_levels=[0.1, 0.5, 0.9],  # Quantile for probabilistic forecast
    id_column="id",  # Column identifying different time series
    timestamp_column="timestamp",  # Column with datetime information
    target="target",  # Column(s) with time series values to predict
)
ts_context = context_df.set_index("timestamp")["target"].tail(256)
ts_pred = pred_df.set_index("timestamp")
ts_ground_truth = test_df.set_index("timestamp")["target"]

ts_context.plot(label="historical data", color="xkcd:azure", figsize=(12, 3))
ts_ground_truth.plot(label="future data (ground truth)", color="xkcd:grass green")
ts_pred["predictions"].plot(label="forecast", color="xkcd:violet")
plt.fill_between(
    ts_pred.index,
    ts_pred["0.1"],
    ts_pred["0.9"],
    alpha=0.7,
    label="prediction interval",
    color="xkcd:light lavender",
)
plt.legend()
<matplotlib.legend.Legend at 0x7a840f3be850>
_images/e9ff7dd77c3adf162a47a7d34501c1699fc0303334218ac8addd1fdb7d40f367.png

We can see that the forecast error is much higher.

34.9. Multivariate stock price forecast#

We download the “magnificent 7” tech stocks: Alphabet, Amazon, Apple, Microsoft, Netflix, Nvidia, Tesla.

df = yf.download(["GOOGL", "AMZN", "AAPL", "MSFT", "NFLX", "NVDA", "TSLA"],
                  start="2023-08-31", end="2025-11-01")
/tmp/ipykernel_3292/2569614512.py:1: FutureWarning: YF.download() has changed argument auto_adjust default to True
  df = yf.download(["GOOGL", "AMZN", "AAPL", "MSFT", "NFLX", "NVDA", "TSLA"],
[*********************100%***********************]  7 of 7 completed
df.head()
Price Close High ... Open Volume
Ticker AAPL AMZN GOOGL MSFT NFLX NVDA TSLA AAPL AMZN GOOGL ... NFLX NVDA TSLA AAPL AMZN GOOGL MSFT NFLX NVDA TSLA
Date
2023-08-31 185.362946 138.009995 134.886475 320.259003 43.368000 49.203983 258.079987 186.596265 138.789993 136.699227 ... 43.123001 49.228908 255.979996 60794500 58781300 30053800 26411000 38030000 528570000 108861700
2023-09-01 186.931732 138.119995 134.381241 321.138458 43.987999 48.360569 245.009995 187.385585 139.960007 136.164277 ... 43.772999 49.609737 257.260010 45766500 40991500 21543700 14942000 47934000 463830000 132541600
2023-09-05 187.168518 137.270004 134.490234 325.916534 44.868000 48.399456 256.489990 187.444780 137.800003 135.134101 ... 43.839001 48.075450 245.000000 45280000 40636700 19403100 18553900 61559000 382653000 129469600
2023-09-06 180.469147 135.360001 133.192566 325.261871 44.576000 46.920864 251.919998 186.329882 137.449997 135.243046 ... 44.861000 48.296756 255.139999 81755800 41785500 18684500 17535800 38623000 468670000 116959800
2023-09-07 175.190536 137.850006 133.985031 322.359863 44.313999 46.103310 251.490005 175.831872 138.029999 134.302022 ... 44.115002 45.389442 245.070007 112488800 48498900 18844300 18381000 29227000 433330000 115312900

5 rows × 35 columns

df1 = df["Close"].reset_index()
print("Length of series =", len(df))
df1["item_id"] = "D1"

# Convert 'Date' to datetime and set it as index
df1['Date'] = pd.to_datetime(df1['Date'])
df1 = df1.set_index('Date')

# Reindex to business day frequency and forward-fill missing values
df1 = df1.asfreq('B').ffill()

# Reset index to make 'Date' a column again, as predict_df expects it
df1 = df1.reset_index()

df1.head()
Length of series = 545
Ticker Date AAPL AMZN GOOGL MSFT NFLX NVDA TSLA item_id
0 2023-08-31 185.362946 138.009995 134.886475 320.259003 43.368000 49.203983 258.079987 D1
1 2023-09-01 186.931732 138.119995 134.381241 321.138458 43.987999 48.360569 245.009995 D1
2 2023-09-04 186.931732 138.119995 134.381241 321.138458 43.987999 48.360569 245.009995 D1
3 2023-09-05 187.168518 137.270004 134.490234 325.916534 44.868000 48.399456 256.489990 D1
4 2023-09-06 180.469147 135.360001 133.192566 325.261871 44.576000 46.920864 251.919998 D1
import pandas as pd  # requires: pip install 'pandas[pyarrow]'
from chronos import Chronos2Pipeline

pipeline = Chronos2Pipeline.from_pretrained("amazon/chronos-2", device_map="cuda")

# Load historical target values and past values of covariates
context_df = df1.iloc[:500]

# (Optional) Load future values of covariates
test_df = df1.iloc[500:]
future_df = test_df.drop(columns=["NVDA"]) # Only drop the target column, keep 'item_id'
pred_length = len(test_df)

# Generate predictions with covariates
pred_df = pipeline.predict_df(
    context_df,
    future_df=future_df,
    prediction_length=pred_length,  # Number of steps to forecast
    quantile_levels=[0.1, 0.5, 0.9],  # Quantile for probabilistic forecast
    id_column="item_id",  # Column identifying different time series
    timestamp_column="Date",  # Column with datetime information
    target="NVDA",  # Column(s) with time series values to predict
)
import matplotlib.pyplot as plt

ts_context = context_df.set_index("Date")["NVDA"]
ts_pred = pred_df.set_index("Date")
ts_ground_truth = test_df.set_index("Date")["NVDA"]

plt.figure(figsize=(12, 3))
ts_context.plot(label="historical data", color="royalblue")
ts_ground_truth.plot(label="future data (ground truth)", color="green")
ts_pred["predictions"].plot(label="forecast", color="tomato")
plt.fill_between(
    ts_pred.index,
    ts_pred["0.1"], # Using '0.1' as the lower quantile column name
    ts_pred["0.9"], # Using '0.9' as the upper quantile column name
    alpha=0.3,
    label="80% prediction interval",
    color="orange",
)
plt.title("Multivariate NVDA Stock Price Forecast")
plt.xlabel("Date")
plt.ylabel("Stock Price (NVDA)")
plt.legend()
plt.grid(True)
plt.show()
_images/f9fb4ae588e8222f67a6a7e4a1af0d382f3571955fa562f6f5bd9efda579fe36.png
print("Mean Absolute Percentage Error (MAPE) =", (abs(ts_ground_truth - ts_pred["predictions"]) / ts_ground_truth).mean())
print("Root Mean Squared Error (RMSE) =", ((ts_ground_truth - ts_pred["predictions"]) ** 2).mean() ** 0.5)
Mean Absolute Percentage Error (MAPE) = 0.03533941792027911
Root Mean Squared Error (RMSE) = 8.073445152407844
# Univariate forecast?
context_df = context_df[["item_id", "Date", "NVDA"]]
test_df = test_df[["item_id", "Date", "NVDA"]]
future_df = test_df.drop(columns="NVDA")
pred_df = pipeline.predict_df(
    context_df,
    future_df=future_df,
    prediction_length=pred_length,  # Number of steps to forecast
    quantile_levels=[0.1, 0.5, 0.9],  # Quantile for probabilistic forecast
    id_column="item_id",  # Column identifying different time series
    timestamp_column="Date",  # Column with datetime information
    target="NVDA",  # Column(s) with time series values to predict
)
ts_context = context_df.set_index("Date")["NVDA"]
ts_pred = pred_df.set_index("Date")
ts_ground_truth = test_df.set_index("Date")["NVDA"]

ts_context.plot(label="historical data", color="xkcd:azure", figsize=(12, 3))
ts_ground_truth.plot(label="future data (ground truth)", color="xkcd:grass green")
ts_pred["predictions"].plot(label="forecast", color="xkcd:violet")
plt.fill_between(
    ts_pred.index,
    ts_pred["0.1"],
    ts_pred["0.9"],
    alpha=0.7,
    label="80% prediction interval",
    color="xkcd:light lavender",
)
plt.legend()
plt.grid()
_images/2efb1ac0c6c00321ffb08893b1a56da0c681fd0915a048ed4b57978c0c5f5496.png
print("Mean Absolute Percentage Error (MAPE) =", (abs(ts_ground_truth - ts_pred["predictions"]) / ts_ground_truth).mean())
print("Root Mean Squared Error (RMSE) =", ((ts_ground_truth - ts_pred["predictions"]) ** 2).mean() ** 0.5)
Mean Absolute Percentage Error (MAPE) = 0.044511502938009824
Root Mean Squared Error (RMSE) = 9.490287046657256