Skip to main content

Unified interface for European and U.S. energy market data

Project description

Clarigrid

Unified Python SDK for European and U.S. energy market data.

PyPI Python License


What it is

Clarigrid provides a single, stable Python interface to access and normalise European and U.S. energy market data from multiple sources. All data comes back as timezone-aware pandas DataFrames with consistent column names and units.

Built-in free providers (no API key required) include Energy-Charts (Europe), Energinet (DK1/DK2), SMARD (DE), Elia (BE), NESO (GB), Elexon/BMRS (GB), and ENTSOG (EU gas). Fingrid (FI), GIE AGSI/ALSI (European gas), and TenneT (NL) are also built in and use free API keys. For the United States, CAISO OASIS and NYISO provide no-auth market and system data. EIA-930 provides nationwide hourly balancing-authority load, forecasts, fuel generation, and physical interchange with a free EIA key. Global historical meteorology and solar data are available from NASA POWER without an API key. ENTSO-E and other key-protected sources can be configured as described in API key setup below.


Install

pip install clarigrid

For the interactive setup wizard and CLI tools:

pip install clarigrid[auth]

Quick start

import clarigrid as cg

# Free providers — no key required.
cg.connect("smard")   # DE prices, load, generation
cg.connect("elia")    # BE load, generation
cg.connect("neso")    # GB load, embedded generation
cg.connect("elexon")  # GB prices, generation mix
cg.connect("entsog")  # EU gas flows (any TSO zone)
cg.connect("energycharts")  # European prices, power, forecasts and flows
cg.connect("energinet")  # DK1/DK2 prices, power, forecasts, flows and CO2
cg.connect("redata")  # ES load, generation, capacity and cross-border flows
cg.connect("rte")  # FR load, generation, forecasts, exchanges and CO2
cg.connect("fingrid")  # FI power, forecasts, flows, balancing and CO2 (free key)
cg.connect("gie")  # European gas storage and LNG inventory (free key)
cg.connect("eia")  # US balancing-authority load, generation and flows (free key)
cg.connect("caiso")  # CAISO day-ahead hub prices (no key)
cg.connect("nyiso")  # NYISO prices, load, forecasts and fuel mix (no key)
cg.connect("nasapower")  # Global daily/hourly weather and solar data (no key)

# Optional: set output timezone (default is UTC).
cg.set_timezone("Europe/Brussels")

# Fetch data — provider is chosen automatically by zone.
prices = cg.get_prices("DE", "2025-01-01", "2025-01-07")  # → smard
load   = cg.get_load("BE",   "2025-01-01", "2025-01-07")  # → elia
gen    = cg.get_generation("GB", "2025-01-01", "2025-01-07")  # → elexon
gas    = cg.get_gas_flows("BE-TSO-0001", "2025-01-01", "2025-01-07")  # → entsog
us_load = cg.get_load("CAISO", "2025-01-01", "2025-01-07")  # → eia (CISO)
np15 = cg.get_prices("CISO_NP15", "2025-01-01", "2025-01-07")  # → caiso
nyc = cg.get_prices("NYISO_NYC", "2025-01-01", "2025-01-07")  # → nyiso
weather = cg.get_weather(
    "40.7128,-74.0060",
    "2025-01-01",
    "2025-01-07",
    source="nasapower",
)

API key setup

Some providers (ENTSO-E, TenneT) require a personal API key issued by the upstream data source. Clarigrid supports two ways to supply these keys.

Option 1 — ClarigGrid account (recommended)

Store all your provider keys in one place at clarigrid.energy/saved. The SDK then fetches them automatically using a single ClarigGrid API key.

First-time setup (interactive):

import clarigrid as cg
cg.connect("entsoe")
# Opens browser → log in at clarigrid.energy → keys fetched automatically.

Or use the CLI:

clarigrid setup          # guided wizard for all providers
clarigrid connect entsoe # authenticate a single provider

Headless / CI environments: set one environment variable and no browser is ever needed:

export CLARIGRID_API_KEY=your-clarigrid-uuid

The SDK uses CLARIGRID_API_KEY to fetch all your stored provider keys from clarigrid.energy on the first connect() call of each session.

