python-entsoe
Python client for the ENTSO-E Transparency Platform API.
Typed, namespace-organized access to European electricity market data — load, prices, generation, transmission, and balancing.
pip install python-entsoe
Quick Start
from entsoe import Client
client = Client() # reads ENTSOE_API_KEY from environment
df = client.load.actual("2024-06-01", "2024-06-08", country="FR")
Strings are interpreted as timestamps in Europe/Brussels (CET — the ENTSO-E standard). You can override this per-client or pass pd.Timestamp objects directly:
client = Client(tz="UTC") # override default timezone
# pd.Timestamp still works — its timezone takes priority
import pandas as pd
start = pd.Timestamp("2024-06-01", tz="Europe/Paris")
df = client.load.actual(start, "2024-06-08", country="FR")
Every method returns a pandas.DataFrame with a timezone-aware timestamp column and a value column.
Authentication
Get a free API key at https://transparency.entsoe.eu/ (register, then request a token via email).
Set it as an environment variable:
export ENTSOE_API_KEY=your-token-here
Or pass it directly:
client = Client(api_key="your-token-here")
API Reference
client.load
| Method | Description | Parameters |
|---|---|---|
actual(start, end, country) |
Actual total system load | country: ISO code (e.g., "FR") |
forecast(start, end, country) |
Day-ahead load forecast | country: ISO code |
df = client.load.actual(start, end, country="FR")
df = client.load.forecast(start, end, country="FR")
client.prices
| Method | Description | Parameters |
|---|---|---|
day_ahead(start, end, country, sequence=1) |
Day-ahead market prices (EUR/MWh) | country: ISO code; sequence: 1 SDAC, 2 EXAA |
df = client.prices.day_ahead(start, end, country="FR")
# Returns: timestamp, value, currency, price_unit
# DE_LU and AT also publish the separate EXAA auction (10:15 CET)
exaa = client.prices.day_ahead(start, end, country="DE_LU", sequence=2)
client.generation
| Method | Description | Parameters |
|---|---|---|
actual(start, end, country, psr_type=None) |
Actual generation per type | psr_type: filter by fuel (optional) |
forecast(start, end, country, psr_type=None) |
Wind & solar forecast | psr_type: filter by fuel (optional) |
installed_capacity(start, end, country, psr_type=None) |
Installed capacity per type | psr_type: filter by fuel (optional) |
per_plant(start, end, country, psr_type=None) |
Generation per production unit | psr_type: filter by fuel (optional) |
# All generation types
df = client.generation.actual(start, end, country="FR")
# Solar only
df = client.generation.actual(start, end, country="FR", psr_type="B16")
# Installed capacity
df = client.generation.installed_capacity(start, end, country="FR")
client.transmission
| Method | Description | Parameters |
|---|---|---|
crossborder_flows(start, end, country_from, country_to) |
Physical cross-border flows | Two country codes |
scheduled_exchanges(start, end, country_from, country_to) |
Scheduled commercial exchanges | Two country codes |
net_transfer_capacity(start, end, country_from, country_to) |
Day-ahead NTC | Two country codes |
df = client.transmission.crossborder_flows(
start, end, country_from="FR", country_to="ES"
)
client.balancing
| Method | Description | Parameters |
|---|---|---|
imbalance_prices(start, end, country) |
System imbalance prices | country: ISO code |
imbalance_volumes(start, end, country) |
System imbalance volumes | country: ISO code |
df = client.balancing.imbalance_prices(start, end, country="FR")
Country Codes
Use standard ISO codes. Some bidding zones have specific codes:
| Code | Area |
|---|---|
FR |
France |
DE_LU |
Germany/Luxembourg (bidding zone) |
ES |
Spain |
NL |
Netherlands |
BE |
Belgium |
IT |
Italy |
IT_NORTH |
Italy North |
NO_1 .. NO_5 |
Norway zones |
SE_1 .. SE_4 |
Sweden zones |
DK_1, DK_2 |
Denmark zones |
Note: For day-ahead prices and balancing data, use
DE_LUinstead ofDE. See data availability notes for details.
Full list of 60+ supported areas in _mappings.py.
PSR Types (Fuel Types)
Use PSR codes to filter generation by fuel type:
| Code | Fuel Type |
|---|---|
B01 |
Biomass |
B04 |
Fossil Gas |
B05 |
Fossil Hard coal |
B06 |
Fossil Oil |
B10 |
Hydro Pumped Storage |
B11 |
Hydro Run-of-river |
B12 |
Hydro Water Reservoir |
B14 |
Nuclear |
B16 |
Solar |
B18 |
Wind Offshore |
B19 |
Wind Onshore |
Full list in _mappings.py. Human-readable names available via:
from entsoe._mappings import PSR_TYPES
print(PSR_TYPES["B16"]) # "Solar"
Timestamps
All start and end parameters accept date strings or tz-aware pd.Timestamp objects:
# Simple — just strings (uses client's default tz: Europe/Brussels)
df = client.load.actual("2024-01-01", "2024-01-07", country="FR")
# pd.Timestamp with explicit timezone — takes priority over default
df = client.load.actual(
pd.Timestamp("2024-01-01", tz="Europe/Paris"),
pd.Timestamp("2024-01-07", tz="Europe/Paris"),
country="FR",
)
# Mixing is fine
df = client.load.actual("2024-01-01", pd.Timestamp("2024-01-07", tz="UTC"), country="FR")
# Naive pd.Timestamp (no tz) — still raises InvalidParameterError
start = pd.Timestamp("2024-01-01") # ← no tz, will error
Timezones
The client tz setting interprets input date strings (default Europe/Brussels); it does not control returned timestamps. The separate output_tz setting controls results: "UTC" (default, unchanged behavior), "local" (the requested area's timezone), or a fixed IANA timezone such as "Europe/Madrid". Every namespace method also accepts output_tz= for one call. The CLI accepts --tz on data commands, or entsoe config set output-tz local as a persistent default; --tz takes precedence.
For a multi-area request, "local" requires matching clock offsets throughout the returned period (for example, FR and ES); otherwise choose "UTC" or a fixed IANA zone. Cross-border results use the first importing (in_domain) zone. During the October DST fall-back, local wall-clock times repeat; each row retains its offset, but timestamps cease to be unique if the timezone is stripped.
Features
- Autocomplete-friendly — type
client.and see all domains, then drill into methods - Automatic year-splitting — requests spanning more than 1 year are split transparently
- ZIP handling — endpoints returning compressed responses are decompressed automatically
- Retry with backoff — rate-limited requests (HTTP 429) are retried with exponential backoff
- Clear errors —
NoDataError,InvalidParameterError,RateLimitErrorwith descriptive messages
Error Handling
from entsoe import Client, NoDataError, InvalidParameterError
client = Client()
try:
df = client.prices.day_ahead(start, end, country="FR")
except NoDataError:
print("No data available for this period")
except InvalidParameterError as e:
print(f"Bad parameters: {e}")
Examples
See the examples/ directory for Jupyter notebooks with plotly visualizations:
load.ipynb— actual load, forecast comparison, multi-country profilesprices.ipynb— day-ahead prices, distributions, hourly heatmapgeneration.ipynb— generation mix, solar vs wind, installed capacitytransmission.ipynb— cross-border flows, bidirectional charts, NTCbalancing.ipynb— imbalance prices, multi-country, distribution
Development
git clone git@gitlab.com:datons.com/libraries/python-entsoe.git
cd python-entsoe
uv sync
# Run tests (requires ENTSOE_API_KEY in .env)
uv run pytest tests/ -v
# Regenerate example notebooks
uv run python scripts/generate_notebooks.py
License
MIT
Metadata
Release files for python-entsoe 0.7.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 | Provenance | Actions |
|---|---|---|---|---|
| python_entsoe-0.7.0.tar.gz | 294.8 kB | With provenance | Details for python_entsoe-0.7.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| python_entsoe-0.7.0-py3-none-any.whl | Python 3 | none | any | Details for python_entsoe-0.7.0-py3-none-any.whl |
Total release size: 350.5 kB
Release files / python_entsoe-0.7.0.tar.gz
| Download URL | python_entsoe-0.7.0.tar.gz |
|---|---|
| Size | 294.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
be55355baf6cc19e55d8e2ccda201a164a6677f08383d682eed9f87b8f139559
|
|
BLAKE2b-256 checksum How to use checksums |
39ed72fc56269735eb636b75a092163b2c8ea4cfa603217e60f9e0f90c037b67
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
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 Nov 2, 2026.
Transparency logRelease files / python_entsoe-0.7.0-py3-none-any.whl
| Download URL | python_entsoe-0.7.0-py3-none-any.whl |
|---|---|
| Size | 55.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
05625caf967a695df714863f2f8d499105b5d5c1623015a043eb58433b6dcb2a
|
|
BLAKE2b-256 checksum How to use checksums |
e1f2e76d725745537c1b9bf940ef64f2e8f5ba3c9db6f341b8ae765fc41e666d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
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 Nov 2, 2026.
Transparency logSecurity for python-entsoe 0.7.0
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.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for python_entsoe-0.7.0.tar.gz
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 Nov 2, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.