Fetching Electricity Prices from OMIE with Python
Access real-time and historical day-ahead electricity prices from the Spanish electricity market operator—no API key required.
Spanish electricity prices swing from €10 to €200 per MWh within a single week. With a simple Python function, you can fetch this data directly from OMIE—no API key required—and use it for energy analytics, battery optimization, or cost forecasting.

In this article, you’ll build a reusable function to download any date range of 15-minute resolution prices for Spain and Portugal.
Questions
- Where does OMIE publish electricity price data?
- How do you download and parse a single day’s prices?
- How do you generalize this into a reusable function?
- How do you fetch multiple days efficiently?
- What are the common pitfalls to avoid?
Implementation
Finding OMIE data
OMIE publishes market data at omie.es/en/file-access-list. Navigate to:
- Day-ahead market
- Day-ahead market prices in Spain
The files follow a predictable naming pattern: marginalpdbc_YYYYMMDD.1
For example, the latest day-ahead prices might be at: https://www.omie.es/en/file-download?parents=marginalpdbc&filename=marginalpdbc_20260112.1
Download a single day
Let’s start by downloading yesterday’s prices directly:
import pandas as pd
import requests
from datetime import datetime, timedelta
yesterday = datetime.now() - timedelta(days=1)
date_str = yesterday.strftime('%Y%m%d')
url = f"https://www.omie.es/en/file-download?parents=marginalpdbc&filename=marginalpdbc_{date_str}.1" Download: https://www.omie.es/en/file-download?parents=marginalpdbc&filename=marginalpdbc_20260111.1
Let’s look at the raw content:
MARGINALPDBC; 2026;01;11;1;108.2;108.2; 2026;01;11;2;97.72;97.72; 2026;01;11;3;93.7;93.7; 2026;01;11;4;87.99;87.99; 2026;01;11;5;90;90;
This is a semicolon-separated file with a header row (“MARGINALPDBC;”). The file contains 96 rows - one for each 15-minute period of the day. The columns are year, month, day, period (1-96), price Portugal, and price Spain. Pandas can read it directly from the URL:
df_raw = pd.read_csv(
url, sep=';', skiprows=1, header=None,
names=['year', 'month', 'day', 'period', 'price_portugal', 'price_spain', '_']
)
df_raw = df_raw.dropna(subset=['period'])
Parse the data
Each period represents a 15-minute interval (period 1 = 00:00, period 2 = 00:15, etc.):
df_prices = df_raw[['period', 'price_spain', 'price_portugal']].copy()
df_prices['datetime'] = pd.to_datetime(yesterday.date()) + pd.to_timedelta((df_prices['period'] - 1) * 15, unit='m')
df_prices = df_prices.set_index('datetime')
Price summary for 2026-01-11: - Minimum: 50.25 €/MWh - Maximum: 108.20 €/MWh - Spread: 57.95 €/MWh
Visualize the daily profile

Create a reusable function
Now let’s wrap this into a function that can fetch any date:
def omie_day_ahead(date):
"""
Fetch day-ahead electricity prices from OMIE for a specific date.
Parameters:
date: datetime object
Returns:
DataFrame with columns: period, price_spain, price_portugal (96 rows per day)
Returns None if data unavailable
"""
date_str = date.strftime('%Y%m%d')
url = f"https://www.omie.es/en/file-download?parents=marginalpdbc&filename=marginalpdbc_{date_str}.1"
try:
df = pd.read_csv(url, sep=';', skiprows=1, header=None,
names=['year', 'month', 'day', 'period', 'price_portugal', 'price_spain', '_'])
df = df.dropna(subset=['period'])
df['datetime'] = pd.to_datetime(date.date()) + pd.to_timedelta((df['period'] - 1) * 15, unit='m')
return df.set_index('datetime')[['period', 'price_spain', 'price_portugal']]
except Exception:
return None Test with a few different dates:
df_yesterday = omie_day_ahead(datetime.now() - timedelta(days=1))
df_week_ago = omie_day_ahead(datetime.now() - timedelta(days=7))
df_future = omie_day_ahead(datetime.now() + timedelta(days=7)) - Yesterday: 96 periods (96 = 24 hours × 4)
- Week ago: 96 periods
- Future date: 0 periods (expected - data not yet available)
Fetch multiple days
For analysis spanning weeks or months, we need to fetch a date range:
import time
def omie_day_ahead_range(start_date, end_date, delay=0.1):
"""
Fetch OMIE prices for a date range.
Parameters:
start_date: First date to fetch
end_date: Last date to fetch (inclusive)
delay: Seconds between requests (be nice to the server)
Returns:
DataFrame with all available data
"""
all_data = []
current = start_date
while current <= end_date:
df = omie_day_ahead(current)
if df is not None:
all_data.append(df)
current += timedelta(days=1)
time.sleep(delay)
if not all_data:
return None
return pd.concat(all_data) end = datetime.now() - timedelta(days=1)
start = end - timedelta(days=6)
df_week = omie_day_ahead_range(start, end) Fetched 672 periods across 7 days.

Common pitfalls
- Period numbering: OMIE uses periods 1-96 (15-minute intervals). Period 1 = 00:00, period 96 = 23:45.
- Data availability: Day D prices are published around 13:00 CET on day D-1. Don’t fetch today’s prices before they exist.
- Rate limiting: Add delays between requests when fetching many days. OMIE may block aggressive scrapers.
- DST transitions: On daylight saving time change days, you’ll get 92 or 100 periods instead of 96.
Conclusions
OMIE electricity price data is freely accessible via predictable URLs:
- Single day:
https://www.omie.es/en/file-download?parents=marginalpdbc&filename=marginalpdbc_YYYYMMDD.1 - Format: Semicolon-separated, 96 periods per day (15-minute resolution)
- Coverage: Spain and Portugal day-ahead prices
With this data, you can build energy analytics applications: