Python client for Volatile forecast data via the public GraphQL API.
Project description
Volatile Forecast SDK
Python client for authenticated access to forecast dataset queries on the Volatile public GraphQL API. It focuses on a small, typed surface (execute_dataset_query, my_datasets, me, token lifecycle) with client-side validation so integrators pick only supported bidding zones, IANA time zones, percentile fields, and aggregation modes.
About Volatile
Volatile is an energy intelligence company focused on making European power-market data and forecasting workflows easier to consume and operationalize.
This SDK is one of the tools provided to help customers integrate Volatile forecast products directly into Python-based analytics, trading, and automation pipelines.
Install
From PyPI (recommended):
pip install volatile-forecast-sdk
Runtime dependency: tzdata (IANA zone database for zoneinfo on all platforms).
Usage examples (login, dataset listing, query execution, and token-only auth) are available in examples/.
License and access model
This SDK is open source under the Apache-2.0 license and is publicly installable.
API usage still requires a valid Volatile customer account and API credentials. The license for this SDK does not grant free API access, and API use is governed by your contract and applicable API Terms of Service.
API endpoint
VolatileForecastClient() targets production by default (https://api.volatile.de). You can override base_url when needed:
from volatile_forecast_sdk import VolatileForecastClient, DEFAULT_BASE_URL
client = VolatileForecastClient() # same as VolatileForecastClient(DEFAULT_BASE_URL)
client = VolatileForecastClient("https://api.staging.example.com")
Existing access token, same default:
client = VolatileForecastClient.from_token("eyJ…") # optional: base_url="https://…"
from_token() accepts the token first, with base_url as an optional keyword argument.
Discover parameters (PFM datasets)
For products such as Volatile Load PFM-1, Volatile Spot PFM-1, and Volatile IDC DAS-1, the SDK ships a structured catalog that mirrors the server rules (zone, issue time, and dataset-specific optional keys):
from volatile_forecast_sdk import format_parameter_hints, list_catalog_dataset_names
print(list_catalog_dataset_names())
print(format_parameter_hints("Volatile Load PFM-1"))
Use ForecastQueryParams for a fluent builder with validation and tab-friendly enums:
from volatile_forecast_sdk import (
VolatileForecastClient,
ForecastQueryParams,
EuropeanBiddingZone,
CommonTimeZone,
ForecastPercentileField,
TimeAggregation,
)
client = VolatileForecastClient()
client.login("user", "pass")
params = (
ForecastQueryParams.for_dataset("Volatile Load PFM-1")
.with_zone(EuropeanBiddingZone.NO_2)
.with_time_zone(CommonTimeZone.EUROPE_BERLIN)
.with_forecast_issue_latest()
.with_fields(ForecastPercentileField.P50, ForecastPercentileField.P90)
.with_aggregation(TimeAggregation.FIFTEEN_MINUTES)
.with_forecast_horizon_hours(168)
)
result = client.execute_dataset_query(name="Volatile Load PFM-1", parameters=params)
rows = result.parsed_rows()
IDC DAS example (lean parameter set):
from volatile_forecast_sdk import CommonTimeZone, EuropeanBiddingZone, ForecastQueryParams
params = (
ForecastQueryParams.for_dataset("Volatile IDC DAS-1")
.with_zone(EuropeanBiddingZone.DE_LU)
.with_time_zone(CommonTimeZone.EUROPE_BERLIN)
.with_forecast_issue_latest()
)
result = client.execute_dataset_query(name="Volatile IDC DAS-1", parameters=params)
European bidding zones are exposed as EuropeanBiddingZone and EUROPEAN_BIDDING_ZONE_CODES (ENTSO-E-style strings). Time zones use CommonTimeZone presets plus validate_time_zone("Europe/Stockholm") against the full IANA set (zoneinfo.available_timezones()).
Refresh token policy
VolatileForecastClient applies a default RefreshTokenPolicy:
- Proactive: if the access token looks like a JWT, refresh when wall-clock time is within
leeway_secondsofexp(requires a refresh token fromlogin). - Reactive: on HTTP 401 or GraphQL errors that look like auth failures, refresh once (configurable) and retry.
Disable automation (manual refresh only):
from volatile_forecast_sdk import VolatileForecastClient, RefreshTokenPolicy
client = VolatileForecastClient(refresh_token_policy=RefreshTokenPolicy(enabled=False))
Tune behavior:
RefreshTokenPolicy(
enabled=True,
leeway_seconds=300,
max_reactive_refreshes=2,
proactive_refresh=True,
reactive_refresh_on_graphql_auth_error=True,
)
Helpers: client.access_token_expires_at_unix(), decode_jwt_exp_unix(token) (signature not verified—scheduling only).
Optional credentials_provider for fully-unattended processes
Pass a callable that returns (username, password) to let the SDK
recover from a hard auth failure (e.g. refresh-token expiry or
server-side session revocation) without operator intervention:
import os
from volatile_forecast_sdk import VolatileForecastClient
client = VolatileForecastClient(
credentials_provider=lambda: (
os.environ["VOLATILE_USER"],
os.environ["VOLATILE_PASSWORD"],
),
max_relogins_per_hour=4, # default — caps password-grant volume
)
client.login(os.environ["VOLATILE_USER"], os.environ["VOLATILE_PASSWORD"])
The provider only fires when reactive-refresh can't recover; a hard cap
of max_relogins_per_hour defends the auth endpoint from
password-grant storms if the API gets stuck in a misconfigured state.
Observability — client.metrics
Every client exposes a plain-dict metrics attribute customers can
sample at any time and feed into Prometheus / structlog / etc:
client.metrics
# {"request_count": 42, "request_errors": 0,
# "token_refreshes": 1, "rate_limit_retries": 0, "relogins": 0}
The counters are best-effort (no locking). Reset by assigning a fresh dict if you want windowed metrics.
Rate-limit retries (HTTP 429)
The public API enforces per-user, per-operation budgets. When you exceed a
budget it replies with HTTP 429 plus a Retry-After header. The SDK
detects this automatically, sleeps the indicated number of seconds, and
retries — up to max_rate_limit_retries times. Each sleep is capped at
rate_limit_retry_cap_seconds so a misbehaving server can't pin your
process indefinitely.
client = VolatileForecastClient(
access_token="...",
max_rate_limit_retries=3, # default
rate_limit_retry_cap_seconds=60.0, # default
)
If the budget is exhausted, the SDK raises RateLimitError — a subclass
of HTTPError — carrying the parsed metadata so you can decide what to
do next:
from volatile_forecast_sdk import RateLimitError
try:
client.execute_dataset_query(name="Volatile IDC DAS-1", parameters=params)
except RateLimitError as e:
# e.retry_after, e.tier, e.window, e.limit, e.operation
log.warning("Throttled on %s (%s): wait %ss", e.operation, e.window, e.retry_after)
raise
Set max_rate_limit_retries=0 to disable the built-in loop entirely
(useful if you want to handle 429s with your own scheduler).
Classic dict parameters
You can still pass a plain mapping (no validation beyond the API):
from volatile_forecast_sdk import VolatileForecastClient, normalize_bidding_zone, validate_time_zone
client = VolatileForecastClient()
client.login("user", "pass")
params = {
"forecast_issue_time": "latest",
"zone_code": normalize_bidding_zone("NO_2"),
"time_zone": validate_time_zone("Europe/Berlin"),
}
result = client.execute_dataset_query(name="Volatile Spot PFM-1", parameters=params)
API reference (high level)
| Symbol | Role |
|---|---|
VolatileForecastClient |
GraphQL HTTP client, token policy, execute_dataset_query |
DEFAULT_BASE_URL |
Production API root (https://api.volatile.de); pass a different base_url to override |
ForecastQueryParams |
Validated fluent builder for query parameters |
EuropeanBiddingZone, EUROPEAN_BIDDING_ZONE_CODES, normalize_bidding_zone |
Curated bidding-zone codes |
CommonTimeZone, validate_time_zone, list_common_european_time_zones |
IANA time zones |
ForecastPercentileField, IDCField, TimeAggregation |
Allowed fields / aggregation values |
ForecastStatus |
Per-slot forecast-quality enum (0..7) returned by IDC datasets — see Forecast quality below |
format_parameter_hints, parameter_hints_for_dataset, STANDARD_FORECAST_DATASETS, IDC_DAS_DATASETS, STANDARD_PFM_DATASETS |
Documentation-oriented catalog |
RefreshTokenPolicy, decode_jwt_exp_unix |
Token lifecycle |
DatasetQueryResult.parsed_rows() |
Normalize row JSON strings vs objects |
The SDK mirrors the public GraphQL schema exposed by https://api.volatile.de/graphql/.
Forecast quality (IDC datasets)
IDC DAS datasets attach a per-slot quality label so consumers can filter or weight the forecast. Two columns are returned alongside the quantile / MC fields:
forecast_status(int 0..7) — see table below.in_scope(bool) —truefor ID1 slots in the 1–6 h horizon (the MC layer's active scope).falsefor ID3 slots or ID1 slots outside that window; MC columns (signal,expected_edge,p_buy,p_sell, …) will benullby design — not a degradation. The LightGBM quantile columns (id1_p10/50/90,id3_p10/50/90) are populated regardless.
forecast_status |
Name | Meaning |
|---|---|---|
| 0 | OK |
All inputs fresh; VWAP-S0 (≤6 h) or DA-S0 (>6 h by design) |
| 1 | OK_DA_FALLBACK |
≤6 h slot, no VWAP, crawler is fresh → liquidity gap, DA-S0 used |
| 2 | OK_IDA_FALLBACK |
Same as 1 but intraday auction is newer than DA → IDA-S0 used |
| 3 | WATCH |
Non-critical input source stale OR borderline VWAP age (15–30 min) |
| 4 | VWAP_STALE |
VWAP older than 30 min — likely crawler lag |
| 5 | IMPUTED |
LightGBM substituted defaults for one or more missing features; data feed is fresh, model output is mildly biased |
| 6 | STALE_CRITICAL |
Data feed itself is stale: EPEX continuous-trades crawler down within MC scope, or day-ahead price missing for the delivery date |
| 7 | FAILED |
LightGBM produced NaN at this slot (model load / feature build failure) |
Statuses are monotonically worse — higher is more degraded. Suggested thresholds:
- LightGBM-only traders: skip slots with
forecast_status >= 5. - MC-signal traders: skip slots with
forecast_status >= 4. - Conservative consumers: only trade
forecast_status <= 1.
Difference between status 5 and status 6
These are the two most commonly confused values, and they imply different operational responses:
- 5
IMPUTED— the model improvised. Input features had one or more NaNs at inference time and the wrapper substituted a default (categorical missing-path, Ridge median, oranalytical_cf=0). The data feed is fresh; only some engineered features were unavailable. Forecast is in the right ballpark; reduce position sizing. - 6
STALE_CRITICAL— the data feed stopped. The EPEX continuous- trades crawler is stale within the MC horizon, or the day-ahead price is missing entirely. The model may have produced a number, but it's reflecting old or absent market reality. Skip the slot.
from volatile_forecast_sdk import (
ForecastQueryParams, ForecastStatus, IDCField, VolatileForecastClient,
)
params = (
ForecastQueryParams.for_dataset("Volatile IDC DAS-1")
.with_zone("DE_LU")
.with_forecast_issue_latest()
.with_fields(
IDCField.ID1_P50, IDCField.ID3_P50,
IDCField.SIGNAL, IDCField.EXPECTED_EDGE,
IDCField.FORECAST_STATUS, IDCField.IN_SCOPE,
)
)
result = client.execute_dataset_query(
name="Volatile IDC DAS-1", parameters=params,
)
rows = [
r for r in result.parsed_rows()
if r.get("in_scope") and int(r.get("forecast_status", 7)) < ForecastStatus.VWAP_STALE
]
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file volatile_forecast_sdk-0.5.0.tar.gz.
File metadata
- Download URL: volatile_forecast_sdk-0.5.0.tar.gz
- Upload date:
- Size: 35.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
68de970f3939bc268ad46e324244438e1aa951cf514fbcee2f7f39a43e48ba9e
|
|
| MD5 |
ba090b37e9df72cf2c5259440998f274
|
|
| BLAKE2b-256 |
0fce97bfa1ae21c7dc3047d17058c5d9b59bde7652feee5756fdfbb3dfcb4cd5
|
File details
Details for the file volatile_forecast_sdk-0.5.0-py3-none-any.whl.
File metadata
- Download URL: volatile_forecast_sdk-0.5.0-py3-none-any.whl
- Upload date:
- Size: 32.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9ad08895cee32940d4d89f46e3eec3ce1d0c1d7019414f57bb91de421fc4067e
|
|
| MD5 |
db8b5868074796897754b572b48dae83
|
|
| BLAKE2b-256 |
e4c618cb6e2cd5bb6c6c38c95a26582958d9fea610b20e05f61412e1e03c9f7e
|