Teil IV: Anwendungen — Energiewirtschaft und Finanzmärkte
Dieser Teil wechselt die Domäne — aber nicht die Methoden. Was hier folgt, ist die konsequente Anwendung dessen, was Sie in den Teilen II und III gelernt haben, auf zwei Gebiete, in denen viel Unsicherheit auf ein unmittelbar messbares Ergebnis trifft: die Energiewirtschaft und die Finanzmärkte.
Er hat drei Abschnitte, und Sie können nach jedem aufhören:
- Die Brücke (Kapitel 16) macht die Behauptung nachprüfbar, dass es dieselben Methoden sind. Sie lässt denselben Code einmal über eine Werkstatt und einmal über ein Depot laufen — und benennt die drei Stellen, an denen die Analogie endet.
- Die Industrieanwendung (Kapitel 17) führt die Werkzeuge an einem zusammenhängenden Fall aus der Energiewirtschaft zusammen: Kraftwerkseinsatzplanung unter Windunsicherheit. Wer mit Produktion, Logistik oder Energie zu tun hat, findet hier die Vertiefung, die für die Finanzkapitel keinen Ersatz braucht.
- Die Finanzanwendung (ab Kapitel 18) ist die spezialisierte Vertiefungsdomäne.
📌 Für wen dieser Teil gedacht ist
Die Finanzkapitel ab Kapitel 18 sind eine Vertiefungsdomäne, kein Pflichtstoff. Wer beruflich mit Logistik, Produktion oder Energie zu tun hat, liest die ersten beiden Kapitel dieses Teils und kann den Rest überspringen, ohne dass etwas fehlt — die Methoden sind dieselben.
Lesen Sie ihn trotzdem, wenn Sie eines der folgenden Themen brauchen: Schätzfehler in Kovarianzmatrizen (das Problem tritt bei jeder Korrelationsschätzung auf, auch bei Lieferzeiten), Risikomaße jenseits der Standardabweichung, oder rollierende Auswertung mit sauberer Trennung von Trainings- und Testzeitraum.
Ein Hinweis vorweg: Die Kapitel ab Kapitel 18 laden aktuelle Kursdaten über yfinance und brauchen dafür einen Internetzugang. Weil die Daten sich täglich ändern, sind die abgedruckten Zahlen dort Beispielläufe, keine reproduzierbaren Werte — anders als im übrigen Buch. Das Brückenkapitel kommt ohne Internet aus.
Kapitel 16: Die Strukturbrücke — dieselbe Mathematik, zwei Welten
📌 Kapitel auf einen Blick
Worum geht es? Um den Nachweis, dass die Verfahren aus Teil II und III unverändert in der Finanzwelt funktionieren — und um die drei Stellen, an denen die Analogie endet.
Voraussetzungen: Kapitel 1 (Allokation als LP), Kapitel 12 (Szenarien) und Abschnitt 22.6 (
or_kern.py).Danach können Sie: ein betriebswirtschaftliches Modell in die andere Domäne übersetzen, ohne den Modellcode anzufassen; Schattenpreise in beiden Welten lesen; und benennen, welche Annahmen dabei nicht mitwandern.
Zeitbedarf: ca. 2,5 Stunden.
Programme:
Strukturbruecke.pyNotebook: bruecke.ipynb
In Google Colab öffnen
16.1 In 5 Minuten gelöst
🚀 In 5 Minuten gelöst: Was ist ein Risikobudget?
Ein Anleger hat 150 000 € und will sie auf drei Anlageklassen verteilen. Neben dem Kapital gibt es eine zweite knappe Größe: das Risikobudget — eine Kennzahl, die die Bankaufsicht oder das eigene Regelwerk vorgibt und die jede Anlage unterschiedlich stark beansprucht.
Anlage Ertrag je 1 000 € Kapital Risikobudget Aktien Welt 75 € 1,0 1,00 Anleihen 28 € 1,0 0,22 Immobilienfonds 46 € 1,0 0,55 verfügbar 150 90 Lesen Sie die Tabelle noch einmal — und ersetzen Sie „Kapital” durch „Montagestunden” und „Risikobudget” durch „Plattenmaterial”. Es ist die Schreinerei aus Kapitel 1, Wort für Wort.
Deshalb genügt der vorhandene Code:
from or_kern import Produkt, Produktionsproblem, loese_mit_scipy depot = Produktionsproblem( produkte=[ Produkt(name="Aktien Welt", deckungsbeitrag=75.0, verbrauch={"Kapital (Tsd. EUR)": 1.0, "Risikobudget": 1.00}), Produkt(name="Anleihen", deckungsbeitrag=28.0, verbrauch={"Kapital (Tsd. EUR)": 1.0, "Risikobudget": 0.22}), Produkt(name="Immobilienfonds", deckungsbeitrag=46.0, verbrauch={"Kapital (Tsd. EUR)": 1.0, "Risikobudget": 0.55}), ], kapazitaeten={"Kapital (Tsd. EUR)": 150.0, "Risikobudget": 90.0}) loesung = loese_mit_scipy(depot) print(loesung.als_bericht()) print(loesung.schattenpreise)Ausgabe:
Status: optimal | Zielwert: 7,634.62 | Gap: 0.00% | Zeit: 0.00s {'Kapital (Tsd. EUR)': 14.74, 'Risikobudget': 60.26}
Und jetzt der Punkt. Die Klasse heißt Produktionsproblem, und das Depot passt hinein, ohne dass eine Zeile geändert wurde. Kein Adapter, keine Unterklasse, keine Fallunterscheidung — die Struktur ist dieselbe, weil das Problem dasselbe ist: knappe Größen auf konkurrierende Verwendungen verteilen.
Der interessanteste Teil steht in der zweiten Zeile der Ausgabe. 60,26 € je Einheit Risikobudget — das ist der Dualwert derselben Nebenbedingung, die in der Werkstatt sagt, was eine zusätzliche Montagestunde wert wäre. In der Finanzwelt hat diese Zahl einen eigenen Namen: der Preis des Risikos. Es ist nicht bloß eine Analogie, es ist derselbe Schattenpreis aus Kapitel 5.
🎯 Merksatz Wenn zwei Probleme dieselbe Struktur haben, brauchen sie nicht zwei Modelle, sondern zwei Datensätze. Ob das der Fall ist, erkennt man daran, dass derselbe Code ohne Änderung läuft — nicht daran, dass eine Tabelle es behauptet.
Warum funktioniert das? Weil ein LP nichts über die Bedeutung seiner Zahlen weiß. Es sieht eine Matrix, einen Kapazitätsvektor und einen Zielvektor. Ob in der Matrix Stunden, Kilogramm oder Risikobeiträge stehen, kommt darin nicht vor.
16.2 Lernziele
Nach diesem Kapitel können Sie …
- … ein Allokationsproblem aus der einen Domäne in die andere übersetzen, indem Sie die Daten austauschen statt des Codes.
- … den Schattenpreis in beiden Welten deuten — als Wert einer Ressource und als Preis des Risikos.
- … erklären, warum die CVaR-Formulierung aus Kapitel 20 auf Lieferverzüge genauso passt wie auf Kursverluste.
- … die drei Stellen benennen, an denen die Analogie nicht trägt — und begründen, warum das Übertragen von Methoden dort gefährlich wird.
16.3 Das Programm
#!/usr/bin/env python3
# Strukturbruecke.py
"""
Kapitel Bruecke: Derselbe Code, zwei Welten - der Beweis statt der Behauptung.
Der Teil-Auftakt stellt eine Tabelle auf: "Ressourcen auf Produkte verteilen"
entspreche "Kapital auf Anlagen verteilen", "gegen den Worst Case absichern"
entspreche "Absicherung gegen Kursabstuerze". Solche Tabellen stehen in vielen
Buechern. Sie sind billig - und man kann sie pruefen.
Dieses Programm prueft sie. Es fuettert zweimal DENSELBEN Code mit Daten aus
zwei Welten und zeigt die Ergebnisse nebeneinander:
1. Die Allokation als LP. Das Domaenenmodell aus or_kern.py, einmal mit einer
Schreinerei (Montagestunden, Plattenmaterial) und einmal mit einem Depot
(Kapital, Risikobudget). Gleiche Klasse, gleicher Modellbauer, gleiche
Abnahmepruefung - und der Schattenpreis heisst in der einen Welt
"Wert einer zusaetzlichen Montagestunde" und in der anderen "Preis des
Risikos".
2. Die Absicherung gegen den schlechtesten Fall als CVaR. EINE Funktion,
einmal mit Kursrenditen und einmal mit Lieferverzuegen.
3. Was NICHT hinueberreicht. Der ehrliche Teil: Drei Unterschiede, die die
Analogie begrenzen - und die man kennen muss, bevor man Methoden aus
der einen Welt in die andere traegt.
ZUR SOLVERWAHL: Teil 1 benutzt 'loese_mit_scipy' und nicht 'loese_mit_glop'.
Das ist kein Zufall - CVXPY laedt fuer Teil 2 highspy, und ortools vertraegt
sich damit nicht im selben Prozess (Kapitel Oekosystem). Wer hier GLOP nimmt,
bekommt beim cvxpy-Import eine Fehlermeldung ueber ein 'undefined symbol'.
Genau deshalb laedt or_kern.py seine Solver erst beim Aufruf.
Benoetigt: numpy, cvxpy, scipy und pydantic (ueber or_kern)
"""
from __future__ import annotations
import numpy as np
from or_kern import (Produkt, Produktionsproblem, loese_mit_scipy,
pruefe_loesung)
SAAT = 7
SZENARIEN = 500
ALPHA = 0.95 # die schlechtesten 5 % der Faelle
MAX_ANTEIL = 0.40 # Streuungsgebot in beiden Welten
# --- Teil 1: Dieselbe Klasse, zwei Welten ----------------------------------
def schreinerei() -> Produktionsproblem:
"""Montagestunden und Plattenmaterial auf Tische und Stuehle verteilen."""
return Produktionsproblem(
produkte=[
Produkt(name="Tisch", deckungsbeitrag=240.0,
verbrauch={"Montagestunden": 3.0, "Plattenmaterial": 6.0}),
Produkt(name="Stuhl", deckungsbeitrag=60.0,
verbrauch={"Montagestunden": 1.0, "Plattenmaterial": 1.0}),
Produkt(name="Regal", deckungsbeitrag=130.0,
verbrauch={"Montagestunden": 2.0, "Plattenmaterial": 4.0}),
],
kapazitaeten={"Montagestunden": 150.0, "Plattenmaterial": 240.0})
def depot() -> Produktionsproblem:
"""Kapital und Risikobudget auf Anlageklassen verteilen.
Eine "Einheit" ist hier 1.000 EUR Anlagesumme. Der Deckungsbeitrag ist der
erwartete Jahresertrag dieser Einheit, der Verbrauch die beanspruchte
Kapital- und Risikomenge. Das ist keine Analogie, sondern buchstaeblich
dasselbe Modell - deshalb passt es in dieselbe Klasse.
"""
return Produktionsproblem(
produkte=[
Produkt(name="Aktien Welt", deckungsbeitrag=75.0,
verbrauch={"Kapital (Tsd. EUR)": 1.0, "Risikobudget": 1.00}),
Produkt(name="Anleihen", deckungsbeitrag=28.0,
verbrauch={"Kapital (Tsd. EUR)": 1.0, "Risikobudget": 0.22}),
Produkt(name="Immobilienfonds", deckungsbeitrag=46.0,
verbrauch={"Kapital (Tsd. EUR)": 1.0, "Risikobudget": 0.55}),
],
kapazitaeten={"Kapital (Tsd. EUR)": 150.0, "Risikobudget": 90.0})
def berichte_allokation(titel: str, problem: Produktionsproblem,
einheit: str, ertragsname: str) -> None:
"""Ein Bericht fuer beide Welten - nur die Beschriftung wechselt."""
loesung = loese_mit_scipy(problem)
beanstandungen = pruefe_loesung(problem, loesung)
print(f" {titel}")
print(f" {loesung.als_bericht()}")
for produkt in problem.produkte:
print(f" {produkt.name:<18} {loesung.werte[produkt.name]:8.2f} {einheit}")
print(f" {ertragsname:<18} {loesung.zielwert:8.2f} EUR")
for ressource, preis in loesung.schattenpreise.items():
print(f" Schattenpreis {ressource:<24} {preis:7.2f} EUR")
print(f" Abnahmepruefung: "
f"{'bestanden' if not beanstandungen else beanstandungen}")
# --- Teil 2: Eine CVaR-Funktion, zwei Welten -------------------------------
def optimiere_cvar(verluste: np.ndarray, ertrag: np.ndarray,
mindestertrag: float, alpha: float = ALPHA,
max_anteil: float = MAX_ANTEIL):
"""Minimiert den CVaR der Verluste unter einer Mindestertragsbedingung.
'verluste' hat die Form (Szenarien x Optionen) und enthaelt, was in
Szenario s passiert, wenn eine Einheit in Option j steckt. Was ein
"Verlust" ist, entscheidet allein die Einheit der Matrix: Prozentpunkte
Kursverlust oder Tage Lieferverzug - die Formel sieht keinen Unterschied.
Das ist die Rockafellar-Uryasev-Formulierung aus dem Kapitel CVaR, hier
ohne jede Aenderung wiederverwendet.
"""
import cvxpy as cp
anzahl_szenarien, anzahl_optionen = verluste.shape
anteil = cp.Variable(anzahl_optionen, nonneg=True)
schwelle = cp.Variable() # wird im Optimum zum VaR
ueberschuss = cp.Variable(anzahl_szenarien, nonneg=True)
cvar = schwelle + (1.0 / (anzahl_szenarien * (1 - alpha))) * cp.sum(ueberschuss)
problem = cp.Problem(
cp.Minimize(cvar),
[ueberschuss >= verluste @ anteil - schwelle,
cp.sum(anteil) == 1,
anteil <= max_anteil,
ertrag @ anteil >= mindestertrag])
problem.solve()
if problem.status not in ("optimal", "optimal_inaccurate"):
raise SystemExit(f"CVaR-Problem nicht loesbar: {problem.status}")
return anteil.value, float(cvar.value), float(schwelle.value)
def kursszenarien(rng) -> tuple[np.ndarray, np.ndarray, list[str]]:
"""Taegliche Verluste (negative Renditen) von sechs Anlageklassen."""
namen = ["Aktien Welt", "Aktien EU", "Schwellenlaender",
"Staatsanleihen", "Unternehmensanl.", "Rohstoffe"]
rendite_pa = np.array([0.080, 0.065, 0.110, 0.025, 0.045, 0.070])
schwankung = np.array([0.180, 0.160, 0.260, 0.040, 0.075, 0.210])
taeglich = rng.normal(rendite_pa / 252, schwankung / np.sqrt(252),
(SZENARIEN, len(namen)))
return -taeglich * 100.0, rendite_pa * 100.0, namen
def lieferszenarien(rng) -> tuple[np.ndarray, np.ndarray, list[str]]:
"""Lieferverzug in Tagen bei sechs Lieferanten.
Der Aufbau ist bewusst anders als bei den Kursen: Hier gibt es einen
normalen Verzug UND seltene Totalausfaelle, die 14 Tage kosten. Das ist
genau die Art fetter Raender, wegen der man in beiden Welten CVaR statt
Standardabweichung benutzt.
"""
namen = ["Nordwerk", "Sued-Metall", "Fernost A", "Lokalzulieferer",
"Fernost B", "Osteuropa"]
zuverlaessigkeit = np.array([0.94, 0.97, 0.90, 0.99, 0.92, 0.95])
verzugsstreuung = np.array([3.5, 1.8, 5.0, 0.9, 4.2, 2.8])
normaler_verzug = np.maximum(0.0, rng.normal(0.5, 1.0, (SZENARIEN, len(namen)))
* verzugsstreuung)
totalausfall = (rng.random((SZENARIEN, len(namen))) > zuverlaessigkeit) * 14.0
return normaler_verzug + totalausfall, zuverlaessigkeit, namen
def berichte_cvar(titel: str, verluste, ertrag, namen, mindestertrag,
einheit: str, ertragsname: str):
anteile, cvar, var = optimiere_cvar(verluste, ertrag, mindestertrag)
mittel = float((verluste @ anteile).mean())
print(f" {titel}")
print(f" VaR {ALPHA:.0%}: {var:8.3f} {einheit}")
print(f" CVaR {ALPHA:.0%}: {cvar:8.3f} {einheit} "
f"(Mittelwert ueber alle Szenarien: {mittel:.3f})")
print(f" {ertragsname}: {float(ertrag @ anteile):.3f}")
print(" Aufteilung:")
for name, anteil in zip(namen, anteile):
balken = "#" * int(round(anteil * 40))
grenze = " <- an der Streuungsgrenze" if anteil > MAX_ANTEIL - 1e-4 else ""
print(f" {name:<18} {anteil:6.1%} {balken}{grenze}")
return anteile
if __name__ == "__main__":
rng = np.random.default_rng(SAAT)
print("=" * 80)
print(" DIESELBE STRUKTUR, ZWEI WELTEN")
print("=" * 80)
# --- Teil 1 ----------------------------------------------------------
print("\n1. Allokation als LP - EINE Klasse, EIN Modellbauer\n")
berichte_allokation("Werkstatt: Produktionsprogramm", schreinerei(),
"Stueck", "Deckungsbeitrag")
print()
berichte_allokation("Depot: Anlageaufteilung", depot(),
"Tsd. ", "Erwarteter Ertrag")
print("\n Beide Ausgaben stammen aus derselben Funktion "
"'berichte_allokation'.")
print(" Ausgetauscht wurden nur die Daten und die Beschriftungen -")
print(" keine Zeile Modellcode.")
print()
print(" Lesen Sie die Schattenpreise nebeneinander: In der Werkstatt sagt")
print(" er, was eine zusaetzliche Montagestunde wert waere. Im Depot sagt")
print(" dieselbe Zahl, was eine zusaetzliche Einheit Risikobudget wert")
print(" waere - der PREIS DES RISIKOS. Das ist kein Sprachbild, sondern")
print(" derselbe Dualwert derselben Nebenbedingung.")
# --- Teil 2 ----------------------------------------------------------
print("\n" + "-" * 80)
print("2. Absicherung gegen den schlechtesten Fall - EINE CVaR-Funktion\n")
kurse, rendite, anlagen = kursszenarien(rng)
anteile_depot = berichte_cvar(
"Depot: die schlechtesten 5 % der Handelstage",
kurse, rendite, anlagen, 5.5,
"% je Tag ", "Erwartete Jahresrendite (%)")
print()
lieferung, zuverlaessig, lieferanten = lieferszenarien(rng)
anteile_einkauf = berichte_cvar("Einkauf: die schlechtesten 5 % der Bestellungen",
lieferung, zuverlaessig, lieferanten, 0.945,
"Tage Verzug ", "Mittlere Zuverlaessigkeit")
print("\n Auch hier: eine Funktion, zwei Aufrufe. Die Zielfunktion")
print(" interessiert sich nicht dafuer, ob in der Matrix Prozentpunkte")
print(" oder Tage stehen.")
print()
print(f" Interessant ist, WO die Streuungsgrenze von {MAX_ANTEIL:.0%} bindet:")
print(f" Depot : {(anteile_depot > MAX_ANTEIL - 1e-4).sum()} von "
f"{len(anteile_depot)} Posten am Anschlag")
print(f" Einkauf : {(anteile_einkauf > MAX_ANTEIL - 1e-4).sum()} von "
f"{len(anteile_einkauf)} Posten am Anschlag")
print()
print(" Im Einkauf zieht es die Loesung an den sicheren Lokalzulieferer,")
print(" bis die Grenze sie stoppt. Im Depot nicht - dort verhindert die")
print(" Mindestrendite, dass alles in Anleihen wandert. Zwei verschiedene")
print(" Bremsen also, und sie stehen an verschiedenen Stellen des Modells:")
print(" einmal in einer Nebenbedingung ueber die Anteile, einmal in einer")
print(" ueber den Ertrag. Wer eine Struktur uebertraegt, uebertraegt eben")
print(" nicht automatisch mit, WELCHE Bedingung am Ende bindet.")
# --- Teil 3: Der ehrliche Teil ---------------------------------------
print("\n" + "=" * 80)
print(" WAS NICHT HINUEBERREICHT")
print("=" * 80)
print("Die Struktur traegt. Drei Unterschiede tragen NICHT mit, und wer sie")
print("uebersieht, macht aus einer nuetzlichen Analogie einen Fehler:")
print()
print("1. WOHER DIE ZAHLEN KOMMEN.")
print(" In der Werkstatt ist der Verbrauch je Tisch gemessen - drei")
print(" Montagestunden sind drei Montagestunden. Im Depot ist die")
print(" erwartete Rendite GESCHAETZT, und zwar mit einem Fehler, der")
print(" groesser sein kann als die Unterschiede zwischen den Anlagen")
print(" (Kapitel Markowitz, Renditeschaetzung_Falle.py). Dieselbe")
print(" Optimierung ist im einen Fall Planung und im anderen")
print(" Fehlerverstaerkung.")
print()
print("2. OB DIE VERGANGENHEIT ETWAS UEBER DIE ZUKUNFT SAGT.")
print(" Lieferzeiten haben physikalische Ursachen: Entfernung, Zoll,")
print(" Kapazitaet. Sie aendern sich langsam und nachvollziehbar.")
print(" Kursrenditen entstehen aus dem Verhalten von Marktteilnehmern,")
print(" die selbst auf Modelle reagieren - dort verschwindet ein")
print(" erkanntes Muster oft genau deshalb, weil es erkannt wurde")
print(" (Kapitel Handelsmaschine, Data_Snooping.py).")
print()
print("3. OB TEILBARKEIT ERLAUBT IST.")
print(" 37,4 % eines Aktienfonds sind ein normaler Auftrag. 37,4 % eines")
print(" Lieferanten sind es nicht - Vertraege, Mindestabnahmen und")
print(" Ruestzeiten machen Einkaufsentscheidungen ganzzahlig. Genau")
print(" deshalb ist Teil II voller MILP und Teil V fast frei davon.")
print()
print("Die Bruecke traegt also die MODELLE, nicht die Annahmen. Wer sie")
print("benutzt, spart sich das Lernen der Methoden - nicht das Nachdenken")
print("ueber die Daten.")
print("=" * 80)Erwartete Ausgabe:
================================================================================
DIESELBE STRUKTUR, ZWEI WELTEN
================================================================================
1. Allokation als LP - EINE Klasse, EIN Modellbauer
Werkstatt: Produktionsprogramm
Status: optimal | Zielwert: 10,800.00 | Gap: 0.00% | Zeit: 0.00s
Tisch 30.00 Stueck
Stuhl 60.00 Stueck
Regal 0.00 Stueck
Deckungsbeitrag 10800.00 EUR
Schattenpreis Montagestunden 40.00 EUR
Schattenpreis Plattenmaterial 20.00 EUR
Abnahmepruefung: bestanden
Depot: Anlageaufteilung
Status: optimal | Zielwert: 7,634.62 | Gap: 0.00% | Zeit: 0.00s
Aktien Welt 73.08 Tsd.
Anleihen 76.92 Tsd.
Immobilienfonds 0.00 Tsd.
Erwarteter Ertrag 7634.62 EUR
Schattenpreis Kapital (Tsd. EUR) 14.74 EUR
Schattenpreis Risikobudget 60.26 EUR
Abnahmepruefung: bestanden
Beide Ausgaben stammen aus derselben Funktion 'berichte_allokation'.
Ausgetauscht wurden nur die Daten und die Beschriftungen -
keine Zeile Modellcode.
Lesen Sie die Schattenpreise nebeneinander: In der Werkstatt sagt
er, was eine zusaetzliche Montagestunde wert waere. Im Depot sagt
dieselbe Zahl, was eine zusaetzliche Einheit Risikobudget wert
waere - der PREIS DES RISIKOS. Das ist kein Sprachbild, sondern
derselbe Dualwert derselben Nebenbedingung.
--------------------------------------------------------------------------------
2. Absicherung gegen den schlechtesten Fall - EINE CVaR-Funktion
Depot: die schlechtesten 5 % der Handelstage
VaR 95%: 0.521 % je Tag
CVaR 95%: 0.644 % je Tag (Mittelwert ueber alle Szenarien: -0.011)
Erwartete Jahresrendite (%): 5.500
Aufteilung:
Aktien Welt 14.9% ######
Aktien EU 12.2% #####
Schwellenlaender 9.6% ####
Staatsanleihen 26.8% ###########
Unternehmensanl. 30.7% ############
Rohstoffe 5.7% ##
Einkauf: die schlechtesten 5 % der Bestellungen
VaR 95%: 4.351 Tage Verzug
CVaR 95%: 5.716 Tage Verzug (Mittelwert ueber alle Szenarien: 2.072)
Mittlere Zuverlaessigkeit: 0.963
Aufteilung:
Nordwerk 12.6% #####
Sued-Metall 22.1% #########
Fernost A 6.2% ##
Lokalzulieferer 40.0% ################ <- an der Streuungsgrenze
Fernost B 8.7% ###
Osteuropa 10.4% ####
Auch hier: eine Funktion, zwei Aufrufe. Die Zielfunktion
interessiert sich nicht dafuer, ob in der Matrix Prozentpunkte
oder Tage stehen.
Interessant ist, WO die Streuungsgrenze von 40% bindet:
Depot : 0 von 6 Posten am Anschlag
Einkauf : 1 von 6 Posten am Anschlag
Im Einkauf zieht es die Loesung an den sicheren Lokalzulieferer,
bis die Grenze sie stoppt. Im Depot nicht - dort verhindert die
Mindestrendite, dass alles in Anleihen wandert. Zwei verschiedene
Bremsen also, und sie stehen an verschiedenen Stellen des Modells:
einmal in einer Nebenbedingung ueber die Anteile, einmal in einer
ueber den Ertrag. Wer eine Struktur uebertraegt, uebertraegt eben
nicht automatisch mit, WELCHE Bedingung am Ende bindet.
================================================================================
WAS NICHT HINUEBERREICHT
================================================================================
Die Struktur traegt. Drei Unterschiede tragen NICHT mit, und wer sie
uebersieht, macht aus einer nuetzlichen Analogie einen Fehler:
1. WOHER DIE ZAHLEN KOMMEN.
In der Werkstatt ist der Verbrauch je Tisch gemessen - drei
Montagestunden sind drei Montagestunden. Im Depot ist die
erwartete Rendite GESCHAETZT, und zwar mit einem Fehler, der
groesser sein kann als die Unterschiede zwischen den Anlagen
(Kapitel Markowitz, Renditeschaetzung_Falle.py). Dieselbe
Optimierung ist im einen Fall Planung und im anderen
Fehlerverstaerkung.
2. OB DIE VERGANGENHEIT ETWAS UEBER DIE ZUKUNFT SAGT.
Lieferzeiten haben physikalische Ursachen: Entfernung, Zoll,
Kapazitaet. Sie aendern sich langsam und nachvollziehbar.
Kursrenditen entstehen aus dem Verhalten von Marktteilnehmern,
die selbst auf Modelle reagieren - dort verschwindet ein
erkanntes Muster oft genau deshalb, weil es erkannt wurde
(Kapitel Handelsmaschine, Data_Snooping.py).
3. OB TEILBARKEIT ERLAUBT IST.
37,4 % eines Aktienfonds sind ein normaler Auftrag. 37,4 % eines
Lieferanten sind es nicht - Vertraege, Mindestabnahmen und
Ruestzeiten machen Einkaufsentscheidungen ganzzahlig. Genau
deshalb ist Teil II voller MILP und Teil V fast frei davon.
Die Bruecke traegt also die MODELLE, nicht die Annahmen. Wer sie
benutzt, spart sich das Lernen der Methoden - nicht das Nachdenken
ueber die Daten.
================================================================================
16.4 Die zwei Brücken im Einzelnen
Erste Brücke: Allokation
| Werkstatt | Depot | im Modell |
|---|---|---|
| Montagestunden, Plattenmaterial | Kapital, Risikobudget | kapazitaeten |
| Tisch, Stuhl, Regal | Aktien, Anleihen, Immobilien | produkte |
| Verbrauch je Stück | Beanspruchung je 1 000 € | verbrauch |
| Deckungsbeitrag je Stück | Erwarteter Ertrag je 1 000 € | deckungsbeitrag |
| Wert einer Montagestunde | Preis des Risikos | schattenpreise |
Die letzte Zeile ist die, die sich zu merken lohnt. Ein Portfoliomanager, der sagt „unser Risikobudget ist zu knapp bemessen”, trifft dieselbe Aussage wie ein Fertigungsleiter, der eine zweite Schicht fordert — und beide können sie mit derselben Zahl belegen.
Zweite Brücke: Absicherung gegen den schlechtesten Fall
Hier ist die Übereinstimmung noch enger, weil sie nicht nur die Struktur betrifft, sondern die Formel. Die Rockafellar-Uryasev-Formulierung aus Kapitel 20
\min_{w,\;\gamma} \;\; \gamma + \frac{1}{S(1-\alpha)} \sum_{s=1}^{S} u_s \qquad \text{mit} \qquad u_s \ge \ell_s^\top w - \gamma, \quad u_s \ge 0
steht im Programm genau einmal und wird zweimal aufgerufen.
🔤 Formel-Übersetzer
Mathematik im Depot im Einkauf w Anteil je Anlageklasse Bestellanteil je Lieferant \ell_s Verlust in Szenario s, in Prozentpunkten Verzug in Szenario s, in Tagen \gamma der VaR: „so schlimm wird es an 95 % der Tage höchstens” „so viele Tage Verzug höchstens bei 95 % der Bestellungen” u_s Überschuss über diese Schwelle dasselbe Zielwert CVaR: Mittelwert der schlechtesten 5 % dasselbe Ohne Formel gesagt: „Sorge dafür, dass die schlimmsten fünf Prozent der Fälle im Mittel so glimpflich wie möglich ausgehen.” Dieser Satz enthält kein Wort, das nur an der Börse Sinn ergibt.
Beide Anwendungen haben denselben Grund, warum sie CVaR und nicht die Standardabweichung benutzen: fette Ränder. Ein Lieferant fällt selten aus, aber wenn, dann kostet es vierzehn Tage — genau die Verteilungsform, bei der die Standardabweichung in die Irre führt (Kapitel 20).
Wo die Lösungen sich unterscheiden
Der Vergleich fördert nebenbei einen Unterschied zutage, den man nicht erwartet: Die Streuungsgrenze von 40 % bindet nur im Einkauf, nicht im Depot.
Im Einkauf zieht es die Lösung an den sicheren Lokalzulieferer, bis die Grenze sie stoppt. Im Depot verhindert stattdessen die Mindestrendite, dass alles in Anleihen wandert. Zwei verschiedene Bremsen also — und sie sitzen an verschiedenen Stellen des Modells.
Das ist die feine, wichtige Lehre dieses Abschnitts: Wer eine Struktur überträgt, überträgt nicht automatisch mit, welche Nebenbedingung am Ende bindet. Und das ist die Information, die im Gespräch mit dem Fachbereich zählt.
16.5 Wo die Brücke endet
Eine Analogie ist nur so nützlich wie die Grenzen, die man ihr zieht. Drei Dinge wandern nicht mit:
| Werkstatt / Einkauf | Depot | |
|---|---|---|
| Woher die Zahlen kommen | gemessen: drei Montagestunden sind drei Montagestunden | geschätzt: die erwartete Rendite hat einen Fehler, der größer sein kann als die Unterschiede zwischen den Anlagen (Kapitel 19) |
| Ob die Vergangenheit trägt | Lieferzeiten haben physikalische Ursachen und ändern sich langsam | Kurse entstehen aus dem Verhalten von Marktteilnehmern, die auf Modelle reagieren — ein erkanntes Muster verschwindet oft deshalb, weil es erkannt wurde (Kapitel 21) |
| Ob Teilbarkeit erlaubt ist | 37,4 % eines Lieferanten gibt es nicht: Verträge, Mindestabnahmen, Rüstzeiten → MILP | 37,4 % eines Fonds sind ein normaler Auftrag → LP/QP genügt |
⚠️ Der Fehler, vor dem diese Tabelle schützt
Dieselbe Optimierung ist in der Werkstatt Planung und im Depot Fehlerverstärkung. Ein LP sucht die Ecke des zulässigen Bereichs mit dem besten Zielwert — und wenn die Zielkoeffizienten Schätzungen mit großem Fehler sind, sucht es genau die Ecke, an der der Schätzfehler am günstigsten aussieht.
In der Werkstatt gibt es dieses Problem nicht, weil der Deckungsbeitrag je Tisch aus der Kalkulation kommt und nicht aus einer Zeitreihe. Deshalb ist Shrinkage (Kapitel 18) im Depot Pflicht und in der Fertigung unbekannt.
Die dritte Zeile erklärt außerdem eine Beobachtung, die aufmerksamen Lesern längst aufgefallen ist: Teil II ist voller MILP, Teil IV fast frei davon. Das liegt nicht an der Methode, sondern daran, was in der jeweiligen Welt teilbar ist.
16.6 Übungsaufgaben
Lösungen: Abschnitt A.16.
Aufgabe 16.1 ⭐ — Die dritte Ressource. Ergänzen Sie im Depot eine dritte knappe Größe: „Liquidität” (wie schnell sich eine Anlage verkaufen lässt). Was entspricht ihr in der Werkstatt?
Aufgabe 16.2 ⭐ — Den Schattenpreis lesen. Das Risikobudget hat einen Schattenpreis von 60,26 €. Die Aufsicht bietet an, es gegen eine Gebühr um 10 Einheiten zu erhöhen. Bis zu welcher Gebühr lohnt sich das — und welche Einschränkung dieser Aussage kennen Sie aus Abschnitt 5.9?
Aufgabe 16.3 ⭐⭐ — Die Brücke rückwärts. Übertragen Sie die Ledoit-Wolf-Shrinkage aus Kapitel 18 auf Lieferzeiten: Wo genau träte dort dasselbe Problem auf, und welche Daten bräuchten Sie?
Aufgabe 16.4 ⭐⭐ — CVaR mit Ganzzahligkeit. Der Einkauf darf höchstens drei Lieferanten beauftragen. Ergänzen Sie die entsprechende Kardinalitätsbedingung (Kapitel 6, Muster 5) und vergleichen Sie den CVaR mit dem teilbaren Fall. Was kostet die Ganzzahligkeit?
Aufgabe 16.5 ⭐⭐⭐ — Die eigene Brücke. Nehmen Sie ein Modell aus Ihrem Arbeitsumfeld und suchen Sie die Entsprechung in der jeweils anderen Welt. Prüfen Sie mit der Tabelle aus Abschnitt 16.5, ob die Übertragung trägt — und schreiben Sie auf, welche der drei Zeilen im Weg steht.
16.7 Finde den Denkfehler
🐛 „Das ist doch dasselbe Problem”
Eine Logistikerin liest dieses Kapitel und überträgt es zurück. Ihre Aufgabe: Aus 40 möglichen Lieferanten sollen die besten ausgewählt und Bestellmengen zugeteilt werden. Sie geht vor wie im Portfoliomanagement:
„Ich habe für jeden Lieferanten aus den letzten drei Jahren die mittlere Lieferzeit und > die Kovarianzmatrix der Lieferzeiten geschätzt. Dann habe ich das Markowitz-Modell > angewendet: minimiere die Varianz der Gesamtlieferzeit bei vorgegebener mittlerer > Lieferzeit. Das Ergebnis ist ein sauber diversifiziertes Lieferantenportfolio.”
Das Vorgehen ist methodisch sauber, die Rechnung stimmt, und das Ergebnis sieht plausibel aus.
Zwei Dinge daran sind falsch — und das eine ist genau der Fehler, vor dem dieses Kapitel warnt, das andere ein zusätzlicher, den es nicht behandelt. Welche?
16.8 Micro-Quiz
❓ Drei Fragen
1. Warum passt das Depot in die Klasse
Produktionsproblem, ohne dass etwas geändert werden muss? a) WeilProduktionsproblemmitAny-Typen arbeitet und alles akzeptiert. b) Weil beide Probleme dieselbe Struktur haben: knappe Größen auf konkurrierende Verwendungen verteilen. c) Weil Pydantic die Feldnamen automatisch übersetzt.2. Der Schattenpreis des Risikobudgets beträgt 60,26 €. Was bedeutet das? a) Das Risikobudget ist zu 60,26 % ausgelastet. b) Eine zusätzliche Einheit Risikobudget würde den erwarteten Ertrag um rund 60,26 € erhöhen — solange die Basis sich nicht ändert. c) Jede Einheit Risikobudget kostet die Bank 60,26 €.
3. Welche der drei Grenzen der Analogie ist der Grund dafür, dass Teil II voller MILP ist und Teil IV fast frei davon? a) Woher die Zahlen kommen. b) Ob die Vergangenheit etwas über die Zukunft sagt. c) Ob Teilbarkeit erlaubt ist.
16.9 Selbsttest
- Nennen Sie drei Größenpaare, die in Werkstatt und Depot einander entsprechen.
- Warum weiß ein LP nichts über die Bedeutung seiner Zahlen — und warum ist das hier ein Vorteil?
- Erklären Sie den „Preis des Risikos” jemandem, der nur Fertigungsplanung kennt.
- Warum benutzen beide Welten CVaR statt der Standardabweichung? Nennen Sie die Verteilungseigenschaft, um die es geht.
- Sie wollen ein Verfahren aus der Finanzwelt in die Produktion übertragen. Welche drei Fragen stellen Sie vorher?
16.10 Zusammenfassung
- Die Behauptung „dieselben Methoden, andere Domäne” ist prüfbar — und hier geprüft: Ein Depot passt unverändert in die Klasse
Produktionsproblem, und eine CVaR-Funktion bearbeitet Kursverluste wie Lieferverzüge. - Der Schattenpreis einer Ressource heißt in der Finanzwelt Preis des Risikos. Es ist derselbe Dualwert derselben Nebenbedingung.
- Die CVaR-Formulierung enthält kein Wort, das nur an der Börse Sinn ergibt. Beide Welten benutzen sie aus demselben Grund: fette Ränder, bei denen die Standardabweichung in die Irre führt.
- Übertragen wird die Struktur, nicht die Annahmen. Drei Dinge wandern nicht mit: woher die Zahlen kommen (gemessen gegen geschätzt), ob die Vergangenheit trägt (Physik gegen reagierende Marktteilnehmer) und ob Teilbarkeit erlaubt ist (MILP gegen LP).
- Die erste dieser Grenzen ist die gefährlichste: Dieselbe Optimierung ist in der Werkstatt Planung und im Depot Fehlerverstärkung.