> For the complete documentation index, see [llms.txt](https://docs.jua.ai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.jua.ai/python-sdk/power-forecast.md).

# Power Forecast

Jua's [Power Forecast](/models-and-products/power-forecast.md) is an end-to-end model trained directly on actual generation data, delivering renewable energy generation forecasts in MW for power trading and grid management.

Power forecasts can be queried directly through the Jua Python SDK using the `client.power_forecast` interface. Forecasts are returned as an `xarray.Dataset` with dimensions `(zone_key, psr_type, time)` and a `value` data variable in MW.

{% hint style="info" %}
Power Forecast support requires `jua >= 0.22.0`. See [Installation](/python-sdk/installation.md) to upgrade.
{% endhint %}

## Example

As an introduction to power forecasts in the SDK, see this simple example. For more examples, please see [our GitHub repository](https://github.com/juaAI/jua-python-sdk/tree/main/examples/power_forecast).

```python
import matplotlib.pyplot as plt
from jua import JuaClient

client = JuaClient()
pf = client.power_forecast

# Fetch the latest German Solar forecast, up to 48h ahead (2880 minutes)
ds = pf.get_data(
    zone_keys=["DE"],
    psr_types=["Solar"],
    init_time="latest",
    max_prediction_timedelta=2880,
)

# The result is an xarray.Dataset; select the single zone/PSR slice and plot it
series = ds["value"].sel(zone_key="DE", psr_type="Solar")

fig, ax = plt.subplots(figsize=(15, 5))
series.plot(ax=ax, x="time")
ax.set_title("Germany — Solar Power Forecast (latest run)")
ax.set_ylabel("Power [MW]")
plt.show()
```

## Documentation

The `PowerForecast` interface is available as `client.power_forecast`. It exposes metadata helpers (`get_zones`, `get_psr_types`, `get_init_times`), the main `get_data` query method, and a `get_day_ahead_timeseries` helper for stitching a continuous day-ahead series across runs.

### Zones and PSR Types

Power Forecast covers a set of market zones, each serving one or more **PSR types** (Production Source types, e.g. `Solar`, `Wind Onshore`). The available zones and PSR types differ per zone, so query them before building requests.

{% tabs %}
{% tab title="List zones and PSR types" %}

```python
from jua import JuaClient

client = JuaClient()
pf = client.power_forecast

# All available zones
zones = pf.get_zones()
print("Zones:", zones)

# All PSR types across all zones
print("All PSR types:", pf.get_psr_types())

# PSR types served for a specific zone
print("DE PSR types:", pf.get_psr_types(zone_key="DE"))
```

{% endtab %}

{% tab title="Output" %}

```
Zones: ['BE', 'DE', 'FR', 'GB', 'NL']
All PSR types: ['Load', 'Solar', 'Wind', 'Wind Embedded', 'Wind Offshore', 'Wind Onshore', 'Wind Transmission']
DE PSR types: ['Load', 'Solar', 'Wind Offshore', 'Wind Onshore']
```

{% endtab %}
{% endtabs %}

{% hint style="info" %}
Requesting a PSR type that a zone does not serve raises a `ValueError` listing the available types. For predicted demand in zones without a fitted `Load` model, use [Market Aggregates](/python-sdk/market-aggregates.md) with `weighting=population` and `unit=mw`, which returns a `load_mw` column.
{% endhint %}

### Init Times

`get_init_times` lists the available forecast runs (init times), newest first. Use **count mode** for the most recent runs, or **time-window mode** to retrieve every run in a date range.

```python
from datetime import datetime, timezone

# Count mode: the 5 most recent German runs
for it in pf.get_init_times(zone_key="DE", limit=5):
    print(it.init_time, "max horizon (min):", it.max_prediction_timedelta)

# Time-window mode: every run in January 2025 (can exceed 1000)
init_times = pf.get_init_times(
    zone_key="DE",
    start_time=datetime(2025, 1, 1, tzinfo=timezone.utc),
    end_time=datetime(2025, 2, 1, tzinfo=timezone.utc),
)
print(f"{len(init_times)} runs in January 2025")
```

Each entry is an `InitTimeInfo` with an `init_time` (timezone-aware `datetime`) and `max_prediction_timedelta` (forecast horizon in minutes).

### Querying Data

`get_data` supports two mutually exclusive query modes.

**Horizon mode** is init-time-centric. Specify `init_time` as a `datetime`, an integer offset (`0` = latest), or a relative token (`"latest"`, `"latest-N"`), and optionally cap the horizon with `max_prediction_timedelta` (in minutes). Relative tokens resolve to the most recent run where *all* requested zone/PSR-type combinations have data.

```python
# Latest run, 48h horizon, German Solar
ds = pf.get_data(
    zone_keys=["DE"],
    psr_types=["Solar"],
    init_time="latest",
    max_prediction_timedelta=2880,
)

# The two most recent runs for several zones, all PSR types, localized times
ds = pf.get_data(
    zone_keys=["DE", "FR"],
    init_time=[0, 1],
    max_prediction_timedelta=1440,
    time_zone="Europe/Berlin",
)
```

**Time range mode** is valid-time-centric. Specify `start_time` and/or `end_time` to filter by the forecast's valid time instead of by run.

```python
from datetime import datetime

ds = pf.get_data(
    zone_keys=["DE"],
    psr_types=["Solar", "Wind Onshore"],
    start_time=datetime(2025, 12, 1),
    end_time=datetime(2025, 12, 3),
)
```

The two modes cannot be combined; passing both horizon and time-range parameters raises a `ValueError`.

```
Attributes:
    zone_keys: list[str] | None
        Zone codes to query (e.g. ["DE", "FR"]).
    psr_types: list[str] | None
        PSR types to query (e.g. ["Solar", "Wind Onshore"]).
        If None, returns all available types.
    init_time: str | int | datetime | list | None
        Horizon-mode run selection: "latest", "latest-N", a datetime,
        an integer offset (0 = latest), or a list of these.
    max_prediction_timedelta: int | None
        Horizon-mode maximum forecast horizon in minutes.
    start_time: datetime | None
        Time-range-mode lower bound on valid time (inclusive).
    end_time: datetime | None
        Time-range-mode upper bound on valid time (exclusive).
    time_zone: str | None
        IANA time zone name for time formatting (e.g. "Europe/Berlin").

Returns:
    xarray.Dataset with dimensions (zone_key, psr_type, time) and the
    data variable `value` in MW.
```

### Day-Ahead Time Series

`get_day_ahead_timeseries` stitches a continuous day-ahead series from the runs whose local init-time hour matches `init_hour`. For each matching run it takes the day-ahead window and concatenates the results onto a single `time` axis — useful for plotting or backtesting a consistent day-ahead product over a long history.

```python
from datetime import datetime, timedelta, timezone

# Last year of German Solar day-ahead generation from the 09:00 UTC run
end = datetime.now(timezone.utc)
start = end - timedelta(days=365)

ds = pf.get_day_ahead_timeseries(
    zone_keys=["DE"],
    psr_types=["Solar"],
    init_hour=9,
    time_zone="UTC",
    start_date=start,
    end_date=end,
)

# Plot the stitched series
df = ds.to_dataframe().reset_index().dropna(subset=["value"])
df.plot(x="time", y="value", figsize=(16, 6), title="DE Solar — day-ahead (09:00 UTC run)")
```

When `start_date`/`end_date` are given (date-range mode), one init run per day is constructed over the range, bypassing the init-times listing limit so arbitrarily long histories can be stitched. When no dates are given (latest mode), the most recent matching runs are discovered automatically (bounded by `max_init_times`).


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.jua.ai/python-sdk/power-forecast.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