How to get a CLARIGRID_API_KEY:

  1. Log in at clarigrid.energy
  2. Add your provider API keys at clarigrid.energy/saved
  3. Run cg.connect("entsoe") once in an interactive terminal — the browser flow logs you in and stores your CLARIGRID_API_KEY locally.

Option 2 — Manual key entry (no account needed)

If you prefer not to use a clarigrid.energy account, set provider keys directly. Keys are stored in ~/.config/clarigrid/.env (permissions: 600).

Environment variable (recommended for CI):

export ENTSOE_API_KEY=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
export TENNET_API_KEY=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

Config file — add to ~/.config/clarigrid/.env:

ENTSOE_API_KEY="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
TENNET_API_KEY="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"

Zone routing

Each call to cg.connect() registers a provider and its capability-specific zone coverage in an internal router. When you call get_prices("DE"), the router picks the best connected provider for that zone and dataset automatically.

Multiple connect() calls accumulate coverage. If two providers both cover the same zone/dataset pair, the later connect() call wins.

cg.connect("neso")    # covers GB: load, generation
cg.connect("elexon")  # covers GB: prices, generation — overwrites generation slot

# Now: GB prices → elexon, GB load → neso, GB generation → elexon
prices = cg.get_prices("GB", "2025-01-01", "2025-01-02")
load   = cg.get_load("GB",   "2025-01-01", "2025-01-02")

If no connected provider covers the requested zone/dataset, a helpful error is raised:

ZoneNotCoveredError: No connected provider has 'prices' data for zone 'BE'.
  Consider: cg.connect('entsoe')

To bypass routing and force a specific provider:

df = cg.get_load("GB", "2025-01-01", "2025-01-07", source="neso")

Output format

All functions return a pandas.DataFrame with:

Property Value
Index DatetimeIndex named utc_time, tz-aware
Timezone UTC by default; change with cg.set_timezone()
Price column price_mwh
Load column load_mw
Generation columns fuel-type specific, e.g. solar_mw, wind_onshore_mw, nuclear_mw
Gas flow column flow_kwh_d
Gas storage inventory in *_mwh; daily rates in *_mwh_d
LNG inventory *_thousand_m3; send-out in *_mwh_d
Cross-border columns signed MW; imports positive, exports negative
Installed capacity *_capacity_mw; storage energy uses *_energy_mwh
Frequency frequency_hz
Renewable shares *_pct

Price currency is stored in df.attrs["currency"] (for example "EUR", "GBP", or "USD"):

df = cg.get_prices("DE", "2025-01-01", "2025-01-07")
print(df.attrs["currency"])  # 'EUR'

European zone codes follow the ENTSO-E bidding zone convention (BE, DE_LU, FR ...). U.S. electricity uses EIA/NERC balancing-authority codes (CISO, ERCO, PJM, NYIS) and explicit market hubs (CISO_NP15). Common aliases (DEDE_LU, CAISOCISO, ERCOTERCO) resolve automatically.


Timezone

cg.set_timezone("Europe/Brussels")   # all subsequent calls return Brussels time
cg.set_timezone("UTC")               # revert to default

df = cg.get_load("BE", "2025-01-01", "2025-01-07")
# df.index is tz-aware in Europe/Brussels

Data is always fetched and cached as UTC. Timezone conversion is applied at the output boundary only.


Caching

Responses are cached locally at ~/.clarigrid/cache/ as Parquet files (requires pip install clarigrid[cache]), keyed by provider + dataset + zone + date range. Historical data is cached indefinitely; live data expires after 1 hour by default.

from clarigrid.core import cache

cache.info()           # DataFrame showing cached entries
cache.clear()          # clear all
cache.clear("smard")   # clear one provider
cache.set_live_ttl(1800)  # change live-data TTL to 30 min

Disable caching per call:

df = cg.get_prices("DE", "2025-01-01", "2025-01-07", use_cache=False)

CLI reference

Requires pip install clarigrid[auth].

