Skip to main content

Official Python client for accessing European electricity balancing market data via the Balancing Services REST API

Project description

Balancing Services Python Client

Python client library for the Balancing Services REST API. Access European electricity balancing market data with a modern, type-safe Python interface.

Features

  • Type-safe: Full type hints for better IDE support and code quality
  • Modern Python: Built with httpx and attrs for async support and clean data models
  • Auto-generated: Generated from the official OpenAPI specification
  • Comprehensive: Access to all API endpoints and data models
  • Well-documented: Inline documentation and usage examples

Installation

uv pip install balancing-services

Or with pip:

pip install balancing-services

For development, install from source:

cd clients/python
uv pip install -e .

Quick Start

from balancing_services import AuthenticatedClient
from balancing_services.api.default import (
    get_imbalance_prices,
    get_balancing_energy_bids,
)

# Create an authenticated client
client = AuthenticatedClient(
    base_url="https://api.balancing.services/v1",
    token="YOUR_API_TOKEN"
)

# Get imbalance prices for Estonia
response = get_imbalance_prices.sync_detailed(
    client=client,
    area="EE",
    period_start_at="2025-01-01T00:00:00Z",
    period_end_at="2025-01-02T00:00:00Z"
)

if response.status_code == 200:
    data = response.parsed
    print(f"Query period: {data.queried_period.start_at} to {data.queried_period.end_at}")
    for imbalance_prices in data.data:
        print(f"Area: {imbalance_prices.area}, Direction: {imbalance_prices.direction}")
        for price in imbalance_prices.prices:
            print(f"  {price.period.start_at}: {price.price} {imbalance_prices.currency}")

Authentication

To obtain an API token:

Include your token when creating the client:

from balancing_services import AuthenticatedClient

client = AuthenticatedClient(
    base_url="https://api.balancing.services/v1",
    token="YOUR_API_TOKEN"
)

Available Endpoints

Imbalance Data

  • get_imbalance_prices - Get imbalance prices for an area
  • get_imbalance_total_volumes - Get total imbalance volumes

Balancing Energy

  • get_balancing_energy_activated_volumes - Get activated balancing energy volumes
  • get_balancing_energy_prices - Get balancing energy prices
  • get_balancing_energy_bids - Get balancing energy bids (paginated)

Balancing Capacity

  • get_balancing_capacity_bids - Get balancing capacity bids (paginated)
  • get_balancing_capacity_prices - Get balancing capacity prices
  • get_balancing_capacity_procured_volumes - Get procured balancing capacity volumes

Usage Examples

Get Balancing Energy Bids with Pagination

from balancing_services import AuthenticatedClient
from balancing_services.api.default import get_balancing_energy_bids

client = AuthenticatedClient(base_url="https://api.balancing.services/v1", token="YOUR_TOKEN")

# First page
response = get_balancing_energy_bids.sync_detailed(
    client=client,
    area="EE",
    period_start_at="2025-01-01T00:00:00Z",
    period_end_at="2025-01-02T00:00:00Z",
    reserve_type="aFRR",
    limit=100
)

if response.status_code == 200:
    data = response.parsed
    print(f"Has more: {data.has_more}")

    # Process first page
    for bid_group in data.data:
        for bid in bid_group.bids:
            print(f"Bid: {bid.volume} MW @ {bid.price} {bid_group.currency}")

    # Get next page if available
    if data.has_more and data.next_cursor:
        next_response = get_balancing_energy_bids.sync_detailed(
            client=client,
            area="EE",
            period_start_at="2025-01-01T00:00:00Z",
            period_end_at="2025-01-02T00:00:00Z",
            reserve_type="aFRR",
            cursor=data.next_cursor,
            limit=100
        )

Async Usage

import asyncio
from balancing_services import AuthenticatedClient
from balancing_services.api.default import get_imbalance_prices

async def fetch_prices():
    client = AuthenticatedClient(
        base_url="https://api.balancing.services/v1",
        token="YOUR_TOKEN"
    )

    response = await get_imbalance_prices.asyncio_detailed(
        client=client,
        area="EE",
        period_start_at="2025-01-01T00:00:00Z",
        period_end_at="2025-01-02T00:00:00Z"
    )

    if response.status_code == 200:
        return response.parsed
    return None

# Run async function
prices = asyncio.run(fetch_prices())

Error Handling

from balancing_services import AuthenticatedClient
from balancing_services.api.default import get_imbalance_prices
from balancing_services.models import Problem

