# Market Aggregates

### What are Market Aggregates for?

Market aggregates, especially used with weighting such as capacity weighting, are useful proxies to estimate how differences in forecasts - either between models or between different forecasts of the same model - impact energy production & consumption.

Imagine you are comparing the latest 12PM forecast of EPT against the 6 AM forecast. In Deckenpfronn, Germany, there is a huge difference in prediction for 100m wind speed. But since there is no wind park in Deckenpfronn this difference in wind speed will have no impact at the energy production at all. However, differences in wind speed at for example Reussenkoge Wind Farm, with a production capacity of over 250 MW, will have significant impacts on the energy output.

This is why we offer to compute capacity weighted averages for both solar and wind parameters. The averages are computed as

$$V\_{avg, weighted} =\sum\_i \dfrac{C\_i}{C\_{tot}} \cdot V\_i$$

Where $$V\_{i}$$ is the value of the variable (e.g. wind speed) at a specific location (e.g. a wind farm), $$C\_i$$ is the production capacity at that location and $$C\_{tot} = \sum\_i C\_i$$ is the total production capacity of the selected region.

### Output MW Mode

By adding `unit=mw` to the `GET /v1/forecast/market-aggregate` endpoint, the query engine applies generic power curves to weather forecasts and returns predicted **megawatts (MW)** instead of raw weather values. This is useful for comparing different models and quick MW estimates across many European zones.

{% hint style="info" %}
**Looking for actual production forecasts?** MW output here provides a model-specific forecast of **potential production** via power curves. For a forecast of **actual production**, use the [Power Forecast](/models-and-products/power-forecast.md) — an end-to-end model trained on real generation data, significantly more accurate. Currently available for Germany (Solar, Wind Onshore).
{% endhint %}

{% hint style="info" %}
MW output is only available on the `GET /v1/forecast/market-aggregate` endpoint, not the `POST /v1/forecast/data` endpoint.
{% endhint %}

MW mode:

* Activated by passing `unit=mw` as a query parameter on the GET endpoint
* Only works with `wind_speed_at_height_level_100m` or `surface_downwelling_shortwave_flux_sum_1h`
* Restricts geo to `market_zone` or `country_key` (no polygon or bounding box)
* Only available for zones with power-curve data (see MW-Capable Zones below)
* Weighting is auto-derived (wind → `wind_capacity`, solar → `solar_capacity`)
* Both wind and solar can be selected simultaneously; the backend issues separate queries per variable and merges
* When `merge_zones_or_countries` is enabled, MW values are summed across zones

#### Example: Wind MW Forecast

{% tabs %}
{% tab title="Curl" %}

```bash
curl -X GET "https://query.jua.ai/v1/forecast/market-aggregate\
?models=ept2\
&init_time=2025-10-22T00:00:00Z\
&weighting=wind_capacity\
&market_zones=DE\
&variables=wind_speed_at_height_level_100m\
&max_prediction_timedelta=72\
&unit=mw\
&include_time=true\
&format=json" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Accept: application/json"
```

{% endtab %}

{% tab title="Python" %}

```python
import requests

url = "https://query.jua.ai/v1/forecast/market-aggregate"
headers = {
    "X-API-Key": "YOUR_API_KEY",
    "Accept": "application/json"
}
params = {
    "models": "ept2",
    "init_time": "2025-10-22T00:00:00Z",
    "weighting": "wind_capacity",
    "market_zones": ["DE"],
    "variables": ["wind_speed_at_height_level_100m"],
    "max_prediction_timedelta": 72,
    "unit": "mw",
    "include_time": True,
    "format": "json",
}

response = requests.get(url, headers=headers, params=params)
data = response.json()
```

{% endtab %}

{% tab title="Response" %}

```json
{
    "model": ["ept2", "ept2", ...],
    "init_time": ["2025-10-22T00:00:00+00:00", ...],
    "prediction_timedelta": [0.0, 1.0, ...],
    "time": ["2025-10-22T00:00:00+00:00", ...],
    "market_zone": ["DE", "DE", ...],
    "wind_onshore_mw": [20109.78, 18485.41, ...],
    "wind_offshore_mw": [4933.67, 4880.13, ...]
}
```

{% endtab %}
{% endtabs %}

#### Example: Get Available MW Zones

