preqts
Prequential (test-then-update) streaming evaluation for time-series forecasters.
Real forecasting is streaming: observations arrive over time, covariates interact, some are known into the future, and a model must update its prediction at each step. Public benchmarks evaluate the batch case: at each cutoff they re-forecast an independent window (fev, GIFT-Eval, GluonTS/Darts rolling backtests). None of them evaluate a stateful forecaster that carries hidden state and updates at constant cost, which is exactly the regime of the new recurrent and state-space foundation models (TiRex-2 / xLSTM, FlowState / SSM). When the TiRex-2 authors needed to measure streaming behaviour, they had to hand-roll a bespoke protocol because nothing standard existed.
preqts is that missing harness: it drives any forecaster through a test-then-update loop, scores
stateful and batch models identically on one stream, simulates realistic covariate arrival, and
measures the per-step compute cost so the streaming-cost argument is verified, not asserted.
Part of the ChronoScope time-series method atlas (extracted as a standalone, PyPI-destined library per CAOS ADR-0061). Core depends on numpy only (Pyodide-safe); model backends are optional extras.
Install
pip install preqts # core (numpy only)
pip install "preqts[statsforecast]" # + a batch backend to wrap
pip install "preqts[dev]" # + pytest, ruff
Quickstart
import numpy as np
from preqts import SeasonalNaive, Stream, run_prequential
rng = np.random.default_rng(0)
y = 50 + 10 * np.sin(np.arange(600) * 2 * np.pi / 12) + rng.normal(0, 2, 600)
stream = Stream(y, seasonality=12, name="demo")
result = run_prequential(SeasonalNaive(12), stream, horizon=1, quantile_levels=[0.1, 0.5, 0.9])
print(result.summary()) # MASE, WQL, SQL, coverage, total_compute_s, final_predict_ms
See examples/quickstart.py for the stateful-vs-batch cost comparison.
Core concepts
| Object | Role |
|---|---|
StatefulForecaster |
The contract every evaluated model implements: start / predict / ingest. |
Stream + Covariate |
A target series plus covariates with arrival policies: aligned past, lagged (late-arriving) past, known-future; NaN for missing. |
SeasonalNaive |
A real pure-numpy reference forecaster with empirical, horizon-widening quantiles. |
ReplayAdapter |
Wraps any batch forecaster into the streaming protocol by replaying accumulated history (makes batch and stateful comparable, and exposes batch cost growth). |
run_prequential |
The test-then-update loop; returns a PrequentialResult. |
AdaptiveConformal |
Online (ACI) recalibration of a forecaster's outer interval to track nominal coverage. |
Metrics
mase, weighted_quantile_loss (WQL), scaled_quantile_loss (SQL, the probabilistic analogue of
MASE used by fev-bench), empirical_coverage, and pinball_loss. MASE and SQL are scaled by the
in-sample seasonal-naive MAE fixed from the warmup window, so every cutoff and every model share one
denominator.
Wrapping a real batch model
Any callable batch_fn(context, horizon, past_cov, future_cov, quantile_levels) -> (horizon, Q) can
be wrapped:
from preqts import ReplayAdapter, run_prequential
def chronos_batch(context, horizon, past_cov, future_cov, levels):
# call a Chronos-2 / TimesFM / StatsForecast model on `context`, return quantile columns
...
result = run_prequential(ReplayAdapter(chronos_batch, name="chronos-2"), stream, horizon=12)
The adapter re-reads the whole history each predict, so result.predict_latency shows the batch
cost growing with the stream: the phenomenon a streaming-native model avoids.
Docs
The docs/ wiki explains the method and the design: why prequential
(docs/00_why-prequential.md), the protocol and stream model
(docs/01_protocol-and-stream.md), the metrics
(docs/02_metrics.md), and the conformal module
(docs/03_conformal.md).
Status
v0.01.000 (2026-07-03), alpha. API may change while 0.x. 32 tests, ruff-clean.
License
Apache-2.0.
Release files for preqts 0.3.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| preqts-0.3.1.tar.gz | 32.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| preqts-0.3.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 60.5 kB
Release files / preqts-0.3.1.tar.gz
| Download URL | preqts-0.3.1.tar.gz |
|---|---|
| Size | 32.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
45d561f2b3b45f2f895467e2a35fa827de7469c1850c2a6a14c6f8e4c1035cfe
|
|
BLAKE2b-256 checksum How to use checksums |
e6844d15ad37cd57916f2f4212a8e3e6698bde509c8f1038220dcf9818c8be7a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 26, 2026.
Transparency logRelease files / preqts-0.3.1-py3-none-any.whl
| Download URL | preqts-0.3.1-py3-none-any.whl |
|---|---|
| Size | 28.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
44082b7bcaac45074facfe55bac0da89472b8f6aa665ba9efcdce8fa428e737c
|
|
BLAKE2b-256 checksum How to use checksums |
bec93c68588b3585503e6faa33b6c3100664ddc3a252436cc4e0c0b3f52df154
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 26, 2026.
Transparency log