Metadata-Version: 2.4
Name: forecast_realtime
Version: 0.5.6
Summary: A package for producing real-time forecasts
Author-email: Paul Labonne <paul.labonne@bankofengland.co.uk>, Sumer Singh <sumer.singh@bankofengland.co.uk>, Harry Li <Harry.Li@bankofengland.co.uk>, Nades Raviraj <Nades.Raviraj@bankofengland.co.uk>
Maintainer-email: Paul Labonne <paul.labonne@bankofengland.co.uk>, Sumer Singh <sumer.singh@bankofengland.co.uk>
License-Expression: MIT
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: statsmodels<0.15.0,>=0.14.0
Requires-Dist: forecast_evaluation>=0.1.13
Requires-Dist: pandas>=3.0.3
Requires-Dist: scipy>=1.17.1
Requires-Dist: tqdm>=4.67.3
Requires-Dist: numpy>=2.4.5
Requires-Dist: pyarrow>=24.0.0
Provides-Extra: dev
Requires-Dist: pre_commit>=4.6.0; extra == "dev"
Requires-Dist: pytest>=9.0.3; extra == "dev"
Requires-Dist: pytest-xdist; extra == "dev"
Requires-Dist: pydoclint>=0.9.1; extra == "dev"
Requires-Dist: syrupy>=5.2.0; extra == "dev"
Requires-Dist: ruff>=0.15.13; extra == "dev"
Provides-Extra: docs
Requires-Dist: mkdocstrings[python]; extra == "docs"
Requires-Dist: zensical; extra == "docs"
Provides-Extra: notebooks
Requires-Dist: marimo==0.24.0; extra == "notebooks"
Requires-Dist: news_decomp>=0.0.7; extra == "notebooks"
Provides-Extra: models
Requires-Dist: bvar>=0.3.1; extra == "models"
Requires-Dist: nowcast-midas>=0.0.1; extra == "models"
Requires-Dist: scikit-learn>=1.8.0; extra == "models"
Requires-Dist: xgboost>=3.2.0; extra == "models"
Provides-Extra: ridge
Requires-Dist: scikit-learn>=1.8.0; extra == "ridge"
Provides-Extra: lasso
Requires-Dist: scikit-learn>=1.8.0; extra == "lasso"
Provides-Extra: elasticnet
Requires-Dist: scikit-learn>=1.8.0; extra == "elasticnet"
Provides-Extra: random-forest
Requires-Dist: scikit-learn>=1.8.0; extra == "random-forest"
Provides-Extra: xgboost
Requires-Dist: xgboost>=3.2.0; extra == "xgboost"
Provides-Extra: bvar
Requires-Dist: bvar>=0.3.1; extra == "bvar"
Provides-Extra: nowcast-midas
Requires-Dist: nowcast-midas>=0.0.1; extra == "nowcast-midas"
Dynamic: license-file

# Real-time Forecast Package

A Python package for real-time orchestration of forecasting models.

The main object, **RealTimeModel**, combines a **ForecastData** object (from the
`forecast_evaluation` package) with one or more **ForecastModel** objects.
`ForecastModel` is an abstract base class with
`_fit()`, `_forecast()` and an optional `_forecast_decomp()` method. All
built-in models inherit from it, and you can subclass it to wrap any Python (or
R, MATLAB, or Julia) forecasting model.

## Installation

```bash
pip install forecast_realtime[models]
```

## Quick demo

```python
import forecast_evaluation as fe
import forecast_realtime as rt

forecast_data = fe.ForecastData(load_fer=True)

ridge = rt.models.ForecastRidge(label="Ridge", cv=5, scale=True)
lasso = rt.models.ForecastLasso(label="LASSO", cv=5, scale=True)

rt_model = rt.RealTimeModel(
    data=forecast_data,
    models=[ridge, lasso],
)

rt_model.forecast(
    y_variables=["cpisa"],
    X_variables=["gdpkp"],
    data_transformation={"cpisa": "pop", "gdpkp": "pop"},
    steps=12,
    y_lags=4,
    X_imputation="last",
)

# Optional interactive dashboard:
# rt_model.data.run_dashboard()
```

### Marimo notebook

Install the notebook and model dependencies from the repository root:

```bash
pip install -e ".[models,notebooks]"
```

Open the demo as an editable notebook with visible code cells and outputs:

```bash
marimo edit notebooks/demo_models.py
```

## Add your own model

Subclass `ForecastModel` and implement `_fit()` and `_forecast()` (plus
`_forecast_decomp()` if you want news decompositions). `y` and `X` arrive as
pandas DataFrames, and the base class handles validation, lags, dummies and
forecast dates.

```python
import numpy as np
import pandas as pd

from forecast_realtime import ForecastModel


class MyOLS(ForecastModel):
    """Small OLS model showing the custom-model authoring pattern."""

    def _fit(self, y, X=None, **kwargs):
        # y and X are passed as pandas DataFrames
        if X is None:
            raise ValueError("MyOLS requires X")
        X = X.to_numpy(dtype=float)
        y = y.to_numpy(dtype=float)

        # OLS estimate: beta = (X'X)^-1 X'y
        self.beta = np.linalg.inv(X.T @ X) @ X.T @ y

        return self

    def _forecast(self, steps, X=None, y=None, **kwargs):
        if X is None:
            raise ValueError("MyOLS requires future X")
        # ForecastModel passes the historical and future design rows.
        future_X = X.loc[X.index > self.last_y_fit_date].iloc[:steps]
        return future_X.to_numpy(dtype=float) @ self.beta
```

Pass it straight to `RealTimeModel`:

```python
rt_model = rt.RealTimeModel(data=forecast_data, models=[MyOLS()])
```

## Documentation

- [docs/index.md](docs/index.md) — how `ForecastModel` and `RealTimeModel` work.
- [docs/models.md](docs/models.md) — built-in models and R/MATLAB/Julia wrappers.
- [docs/usage.md](docs/usage.md) — lags, dummies, imputation, transformations,
  news decomposition and parallel execution.
- [adding_a_model.md](docs/adding_a_model.md) — the full `ForecastModel` interface.
- [forecasting_strategy.md](docs/forecasting_strategy.md) — forecasting methodology.
- [CONTRIBUTING.md](CONTRIBUTING.md) — development setup and workflow.

## Data Classification
Bank of England Data Classification: OFFICIAL BLUE