clarigrid setup                    # guided wizard — configure all providers
clarigrid connect <source>         # authenticate a single provider
clarigrid auth --show              # list configured sources (keys masked)
clarigrid auth --clear <source>    # remove key for a specific source
clarigrid auth --clear --all       # remove all stored keys

API reference

Function Description
cg.connect(provider) Connect provider; handles auth for key-guarded sources
cg.set_timezone(tz) Set output timezone (IANA string, default "UTC")
cg.get_prices(zone, start, end, market="day_ahead", node=None) Electricity prices → price_mwh; optional node for nodal markets
cg.get_load(zone, start, end) Actual total load → load_mw
cg.get_generation(zone, start, end) Generation per fuel type → *_mw columns
cg.get_generation_forecast(zone, start, end) Wind/solar generation forecast → *_forecast_mw
cg.get_load_forecast(zone, start, end) Load forecast → load_forecast_mw
cg.get_physical_flows(zone, start, end) Signed cross-border physical flows in MW
cg.get_commercial_schedule(zone, start, end) Signed commercial exchanges in MW
cg.get_installed_capacity(zone, start, end) Installed power by technology in MW
cg.get_frequency(zone, start, end) System frequency → frequency_hz
cg.get_renewable_share(zone, start, end) Renewable share in percent
cg.get_co2_intensity(zone, start, end) Electricity carbon intensity in gCO2/kWh
cg.get_co2_forecast(zone, start, end) Forecast carbon intensity in gCO2/kWh
cg.get_gas_flows(zone, start, end) Gas physical flows → flow_kwh_d
cg.get_capacity(zone, start, end) Firm technical gas capacity → capacity_kwh_d
cg.get_gas_storage(zone, start, end) Gas inventory, capacity, injection and withdrawal
cg.get_lng_inventory(zone, start, end) LNG tank inventory and terminal send-out
cg.get_weather(zone, start, end) Weather observations / forecasts
cg.status() Print connected providers, zones, capabilities
cg.set_api_key(provider, key) Store a provider key locally
cg.list_providers() List all registered provider names
cg.register_provider(name, instance) Register an external provider

All data functions accept:

  • source="name" — override the router for this call only
  • use_cache=False — bypass the local cache

Built-in providers

Name Data Zones Auth
energycharts prices, load, generation, forecasts, capacity, cross-border flows, frequency, renewable share European countries and openly licensed price zones None
energinet prices, load, generation, forecasts, physical flows, actual/forecast CO2 DK1, DK2 None
redata five-minute load/forecast; daily-average generation, shares and physical flows; installed capacity ES None
rte load, generation, load forecasts, physical/commercial exchanges, generation shares and CO2 FR None
fingrid load, generation, forecasts, flows, NTC, capacity, frequency, CO2, imbalance and balancing FI Free API key
gie daily underground gas storage and LNG terminal inventory Europe, countries, facilities Free API key
eia hourly load, forecast, fuel generation, physical interchange and generation shares U.S. balancing authorities and regions Free API key
caiso day-ahead LMP at NP15, SP15, ZP26 or an explicit node California ISO None
nyiso day-ahead zonal LBMP, actual/forecast load, fuel mix and shares New York ISO and NYISO load zones None
nasapower daily/hourly meteorology, precipitation, wind and solar radiation Global point locations (lat,lon) None
smard prices, load, generation DE, AT, LU + TSO sub-zones None
elia load, generation BE None
neso load, embedded generation, actual/forecast CO2, generation shares GB None
elexon prices, generation mix GB None
entsog gas flows, capacity All ENTSOG operators None
entsoe prices, load, generation All ENTSO-E bidding zones ENTSOE_API_KEY
tennet (data fetching coming soon) NL TENNET_API_KEY

Keys for entsoe and tennet are issued by the respective upstream provider. Store them via a clarigrid.energy account or set them manually as described in API key setup.


Architecture

