What it does
Describe a battery and a forecasting approach in a short YAML file. OpenEnergy plans each day on the forecast, settles the plan at the prices that actually cleared, and reports what the battery earned, how hard it worked, and how close it came to perfect foresight.
- Battery physics: power and energy ratings, charge/discharge efficiencies, SOC window, cycle and calendar ageing.
- Dispatch: a daily mixed-integer optimisation solved with HiGHS, optionally planning
the following days too (
dispatch.lookahead_days; one day adds 5–15% revenue). - Backtesting without lookahead: forecasts see only data available at the decision time; plans settle at actual prices.
- Revenue stacking: GB Dynamic Containment, Moderation and Regulation co-optimised with
day-ahead trading (
responsein a scenario). Adding Dynamic Containment raised a 2-hour battery's revenue by 58–155% a year in 2022–2025 (examples/gb-2025-stacked.yaml). - Forecasters: perfect foresight, last week's prices, noisy foresight and a gradient-boosting model.
- Renewables: solar and wind plants from capacity-factor profiles, captured price and
capture rate by year (
openenergy capture). - Co-located sites: a plant and a battery behind one grid connection with export and import limits and optional support payments, compared with separate connections.
- System analysis: net load, ramps and renewable surplus as wind and solar scale,
storage sizing for the system (
openenergy storage) and for a site (openenergy sweep). - Emissions: net emissions from GB carbon intensity and an optional carbon price that steers dispatch, planned without lookahead.
- GB system model: CCGT, coal and peaking plant dispatched in merit order (optionally
with unit commitment) from fleet, fuel and carbon data, checked against 2015–2025 prices
and fuel use (
openenergy system validate), with scenarios for renewables, storage, fleet and carbon policy (openenergy system run); storage uses the optional PyPSA backend. - Forward scenarios: NESO's Future Energy Scenarios pathways (2025–2035) applied to a
historic weather year, with GB's ten interconnectors trading at neighbouring markets'
actual prices up to each link's availability fitted from its flows, and unit commitment
(
system.fes,system.interconnectors: links,system.commitment). - Web app: value a battery on any GB year from 2017 or on a FES pathway's modelled
prices in the browser at open-energy-eight.vercel.app
(
openenergy.app, FastAPI on Vercel). - Data: hourly GB day-ahead prices, demand and wind and solar output for 2015–2020
and capacity factors for 2015–2019 from Open Power System Data; GB hourly day-ahead
prices for mid-2016 to October 2026 from Ember; half-hourly GB carbon intensity for
2018 to October 2026 and generation by fuel for 2015–2025 from NESO; GB frequency-response auction
prices from September 2021 and monthly response utilisation from NESO; GB imbalance
prices for 2016 to October 2026 from Elexon; and GB fleet, fuel and carbon prices from DESNZ, HMRC,
the World Bank and the ECB, are bundled. So are NESO's Future Energy Scenarios tables,
its interconnector register, daily interconnector flows from Elexon and hourly
day-ahead prices in the six neighbouring markets from Ember.
openenergy data updatedownloads the latest prices. - Reports:
openenergy reportturns saved runs, system scenarios, backcasts and sweeps into one interactive HTML file of charts and tables (optionalreportextra, plotly).
Quick start
Requires Python 3.14 and uv. The bundled data come with the repository, so clone it:
git clone https://github.com/koulakhilesh/OpenEnergy.git
cd OpenEnergy
uv sync --extra forecast
uv run openenergy compare examples/gb-2019-{naive,ml,perfect}.yaml
The library and command line are also on PyPI (pip install openenergy, with extras
forecast, system, report and app); the package carries no data, and
openenergy data update downloads the latest GB prices.
scenario forecast days revenue per MW-yr capture cycles
gb-2019-perfect perfect_foresight 363 19,075 19,180 100.0% 464
gb-2019-ml gradient_boosting 363 14,086 14,164 73.8% 400
gb-2019-naive naive_last_week 363 13,918 13,995 73.0% 465
A 1 MW / 2 MWh battery trading GB day-ahead prices in 2019 would have earned about £14k
per MW-year planning on last week's prices: 73% of what perfect foresight allows. In the
2022 gas crisis the same battery would have earned about £77k
(examples/gb-2022-naive.yaml, on Ember prices).
Run one scenario and write its results to outputs/<name>/, then chart them:
uv run openenergy run examples/gb-2019-naive.yaml
uv sync --extra report
uv run openenergy report outputs/gb-2019-naive -o outputs/report.html
Rebuild GB prices from the plants behind them and compare with what happened:
uv run openenergy system validate
uv sync --extra system # PyPSA, needed for scenarios with storage
uv run openenergy system run examples/gb-2019-wind3-storage.yaml
uv run openenergy system run examples/gb-2035-holistic.yaml # a FES pathway in 2035
Run the web app locally (or use it at open-energy-eight.vercel.app):
uv run uvicorn openenergy.app:app
See the documentation for the equations, every scenario setting and the Python API.
Development
uv sync --all-extras --group docs
uv run ruff check && uv run ruff format --check && uv run mypy && uv run pytest
uv run mkdocs serve
Roadmap
Released
| Release | Scope |
|---|---|
| v2.0 | Battery arbitrage backtesting: physics, ageing, dispatch, forecasters, CLI |
| v2.1 | PV and wind assets, captured price, co-located storage |
| v2.2 | Net load, surplus, storage sizing, emissions |
| v3.0 | GB system dispatch with conventional generation via PyPSA, checked against 2015–2020 |
| v3.1 | Optional unit commitment (start-up costs, minimum stable output) and a start-cost price, re-checked against 2015–2020 without fitting to prices |
| v3.2 | Data to 2025: GB prices from Ember, NESO generation and carbon intensity, DUKES and fuel prices, UK ETS; openenergy data update; backcast of the gas crisis and coal exit |
| v3.3 | Multi-day planning horizon (dispatch.lookahead_days), and a measured answer on planning under price uncertainty: for day-ahead-only trading a scenario plan equals one forecast, and risk aversion costs revenue |
| v3.4 | Reports: openenergy report turns saved runs, system scenarios, backcasts and sweeps into one interactive HTML file; chart functions reusable from Python |
| v3.5 | Revenue stacking: GB Dynamic Containment, Moderation and Regulation co-optimised with day-ahead trading; a measured answer on balancing (imbalance prices are valuable only with a forecast open data does not give) and on stochastic planning (still no value) |
| v4.0 | Forward scenarios from NESO's Future Energy Scenarios on a historic weather year; GB's interconnectors as price-taking links to six neighbouring markets, checked against actual flows 2019–2025; a web app (FastAPI, Vercel) valuing a battery on history or a FES pathway |
| v4.1 | A usable web app: the answer first in plain words, instant results for common batteries, value by year and by FES pathway at a glance, side-by-side comparison with shareable links, explanations next to each term, CSV and scenario downloads, and a JSON API; CITATION.cff and PyPI release |
| v4.2 | A more credible model: unit commitment with interconnector links; each link's availability fitted from its actual flows, never from prices; a measured answer on the missing daily spread (the everyday intraday shape, not negative prices); forward scenarios and the app re-run. GB zones were dropped: GB keeps one national wholesale price (DESNZ, REMA summer update, July 2025) |
Planned
| Release | Scope |
|---|---|
| v5.0 | A React and TypeScript front end on the v4.1 JSON API, with the same Python back end |
Alongside releases: a Zenodo DOI and versioned docs; refresh and re-check the bundled data every release; keep CI and its actions current; revisit stochastic planning if an open, forecastable market price appears.
Ideas and bug reports are welcome in issues.
Data
Prices, load and renewable generation come from Open Power System Data:
Open Power System Data. 2020. Data Package Time series. Version 2020-10-06. https://doi.org/10.25832/time_series/2020-10-06. (Primary data from various sources, for a complete list see URL).
GB day-ahead prices after September 2020 come from Ember, European Wholesale Electricity Price Data (primary sources ENTSO-E and EMR Settlement), licensed under CC BY 4.0, and are converted from EUR with European Central Bank reference rates (source: ECB).
GB carbon intensity comes from the National Energy System Operator (NESO) Carbon Intensity API, https://carbonintensity.org.uk/, licensed under CC BY 4.0.
GB generation by fuel comes from NESO's historic generation mix, licensed under the NESO Open Data Licence v1.0. Supported by National Energy SO Open Data.
GB frequency-response clearing prices come from NESO's Dynamic Containment, Regulation and Moderation auction results and EAC auction results, and the energy each service moves is derived from NESO's system frequency data with the delivery envelopes in NESO's Response Services Service Terms; all under the NESO Open Data Licence v1.0, accessed 13 October 2026. Supported by National Energy SO Open Data.
GB imbalance (system) prices come from Elexon's BMRS, reused under the BMRS data licence. Contains BMRS data © Elexon Limited copyright and database right 2026.
Forward scenarios use NESO's Future Energy Scenarios 2025 and 2026 Ten Year Outlook (ES1 and ED1 tables) and its Interconnector Register, under the NESO Open Data Licence v1.0, accessed 13 October 2026; supported by National Energy SO Open Data. Interconnector flows come from Elexon's BMRS (FUELHH), under the same BMRS data licence. Day-ahead prices in France, the Netherlands, Belgium, Norway, Denmark and Ireland come from Ember's European Wholesale Electricity Price Data (primary sources ENTSO-E and SEMOpx), CC BY 4.0, converted with ECB rates.
Fleet capacity and efficiency (DUKES 5.8 and 5.10) and fuel prices (Quarterly Energy Prices 3.2.1) come from the Department for Energy Security and Net Zero, the 2021 UK ETS price from the UK ETS Authority's carbon price determination, and carbon price support rates from HM Revenue & Customs; they contain public sector information licensed under the Open Government Licence v3.0. EU ETS (to 2020) and UK ETS (from 2022) prices come from the World Bank Carbon Pricing Dashboard (CC BY 4.0), converted to GBP with a cross rate OpenEnergy derives from euro reference rates (source: European Central Bank). Unit sizes and minimum loads for unit commitment come from the Danish Energy Agency's Technology Data catalogue (CC BY 4.0), and start-up costs from Kumar et al., Power Plant Cycling Costs, NREL/SR-5500-55433, 2012, Table 1-1 (https://www.osti.gov/biblio/1046269), converted with 2011 ECB rates. All accessed 10 October 2026.
The optional storage backend uses PyPSA (Brown, Hörsch and Schlachtberger, PyPSA: Python for Power System Analysis, Journal of Open Research Software 6(1), 2018, https://doi.org/10.5334/jors.188).
See data/time_series, data/prices, data/carbon_intensity, data/system, data/fes, data/scenarios, data/app, data/response and data/balancing for sources, changes and known issues. OpenEnergy is not affiliated with or endorsed by any data provider.
License
The code is MIT licensed; see LICENSE.txt. The written documentation in
docs/ (text, tables and findings) is licensed under
CC BY 4.0. Bundled data is not covered by
either and keeps its own licence:
| Folder | Data | Licence |
|---|---|---|
data/time_series |
Open Power System Data time series (prices, load, renewables, to 2020) | Terms of the original sources; see the OPSD package |
data/prices |
Ember GB and neighbouring-market day-ahead prices; ECB exchange rates | CC BY 4.0; ECB reuse terms |
data/carbon_intensity |
NESO Carbon Intensity API | CC BY 4.0 |
data/system |
NESO historic generation mix and Interconnector Register | NESO Open Data Licence v1.0 |
data/system |
DESNZ (DUKES, Quarterly Energy Prices, UK ETS 2021), HMRC | Open Government Licence v3.0 |
data/system |
World Bank Carbon Pricing Dashboard; Danish Energy Agency technology data | CC BY 4.0 |
data/system |
NREL Power Plant Cycling Costs (values recorded from the report) | US government-sponsored report |
data/system |
Elexon BMRS interconnector flows (daily totals) | BMRS data licence |
data/fes |
NESO Future Energy Scenarios tables (unchanged) | NESO Open Data Licence v1.0 |
data/scenarios |
OpenEnergy model output built from the sources above | Attribution of every source used; see its README |
data/app |
Precomputed web app results built from the sources above | Attribution of every source used; see its README |
data/response |
NESO response auction results and system frequency (derived monthly averages) | NESO Open Data Licence v1.0 |
data/balancing |
Elexon BMRS system prices | BMRS data licence |
Reuse of any of these requires the attribution given in the folder's README.md.
Citing
If you use OpenEnergy, please cite it with the details in CITATION.cff (GitHub's "Cite this repository" button reads it), and credit the data sources each result lists.
Contact
Akhilesh Koul · koulakhilesh@gmail.com · LinkedIn
Metadata
Release files for openenergy 4.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| openenergy-4.2.0.tar.gz | 101.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| openenergy-4.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 231.9 kB
Release files / openenergy-4.2.0.tar.gz
| Download URL | openenergy-4.2.0.tar.gz |
|---|---|
| Size | 101.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
b21cba2e22b6943ca3d70c80ae7fb4b2eef13a37c8403d345bec5cee169d02a9
|
|
BLAKE2b-256 checksum How to use checksums |
ea0b8bd20937bfcc00e6042181860d76c5af1a63a13d7dc95d22e14404b92184
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 14, 2026.
Transparency logRelease files / openenergy-4.2.0-py3-none-any.whl
| Download URL | openenergy-4.2.0-py3-none-any.whl |
|---|---|
| Size | 130.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
4ef7d2067e77f23a4fc24f8b13bdc1c64d364f28f6e7cc2c5d44f0576b50746a
|
|
BLAKE2b-256 checksum How to use checksums |
8365a0983f3d287461bbcbc4d939d51cb790118e70766d6f3d29cafc79d5ccc5
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 14, 2026.
Transparency log