```bash
curl -X GET "https://query.jua.ai/v1/forecast/market-aggregate/mw-zones" \
  -H "X-API-Key: YOUR_API_KEY"
```

```json
{
    "wind": ["BE", "DE", "DK-DK1", "DK-DK2", "ES", "FR", ...],
    "solar": ["BE", "DE", "DK-DK1", "DK-DK2", "ES", "FR", ...]
}
```

#### MW-Capable Zones

The list of MW-capable zones is dynamic (queried from the `mw-zones` endpoint based on which zones have facility data and fitted power curves).

**Wind MW zones:** BE, DE, DK-DK1, DK-DK2, ES, FR, IT-CNO, IT-CSO, IT-NO, IT-SAR, IT-SIC, IT-SO, NL, NO-NO1, NO-NO2, SE-SE1, SE-SE2, SE-SE3, SE-SE4

**Solar MW zones:** BE, DE, DK-DK1, DK-DK2, ES, FR, IT-CNO, IT-CSO, IT-NO, IT-SAR, IT-SIC, IT-SO, NL, NO-NO1, SE-SE1, SE-SE2, SE-SE3, SE-SE4

{% hint style="info" %}
NO-NO2 has wind MW support but not solar.
{% endhint %}

#### MW Column Names

When MW mode is enabled, output columns are renamed:

| Raw Column Name    | Display Name     | Unit |
| ------------------ | ---------------- | ---- |
| `wind_onshore_mw`  | Wind Onshore MW  | MW   |
| `wind_offshore_mw` | Wind Offshore MW | MW   |
| `solar_mw`         | Solar MW         | MW   |

### Variable-to-Weighting Mapping

When not using MW mode, the `weighting` field is applied based on the variable:

| Variable                                    | Weighting        |
| ------------------------------------------- | ---------------- |
| `wind_speed_at_height_level_100m`           | `wind_capacity`  |
| `surface_downwelling_shortwave_flux_sum_1h` | `solar_capacity` |
| `air_temperature_at_height_level_2m`        | `population`     |

### Aggregation Periods and Column Naming

Market aggregate responses use an `avg__` prefix on variable columns:

* Hourly: `avg__wind_speed_at_height_level_100m`
* Daily: `avg__wind_speed_at_height_level_100m`, time column becomes `time__to_start_of(day)`
* Weekly: `avg__wind_speed_at_height_level_100m`, time column becomes `time__to_start_of(week)`

In MW mode (GET endpoint only), columns use entirely different names (see MW Column Names above).

## Accessing Market Aggregates

There are two ways to access market aggregates:

* Making a request to `GET https://query.jua.ai/v1/forecast/market-aggregate`
* Using `POST https://query.jua.ai/v1/forecast/data` which allows selecting custom regions such as polygons and bounding boxes

### Using the \`market-aggregate\` endpoint

A convenient `GET` endpoint that allows fast and easy access to one or multiple market zones.

