suiren-1 / GUIDE.md
kitfunso's picture
docs: GUIDE says the script serves every id except gb
b49ef79 verified
|
Raw History Blame Contribute Delete
16.1 kB

Using suiren 1

suiren 1 forecasts each country's total hourly electricity demand for the next day or so, with a 5% to 95% band. It covers 33 European countries and runs on an ordinary computer. This guide shows how to run it, what it needs, how accurate it was, and how an energy supplier or a trader would use it. The model card (README.md) has the full results and the method.

Every number here is from a backtest. The weights and code are for non-commercial use (CC BY-NC 4.0); see Licence.

Quick start

hf download kitfunso/suiren-1 --local-dir suiren-1
cd suiren-1
pip install -r requirements.txt
python -m eval.forecast --zone de > de.csv

de.csv holds one row per hour, in UTC, from the first hour with no published demand yet through the end of tomorrow:

hour_utc,p05_mw,p50_mw,p95_mw

p50_mw is the median forecast in MW. p05_mw and p95_mw are the 5% to 95% band.

Options:

  • --seeds 0,1,2 averages the three weight files. The card scored each file on its own, so averaging is cheap and usually helps, but it was not scored.
  • --hours 38 forecasts a set number of hours instead of running to the end of tomorrow.
  • --device cpu stays off the GPU. One 24-hour forecast took about two minutes on a desktop CPU; a GPU is faster.

The script needs internet access. Progress and the count of missing history hours go to stderr.

Use it from an agent

A daily job publishes a forecast for 32 countries at 09:45 London time. An agent can read it three ways.

  • Raw JSON. https://huggingface.co/datasets/kitfunso/suiren-1-forecasts/resolve/main/latest.json needs no sign-in and never sleeps. Start here.

  • MCP server. Run claude mcp add --transport http suiren https://suiren-anatomy.pages.dev/mcp. The agent gets two tools, get_forecast(zone) and list_zones(). A zone with no forecast returns an error with the reason. Claude Code's .mcp.json takes this entry; other clients use their own key for the same URL.

    {"mcpServers": {"suiren": {"type": "http", "url": "https://suiren-anatomy.pages.dev/mcp"}}}
    
  • Command line. python -m eval.forecast --zone de --json prints one forecast record instead of a CSV. This one is shortened to two rows, and its numbers are made up to show the shape:

{"model": "suiren-1", "zone": "de", "issued_at": "2026-10-26T09:45:12Z", "first_hour_utc": "2026-10-26T08:00Z",
 "unit": "MW", "seeds": [0], "missing_history_hours": 0,
 "rows": [{"hour_utc": "2026-10-26T08:00Z", "p05_mw": 58210, "p50_mw": 60140, "p95_mw": 62390},
          {"hour_utc": "2026-10-26T09:00Z", "p05_mw": 59480, "p50_mw": 61530, "p95_mw": 63810}]}

The record holds one row per hour, as in the CSV. missing_history_hours counts the hours of demand the script could not fetch. The raw JSON file keeps the last good record for each country under zones. The MCP tool adds age_hours and stale (true after 26 hours) to the record it returns, and failed_this_run (the error and its time) when the last run failed for that country and the record is an older one.