client = AuthenticatedClient(base_url="https://api.balancing.services/v1", token="YOUR_TOKEN")

response = get_imbalance_prices.sync_detailed(
    client=client,
    area="EE",
    period_start_at="2025-01-01T00:00:00Z",
    period_end_at="2025-01-02T00:00:00Z"
)

if response.status_code == 200:
    data = response.parsed
    # Process successful response
elif response.status_code == 400:
    error = response.parsed
    print(f"Bad request: {error.detail}")
elif response.status_code == 401:
    print("Authentication failed - check your API token")
elif response.status_code == 429:
    print("Rate limited - please retry later")
else:
    print(f"Error {response.status_code}: {response.content}")

Data Models

All response and request models are fully typed using attrs. Key models include:

  • ImbalancePricesResponse, ImbalanceTotalVolumesResponse
  • BalancingEnergyVolumesResponse, BalancingEnergyPricesResponse, BalancingEnergyBidsResponse
  • BalancingCapacityBidsResponse, BalancingCapacityPricesResponse, BalancingCapacityVolumesResponse
  • Enums: Area, ReserveType, Direction, Currency, ActivationType, BidStatus

Development

Regenerating the Client

The client is generated from the OpenAPI specification. To regenerate:

cd clients/python
./generate.sh

Running Tests

# Install development dependencies
uv pip install -e ".[dev]"

# Run tests
pytest

# Run tests with coverage
pytest --cov=balancing_services --cov-report=html

Code Quality

# Format code
ruff format .

# Lint code
ruff check .

# Type checking
mypy balancing_services

Troubleshooting

Authentication Errors (401)

Problem: Receiving 401 Unauthorized responses

Solutions:

  • Verify your API token is correct
  • Check that the token is being passed to AuthenticatedClient
  • Ensure your token hasn't expired (contact support if needed)

Bad Request Errors (400)

Problem: Receiving 400 Bad Request responses

Common causes:

  • Invalid date range (end date before start date)
  • Date range too large
  • Invalid area code or reserve type
  • Malformed datetime strings

Solution: Check the error detail in the response for specific information:

if response.status_code == 400:
    error = response.parsed
    print(f"Error detail: {error.detail}")

Empty Results

Problem: Receiving 200 OK but no data

Possible reasons:

  • No data available for the requested period
  • Data not yet published for recent periods
  • Requesting data for a period before data collection started

Solution: Try a different time period or check if data exists for your area

Timeout Issues

Problem: Requests timing out

Solutions:

  • Increase the client timeout:
client = AuthenticatedClient(
    base_url="https://api.balancing.services/v1",
    token="YOUR_TOKEN",
    timeout=30.0  # Increase from default
)
  • Reduce the date range in your request
  • Use pagination for large datasets

Type Errors with Enums

Problem: Type errors when passing area or reserve type

Solution: Use the provided enum classes:

from balancing_services.models import Area, ReserveType

# Correct
area=Area.EE

# Incorrect
area="EE"  # String might work but not type-safe

Documentation

Support

License

MIT License - see LICENSE for details.

Changelog

See CHANGELOG.md for version history and changes.

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

balancing_services-1.0.0.tar.gz (24.1 kB view details)

Uploaded Source

Built Distribution

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

balancing_services-1.0.0-py3-none-any.whl (55.1 kB view details)

Uploaded Python 3

File details

Details for the file balancing_services-1.0.0.tar.gz.

File metadata

  • Download URL: balancing_services-1.0.0.tar.gz
  • Upload date:
  • Size: 24.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.3

File hashes

Hashes for balancing_services-1.0.0.tar.gz
Algorithm Hash digest
SHA256 75fd79a809a1fb4ee10da52970cacf8185c7da4bbd9380291946196f782c8ef1
MD5 584064c8946b56a12c5419911568cdd8
BLAKE2b-256 eab65528d4c75ee389c4ccee54d2317bee11a99a4b6e30e72fbd713874ec237a

See more details on using hashes here.

File details

Details for the file balancing_services-1.0.0-py3-none-any.whl.

File metadata

File hashes

Hashes for balancing_services-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 9636dfa1014ccd437e842916934903658786b548a40435dbc9271bb3e674a4f9
MD5 1c63f057c6139d2792986f6156693785
BLAKE2b-256 322f85ff01e2e88de488c84c15d61b5f1d09b81a50840bf136bc108c02e1ce56

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