clarigrid/
├── __init__.py           # public surface: connect, get_prices, set_timezone, …
├── _auth.py              # KeyState machine, auth flows, provider key registry
├── _keystore.py          # ~/.config/clarigrid/.env  read/write (chmod 600)
├── _browser_flow.py      # browser-based OAuth flow (localhost callback server)
├── cli.py                # clarigrid CLI (setup, connect, auth)
├── core/
│   ├── api.py            # top-level functions — routing + normalisation
│   ├── router.py         # ZoneRouter — (zone, capability) → provider
│   ├── session.py        # runtime state: router, connected map, output TZ
│   ├── normalise.py      # canonical column names + unit normalisation
│   ├── registry.py       # register_provider / get_provider
│   ├── interface.py      # DataProvider ABC ← providers implement this
│   ├── cache.py          # filesystem Parquet cache
│   ├── config.py         # legacy key store (~/.clarigrid/keys.toml)
│   ├── exceptions.py     # exception hierarchy
│   └── types.py          # shared constants, zone aliases
├── providers/
│   ├── smard.py          # Bundesnetzagentur SMARD (DE)
│   ├── energycharts.py   # Fraunhofer ISE Energy-Charts (Europe)
│   ├── energinet.py      # Energinet Energi Data Service (DK1/DK2)
│   ├── redata.py         # Red Electrica REData (ES)
│   ├── rte.py            # RTE Eco2mix (FR)
│   ├── elia.py           # Elia Open Data (BE)
│   ├── neso.py           # NESO Data Portal (GB)
│   ├── elexon.py         # Elexon BMRS (GB)
│   ├── eia.py            # EIA-930 balancing-authority operations (US)
│   ├── caiso.py          # CAISO OASIS day-ahead prices (US)
│   ├── nyiso.py          # NYISO prices, load, forecasts and fuel mix (US)
│   ├── nasapower.py      # NASA POWER meteorology and solar data (global)
│   └── entsog.py         # ENTSOG Transparency Platform (EU gas)
└── utils/
    ├── time.py           # parse_dt, normalise_index
    └── validation.py     # resolve_zone, validate_date_range

Plugin system

External providers subclass DataProvider, declare their zones() and capabilities(), and self-register on import. Providers whose capabilities have different geographical coverage can additionally override capability_zones():

from clarigrid.core.interface import DataProvider
from clarigrid.core.registry import register_provider
import pandas as pd

class NordpoolProvider(DataProvider):
    def zones(self) -> set[str]:
        return {"NO1", "NO2", "SE1", "SE2", "DK1", "DK2", "FI"}

    def capabilities(self) -> set[str]:
        return {"prices"}

    def get_prices(self, zone, start, end, **kwargs) -> pd.DataFrame: ...

register_provider("nordpool", NordpoolProvider())

After cg.connect("nordpool"), calls to cg.get_prices("NO1", …) route to this provider automatically.


Development

git clone https://github.com/clarigrid/clarigrid
cd clarigrid
pip install -e ".[dev]"
pytest
ruff check .
mypy clarigrid

License

Apache 2.0 — see LICENSE.

Copyright (c) 2026 Alexander Hoogsteyn.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

clarigrid-0.2.0.tar.gz (126.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

clarigrid-0.2.0-py3-none-any.whl (124.4 kB view details)

Uploaded Python 3

File details

Details for the file clarigrid-0.2.0.tar.gz.

File metadata

  • Download URL: clarigrid-0.2.0.tar.gz
  • Upload date:
  • Size: 126.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.13.5

File hashes

Hashes for clarigrid-0.2.0.tar.gz
Algorithm Hash digest
SHA256 c074e0b492dde0aba313db326f6658aa36f33d390cac1e0a2ca39b821f1425df
MD5 627e11c7df621bc1303991be24b547cb
BLAKE2b-256 7d2ab30e2ac035e545e4ac23b59201f88e5b0efce6362fdb184c867dae48e88d

See more details on using hashes here.

File details

Details for the file clarigrid-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: clarigrid-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 124.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.13.5

File hashes

Hashes for clarigrid-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 d9db56e3dfa94f3bcfc1d091344d4174583f642824a9b788602abe5d1f8cdaf4
MD5 ac1819136aa582ad073198716d6745e8
BLAKE2b-256 8eb633f10a935859260a08109a9f2ca2c30d39bb38f75e4c56ea5d7f119a963d

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page