Case study
German Energy Shift
German day-ahead prices plus heat-pump stress into a deterministic shift recommender, with a published 2022 ridge MAE.
At a glance
Plain summary for recruiters and visitors. Technical detail follows below.
- What it is
- I built a German energy hybrid that scores day-ahead power prices with heat-pump stress. It recommends run and avoid hours for flexible loads on curated weeks.
- What I owned
- Solo end to end. SMARD and When2Heat ingest, ridge price holdout, stress index, deterministic shift scorer, and the Cloudflare demo Worker.
- Why it matters
- Recruiters can see price spikes, stress bands, and shift windows in one play. Privacy stays public data only. No live household meters.
- Try it on this page vs full project
- The page demo serves frozen SMARD-style scenarios from a Worker. Training notebooks, aligned CSV rebuild, and full eval stack stay on request.

Problem
Flexible loads need hours that are cheap on the day-ahead market and gentle on heat-pump stress.
Method
Aligned SMARD filter 4169 prices with When2Heat DE demand and COP. Trained offline price models, published ridge MAE on 2022, and scored weeks with a weighted price-stress blend.
Result
Ridge MAE 16.91 EUR/MWh on the 2022 holdout beats naive last-hour at 21.87. The live demo serves frozen winter spike, wind surplus, and normal week scenarios only.
Architecture
How the system is shaped. Full implementation stays private.
Step 1
Ingest
SMARD day-ahead prices (filter 4169) and When2Heat DE heat demand plus COP, both CC BY 4.0 public series.
Step 2
Price model
Offline train on 2020 to 2021. Publish ridge MAE on the hard 2022 holdout year. Freeze metrics.json.
Step 3
Heat stress
Normalized DE space-heat demand blended with inverted ASHP COP into a unitless stress index.
Step 4
Shift score
score = w1 * norm_price + w2 * norm_stress. Top-K run hours and avoid hours. Worker serves frozen scenarios only.
Holdout day-ahead MAE (2022)
SMARD DE-LU filter 4169, hourly 2020 to 2021 train and 2022 holdout. The table publishes MAE in EUR/MWh as the primary score. Floored MAPE was also computed with |price| at least 5 EUR/MWh. It stays secondary because near-zero and negative prices explode raw MAPE.
| Model | MAE | Note |
|---|---|---|
| Ridge | 16.91 EUR/MWh | Published model |
| Naive last hour | 21.87 EUR/MWh | |
| Hist GBM | 24.18 EUR/MWh | |
| Naive same hour yesterday | 57.99 EUR/MWh |
Algorithm
Hybrid price-stress shift ranking
Normalize day-ahead price and heat-pump stress, blend with recruiter-tunable weights, then pick the cheapest low-stress windows.
price_n = minmax(prices_eur_mwh)
stress_n = minmax(stress_index)
score = w_price * price_n + w_stress * stress_n
run_hours = argsort(score)[:top_k]
avoid_hours = argsort(score, descending)[:top_k]Key logic
Compact illustrative snippet (Deterministic shift blend (illustrative)). Not the full codebase.
def build_shift_recommendation(prices, stress, price_weight=0.6, stress_weight=0.4, top_k=24):
w1, w2 = clamp01(price_weight), clamp01(stress_weight)
score = w1 * minmax(prices) + w2 * minmax(stress)
order = np.argsort(score)
return {"run_hours": order[:top_k].tolist(), "avoid_hours": order[::-1][:top_k].tolist()}Stack
Try a live shift week
Free Cloudflare demo on curated SMARD-style weeks plus When2Heat stress. Not live trading data. Published holdout MAE stays on the metrics table above. SMARD day-ahead prices and When2Heat DE heat series are CC BY 4.0 public data. Toy run versus week-mean percent in the KPIs is illustrative only. It is not a retail electricity bill claim.
Scenario
Source code
Full source is available to hiring managers on request. The public page shows architecture, algorithms, and compact proofs only.