# EU Balancing Activation Panel (`atlas-data/eu-balancing-activation-panel`) Actor

Normalized aFRR/mFRR activation and imbalance price-volume panel for EU bidding zones with regime-shift flags and per-day gap registers.

- **URL**: https://apify.com/atlas-data/eu-balancing-activation-panel.md
- **Developed by:** [Atlas](https://apify.com/atlas-data) (community)
- **Categories:** Other
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per usage

This Actor is paid per platform usage. The Actor is free to use, and you only pay for the Apify platform usage, which gets cheaper the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-usage

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## EU Balancing Activation Panel

A normalized price–volume panel for EU balancing activation and imbalance settlement: aFRR, mFRR and RR-related series per bidding zone and UTC quarter-hour interval, with regime-shift flags keyed to published platform milestones, per-day gap registers, stable IDs, edit detection, and replay-safe incremental state.

Built for BESS/flexibility revenue modelers, quant analysts at aggregators, traders, and energy consultants who need audit-friendly, machine-readable balancing history without days of manual ENTSO-E/TSO wrangling.

The value is not access to public data — it is the production workflow around it: deterministic normalization with documented methodology notes, DST-safe UTC intervals, original-currency preservation, completeness/gap disclosure, regime-era annotation, change tracking across upstream revisions, bounded durable state, and conservative failure behavior.

### Output

Each dataset row is one normalized observation: **zone × product × UTC 15-minute interval**, output `schemaVersion` **1.0.0**:

- stable `recordId` (SHA-256 over source + zone + product + interval start) and separate `contentDigest`;
- `zone`, `product`, `direction` (up/down/none where applicable);
- `intervalStartUTC` / `intervalEndUTC`, always fixed 15-minute resolution;
- `volume` with explicit `volumeUnit` (`MW` instantaneous vs `MWh` per-interval energy) because upstream semantics differ;
- `priceEURperMWh` plus `originalCurrencyPrice`/`originalCurrency` (e.g. DKK) when the source publishes them;
- `aggregationMethod`: `native-interval` for natively published intervals, `sample-mean` for second-resolution aFRR activations averaged per quarter-hour (with `sampleCount`);
- `components` for related published fields (spot price, dominating direction, offered/total volumes);
- `regimeFlags`: milestone era/adjacency IDs plus rolling z-score volatility clusters (analytical estimate only);
- `completeness`: expected vs observed vs missing intervals for the row's UTC day;
- `methodologyNote`, `fetchedAt`, `changeType`, `changedFields`, and explicit source attribution.

Products from EnergiDataService: `imbalance`, `aFRR-VWA-up/down`, `mFRR-marginal-up/down`, `mFRR-SA-up/down`, `mFRR-DA-up/down`, optional `aFRR-activation`. Products from the ENTSO-E Transparency Platform path: `activated-price` (A85), `activated-quantity` (A83), `procured-quantity` (A86), `procured-price` (A87).

### Sources, licenses and honest coverage

| Source | Access | Zones | License/terms |
| --- | --- | --- | --- |
| [Energinet Energi Data Service](https://www.energidataservice.dk/) | Anonymous REST API | DK1, DK2 | CC BY 4.0; attribution included on every row |
| [ENTSO-E Transparency Platform](https://transparency.entsoe.eu/) | REST API with **your free registered security token** | DK1/DK2/DE-LU/AT/NL/BE/FI/ES defaults | Published market information under TP terms; carry its accuracy disclaimer |

Coverage is deliberately deep where sources are verified and explicitly disclosed elsewhere:

- The anonymous default path covers DK1/DK2 with aFRR volume-weighted prices/volumes, mFRR scheduled/direct activation price-volume pairs, marginal prices, and full imbalance-price components.
- The ENTSO-E path implements the official document types A85/A86/A87 (+A83) with strict IEC 62325-451 XML parsing. It requires your own token registered at the Transparency Platform. Default area-EIC codes are provided for eight launch zones but should be verified by you against the official area list before production use.
- National supplements named in the underlying opportunity research (regelleistung.net, OTE-CR, Fingrid, ESIOS) are **not covered in v1**: their redistribution/automated-access terms were not verifiable at build time and remain an explicit unknown rather than a silently weakened promise.

### Regime-shift flags

- Built-in milestone: **PICASSO go-live 2024-10-02T00:00Z** — verified via Energinet's official discontinued-dataset notice ("no longer updated after October 2nd, 2024, because of the go-live of the PICASSO platform").
- Rows carry `postMilestoneEraId` (the latest milestone at or before the interval) and milestone adjacency within a 7-day window after each milestone.
- Add your own published milestones (for example MARI's go-live once you have confirmed the exact date you trust) via the `milestones` input; each entry carries its own source URL so annotations stay auditable.
- Volatility clusters are rolling |z|-score flags over trailing same-product prices inside the fetched window. They are analytical estimates, never settlement facts.

### Run modes

`full` re-emits every collected row as `snapshot` (stateless; ideal for warehouse rebuilds and the default example).

`incremental` emits only `new` and `updated` rows, overlapping the last watermark by `overlapHours` to catch late upstream revisions.

`diff` behaves like incremental but also emits `unchanged` rows for reconciliation.

Change tracking keys digests on `recordId`; only source observations participate in digests (annotations like flags/fetchedAt do not trigger false updates). `changedFields` names exactly which normalized fields changed.

### Example input

```json
{
  "mode": "full",
  "zones": ["DK1", "DK2"],
  "sources": ["energidataservice"],
  "lookbackHours": 24
}
```

This default finishes in well under five minutes, always produces a non-empty schema-correct dataset from real Energinet data, and requires no credentials. For the token-gated path add `"sources": ["entsoe-tp"]` and your `entsoeSecurityToken`.

Second-resolution aFRR activation (`AfrrEnergyActivation`) is off by default: it publishes one sample per second and is aggregated client-side into quarter-hour means. Enable it with short windows (hours, not weeks).

### Traversal caps, resume, and write ordering

Cost and runtime are independently bounded by `maxItems`, `maxPagesPerDataset`, `maxScannedRecords`, and `pageSize`. HTTP 429/5xx and network errors receive bounded exponential-backoff retries honoring `retry-after`; malformed envelopes/records fail closed or are counted as `malformedRecords`.

If a cap lands mid-window, durable state saves the exact window, mode, per-dataset forward offsets, and a compact replay ledger of already-emitted rows. A truncated window rewinds its source offset to the page start and replays without duplicating dataset writes. Completed windows clear their cursor and advance the watermark.

Before any source call the Actor acquires an exclusive writer lease (request-queue-backed with server-side expiry). The write order is strict: dataset rows → key-value-store `OUTPUT` summary → durable state last. Any earlier failure leaves work replayable; consumers should upsert by `recordId` and use `contentDigest`/`changeType`/`fetchedAt` to distinguish revisions.

State lives in this Actor's own resources (named KV store `eu-balancing-activation-panel-state-v1`, lock queue `eu-balancing-activation-panel-lock-v1`) as immutable uniquely-keyed snapshots with semantic revision selection, retention-based pruning (`stateRetentionDays`, `maxStateEntries`), and a hard 3.5 MB budget that degrades gracefully by dropping oldest digests rather than failing runs. Schedule non-overlapping runs; overlapping runs can still duplicate replayed rows even though stale state commits are rejected.

### OUTPUT record

The `OUTPUT` key holds the run summary: status/stop reason, per-source windows, scanned/malformed/duplicate/emitted counts, change counts, a bounded gap register (per zone×product×UTC day missing-interval counts), applied milestones, volatility cluster count, explicit disclaimers, timestamp, dataset ID, and attribution array.

### Cost expectations

Default memory 1024 MB ≈ 1 compute unit per hour (~$0.20/CU planning example → ~$0.03 per 10-minute run). Typical anonymous-path runs complete in seconds to low minutes depending on lookback and caps. These are planning examples, not quotes; check your run's Usage details.

### Limitations and disclaimers

- Outputs are analytical estimates normalized from official publications — **not official settlement data**. Verify against your TSO/settlement statements before commercial decisions.
- Coverage mirrors what configured sources publish; per-row completeness counters and the OUTPUT gap register disclose holes instead of hiding them. Upstream restatements are detected via overlap windows within retained state.
- No FX conversion: EUR values are used as published and original-currency values preserved alongside.
- This Actor is not investment, trading, regulatory, or financial advice, and makes no accuracy or fitness guarantees. Source figures inherit each platform's own disclaimers.

### Local development

```bash
npm ci
npm run lint
npm run typecheck
npm run build
npm test            # unit/integration/adversarial/schema/smoke (no network)
npm run smoke:live  # LIVE_SMOKE=1 real EnergiDataService smoke
npm audit --omit=dev && npm audit
apify validate-schema
```

### Data source attribution

Data: [Energinet Energi Data Service](https://www.energidataservice.dk/) (CC BY 4.0 — "Source: Energinet") and [ENTSO-E Transparency Platform](https://transparency.entsoe.eu/) when the user supplies a token. Attribution objects ship with every dataset row and every OUTPUT record; review each platform's current terms for your use case. This Actor does not claim ownership of source data.

# Actor input Schema

## `mode` (type: `string`):

Full emits a snapshot; incremental emits only new/updated intervals; diff also emits unchanged intervals.

## `zones` (type: `array`):

Bidding-zone codes. EnergiDataService covers DK1/DK2. ENTSO-E defaults exist for DK1, DK2, DE-LU, AT, NL, BE, FI, ES; other zones are skipped with a note.

## `sources` (type: `array`):

energidataservice is anonymous (CC BY 4.0). entsoe-tp requires your free registered security token.

## `products` (type: `array`):

Empty emits every available product. Products: imbalance, aFRR-VWA-up, aFRR-VWA-down, mFRR-marginal-up, mFRR-marginal-down, mFRR-SA-up, mFRR-SA-down, mFRR-DA-up, mFRR-DA-down, aFRR-activation, activated-price, activated-quantity, procured-quantity, procured-price.

## `windowFrom` (type: `string`):

YYYY-MM-DD or YYYY-MM-DDTHH:MMZ; defaults to lookbackHours before the window end.

## `windowTo` (type: `string`):

Defaults to the current top of the hour.

## `lookbackHours` (type: `integer`):

Window length when windowFrom is not given.

## `overlapHours` (type: `integer`):

Recheck this many hours before the watermark so late upstream revisions are detected.

## `includeAfrrSecondResolution` (type: `boolean`):

Adds EnergiDataService AfrrEnergyActivation (1-second samples averaged per UTC quarter-hour). Heavier; keep windows short.

## `entsoeSecurityToken` (type: `string`):

Your registered token from transparency.entsoe.eu. Required only when entsoe-tp is selected.

## `entsoeDocumentTypes` (type: `array`):

A85 activated prices, A86 procured quantities, A87 procured prices, A83 activated quantities.

## `entsoeBusinessType` (type: `string`):

Optional official business-type code (for example A25 or A43) appended to ENTSO-E queries.

## `milestones` (type: `array`):

Extra published regime milestones to key flags on. The built-in PICASSO go-live (2024-10-02) is always included.

## `volatility` (type: `object`):

Rolling z-score cluster detection over trailing same-product prices. Analytical estimate only.

## `maxItems` (type: `integer`):

Maximum emitted dataset rows before a bounded stop.

## `maxPagesPerDataset` (type: `integer`):

Forward page budget per source dataset in one run.

## `maxScannedRecords` (type: `integer`):

Maximum raw source records scanned in one run.

## `pageSize` (type: `integer`):

Records requested per API page.

## `stateRetentionDays` (type: `integer`):

How many days of change digests are retained.

## `maxStateEntries` (type: `integer`):

Maximum change digests kept per configuration.

## Actor input object example

```json
{
  "mode": "full",
  "zones": [
    "DK1",
    "DK2"
  ],
  "sources": [
    "energidataservice"
  ],
  "products": [],
  "lookbackHours": 24,
  "overlapHours": 6,
  "includeAfrrSecondResolution": false,
  "entsoeDocumentTypes": [
    "A85",
    "A86",
    "A87"
  ],
  "milestones": [],
  "volatility": {
    "trailingIntervals": 288,
    "zThreshold": 4,
    "enabled": true
  },
  "maxItems": 5000,
  "maxPagesPerDataset": 20,
  "maxScannedRecords": 30000,
  "pageSize": 2000,
  "stateRetentionDays": 180,
  "maxStateEntries": 5000
}
```

# Actor output Schema

## `dataset` (type: `string`):

Normalized zone x product x interval price-volume observations with regime flags and completeness counters.

## `summary` (type: `string`):

Counts, windows, gap register, regime milestones, stop reason, and attribution.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {};

// Run the Actor and wait for it to finish
const run = await client.actor("atlas-data/eu-balancing-activation-panel").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {}

# Run the Actor and wait for it to finish
run = client.actor("atlas-data/eu-balancing-activation-panel").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{}' |
apify call atlas-data/eu-balancing-activation-panel --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,atlas-data/eu-balancing-activation-panel"
        }
    }
}

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/6N4o4N17fHaHHpSaR/builds/wLMLdurfdBamVmmqt/openapi.json