{% hint style="info" %}
The [Query Engine OpenAPI docs](https://query.jua.ai/docs) provide an interactive description of all endpoints
{% endhint %}

{% tabs %}
{% tab title="Curl" %}

```bash
curl -X GET "https://query.jua.ai/v1/forecast/market-aggregate\
?models=ept2\
&init_time=2025-10-22T00:00:00Z\
&weighting=wind_capacity\
&market_zones=DE\
&variables=wind_speed_at_height_level_100m\
&max_prediction_timedelta=72\
&include_time=true \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Accept: application/json"
```

{% endtab %}

{% tab title="Python" %}

```python
import requests

url = "https://query.jua.ai/v1/forecast/market-aggregate"
headers = {
    "X-API-Key": "YOUR_API_KEY",
    "Accept": "application/json"
}
params = {
    "models": "ept2",
    "init_time": "2025-10-22T00:00:00Z",
    "weighting": "wind_capacity",
    "market_zones": ["DE"],  # Germany
    "variables": ["wind_speed_at_height_level_100m"],
    "max_prediction_timedelta": 72, # hours
    "include_time": True,
}

response = requests.get(url, headers=headers, params=params)
data = response.json()
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
const url = new URL("https://query.jua.ai/v1/forecast/market-aggregate");
url.searchParams.append("models", "ept2");
url.searchParams.append("init_time", "2025-10-22T00:00:00Z");
url.searchParams.append("weighting", "wind_capacity");
url.searchParams.append("market_zones", "DE");
url.searchParams.append("variables", "wind_speed_at_height_level_100m");
url.searchParams.append("max_prediction_timedelta", "2880");
url.searchParams.append("include_time", "true");

const response = await fetch(url, {
  method: "GET",
  headers: {
    "X-API-Key": "YOUR_API_KEY",
    Accept: "application/json",
  },
});

const data = await response.json();
```

{% endtab %}

{% tab title="Response" %}

```json
{
    "model": [
        "ept2",
        "ept2",
        71 more entries...
    ],
    "init_time": ["2025-10-22T00:00:00Z", ...],
    "prediction_timedelta": [0, 1, ...., 72],
    "time": ["2025-10-22T00:00:00Z", "2025-10-22T01:00:00Z", ...],
    "avg__wind_speed_at_height_level_100m": [0.23, 0.51, ...]
}    
```

{% endtab %}
{% endtabs %}

### Using the generic \`data\` endpoint

While adding slightly more overhead to the query, the `data` endpoint provides more flexibility such as defining custom regions using polygons and bounding boxes. The example below is equivalent to the request to the `market-aggregate` endpoint above.

{% hint style="info" %}
Checkout the [examples](/api-v2/query-engine/examples.md) on how to use market aggregates with polygons
{% endhint %}

{% tabs %}
{% tab title="Python" %}

```python
import requests

url = "https://query.jua.ai/v1/forecast/data"
headers = {
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json",
    "Accept": "application/json"
}
params = {
    "format": "json"
}
payload = {
    "models": ["ept2"],
    "geo": {
        "type": "market_zone",
        "value": ["DE"]
    },
    "variables": ["wind_speed_at_height_level_100m"],
    "init_time": "2025-10-22T00:00:00Z",
    "prediction_timedelta": {
        "start": 0,
        "end": 72
    },
    "weighting": {
        "type": "wind_capacity"
    },
    "group_by": ["model", "init_time", "prediction_timedelta", "time"],
}

response = requests.post(url, headers=headers, params=params, json=payload)
data = response.json()
```

{% endtab %}

{% tab title="Javascript" %}

```javascript
const url = "https://query.jua.ai/v1/forecast/data?format=json";

const payload = {
  models: ["ept2"],
  geo: {
    type: "market_zone",
    value: ["DE"],
  },
  variables: ["wind_speed_at_height_level_100m"],
  init_time: "2025-10-22T00:00:00Z",
  prediction_timedelta: {
    start: 0,
    end: 72,
  },
  weighting: {
    type: "wind_capacity",
  },
  group_by: ["model", "init_time", "prediction_timedelta", "time"],
};

const response = await fetch(url, {
  method: "POST",
  headers: {
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json",
    Accept: "application/json",
  },
  body: JSON.stringify(payload),
});

const data = await response.json();
```

{% endtab %}

{% tab title="Response" %}

```json
{
    "model": [
        "ept2",
        "ept2",
        71 more entries...
    ],
    "init_time": ["2025-10-08T00:00:00Z", ...],
    "prediction_timedelta": [0, 1, ...., 72],
    "avg__wind_speed_at_height_level_100m": [285.34, 285.91, ...],
}
```

{% endtab %}
{% endtabs %}

### Countries with Regional Zones

Some countries don't have a single zone code — use their regional zones instead:

| Country | Zone Codes                                                            |
| ------- | --------------------------------------------------------------------- |
| Italy   | IT-CNO, IT-CSO, IT-NO, IT-SAR, IT-SIC, IT-SO                          |
| Norway  | NO-NO1, NO-NO2, NO-NO3, NO-NO4, NO-NO5                                |
| Sweden  | SE-SE1, SE-SE2, SE-SE3, SE-SE4                                        |
| Denmark | DK-DK1, DK-DK2                                                        |
| Japan   | JP-CB, JP-CG, JP-HKD, JP-HR, JP-KN, JP-KY, JP-ON, JP-SK, JP-TH, JP-TK |

Countries with single zone codes: DE, FR, GB, NL, PL, ES, BE, AT, CH, CZ, PT, GR, IE


---

# Agent Instructions: 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:

```
GET https://docs.jua.ai/api-v2/query-engine/market-aggregates.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
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.
