Day-ahead forecasting: accuracy and limits

Five models forecast the hourly DE-LU day-ahead price using only what a bidder knows when the order book closes at 12:00 on the day before delivery. Per-hour Ridge regression is the most accurate overall and holds up best in the tail hours that drive storage value. The more complex pooled LightGBM model is close in ordinary hours but breaks down in negative-price and scarcity hours: model complexity did not buy tail performance.

Retrospective benchmark, to , on history inspected during development. It is not a record of forecasts issued before delivery; the prospective pilot is reported at the end of this page.

Results

Ridge's mean absolute error is EUR/MWh, against for LightGBM. Skill is the share of the best naive forecast's error that a model removes; bias is the realised price minus the forecast, so a positive bias means the model forecasts too low. Accuracy is not money: an error cut in flat hours is worth little to a battery. The storage page converts these forecasts into dispatch margin.

Controls against look-ahead. The forecast uses only data public before 12:00 on D-1: lagged prices, the calendar and residual load from two days earlier. Model settings are frozen before the test window, and every refit uses only earlier days. Published numbers come from a committed, hashed release that gpa export --check verifies against the site. Live forecasts that miss the gate are refused, never backdated.

Does it pick the right hours?

A battery needs the order of the hours more than their level. Ridge places the day's cheapest hour within an hour of the realised one on of days and the dearest on , against and for the similar-day forecast. It is weak on negative prices: its point forecast goes below zero for only of the negative hours. Its lower quantile does better as a risk flag, catching of them at precision. Like most regressions it also shrinks extremes: its daily spread is EUR/MWh narrower than the realised one on average.

Where the models fail

Complexity did not buy tail performance. In the scarcest 5% of hours, Ridge still beats the best naive forecast () while LightGBM loses badly (). In negative-price hours, both trail the best naive forecast: Ridge narrowly (), LightGBM by far (). These are the hours where a battery's margin is made or lost.

Across years. Ridge's error ranges from EUR/MWh in to in , the gas crisis, with the same method throughout. LightGBM lost to the best naive in , while Ridge kept a positive margin every year.

The comparison is between two specific designs: a separate linear model for each hour, and one tree model pooled across hours, both with the same limited inputs. It does not show that linear models generally beat tree models. It shows that this pooled tree model did not extrapolate to price levels rarely seen in training.

Breakdown by price regime, market block, year and hour

Negative-price hours and the top 5% of evaluation prices are regimes assigned after the fact; they are never model inputs.

model–bucket comparisons show no improvement over the best naive forecast. The breakdowns overlap, so these are not independent failures.

Would operator forecasts help?

Adding the operators' day-ahead forecasts of load, wind and solar, on the same test window and protocol:

They help, but this source cannot supply them in time. EU rules only require wind and solar forecasts by 18:00 Brussels time on D-1, six hours after the gate, and a probe of Energy-Charts found neither at checks two to nearly five hours after the gate on each of the five delivery days it covered (25 to 29 September 2026). The gain is therefore an upper bound: it credits the model with forecasts this public source only has hours after the auction. A desk closes that gap with commercial forecasts issued before the gate.

Design: target, inputs and test protocol
  • Target: the duration-weighted hourly average of DE-LU day-ahead prices, in EUR/MWh. Since delivery on 1 October 2025 the auction clears quarter-hours, so the hourly figure is an analytical aggregate rather than a traded product.
  • Gate: 12:00 market time on D-1, when the order book closes. Prices for the previous delivery day have already cleared and are available.
  • Inputs: lagged prices, calendar variables and residual load (demand minus wind and solar) from at least two delivery days earlier. Realised delivery-day values never enter a forecast.
  • Protocol: training starts and validation ; the test runs from to . The ridge penalty and tree settings are chosen on the validation window and frozen. Every model refits using only dates before the forecast day. All five models are scored on the same hours out of in the period.
  • Models: Ridge fits one regression per delivery hour; LightGBM fits one model across hours, with the hour as a feature. The naive forecasts repeat the previous day, the previous week or the last similar day: what a desk falls back on without a model.
  • Data handling: only complete hours enter the panel, and missing observations stay missing. The two occurrences of the autumn clock-change hour are averaged. Stored inputs carry the providers' latest revisions, so the exact values visible at each historical gate cannot be verified.
Predictive intervals

Each model's 80% interval uses quantiles of its own previous 56 errors at the same clock hour; current-day errors never enter the calibration.

Coverage falls short of the nominal 80% for every model. Pinball loss and interval width are shown because a very wide interval can cover prices while saying little.

Inspect a week

Twelve evenly spaced weeks from the test period.

Prospective pilot

Since 23 September 2026, a scheduled job issues Ridge and the three naive forecasts before each gate and stores the inputs each forecast used. Runs that arrive after the gate are refused rather than backdated. A second Ridge arm with the operator forecasts, ridge_da, found nothing to read in 11 pre-gate runs across six delivery days and was retired on 28 September, for the reason above. Each delivery day counts once, at the best outcome any attempt reached:

Ledger as of ; the site is rebuilt on each release, not on each run. The pilot's bar is six weeks with at least 95% of delivery days issued on time. It tests whether the process runs reliably; it cannot establish economic value across seasons.

Reproduce
pip install -e ".[dev]"
gpa backtest --scope all
gpa fundamentals-ablation
gpa export --check

The frozen release under data/experiments/ stores the predictions, scores, parameter searches, ridge coefficients and input panel, together with a hash of the forecasting code. The input-panel SHA-256 is ; gpa export --check confirms every published table still matches it.