Skip to content

Forecast-Only Mode

Forecast-Only Mode

forecast_only=True runs models in operational mode: trains on all available history and predicts the next horizon days from today. No evaluators run, no exporters fire, and report.predictions() returns a clean DataFrame with no “actual” column.


Minimum Example

import os
os.environ["THREADS_PER_PROCESS"] = "8"
os.environ["MAX_PROCESSES"] = "2"
from epftoolbox2.pipelines import DataPipeline, ModelPipeline
from epftoolbox2.data.sources import EntsoeSource, OpenMeteoSource, CalendarSource
from epftoolbox2.data.transformers import TimezoneTransformer, ResampleTransformer, LagTransformer
from epftoolbox2.models import OLSModel
ENTSOE_API_KEY = os.environ["ENTSOE_API_KEY"]
if __name__ == "__main__":
df = (
DataPipeline()
.add_source(EntsoeSource(country_code="PL", api_key=ENTSOE_API_KEY, type=["load", "price"]))
.add_source(OpenMeteoSource(latitude=52.2297, longitude=21.0122, horizon=7, prefix="warsaw"))
.add_source(CalendarSource(country="PL", holidays="binary", weekday="onehot", daylight=True))
.add_transformer(TimezoneTransformer(target_tz="Europe/Warsaw"))
.add_transformer(ResampleTransformer(freq="1h"))
.add_transformer(LagTransformer(columns=["price"], lags=[1, 2, 7], freq="day"))
.run(start="now_d-730", end="today_d+7", cache=True)
)
report = (
ModelPipeline()
.add_model(OLSModel(predictors=["price_d-1", "price_d-2", "price_d-7","warsaw_temperature_2m_d+{horizon}"], training_window=365))
.run(data=df, target="price", horizon=7, forecast_only=True)
)
forecast = report.predictions()
print(forecast)

Output — 168 rows per model (24 hours × 7 horizons):

run_date (today)target_datehourhorizonpredictionmodel
2026-04-032026-04-0401312.4OLS
2026-04-032026-04-0411287.1OLS
2026-04-032026-04-10237341.8OLS

Date Keywords

Both pipelines accept runtime date keywords so the script runs correctly every day without editing dates:

KeywordResolves to
"today" / "now"Today’s local date
"today_d+7" / "now_d+7"Today + 7 days
"now_d-735"Today − 735 days
"2024-01-01"Passed through unchanged

The offset N in _d±N accepts any integer, so it can match any model’s training_window.


Horizon Mechanics

With test_start = test_end = "today" and horizon=7, the model runs once from today and produces predictions for:

  • today + 1 day (horizon 1) — all 24 hours
  • today + 2 days (horizon 2) — all 24 hours
  • today + 7 days (horizon 7) — all 24 hours

Total: 24 × 7 = 168 prediction rows per model.


YAML Workflow (Daily Automation)

Save once and schedule via cron — no date changes needed:

data_pipeline:
start: now_d-730 # adjust to cover largest training_window + horizon
end: today_d+7 # include forecast window for weather/calendar features
cache: true
model_pipeline:
target: price
horizon: 7
forecast_only: true # test_start/test_end default to today
from epftoolbox2.pipelines import Workflow
report = Workflow.load("forecast_workflow.yaml").run()
forecast = report.predictions()

See Also