The renewable revenue trap: why average power prices lie to you
A surprising number of renewable developers and infrastructure funds still model the future revenue of a solar or wind asset on "baseload" — the simple average day-ahead power price. In modern European power markets that is a fatal mathematical error.
If the average day-ahead price in Germany is €80/MWh, a new solar farm will not earn €80/MWh. It will earn meaningfully less. That gap is profile risk, or more bluntly, renewable cannibalisation.
The physics of cannibalisation
Renewable output is non-dispatchable and highly correlated. When the sun shines in Spain, it shines on *every* panel in Spain at once. Because solar's marginal cost is zero, that simultaneous flood of supply pushes the day-ahead clearing price down — frequently to zero, sometimes negative. Renewables actively depress the price of the exact product they are selling, at the exact moment they sell it.
So you cannot model an asset on a time-weighted average. You need the capture price — the volume-weighted average price a specific technology actually achieved:
Capture Price = sum(Generation_t x Price_t) / sum(Generation_t)
And the ratio that matters over time is the cannibalisation index — capture price divided by the baseload average — which shows how fast a technology's revenue is degrading as more of it is built.
The data-engineering headache
Computing historical capture prices for every European bidding zone sounds trivial until you pull the data from ENTSO-E:
- You need two large feeds — day-ahead prices (
A44) and actual generation per type (A75) — aligned to the same clock. - Prices are often hourly; generation is frequently 15-minute. Mismatch the grains and every weight is wrong.
- Fuels hide behind PSR B-codes (
B16solar,B19wind onshore). - If a zone's price feed drops for a few hours, a naive
groupby().mean()silently miscomputes the month's volume-weighting.
Skip the ETL
We already did the maths. Across European bidding zones we aligned every hour of generation and price to UTC, mapped the fuel codes, and pre-computed the monthly volume-weighted capture prices — as clean Parquet, from €9:
- European Solar Capture Price and Wind Capture Price — monthly, per zone.
- European Renewable Cannibalisation — the capture-to-baseload index, so you can see revenue erosion year over year.
- European Renewable Forecast Error — the other half of an honest revenue model.
Stop modelling with inflated baseload prices. Buy the capture-price file for the price of a coffee, or browse the whole energy catalog.
Stop building parsers. Start at the analysis.
We've already cleaned, documented and QC'd sources like the one in this post into query-ready Parquet - with a free sample on every dataset. Buy a file from €9, or go All-Access for the lot.