Bisher nimmt dein Optimierer Preise als gegeben und erzeugt einen Fahrplan. Aber in der Realität kennst du die Preise von morgen nicht, wenn du bietest. Die Day-Ahead-Auktion clearet alle Gebote gleichzeitig — dein Gebot beeinflusst den Preis. Diese Lektion zeigt, wie der Day-Ahead-Markt tatsächlich funktioniert und wie du die Ausgabe deines Optimierers in gültige Börsengebote übersetzt.
Die EPEX-SPOT-Day-Ahead-Auktion (verwendet in Zentral-/Westeuropa) funktioniert so:
Du gibst ein Preis-Mengen-Paar für jede Stunde ab. Beispiel: „Ich kaufe 10 MW in Stunde 3, wenn Preis ≤ €25/MWh" oder „Ich verkaufe 10 MW in Stunde 17, wenn Preis ≥ €60/MWh."
Für eine Batterie gibst du zwei Gebote pro Stunde ab:
Ein Blockgebot ist ein Alles-oder-Nichts-Gebot über mehrere aufeinanderfolgende Stunden. Beispiel: „Kaufe 10 MW für Stunden 1–4 zum Durchschnittspreis ≤ €22/MWh — akzeptiere alle Stunden oder keine." Nützlich für Batterien, weil Laden eine Sequenz von Stunden braucht, nicht nur eine.
Eltern-Kind-Verknüpfungen: „Akzeptiere mein Entlade-Block (Stunden 17–19) nur, wenn mein Lade-Block (Stunden 2–5) ebenfalls akzeptiert wurde." Das stellt sicher, dass die Batterie Energie hat, bevor sie verkauft.
Der einfachste Ansatz — und der von den meisten BESS-Betreibern in der Praxis verwendete:
"""
day_ahead_gebote.py — Erzeuge Börsengebote aus Optimierer-Ergebnis
"""
import pyomo.environ as pyo
import numpy as np
import pandas as pd
# ... (Modell aus Lektion 3, gelöst) ...
# Annahme: Modell ist gelöst, Fahrplan-DataFrame existiert
# --- Gebotserzeugung ---
preis_prognose = preise # In Produktion: aus deinem Prognosemodell
marge = 2.0 # €/MWh — Gebotsmarge (Toleranz für Prognosefehler)
gebote = []
for t in range(T):
laden_mw = round(pyo.value(model.p_laden[t]), 2)
entladen_mw = round(pyo.value(model.p_entladen[t]), 2)
if laden_mw > 0.1: # Ladestunde
# Kaufgebot: bereit bis Prognose + Marge zu zahlen
gebote.append({
'stunde': t,
'richtung': 'KAUF',
'menge_mw': laden_mw,
'preis_eur_mwh': round(preis_prognose[t] + marge, 2),
'typ': 'stündlich'
})
elif entladen_mw > 0.1: # Entladestunde
# Verkaufsgebot: bereit ab Prognose - Marge zu verkaufen
gebote.append({
'stunde': t,
'richtung': 'VERKAUF',
'menge_mw': entladen_mw,
'preis_eur_mwh': round(preis_prognose[t] - marge, 2),
'typ': 'stündlich'
})
gebot_df = pd.DataFrame(gebote)
print(gebot_df.to_string(index=False))
Wenn der Clearing-Preis zwischen deinen Kauf- und Verkaufsgeboten liegt, werden manche Stunden nicht gecleart. Dein Fahrplan ist dann teilweise gefüllt. Das ist ein Problem: vielleicht wurden nur die Ladestunden gecleart, aber nicht die Entladestunden. Du sitzt mit einer vollen Batterie ohne Verkaufsposition da.
Lösungen:
# Preisnehmer: Annahme garantieren, jeden Clearing-Preis akzeptieren
preisnehmer_gebote = []
for t in range(T):
laden_mw = round(pyo.value(model.p_laden[t]), 2)
entladen_mw = round(pyo.value(model.p_entladen[t]), 2)
if laden_mw > 0.1:
preisnehmer_gebote.append({
'stunde': t,
'richtung': 'KAUF',
'menge_mw': laden_mw,
'preis_eur_mwh': 3000.00, # Maximum erlaubt — immer angenommen
'typ': 'stündlich'
})
elif entladen_mw > 0.1:
preisnehmer_gebote.append({
'stunde': t,
'richtung': 'VERKAUF',
'menge_mw': entladen_mw,
'preis_eur_mwh': -500.00, # Minimum erlaubt — immer angenommen
'typ': 'stündlich'
})
┌─────────────────────────────────────────────────┐
│ D-1, morgens: Preisprognose empfangen │
│ ↓ │
│ Optimierer ausführen → Fahrplan erhalten │
│ ↓ │
│ Gebote erzeugen (stündlich oder Block) │
│ ↓ │
│ An Börse senden vor 12:00 MEZ │
│ ↓ │
│ ~12:42: Clearing-Ergebnisse empfangen │
│ ↓ │
│ Angenommene vs. abgelehnte Gebote prüfen │
│ ↓ │
│ Bei Teilfüllung → im Intraday korrigieren │
└─────────────────────────────────────────────────┘
Eine Batterie gibt ein VERKAUF-Gebot bei €65/MWh für Stunde 18 ab. Der Clearing-Preis ist €72/MWh. Was passiert?
Warum könnte ein Batteriebetreiber verknüpfte Blockgebote statt unabhängiger Stundengebote verwenden?
Was ist das Hauptrisiko bei Preisnehmer-Geboten (Kauf bei €3000, Verkauf bei -€500)?
EPEX SPOT — Day-Ahead-Handelsprodukte — offizielle Dokumentation zu stündlichen Geboten, Blockgeboten, verknüpften Blöcken und Clearing-Regeln.
Rechtliches: Impressum