What it forecasts

  • Whole countries, hourly. The ids are at ba be bg ch cz de dk ee es fi fr gb ge gr hr hu ie it lt lu lv md nl no pl pt ro rs se si sk xk. The script serves all of them except gb (see below).
  • de is Germany alone. The German price zone, DE-LU, also includes Luxembourg (lu), so add the two.
  • dk, no, se and it are whole-country totals. Price areas inside them (DK1, NO2, SE3, Italy's zones) are not forecast one by one.
  • The model also knows 25 upper-case ids such as DE-LU and DK1. Those were price series, and suiren 1 never trained on price, so do not use them.
  • Demand only. No price, wind or solar forecast.
  • Hourly only. The European day-ahead auction has traded 15-minute products since 1 October 2025, so a desk needs its own way to split each hour into quarters.

What the script fetches

eval/forecast.py builds the same inputs the model trained on.

  1. Demand. The last 2,048 hours (about 12 weeks) of the country's demand from the Energy-Charts public_power endpoint, series Load. Quarter-hours are averaged to hours, and an hour missing any quarter is left as a gap, as in training. This series matches ENTSO-E's published actual total load (article 6.1.A).
  2. Weather. Temperature at 2 m, wind speed at 10 m, shortwave radiation and cloud cover from the Open-Meteo historical forecast API, at the point for that country in weather_points.json. The script reads the _previous_day1 columns: the forecast issued the day before each hour. For tomorrow's hours that is today's forecast.
  3. Holidays. National public holidays from Nager.Date, only days typed Public and flagged global. Nager.Date does not serve Kosovo, so xk has no holidays, as in training.
  4. Calendar. Hour, weekday and month, all in UTC.

gb is not in the script. Its training target was Elexon's demand outturn, which Energy-Charts does not serve. To forecast gb, fetch Elexon's demand yourself, average it to hours, and call the model directly as below.

Calling the model directly

Use this when you have your own data feed. The model card's "Making a forecast" section has a full example.

from eval.suiren import Suiren

model = Suiren.from_checkpoint("weights/v31_final_stepC_seed0.pt")
bands = model.predict(history, horizon=24, levels=(0.05, 0.5, 0.95),
                      covariates=covariates, zone="de")
  • history: 2,048 hourly loads in MW, oldest first, NaN for a missing hour.
  • covariates: one row per hour for the history and the hours ahead (2,048 + horizon rows), eight columns: hour, weekday (0 is Monday), month, holiday flag, then the four weather columns. NaN for anything you do not have.
  • Each covariate column is standardised over the window, so units do not matter. Keep one source and one unit per column across the whole window.
  • Use the v31_final_* files for new forecasts. They trained on every hour before 2026-09-01. The v31_backtest_* files trained on hours before 2025-09-01 and are the ones the card scores.

Timing for a day-ahead bid

The European day-ahead auction closes at 12:00 CET on the day before delivery and covers 00:00 to 24:00 of the delivery day. A desk bidding into it runs its forecast on the morning before, about 38 hours before the last hour it bids for.

  • The card's headline numbers start at midnight UTC on the delivery day and run 24 hours. That is after the auction has closed, so they describe an intraday forecast.
  • The comparison with the grid operators started each forecast when the operator's own forecast appeared, a median of 12 hours before the delivery day (Spain 2 hours, Italy 19), and ran to the end of that day. That is about 36 hours ahead, close to what a bidder needs.
  • Nobody has scored suiren at exactly the bidder's timing.

Example: on Wednesday at 10:00 in Berlin, a run for Thursday's auction starts at 08:00 UTC and ends at 21:00 UTC on Thursday, the last hour of Thursday in Berlin. That is 38 hours: python -m eval.forecast --zone de --hours 38, then keep the last 24 rows.

How accurate it was

MAPE is the average error as a percent of actual demand. An error of 3% on a 50 GW hour is 1.5 GW.

Test suiren 1 Compared with
33 countries, midnight UTC start, 24 hours, Sep 2025 to Jun 2026 2.98% Chronos-2 given the same weather and calendar 3.11%; Chronos-2 on demand history alone 3.62%; repeating last week 7.21%
26 countries, operator timing, mid-Nov 2025 to Jun 2026 3.02% The grid operators' own day-ahead forecasts 3.76%; more accurate in 15 of 26 countries
23 countries, operator forecast corrected for its own repeat errors, with suiren added 5.7% lower error (median) The corrected operator forecast alone; lower in 20 of 23 countries

The 5% to 95% band held 88% of actual hours where 90% was the aim, so it runs a little narrow.

Country by country

The two operator columns cover different days and a longer horizon than the first two, so compare down a column. Blank cells are countries left out of the operator tests. gb has no operator forecast in the ENTSO-E data used. In ba, nl, md, lt, ee and ie, the operator's forecast and the published actual measure slightly different things at midday. be, dk and gr had under 30 usable days for the correction test.

Country suiren, midnight start (MAPE %) Chronos-2 with weather (MAPE %) suiren at operator timing (MAPE %) Operator (MAPE %) Error cut from adding suiren to the corrected operator forecast Median hours before the day
at 2.36 2.72 2.78 5.25 +39.3% 13
ba 9.08 9.49
be 2.14 2.45 1.77 4.63 18
bg 2.91 2.78 3.78 4.61 +11.3% 16
ch 4.07 4.21 4.80 6.55 +1.8% 16
cz 1.43 1.65 2.27 1.28 +0.6% 15
de 2.12 2.36 2.78 4.23 +20.4% 15
dk 2.99 2.89 3.56 10.69 5
ee 5.66 5.67
es 1.89 2.26 2.22 1.61 +1.0% 2
fi 2.80 2.61 3.20 3.04 -0.4% 3
fr 1.73 1.96 2.69 1.85 +3.4% 10
gb 3.98 3.93
ge 2.51 2.40 3.41 3.31 +5.6% 13
gr 2.35 2.41 2.14 5.02 9
hr 2.69 2.88 3.07 2.74 +14.2% 9
hu 2.91 2.99 3.46 4.45 +5.7% 12
ie 2.01 2.08
it 1.96 2.59 2.90 2.34 +7.0% 19
lt 5.29 5.33
lu 2.24 2.69 2.99 3.26 +7.0% 10
lv 1.94 2.13 2.59 3.79 +24.1% 11
md 7.17 6.68
nl 1.92 2.03
no 1.50 1.36 2.25 2.29 +4.5% 16
pl 1.93 2.18 2.56 2.28 +9.4% 16
pt 2.30 2.63 2.89 1.95 +0.2% 9
ro 2.88 3.21 3.43 2.27 -1.2% 12
rs 2.05 2.34 2.57 3.16 +19.9% 17
se 2.91 3.04 4.15 3.36 -1.6% 16
si 3.30 3.23 3.69 4.29 +17.4% 11.5
sk 1.84 2.18 2.17 2.29 +19.2% 11
xk 3.38 3.34 4.39 7.24 +4.8% 12

Sources: eval/results/backtest_2025_v31.json, backtest_2025_chronos2x.json, backtest_2025_tso_v31_backtest_stepC.json and lane_o_v31.json.

For an energy supplier

A retail supplier estimates its customers' demand for tomorrow and buys it in the day-ahead auction. It trades the difference in the intraday market and pays the imbalance price on whatever is left. suiren forecasts the whole country, not one supplier's customers, so it goes in as an input.

  1. National demand as a driver. Run suiren over the past year, one forecast per day at the time you would have run it. At about two minutes a forecast, that is at least 12 hours of CPU per country. Fit your customers' demand on suiren's forecast plus your own terms (customer count, tariff mix, large sites). Each morning, put the new forecast into the fit. Fit on suiren's past forecasts rather than on actual national demand, so the fit learns how suiren's errors show up in your book.
  2. Sizing what to leave for intraday. The band shows how uncertain each hour is. If your customers use about 2% of national demand and suiren's band for 18:00 runs from 48 to 52 GW, your own band is roughly 0.96 to 1.04 GW. Keep the wide hours flexible. Widen the band a touch, since it runs narrow.
  3. A second opinion before the gate closes. Put suiren next to the operator's forecast and your current one. When they disagree by more than usual, look for the reason before noon: a holiday, a change in the weather run, a data gap.
  4. An experiment. Feed your customers' own demand series to model.predict with the country's id. The model scales each window by its own average, so it sees the shape of a series and not its size, and it trained on generation series as well as demand. Nobody has scored this, so backtest it against your current forecast first.

It does not do hedging months or years ahead, customer-level forecasts or settlement periods shorter than an hour.

For an energy trader

Price follows residual load: demand minus wind and solar. suiren gives the demand half.

  1. A price view. Subtract your own wind and solar forecasts from suiren's demand, and feed the residual load into your price model. suiren 1 trained on generation series too, but only demand was scored.
  2. Trading the disagreement. Each operator's day-ahead demand forecast is public on ENTSO-E (article 6.1.B), so the market sees it. The backtest built a three-step forecast a desk can rebuild: store each operator forecast with its publish time; correct the operator's own repeat errors with a model fitted only on past days; add a fitted weight times the gap between suiren and the operator. The last step cut the error of the first two by a median 5.7% across 23 countries, by 39% in Austria and about 20% in Germany. A large gap in a country where suiren adds most is where your demand view differs from the public one.
  3. When to lean which way. In Denmark, Belgium, Greece, Austria, Kosovo and Germany, suiren on its own was far more accurate than the operator. In Czechia, Spain, France, Portugal and Romania the operator was better, and adding suiren helped little.
  4. Intraday. Re-run as fresh demand comes in and look at the hours where the median moves. How much a re-run gains was not measured.
  5. Scenarios. The 5th and 95th percentiles give a low and a high case per hour. They are worked out hour by hour, so adding up each hour's 95th percentile does not give the 95th percentile of the day's total. predict draws 100 sampled futures inside; returning them is a small code change.

Nothing here measured profit. A lower demand error turns into money only if the market price has not already taken in the same information. The comparison covered the operators' public forecasts only, not commercial forecast vendors. Keep a paper ledger for a few months before trading on it: log each day's view and the trade it implies before the gate closes, then score the error and the paper profit and loss.

Limits

  1. Backtest only. The 2025-26 year had been read before the recipe was chosen. A clean forward test runs from 15 September to 1 December 2026.
  2. Holidays are the weak spot. On public holidays the earlier model's error was 1.7 times its normal-day error, and the operator was better in most countries. suiren 1 trained with a fixed holiday table, but its holiday error was not measured on its own. On a holiday, trust the operator.
  3. No autumn in the operator tests. They cover mid-November to June.
  4. One weather point per country. Operators use weather across their whole area.
  5. Late data. The backtests read demand as stored later, so every hour before the start was present. Live, the last hours may be missing; the script starts at the first unpublished hour. It stops with a message when a country's load is more than 48 hours late.
  6. In ba, md and nl the published actual is net of something at midday from some date. suiren forecasts the published series as it is.

Licence

  • Weights and code: CC BY-NC 4.0 (LICENSE). Research and personal use are fine. Commercial use needs a separate licence from the author; ask on this repository's Community tab.
  • Weather: the script calls Open-Meteo's free API, which is for non-commercial use. A commercial user needs a paid Open-Meteo plan or another feed with the same four variables at the same points.
  • Demand data: Energy-Charts data is CC BY 4.0, with attribution to Fraunhofer ISE. Elexon's BMRS data comes under its own licence, also with attribution.

More

  • anatomy.html is an interactive 3D tour of the model's parts, live at suiren-anatomy.pages.dev.
  • README.md is the model card: method, every result and every limit.