operations_research/OR_HTML_04/cvar.html

780 lines
112 KiB
HTML
Raw Normal View History

Version 04 als eigenes Repository Erster Commit des Strangs "Optimierte Entscheidungsfindung mit Python" (Version 04). Die Historie der 71 Commits bis zur Trennung bleibt im uebergeordneten Repository OR_mit_Python liegen, das ab jetzt nur noch Version_03 (eingefroren) verwaltet und Version_04/ ignoriert. Bewusst kein "git subtree split": Der Pfad Version_04/ existiert erst seit der Verzeichnistrennung, ein Split braechte daher nur 7 der 41 einschlaegigen Commits - eine Teilhistorie, die vollstaendig aussieht und es nicht ist. Stand: 5 Teile, 23 Kapitel, 5 Anhaenge, 292 Abschnitte, 703 Querverweise, 325 Indexmarken, 73 Beispielprogramme, 32 SVGs, 4 Plotly-Figuren, 25 Notebooks, PDF mit 715 Seiten. Zusaetzlich in diesem Commit: * pyproject.toml mit Abhaengigkeitsgruppen finance, large-scale, api, figures, dev, empfehlungen. Die abgedruckte requirements.txt bleibt unveraendert daneben bestehen. ortools steht in der Grundausstattung, highspy erst in [large-scale] - so kann der HiGHS-Symbolkonflikt bei der schlanken Installation gar nicht erst auftreten. * Dabei zwei Funde: graphviz wird von erzeuge_architektur_diagramme.py importiert, fehlt aber in requirements.txt (jetzt in [figures]); pymoo steht in requirements.txt, wird aber von keinem Programm importiert, sondern nur im Kapitel Metaheuristiken empfohlen (jetzt in [empfehlungen]). * NEUER_TITEL.md nach Kritik_und_Verbesserungsvorschlaege/ verschoben - es ist die Vorlage des Titelblatts, kein Bestandteil des Werks. Die beiden Fundstellen in PROGRESS.md und erzeuge_titelseite.py nachgezogen. * PROGRESS.md nannte noch den Untertitel der ersten Fassung; auf den tatsaechlichen aus erzeuge_titelseite.py korrigiert. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-08 01:20:09 +02:00
<!doctype html>
<html lang="de">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Kapitel 20: Tail-Risiko, CVaR und Transaktionskosten · Optimierte Entscheidungsfindung mit Python</title>
<script>
(function () {
try {
var t = localStorage.getItem("or-theme");
if (t) document.documentElement.setAttribute("data-theme", t);
} catch (e) {}
})();
</script>
<link rel="stylesheet" href="assets/highlight.css" />
<link rel="stylesheet" href="katex/katex.min.css" />
<script defer="" src="katex/katex.min.js"></script>
<script>document.addEventListener("DOMContentLoaded", function () {
var mathElements = document.getElementsByClassName("math");
var macros = [];
for (var i = 0; i < mathElements.length; i++) {
var texText = mathElements[i].firstChild;
if (mathElements[i].tagName == "SPAN") {
katex.render(texText.data, mathElements[i], {
displayMode: mathElements[i].classList.contains('display'),
throwOnError: false,
macros: macros,
fleqn: false
});
}}
// Der Browser springt zu einem #anker in der URL schon beim ersten Rendern
// an, BEVOR die KaTeX-Formeln oben im Text ihre finale Hoehe bekommen -
// durch den Reflow landet der Anker danach zu weit unten. Nach dem
// Formel-Rendering hier erneut zum Anker springen, das behebt es.
if (location.hash) {
var ziel = document.getElementById(decodeURIComponent(location.hash.slice(1)));
if (ziel) ziel.scrollIntoView({behavior: "instant", block: "start"});
}
});
</script>
<link rel="stylesheet" href="assets/site.css" />
</head>
<body>
<svg style="display:none" aria-hidden="true"><symbol id="icon-menu" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round">
<line x1="3" y1="6" x2="21" y2="6"/><line x1="3" y1="12" x2="21" y2="12"/><line x1="3" y1="18" x2="21" y2="18"/>
</symbol>
<symbol id="icon-search" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round">
<circle cx="11" cy="11" r="7"/><line x1="21" y1="21" x2="16.2" y2="16.2"/>
</symbol>
<symbol id="icon-sun" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round">
<circle cx="12" cy="12" r="4.5"/>
<line x1="12" y1="1.5" x2="12" y2="4"/><line x1="12" y1="20" x2="12" y2="22.5"/>
<line x1="1.5" y1="12" x2="4" y2="12"/><line x1="20" y1="12" x2="22.5" y2="12"/>
<line x1="4.5" y1="4.5" x2="6.2" y2="6.2"/><line x1="17.8" y1="17.8" x2="19.5" y2="19.5"/>
<line x1="19.5" y1="4.5" x2="17.8" y2="6.2"/><line x1="6.2" y1="17.8" x2="4.5" y2="19.5"/>
</symbol>
<symbol id="icon-moon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M20 14.5A8.5 8.5 0 1 1 9.5 4a6.8 6.8 0 0 0 10.5 10.5z"/>
</symbol>
<symbol id="icon-chevron-left" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<polyline points="15 4 7 12 15 20"/>
</symbol>
<symbol id="icon-chevron-right" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<polyline points="9 4 17 12 9 20"/>
</symbol>
<symbol id="icon-check" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<polyline points="4 13 9.5 18.5 20 6"/>
</symbol>
<symbol id="icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M18 13.5V19a1.5 1.5 0 0 1-1.5 1.5H5A1.5 1.5 0 0 1 3.5 19V7A1.5 1.5 0 0 1 5 5.5h5.5"/>
<polyline points="14.5 3.5 20.5 3.5 20.5 9.5"/><line x1="11" y1="13" x2="20" y2="4"/>
</symbol>
<symbol id="icon-book" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M4 5.5A2 2 0 0 1 6 4h6v16H6a2 2 0 0 0-2 1.5z"/>
<path d="M20 5.5A2 2 0 0 0 18 4h-6v16h6a2 2 0 0 1 2 1.5z"/>
</symbol>
<symbol id="icon-copy" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/>
</symbol>
<symbol id="icon-download" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M12 3v12"/><polyline points="7 10 12 15 17 10"/><path d="M4 19.5h16"/>
</symbol></svg>
<header class="site-header">
<button type="button" class="icon-btn" id="sidebar-toggle" aria-label="Menü öffnen"><svg class="icon" aria-hidden="true"><use href="#icon-menu"></use></svg></button>
<a class="brand" href="index.html"><svg class="icon" aria-hidden="true"><use href="#icon-book"></use></svg> <span>Optimierte Entscheidungsfindung mit Python</span></a>
<div class="site-search">
<input id="suche-eingabe" type="search" placeholder="Suchen …" aria-label="Suche" autocomplete="off" />
<svg class="icon such-icon" aria-hidden="true"><use href="#icon-search"></use></svg>
<div id="suche-ergebnisse" class="suche-ergebnisse" hidden></div>
</div>
<button type="button" class="icon-btn" id="theme-toggle" aria-label="Darstellung umschalten">
<svg class="icon icon-sun" aria-hidden="true"><use href="#icon-sun"></use></svg><svg class="icon icon-moon" aria-hidden="true"><use href="#icon-moon"></use></svg>
</button>
</header>
<div class="site-body">
<div class="sidebar-overlay" id="sidebar-overlay" hidden></div>
<nav class="sidebar" id="sidebar" aria-label="Kapitelnavigation"><div class="sidebar-inhalt"><details class="sidebar-gruppe"><summary>Einstieg</summary><ul><li data-kapitel="vorwort.html"><a href="vorwort.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Vorwort & Lesehilfe</span></a></li><li data-kapitel="notation.html"><a href="notation.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Notation & Abkürzungen</span></a></li></ul></details><details class="sidebar-gruppe"><summary>Teil I: Grundlagen des Operations Research</summary><ul><li data-kapitel="einfuehrung.html"><a href="einfuehrung.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 1: Einführung in Operations Research — Vom Ursprung zur mathematischen Entscheidungsfindung</span></a></li><li data-kapitel="fundament.html"><a href="fundament.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 2: Das mathematische Fundament — Vektoren, Matrizen, Konvexität</span></a></li><li data-kapitel="oekosystem.html"><a href="oekosystem.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 3: Das Python-Ökosystem für OR — Solver, Bindings und Modellierungsschichten</span></a></li><li data-kapitel="modellierung.html"><a href="modellierung.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 4: Vom Management-Wunsch zum Modell</span></a></li></ul></details><details class="sidebar-gruppe"><summary>Teil II: Die Kernverfahren der deterministischen Optimierung</summary><ul><li data-kapitel="lp.html"><a href="lp.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 5: Lineare Programmierung — Simplex, Dualität und Schattenpreise</span></a></li><li data-kapitel="milp.html"><a href="milp.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 6: Gemischt-ganzzahlige Optimierung — Diskrete Entscheidungen und Branch-and-Bound</span></a></li><li data-kapitel="cpsat.html"><a href="cpsat.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 7: Constraint Programming mit CP-SAT — Logik, Scheduling und Zuweisung</span></a></li><li data-kapitel="graphen.html"><a href="graphen.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 8: Graphen, Flüsse und Touren — Min-Cost-Flow, Matching und VRP</span></a></li><li data-kapitel="metaheuristiken.html"><a href="metaheuristiken.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 9: Metaheuristiken — wenn der exakte Solver aussteigt</span></a></li><li data-kapitel="dekomposition.html"><a href="dekomposition.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 10: Spaltengenerierung — das Modell umbauen statt die Lösung raten</span></a></li></ul></details><details class="sidebar-gruppe"><summary>Teil III: Nichtlinearität, Unsicherheit und mehrperiodige Dynamik</summary><ul><li data-kapitel="qp-nlp.html"><a href="qp-nlp.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 11: Quadratische und nichtlineare Optimierung — KKT, Lagrange, Konvexität</span></a></li><li data-kapitel="unsicherheit.html"><a href="unsicherheit.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></
<main class="content">
<nav class="breadcrumb" aria-label="Breadcrumb"><a href="index.html">Start</a> <span>Teil IV</span> <span>Kapitel 20: Tail-Risiko, CVaR und Transaktionskosten</span></nav>
<nav class="prev-next"><a class="prev-next-knopf prev-next-prev" href="markowitz.html"><svg class="icon" aria-hidden="true"><use href="#icon-chevron-left"></use></svg><span><small>Zurück</small>Kapitel 19: Die moderne Portfoliotheorie nach Markowitz</span></a><a class="prev-next-knopf prev-next-next" href="handelsmaschine.html"><span><small>Weiter</small>Kapitel 21: Die vollständige quantitative Handelsmaschine</span><svg class="icon" aria-hidden="true"><use href="#icon-chevron-right"></use></svg></a></nav>
<article>
<h1 id="kap-cvar">Kapitel 20: Tail-Risiko, CVaR und Transaktionskosten</h1>
<div class="card card-blick">
<blockquote>
<p><strong>📌 Kapitel auf einen Blick</strong></p>
<p><strong>Worum geht es?</strong> Um zwei Schwächen des Markowitz-Modells: Es unterschätzt Extremverluste und ignoriert die Kosten des Umschichtens. Beide lassen sich mit konvexen Mitteln beheben.</p>
<p><strong>Voraussetzungen:</strong> <a href="markowitz.html#kap-markowitz">Kapitel 19</a>, <a href="lp.html#kap-lp">Kapitel 5</a> (LP-Formulierungen).</p>
<p><strong>Danach können Sie:</strong> VaR und CVaR unterscheiden, den CVaR nach Rockafellar/Uryasev als lineares Programm formulieren, Turnover über die <span class="math inline">L_1</span>-Norm bestrafen — und begründen, warum VaR-Kennzahlen nicht über Einheiten addiert werden dürfen.</p>
<p><strong>Zeitbedarf:</strong> ca. 5 Stunden.</p>
<p><strong>Programme:</strong><br />
<code>VaR_CVaR_Demo.py</code><br />
<code>CVaR_Portfolio.py</code></p>
<p><strong>Notebook:</strong> <a href="Notebooks_04/cvar.ipynb">cvar.ipynb</a><br />
<a href="https://colab.research.google.com/github/dschlueter/or-mit-python/blob/main/Notebooks_04/cvar.ipynb">In Google Colab öffnen</a></p>
</blockquote>
</div>
<hr />
<h2 id="sec:cvar-schnellstart">20.1 In 5 Minuten gelöst</h2>
<div class="card card-schnellstart">
<blockquote>
<p><strong>🚀 In 5 Minuten gelöst: Zwei Anlagen, dasselbe Risiko?</strong></p>
<p>Zwei Anlagen wurden über 100 Tage beobachtet. An 94 Tagen legten <strong>beide</strong> um 0,5 % zu. Sie unterscheiden sich nur in den sechs schlechten Tagen:</p>
<ul>
<li><strong>Anlage A:</strong> sechsmal 3 %.</li>
<li><strong>Anlage B:</strong> fünfmal 3 % — und einmal <strong>40 %</strong>.</li>
</ul>
<div class="sourceCode" id="cb1"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> numpy <span class="im">as</span> np</span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a>gut <span class="op">=</span> np.full(<span class="dv">94</span>, <span class="fl">0.5</span>)</span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a>A <span class="op">=</span> np.concatenate([gut, np.full(<span class="dv">6</span>, <span class="op">-</span><span class="fl">3.0</span>)])</span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a>B <span class="op">=</span> np.concatenate([gut, np.full(<span class="dv">5</span>, <span class="op">-</span><span class="fl">3.0</span>), [<span class="op">-</span><span class="fl">40.0</span>]])</span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a><span class="cf">for</span> name, r <span class="kw">in</span> [(<span class="st">&quot;Anlage A&quot;</span>, A), (<span class="st">&quot;Anlage B&quot;</span>, B)]:</span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a> schwelle <span class="op">=</span> np.percentile(r, <span class="dv">5</span>) <span class="co"># 5-%-Quantil</span></span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a> var <span class="op">=</span> <span class="op">-</span>schwelle <span class="co"># Value at Risk</span></span>
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a> cvar <span class="op">=</span> <span class="op">-</span>r[r <span class="op">&lt;=</span> schwelle].mean() <span class="co"># Mittel der schlimmsten 5 %</span></span>
<span id="cb1-11"><a href="#cb1-11" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f&quot;</span><span class="sc">{</span>name<span class="sc">}</span><span class="ss">: VaR(95) </span><span class="sc">{</span>var<span class="sc">:5.2f}</span><span class="ss"> % CVaR(95) </span><span class="sc">{</span>cvar<span class="sc">:5.2f}</span><span class="ss"> %&quot;</span>)</span></code></pre></div>
<p><strong>Ausgabe:</strong></p>
<pre><code>Anlage A: VaR(95) 3.00 % CVaR(95) 3.00 %
Anlage B: VaR(95) 3.00 % CVaR(95) 9.17 %</code></pre>
</blockquote>
</div>
<p><strong>Der Value at Risk ist für beide Anlagen exakt gleich: 3,00 %.</strong> Ein Risikobericht, der nur den VaR ausweist, würde die beiden als gleich riskant einstufen.</p>
<p>Dabei kann Anlage B an einem einzigen Tag <strong>40 %</strong> verlieren. Das ist kein Randfall, den man übersehen darf — es ist der Fall, wegen dessen es Risikomanagement gibt.</p>
<p>Der Grund für diese Blindheit steckt in der Definition:</p>
<table>
<colgroup>
<col style="width: 33%" />
<col style="width: 33%" />
<col style="width: 33%" />
</colgroup>
<thead>
<tr class="header">
<th>Maß</th>
<th>Was es beantwortet</th>
<th>Was es dabei übersieht</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><strong>VaR (95 %)</strong></td>
<td>„Welchen Verlust überschreite ich an höchstens 5 % der Tage?“</td>
<td><strong>Alles</strong>, was jenseits dieser Schwelle passiert</td>
</tr>
<tr class="even">
<td><strong>CVaR (95 %)</strong></td>
<td>„Wie hoch ist der Verlust <em>im Mittel</em>, <strong>wenn</strong> es schiefgeht?“</td>
<td>nichts im Schwanz</td>
</tr>
</tbody>
</table>
<p>Der VaR ist ein <strong>Quantil</strong> — er markiert eine Grenze und schaut nicht dahinter. Ob hinter der Grenze 3 % oder 40 % liegen, ändert ihn nicht. Der CVaR mittelt genau über diesen Bereich und macht den Unterschied sichtbar: 3,00 % gegen 9,17 %.</p>
<blockquote>
<p><strong>🎯 Merksatz</strong> Der VaR sagt Ihnen, <strong>wie oft</strong> es schiefgeht. Der CVaR sagt Ihnen, <strong>wie schlimm</strong> es dann ist. Für die Frage, ob ein Unternehmen einen Verlust überlebt, zählt ausschließlich die zweite.</p>
</blockquote>
<p><strong>Und es kommt noch besser.</strong> Der CVaR ist nicht nur aussagekräftiger, er ist auch mathematisch handlicher: Er lässt sich als <strong>lineares Programm</strong> minimieren, während die Minimierung des VaR ein nicht-konvexes Problem mit vielen lokalen Optima ist (<a href="qp-nlp.html#kap-qp-nlp">Kapitel 11</a>). Das ist ein seltener Glücksfall — das bessere Maß ist hier zugleich das leichter optimierbare. Wie das geht, zeigt <a href="#sec:cvar-value-at-risk-und-conditional-value">Abschnitt 20.4</a>.</p>
<hr />
<h2 id="sec:cvar-lernziele">20.2 Lernziele</h2>
<p>Nach diesem Kapitel können Sie …</p>
<ol type="1">
<li>… erklären, warum Marktrenditen keine Normalverteilung haben und was daraus folgt.</li>
<li>… VaR und CVaR definieren und begründen, warum nur der CVaR kohärent ist.</li>
<li>… das Rockafellar-Uryasev-Theorem anwenden, um den CVaR linear zu formulieren.</li>
<li>… Transaktionskosten über die <span class="math inline">L_1</span>-Norm modellieren.</li>
<li>… Einheiten konsistent halten und Nebenbedingungen vektorisieren.</li>
<li>… erklären, warum zwei Anlagen mit identischem VaR völlig verschiedene Extremverluste haben können.</li>
<li>… die Folgen fehlender Subadditivität für die Verteilung von Risikobudgets benennen.</li>
</ol>
<hr />
<h2 id="sec:cvar-die-zwei-schwaechen-des-markowitz-modells">20.3 Die zwei Schwächen des Markowitz-Modells</h2>
<p><strong>Erstens: die Normalverteilungs-Illusion.</strong> Die Varianz behandelt Aufwärts- und Abwärtsschwankungen gleich und unterstellt implizit symmetrische, dünn auslaufende Verteilungen. Reale Marktrenditen haben aber <strong>fette Ränder</strong> (<em>fat tails</em>) und <strong>negative Schiefe</strong>: Extreme Verluste treten deutlich häufiger auf, als eine Normalverteilung vorhersagt.</p>
<p><strong>Zweitens: Reibungsblindheit.</strong> Ein ungedämpftes Mean-Variance-Modell schichtet bei minimalen Schätzänderungen das gesamte Portfolio um. Ohne Berücksichtigung von Gebühren, Spreads und Steuern frisst der Umschlag (<em>turnover</em>) den theoretischen Mehrertrag auf.</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="co">#!/usr/bin/env python3</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a><span class="co"># VaR_CVaR_Demo.py</span></span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a><span class="co">&quot;&quot;&quot;</span></span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a><span class="co">Kapitel CVaR: Fat Tails, VaR und CVaR anschaulich.</span></span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a><span class="co">Teil 1: Wie oft treten &quot;unmoegliche&quot; Tage wirklich auf?</span></span>
<span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a><span class="co">Teil 2: Warum ist der VaR nicht subadditiv - ein Gegenbeispiel zum Nachrechnen.</span></span>
<span id="cb3-9"><a href="#cb3-9" aria-hidden="true" tabindex="-1"></a><span class="co">&quot;&quot;&quot;</span></span>
<span id="cb3-10"><a href="#cb3-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-11"><a href="#cb3-11" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> numpy <span class="im">as</span> np</span>
<span id="cb3-12"><a href="#cb3-12" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> scipy <span class="im">import</span> stats</span>
<span id="cb3-13"><a href="#cb3-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-14"><a href="#cb3-14" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-15"><a href="#cb3-15" aria-hidden="true" tabindex="-1"></a><span class="kw">def</span> var_quantil(verluste: np.ndarray, alpha: <span class="bu">float</span> <span class="op">=</span> <span class="fl">0.95</span>) <span class="op">-&gt;</span> <span class="bu">float</span>:</span>
<span id="cb3-16"><a href="#cb3-16" aria-hidden="true" tabindex="-1"></a> <span class="co">&quot;&quot;&quot;VaR = Quantil der Verlustverteilung (Verluste positiv, Gewinne negativ).&quot;&quot;&quot;</span></span>
<span id="cb3-17"><a href="#cb3-17" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> <span class="bu">float</span>(np.quantile(verluste, alpha))</span>
<span id="cb3-18"><a href="#cb3-18" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-19"><a href="#cb3-19" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-20"><a href="#cb3-20" aria-hidden="true" tabindex="-1"></a><span class="kw">def</span> cvar_rockafellar(verluste: np.ndarray, alpha: <span class="bu">float</span> <span class="op">=</span> <span class="fl">0.95</span>) <span class="op">-&gt;</span> <span class="bu">float</span>:</span>
<span id="cb3-21"><a href="#cb3-21" aria-hidden="true" tabindex="-1"></a> <span class="co">&quot;&quot;&quot;</span></span>
<span id="cb3-22"><a href="#cb3-22" aria-hidden="true" tabindex="-1"></a><span class="co"> CVaR ueber die Rockafellar-Uryasev-Formel:</span></span>
<span id="cb3-23"><a href="#cb3-23" aria-hidden="true" tabindex="-1"></a><span class="co"> CVaR = min_gamma { gamma + 1/(1-alpha) * E[max(Verlust - gamma, 0)] }</span></span>
<span id="cb3-24"><a href="#cb3-24" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-25"><a href="#cb3-25" aria-hidden="true" tabindex="-1"></a><span class="co"> WICHTIG: Der naheliegende Weg &quot;Mittelwert aller Werte &gt;= VaR&quot; ist FALSCH,</span></span>
<span id="cb3-26"><a href="#cb3-26" aria-hidden="true" tabindex="-1"></a><span class="co"> sobald die Verteilung Atome hat (z. B. genau zwei moegliche Verluste).</span></span>
<span id="cb3-27"><a href="#cb3-27" aria-hidden="true" tabindex="-1"></a><span class="co"> Dann liegt der VaR selbst auf einem Atom, und der Vergleich &#39;&gt;=&#39; erfasst</span></span>
<span id="cb3-28"><a href="#cb3-28" aria-hidden="true" tabindex="-1"></a><span class="co"> zu viel Wahrscheinlichkeitsmasse. Die Formel unten behandelt das korrekt -</span></span>
<span id="cb3-29"><a href="#cb3-29" aria-hidden="true" tabindex="-1"></a><span class="co"> und ist zugleich genau der Ausdruck, den wir im Abschnitt &#39;Value at Risk</span></span>
<span id="cb3-30"><a href="#cb3-30" aria-hidden="true" tabindex="-1"></a><span class="co"> und Conditional Value at Risk&#39; optimieren.</span></span>
<span id="cb3-31"><a href="#cb3-31" aria-hidden="true" tabindex="-1"></a><span class="co"> &quot;&quot;&quot;</span></span>
<span id="cb3-32"><a href="#cb3-32" aria-hidden="true" tabindex="-1"></a> kandidaten <span class="op">=</span> np.unique(verluste) <span class="co"># Optimum liegt immer auf einem Datenpunkt</span></span>
<span id="cb3-33"><a href="#cb3-33" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> <span class="bu">float</span>(<span class="bu">min</span>(g <span class="op">+</span> np.mean(np.maximum(verluste <span class="op">-</span> g, <span class="fl">0.0</span>)) <span class="op">/</span> (<span class="fl">1.0</span> <span class="op">-</span> alpha)</span>
<span id="cb3-34"><a href="#cb3-34" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> g <span class="kw">in</span> kandidaten))</span>
<span id="cb3-35"><a href="#cb3-35" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-36"><a href="#cb3-36" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-37"><a href="#cb3-37" aria-hidden="true" tabindex="-1"></a><span class="cf">if</span> <span class="va">__name__</span> <span class="op">==</span> <span class="st">&quot;__main__&quot;</span>:</span>
<span id="cb3-38"><a href="#cb3-38" aria-hidden="true" tabindex="-1"></a> rng <span class="op">=</span> np.random.default_rng(<span class="dv">2026</span>)</span>
<span id="cb3-39"><a href="#cb3-39" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-40"><a href="#cb3-40" aria-hidden="true" tabindex="-1"></a> <span class="co"># --- Teil 1: Fat Tails (analytisch, nicht simuliert) ------------------</span></span>
<span id="cb3-41"><a href="#cb3-41" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">&quot;=&quot;</span> <span class="op">*</span> <span class="dv">88</span>)</span>
<span id="cb3-42"><a href="#cb3-42" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">&quot; TEIL 1: WIE OFT TRITT DAS &#39;UNMOEGLICHE&#39; EIN?&quot;</span>)</span>
<span id="cb3-43"><a href="#cb3-43" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">&quot;=&quot;</span> <span class="op">*</span> <span class="dv">88</span>)</span>
<span id="cb3-44"><a href="#cb3-44" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">&quot;Vergleich: Normalverteilung gegen t-Verteilung mit 3 Freiheitsgraden&quot;</span>)</span>
<span id="cb3-45"><a href="#cb3-45" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">&quot;(beide auf Standardabweichung 1 normiert).</span><span class="ch">\n</span><span class="st">&quot;</span>)</span>
<span id="cb3-46"><a href="#cb3-46" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-47"><a href="#cb3-47" aria-hidden="true" tabindex="-1"></a> t_verteilung <span class="op">=</span> stats.t(df<span class="op">=</span><span class="dv">3</span>)</span>
<span id="cb3-48"><a href="#cb3-48" aria-hidden="true" tabindex="-1"></a> skalierung <span class="op">=</span> t_verteilung.std() <span class="co"># auf Varianz 1 bringen</span></span>
<span id="cb3-49"><a href="#cb3-49" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-50"><a href="#cb3-50" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f&quot;</span><span class="sc">{</span><span class="st">&#39;Ereignis&#39;</span><span class="sc">:&lt;22}</span><span class="ss"> </span><span class="sc">{</span><span class="st">&#39;Normal&#39;</span><span class="sc">:&gt;14}</span><span class="ss"> </span><span class="sc">{</span><span class="st">&#39;t (df=3)&#39;</span><span class="sc">:&gt;14}</span><span class="ss"> </span><span class="sc">{</span><span class="st">&#39;Faktor&#39;</span><span class="sc">:&gt;11}</span><span class="ss"> &quot;</span></span>
<span id="cb3-51"><a href="#cb3-51" aria-hidden="true" tabindex="-1"></a> <span class="ss">f&quot;</span><span class="sc">{</span><span class="st">&#39;Normal: 1 Tag in&#39;</span><span class="sc">:&gt;18}</span><span class="ss">&quot;</span>)</span>
<span id="cb3-52"><a href="#cb3-52" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">&quot;-&quot;</span> <span class="op">*</span> <span class="dv">88</span>)</span>
<span id="cb3-53"><a href="#cb3-53" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> k <span class="kw">in</span> [<span class="dv">3</span>, <span class="dv">4</span>, <span class="dv">5</span>, <span class="dv">6</span>]:</span>
<span id="cb3-54"><a href="#cb3-54" aria-hidden="true" tabindex="-1"></a> p_normal <span class="op">=</span> <span class="dv">2</span> <span class="op">*</span> stats.norm.sf(k) <span class="co"># beidseitig</span></span>
<span id="cb3-55"><a href="#cb3-55" aria-hidden="true" tabindex="-1"></a> p_t <span class="op">=</span> <span class="dv">2</span> <span class="op">*</span> t_verteilung.sf(k <span class="op">*</span> skalierung)</span>
<span id="cb3-56"><a href="#cb3-56" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f&quot;Abweichung &gt; </span><span class="sc">{</span>k<span class="sc">}</span><span class="ss"> Sigma </span><span class="sc">{</span>p_normal<span class="op">*</span><span class="dv">100</span><span class="sc">:&gt;13.6f}</span><span class="ss"> % </span><span class="sc">{</span>p_t<span class="op">*</span><span class="dv">100</span><span class="sc">:&gt;13.6f}</span><span class="ss"> % &quot;</span></span>
<span id="cb3-57"><a href="#cb3-57" aria-hidden="true" tabindex="-1"></a> <span class="ss">f&quot;</span><span class="sc">{</span>p_t<span class="op">/</span>p_normal<span class="sc">:&gt;10.1f}</span><span class="ss">x </span><span class="sc">{</span><span class="dv">1</span><span class="op">/</span>p_normal<span class="op">/</span><span class="dv">252</span><span class="sc">:&gt;15,.0f}</span><span class="ss"> Jahre&quot;</span>)</span>
<span id="cb3-58"><a href="#cb3-58" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-59"><a href="#cb3-59" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">&quot;</span><span class="ch">\n</span><span class="st">Deutung: Ein 5-Sigma-Tag ist unter Normalverteilung ein Ereignis von&quot;</span>)</span>
<span id="cb3-60"><a href="#cb3-60" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">&quot;etwa einmal in 6.900 Jahren. Reale Aktienmaerkte liefern solche Tage&quot;</span>)</span>
<span id="cb3-61"><a href="#cb3-61" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">&quot;mehrfach pro Jahrzehnt. Wer allein mit Varianz steuert, plant fuer&quot;</span>)</span>
<span id="cb3-62"><a href="#cb3-62" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">&quot;eine Welt, in der Crashs praktisch nicht vorkommen.&quot;</span>)</span>
<span id="cb3-63"><a href="#cb3-63" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-64"><a href="#cb3-64" aria-hidden="true" tabindex="-1"></a> <span class="co"># --- Teil 2: VaR ist nicht subadditiv ---------------------------------</span></span>
<span id="cb3-65"><a href="#cb3-65" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">&quot;</span><span class="ch">\n</span><span class="st">&quot;</span> <span class="op">+</span> <span class="st">&quot;=&quot;</span> <span class="op">*</span> <span class="dv">88</span>)</span>
<span id="cb3-66"><a href="#cb3-66" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">&quot; TEIL 2: WARUM DER VaR KEIN KOHAERENTES RISIKOMASS IST&quot;</span>)</span>
<span id="cb3-67"><a href="#cb3-67" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">&quot;=&quot;</span> <span class="op">*</span> <span class="dv">88</span>)</span>
<span id="cb3-68"><a href="#cb3-68" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">&quot;Zwei unabhaengige Anleihen, je 100 EUR Nominal.&quot;</span>)</span>
<span id="cb3-69"><a href="#cb3-69" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">&quot;Jede faellt mit 4 % Wahrscheinlichkeit aus (Verlust 100),&quot;</span>)</span>
<span id="cb3-70"><a href="#cb3-70" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">&quot;sonst zahlt sie 2 EUR Kupon (Verlust -2).</span><span class="ch">\n</span><span class="st">&quot;</span>)</span>
<span id="cb3-71"><a href="#cb3-71" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-72"><a href="#cb3-72" aria-hidden="true" tabindex="-1"></a> ziehungen <span class="op">=</span> <span class="dv">2_000_000</span></span>
<span id="cb3-73"><a href="#cb3-73" aria-hidden="true" tabindex="-1"></a> verlust_a <span class="op">=</span> np.where(rng.random(ziehungen) <span class="op">&lt;</span> <span class="fl">0.04</span>, <span class="fl">100.0</span>, <span class="op">-</span><span class="fl">2.0</span>)</span>
<span id="cb3-74"><a href="#cb3-74" aria-hidden="true" tabindex="-1"></a> verlust_b <span class="op">=</span> np.where(rng.random(ziehungen) <span class="op">&lt;</span> <span class="fl">0.04</span>, <span class="fl">100.0</span>, <span class="op">-</span><span class="fl">2.0</span>)</span>
<span id="cb3-75"><a href="#cb3-75" aria-hidden="true" tabindex="-1"></a> verlust_ab <span class="op">=</span> verlust_a <span class="op">+</span> verlust_b</span>
<span id="cb3-76"><a href="#cb3-76" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-77"><a href="#cb3-77" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f&quot;</span><span class="sc">{</span><span class="st">&#39;&#39;</span><span class="sc">:&lt;28}</span><span class="ss"> </span><span class="sc">{</span><span class="st">&#39;VaR 95%&#39;</span><span class="sc">:&gt;12}</span><span class="ss"> </span><span class="sc">{</span><span class="st">&#39;CVaR 95%&#39;</span><span class="sc">:&gt;12}</span><span class="ss">&quot;</span>)</span>
<span id="cb3-78"><a href="#cb3-78" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">&quot;-&quot;</span> <span class="op">*</span> <span class="dv">88</span>)</span>
<span id="cb3-79"><a href="#cb3-79" aria-hidden="true" tabindex="-1"></a> werte <span class="op">=</span> {}</span>
<span id="cb3-80"><a href="#cb3-80" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> name, v <span class="kw">in</span> [(<span class="st">&quot;Anleihe A allein&quot;</span>, verlust_a),</span>
<span id="cb3-81"><a href="#cb3-81" aria-hidden="true" tabindex="-1"></a> (<span class="st">&quot;Anleihe B allein&quot;</span>, verlust_b),</span>
<span id="cb3-82"><a href="#cb3-82" aria-hidden="true" tabindex="-1"></a> (<span class="st">&quot;Portfolio A+B&quot;</span>, verlust_ab)]:</span>
<span id="cb3-83"><a href="#cb3-83" aria-hidden="true" tabindex="-1"></a> werte[name] <span class="op">=</span> (var_quantil(v), cvar_rockafellar(v))</span>
<span id="cb3-84"><a href="#cb3-84" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f&quot;</span><span class="sc">{</span>name<span class="sc">:&lt;28}</span><span class="ss"> </span><span class="sc">{</span>werte[name][<span class="dv">0</span>]<span class="sc">:&gt;12.2f}</span><span class="ss"> </span><span class="sc">{</span>werte[name][<span class="dv">1</span>]<span class="sc">:&gt;12.2f}</span><span class="ss">&quot;</span>)</span>
<span id="cb3-85"><a href="#cb3-85" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-86"><a href="#cb3-86" aria-hidden="true" tabindex="-1"></a> var_summe <span class="op">=</span> werte[<span class="st">&quot;Anleihe A allein&quot;</span>][<span class="dv">0</span>] <span class="op">+</span> werte[<span class="st">&quot;Anleihe B allein&quot;</span>][<span class="dv">0</span>]</span>
<span id="cb3-87"><a href="#cb3-87" aria-hidden="true" tabindex="-1"></a> cvar_summe <span class="op">=</span> werte[<span class="st">&quot;Anleihe A allein&quot;</span>][<span class="dv">1</span>] <span class="op">+</span> werte[<span class="st">&quot;Anleihe B allein&quot;</span>][<span class="dv">1</span>]</span>
<span id="cb3-88"><a href="#cb3-88" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f&quot;</span><span class="sc">{</span><span class="st">&#39;Summe der Einzelwerte&#39;</span><span class="sc">:&lt;28}</span><span class="ss"> </span><span class="sc">{</span>var_summe<span class="sc">:&gt;12.2f}</span><span class="ss"> </span><span class="sc">{</span>cvar_summe<span class="sc">:&gt;12.2f}</span><span class="ss">&quot;</span>)</span>
<span id="cb3-89"><a href="#cb3-89" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-90"><a href="#cb3-90" aria-hidden="true" tabindex="-1"></a> var_port, cvar_port <span class="op">=</span> werte[<span class="st">&quot;Portfolio A+B&quot;</span>]</span>
<span id="cb3-91"><a href="#cb3-91" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">&quot;-&quot;</span> <span class="op">*</span> <span class="dv">88</span>)</span>
<span id="cb3-92"><a href="#cb3-92" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f&quot;VaR: Portfolio </span><span class="sc">{</span>var_port<span class="sc">:7.2f}</span><span class="ss"> vs. Summe </span><span class="sc">{</span>var_summe<span class="sc">:7.2f}</span><span class="ss"> -&gt; &quot;</span></span>
<span id="cb3-93"><a href="#cb3-93" aria-hidden="true" tabindex="-1"></a> <span class="ss">f&quot;</span><span class="sc">{</span><span class="st">&#39;VERLETZT die Subadditivitaet!&#39;</span> <span class="cf">if</span> var_port <span class="op">&gt;</span> var_summe <span class="cf">else</span> <span class="st">&#39;subadditiv&#39;</span><span class="sc">}</span><span class="ss">&quot;</span>)</span>
<span id="cb3-94"><a href="#cb3-94" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f&quot;CVaR: Portfolio </span><span class="sc">{</span>cvar_port<span class="sc">:7.2f}</span><span class="ss"> vs. Summe </span><span class="sc">{</span>cvar_summe<span class="sc">:7.2f}</span><span class="ss"> -&gt; &quot;</span></span>
<span id="cb3-95"><a href="#cb3-95" aria-hidden="true" tabindex="-1"></a> <span class="ss">f&quot;</span><span class="sc">{</span><span class="st">&#39;subadditiv (kohaerent)&#39;</span> <span class="cf">if</span> cvar_port <span class="op">&lt;=</span> cvar_summe <span class="op">+</span> <span class="fl">1e-6</span> <span class="cf">else</span> <span class="st">&#39;verletzt&#39;</span><span class="sc">}</span><span class="ss">&quot;</span>)</span>
<span id="cb3-96"><a href="#cb3-96" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-97"><a href="#cb3-97" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">&quot;</span><span class="ch">\n</span><span class="st">Deutung: Einzeln betrachtet meldet der VaR fuer jede Anleihe einen&quot;</span>)</span>
<span id="cb3-98"><a href="#cb3-98" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">&quot;GEWINN von 2 EUR - denn mit 96 % Wahrscheinlichkeit passiert nichts,&quot;</span>)</span>
<span id="cb3-99"><a href="#cb3-99" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">&quot;und 4 </span><span class="sc">% li</span><span class="st">egen unterhalb der 5-%-Schwelle. Im Portfolio steigt die&quot;</span>)</span>
<span id="cb3-100"><a href="#cb3-100" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">&quot;Wahrscheinlichkeit mindestens eines Ausfalls auf 7,8 </span><span class="sc">% u</span><span class="st">nd damit UEBER&quot;</span>)</span>
<span id="cb3-101"><a href="#cb3-101" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">&quot;die Schwelle - der VaR springt auf 98. Er behauptet also, Streuung&quot;</span>)</span>
<span id="cb3-102"><a href="#cb3-102" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">&quot;habe das Risiko erhoeht. Das ist oekonomisch unsinnig und der Grund,&quot;</span>)</span>
<span id="cb3-103"><a href="#cb3-103" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">&quot;warum die Bankenaufsicht mit Basel III auf den Expected Shortfall&quot;</span>)</span>
<span id="cb3-104"><a href="#cb3-104" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">&quot;umgestellt hat.&quot;</span>)</span>
<span id="cb3-105"><a href="#cb3-105" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">&quot;=&quot;</span> <span class="op">*</span> <span class="dv">88</span>)</span></code></pre></div>
<p><strong>Erwartete Ausgabe (gekürzt):</strong></p>
<pre><code>========================================================================================
TEIL 1: WIE OFT TRITT DAS &#39;UNMOEGLICHE&#39; EIN?
========================================================================================
Ereignis Normal t (df=3) Faktor Normal: 1 Tag in
----------------------------------------------------------------------------------------
Abweichung &gt; 3 Sigma 0.269980 % 1.384683 % 5.1x 1 Jahre
Abweichung &gt; 4 Sigma 0.006334 % 0.616537 % 97.3x 63 Jahre
Abweichung &gt; 5 Sigma 0.000057 % 0.323904 % 5649.8x 6,922 Jahre
Abweichung &gt; 6 Sigma 0.000000 % 0.190127 % 963561.0x 2,011,101 Jahre
========================================================================================
TEIL 2: WARUM DER VaR KEIN KOHAERENTES RISIKOMASS IST
========================================================================================
VaR 95% CVaR 95%
----------------------------------------------------------------------------------------
Anleihe A allein -2.00 79.59
Anleihe B allein -2.00 79.66
Portfolio A+B 98.00 101.33
Summe der Einzelwerte -4.00 159.24
----------------------------------------------------------------------------------------
VaR: Portfolio 98.00 vs. Summe -4.00 -&gt; VERLETZT die Subadditivitaet!
CVaR: Portfolio 101.33 vs. Summe 159.24 -&gt; subadditiv (kohaerent)
========================================================================================</code></pre>
<p><strong>Die 6-Sigma-Zeile setzt die Sache ins Verhältnis:</strong> Unter Normalverteilung wäre ein solcher Tag ein Ereignis von einmal in <strong>zwei Millionen Jahren</strong>. Unter der t-Verteilung mit drei Freiheitsgraden — die realen Aktienrenditen deutlich näher kommt — passiert er etwa alle <strong>zwei Jahre</strong>. Der Faktor beträgt fast <strong>eine Million</strong>.</p>
<p>Und Teil 2 zeigt das Grundproblem des VaR an einem Beispiel, das Sie von Hand nachrechnen können: Einzeln meldet er für jede Anleihe einen <em>Gewinn</em> von 2 €, im Portfolio einen <em>Verlust</em> von 98 €. Diversifikation hätte demnach das Risiko um 102 € erhöht. Der CVaR dagegen verhält sich korrekt: 101,33 € im Portfolio gegenüber 159,24 € bei getrennter Betrachtung — die Streuung <strong>senkt</strong> das Risiko, wie es sein muss.</p>
<blockquote>
<p><strong>⚠️ Eine Falle bei der CVaR-Berechnung</strong> Der naheliegende Weg — „Mittelwert aller Verluste <span class="math inline">\ge</span> VaR“ — ist <strong>falsch</strong>, sobald die Verteilung <strong>Atome</strong> hat (also einzelne Werte mit positiver Wahrscheinlichkeit, wie hier die zwei möglichen Ausgänge). Der VaR liegt dann selbst auf einem Atom, und der Vergleich <code>&gt;=</code> erfasst zu viel Wahrscheinlichkeitsmasse. Im Beispiel oben liefert dieser naive Schätzer für Anleihe A den Wert 2,08 statt der korrekten 79,59 — ein Fehler um Faktor 38.</p>
<p>Die Rockafellar-Uryasev-Formel behandelt Atome von sich aus korrekt. Verwenden Sie sie auch dann, wenn Sie „nur schnell“ einen CVaR ausrechnen wollen.</p>
</blockquote>
<hr />
<h2 id="sec:cvar-value-at-risk-und-conditional-value">20.4 Value at Risk und Conditional Value at Risk</h2>
<figure>
<img src="bilder_04/kap_cvar_var_vergleich.svg" alt="Abb. 20.1: Der VaR ist eine Schwelle, der CVaR ein Mittelwert. 20 000 simulierte Tagesrenditen aus dem Fat-Tail-Modell dieses Kapitels (t-Verteilung mit drei Freiheitsgraden). Der schraffierte Bereich sind die schlechtesten 5 % der Tage; der VaR markiert nur ihren Rand, der CVaR ihren Mittelwert. Erzeugt von bilder_04/erzeuge_var_cvar.py." />
<figcaption aria-hidden="true">Abb. 20.1: Der VaR ist eine Schwelle, der CVaR ein Mittelwert. 20 000 simulierte Tagesrenditen aus dem Fat-Tail-Modell dieses Kapitels (<span class="math inline">t</span>-Verteilung mit drei Freiheitsgraden). Der schraffierte Bereich sind die schlechtesten 5 % der Tage; der VaR markiert nur ihren Rand, der CVaR ihren Mittelwert. Erzeugt von <code>bilder_04/erzeuge_var_cvar.py</code>.</figcaption>
</figure>
<p><strong>Value at Risk (<span class="math inline">\text{VaR}_\alpha</span>):</strong> Der Verlust, der mit Wahrscheinlichkeit <span class="math inline">\alpha</span> nicht überschritten wird.</p>
<p><strong>Conditional Value at Risk (<span class="math inline">\text{CVaR}_\alpha</span>, auch <em>Expected Shortfall</em>):</strong> Der <strong>durchschnittliche Verlust in den schlimmsten <span class="math inline">(1-\alpha)</span> Prozent</strong> der Fälle.</p>
<blockquote>
<p><strong>📐 Der Unterschied in einem Satz</strong> Der VaR sagt: <em>„In 95 % der Tage verlieren Sie höchstens 1,86 %.“</em> Der CVaR sagt: <em>„Und wenn es doch schiefgeht, verlieren Sie im Mittel 2,99 %.“</em></p>
<p>Beide Zahlen stammen aus der Verteilung oben — nachzurechnen mit <code>bilder_04/erzeuge_var_cvar.py</code>.</p>
<p>Der VaR ist eine <strong>Schwelle</strong>, der CVaR ein <strong>Mittelwert dahinter</strong>. Der VaR sagt nichts darüber, wie schlimm es hinter der Schwelle wird — ob dort 2,4 % oder 40 % stehen, ist ihm gleich. In der Stichprobe oben liegt der schlechteste Tag bei <strong>23,0 %</strong>; am VaR von 1,86 % ändert dieser eine Tag <strong>nichts</strong>, am CVaR sehr wohl.</p>
</blockquote>
<table>
<colgroup>
<col style="width: 33%" />
<col style="width: 33%" />
<col style="width: 33%" />
</colgroup>
<thead>
<tr class="header">
<th>Eigenschaft</th>
<th>VaR</th>
<th>CVaR</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>Berücksichtigt Verlusthöhe im Rand</td>
<td>✗ nein</td>
<td>✓ ja</td>
</tr>
<tr class="even">
<td><strong>Subadditiv</strong> (<span class="math inline">\rho(A+B) \le \rho(A)+\rho(B)</span>)</td>
<td>✗ nein</td>
<td>✓ ja</td>
</tr>
<tr class="odd">
<td>Kohärentes Risikomaß</td>
<td>✗ nein</td>
<td>✓ ja</td>
</tr>
<tr class="even">
<td>Konvex und optimierbar</td>
<td>✗ nein</td>
<td>✓ ja</td>
</tr>
<tr class="odd">
<td>Regulatorischer Standard</td>
<td>bis Basel II</td>
<td><strong>ab Basel III</strong></td>
</tr>
</tbody>
</table>
<blockquote>
<p><strong>⚠️ Eine verbreitete Ungenauigkeit</strong> Der CVaR wird manchmal „<strong>streng</strong> konvex“ genannt. Das ist zu stark: Der CVaR ist konvex, in der Szenario-Darstellung sogar <strong>stückweise linear</strong> — und damit gerade <strong>nicht</strong> streng konvex. Genau das ist sein praktischer Vorteil: Stückweise linear heißt, er lässt sich als <strong>lineares Programm</strong> lösen.</p>
</blockquote>
<h3 id="das-rockafellar-uryasev-theorem-2000">Das Rockafellar-Uryasev-Theorem (2000)</h3>
<p>Rockafellar und Uryasev zeigten, dass sich der CVaR über <span class="math inline">S</span> Szenarien exakt als lineares Programm formulieren lässt:</p>
<p><span class="math display">
\text{CVaR}_\alpha(\mathbf{w}) = \min_{\gamma,\ \mathbf{u}\ \ge 0}\ \
\gamma + \frac{1}{S(1-\alpha)}\sum_{s=1}^S u_s
</span></p>
<p><span class="math display">
\text{u. d. N.}\qquad u_s \ \ge\ -\mathbf{R}_s^\top\mathbf{w} - \gamma \quad\forall s,
\qquad u_s \ge 0 \quad\forall s
</span></p>
<blockquote>
<p><strong>📐 Formel-Lesehilfe — der Trick in drei Schritten</strong> * <span class="math inline">\gamma</span> ist eine <strong>Hilfsvariable</strong>, die im Optimum automatisch den VaR annimmt. Man muss ihn also <strong>nicht vorher kennen</strong> — das ist der eigentliche Durchbruch. * <span class="math inline">-\mathbf{R}_s^\top\mathbf{w}</span> ist der <strong>Verlust</strong> im Szenario <span class="math inline">s</span> (Rendite mit negativem Vorzeichen). * <span class="math inline">u_s \ge \text{Verlust}_s - \gamma</span> zusammen mit <span class="math inline">u_s \ge 0</span> bedeutet: <span class="math inline">u_s = \max(\text{Verlust}_s - \gamma,\ 0)</span> — der <strong>Überschuss über die Schwelle</strong>. Liegt der Verlust unter <span class="math inline">\gamma</span>, ist <span class="math inline">u_s = 0</span> und das Szenario zählt nicht.</p>
<p><strong>Ohne Formel gesagt:</strong> „Wähle eine Schwelle <span class="math inline">\gamma</span>. Zähle für jedes Szenario, wie weit der Verlust darüber hinausgeht. Der CVaR ist die Schwelle plus der gemittelte Überschuss — und zwar für diejenige Schwelle, bei der diese Summe minimal wird.“</p>
<p><strong>Warum <span class="math inline">u_s</span> automatisch das Maximum wird:</strong> Die Zielfunktion minimiert die Summe der <span class="math inline">u_s</span>. Jedes <span class="math inline">u_s</span> wird also so klein wie möglich gedrückt — bis an die Grenze, die die beiden Ungleichungen erlauben. Das ist genau das Maximum der beiden Untergrenzen.</p>
</blockquote>
<div class="card card-formel">
<blockquote>
<p><strong>🔤 Formel-Übersetzer: jedes Zeichen der Zielfunktion</strong></p>
<p>Die Lesehilfe oben erklärt den <em>Trick</em>. Hier steht, was die einzelnen Zeichen <strong>bedeuten</strong> — vor allem der Bruch, an dem die meisten Leser hängen bleiben:</p>
<table>
<colgroup>
<col style="width: 50%" />
<col style="width: 50%" />
</colgroup>
<thead>
<tr class="header">
<th>Mathematik</th>
<th>Alltagssprache</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><span class="math inline">\alpha</span></td>
<td>Das <strong>Konfidenzniveau</strong>, üblich <span class="math inline">0{,}95</span> oder <span class="math inline">0{,}99</span>. <em>Nicht</em> der Randanteil.</td>
</tr>
<tr class="even">
<td><span class="math inline">1-\alpha</span></td>
<td>Der <strong>Randanteil</strong>: die schlechtesten 5 % (bzw. 1 %) der Fälle. Das ist der Teil, um den es geht.</td>
</tr>
<tr class="odd">
<td><span class="math inline">S</span></td>
<td>Die Anzahl der durchgerechneten Szenarien — Handelstage, Simulationsläufe, historische Perioden.</td>
</tr>
<tr class="even">
<td><span class="math inline">S(1-\alpha)</span></td>
<td><strong>Wie viele Szenarien im Rand liegen.</strong> Bei <span class="math inline">S = 2\,000</span> und <span class="math inline">\alpha = 0{,}95</span>: genau 100.</td>
</tr>
<tr class="odd">
<td><span class="math inline">\frac{1}{S(1-\alpha)}\sum_s u_s</span></td>
<td>Kein Mittelwert über <em>alle</em> Szenarien, sondern über die <strong>Randszenarien allein</strong>. Genau deshalb steht dort nicht <span class="math inline">\frac1S</span>.</td>
</tr>
<tr class="even">
<td><span class="math inline">\gamma</span></td>
<td>Die Schwelle, ab der ein Verlust zum Randfall wird — im Optimum der VaR.</td>
</tr>
<tr class="odd">
<td><span class="math inline">\gamma + \frac{1}{S(1-\alpha)}\sum_s u_s</span></td>
<td>„Schwelle <strong>plus</strong> durchschnittlicher Überschuss darüber“ — und das ist der CVaR.</td>
</tr>
</tbody>
</table>
<p><strong>In einem Satz:</strong> <em>Der CVaR ist der Mittelwert der schlimmsten <span class="math inline">1-\alpha</span> Prozent — der Bruch vor der Summe sorgt allein dafür, dass durch die richtige Anzahl geteilt wird.</em></p>
<blockquote>
<p><strong>⚠️ Die teuerste Verwechslung des Kapitels</strong> &gt; <span class="math inline">\alpha</span> und <span class="math inline">1-\alpha</span> zu vertauschen führt zu <strong>keiner Fehlermeldung</strong>. Das Modell &gt; rechnet weiter, nur eben über die falsche Menge. An 2 000 simulierten Tagesrenditen mit &gt; Fat Tails gemessen: &gt; &gt; | Rechnung | gemittelt über | CVaR | &gt; | — | — | — | &gt; | richtig (<span class="math inline">\alpha = 0{,}95</span>, Rand 5 %) | 100 von 2 000 Szenarien | <strong>3,43 %</strong> | &gt; | vertauscht (Rand 95 %) | 1 900 von 2 000 Szenarien | <strong>0,18 %</strong> | &gt; &gt; Ein Faktor <strong>19</strong> — und die zweite Zahl ist kein schlecht geschätztes Randrisiko, sondern &gt; überhaupt kein Randmaß mehr: Sie mittelt über fast alle Tage und schließt die schlimmen &gt; gerade nicht ein. Der größte Einzelverlust der Stichprobe beträgt 21,4 %. &gt; &gt; <strong>Die Gegenprobe kostet eine Zeile:</strong> Ist der berechnete CVaR nicht deutlich größer als &gt; der mittlere Verlust, stimmt <span class="math inline">\alpha</span> nicht.</p>
</blockquote>
</blockquote>
</div>
<hr />
<h2 id="sec:cvar-transaktionskosten-ueber-die-l-1-norm">20.5 Transaktionskosten über die <span class="math inline">L_1</span>-Norm</h2>
<p>Sei <span class="math inline">\mathbf{w}_{\text{alt}}</span> das bestehende Portfolio und <span class="math inline">\mathbf{w}</span> das neue Ziel. Der <strong>Umschlag</strong> (<em>turnover</em>) ist:</p>
<p><span class="math display">
\text{Turnover} = \sum_{i=1}^N \lvert w_i - w_{\text{alt},i}\rvert
= \lVert \mathbf{w}-\mathbf{w}_{\text{alt}}\rVert_1
</span></p>
<figure>
<img src="bilder_04/kap13_cvar_zielfunktion.svg" alt="Abb. 20.2: CVaR-Zielfunktion mit Reibungs-Penalty" />
<figcaption aria-hidden="true">Abb. 20.2: CVaR-Zielfunktion mit Reibungs-Penalty</figcaption>
</figure>
<blockquote>
<p><strong>📐 Formel-Lesehilfe</strong> Die <span class="math inline">L_1</span>-Norm ist die Summe der <strong>Beträge</strong>. Sie misst, wie viel Prozent des Portfolios insgesamt bewegt werden — Käufe und Verkäufe zusammen.</p>
<p><strong>Ohne Formel gesagt:</strong> „Wenn du 5 % von A verkaufst und 5 % von B kaufst, hast du 10 % Umschlag und zahlst darauf Gebühren.“</p>
<p><strong>Warum <span class="math inline">L_1</span> und nicht <span class="math inline">L_2</span>?</strong> Die <span class="math inline">L_1</span>-Norm ist konvex (also optimierbar) und erzeugt zusätzlich <strong>dünn besetzte Änderungen</strong>: Sie bevorzugt wenige große Umschichtungen gegenüber vielen kleinen. Das entspricht genau dem, was man in der Praxis will — nicht 50 Kleinstorders mit je 3 € Mindestgebühr.</p>
</blockquote>
<p>In CVXPY schreibt man einfach <code>cp.norm1(w - w_alt)</code>; intern wird das in lineare Hilfsvariablen zerlegt.</p>
<hr />
<h2 id="sec:cvar-implementierung-cvar-portfolio-mit-reibung">20.6 Implementierung: CVaR-Portfolio mit Reibung</h2>
<blockquote>
<p><strong>⚠️ Einheiten konsistent halten</strong></p>
<p>Ein häufiger Fehler verrechnet eine <strong>annualisierte</strong> Rendite gegen einen <strong>täglichen</strong> CVaR:</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a>mu <span class="op">=</span> returns_df.mean().values <span class="op">*</span> <span class="dv">252</span> <span class="co"># ANNUALISIERT</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a>cvar <span class="op">=</span> gamma <span class="op">+</span> (<span class="dv">1</span><span class="op">/</span>(S<span class="op">*</span>(<span class="dv">1</span><span class="op">-</span>alpha))) <span class="op">*</span> cp.<span class="bu">sum</span>(u) <span class="co"># TAEGLICH</span></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a>objective <span class="op">=</span> cp.Maximize(mu <span class="op">@</span> w <span class="op">-</span> lambda_risk <span class="op">*</span> cvar <span class="op">-</span> trans_costs)</span></code></pre></div>
<p>Der Risikoterm ist dadurch faktisch um Faktor 252 zu schwach gewichtet: <code>lambda_risk = 1.5</code> bedeutet dann effektiv eine Risikoaversion von <span class="math inline">1{,}5/252 \approx 0{,}006</span>. Das Modell ist nicht falsch im Sinne von unlösbar — aber der Parameter bedeutet nicht, was er zu bedeuten scheint, und lässt sich daher nicht sinnvoll einstellen.</p>
<p><strong>Dieses Programm rechnet deshalb durchgehend auf Tagesbasis</strong> und annualisiert erst in der Ausgabe.</p>
</blockquote>
<div class="sourceCode" id="cb6"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="co">#!/usr/bin/env python3</span></span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a><span class="co"># CVaR_Portfolio.py</span></span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a><span class="co">&quot;&quot;&quot;</span></span>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a><span class="co">Kapitel CVaR: CVaR-Optimierung mit L1-Transaktionskosten via CVXPY.</span></span>
<span id="cb6-6"><a href="#cb6-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-7"><a href="#cb6-7" aria-hidden="true" tabindex="-1"></a><span class="co">Eigenschaften:</span></span>
<span id="cb6-8"><a href="#cb6-8" aria-hidden="true" tabindex="-1"></a><span class="co"> * Spaltenreihenfolge erzwungen</span></span>
<span id="cb6-9"><a href="#cb6-9" aria-hidden="true" tabindex="-1"></a><span class="co"> * Einheiten konsistent (alles taeglich, Annualisierung nur in der Ausgabe)</span></span>
<span id="cb6-10"><a href="#cb6-10" aria-hidden="true" tabindex="-1"></a><span class="co"> * Szenario-Nebenbedingungen VEKTORISIERT statt in einer Python-Schleife</span></span>
<span id="cb6-11"><a href="#cb6-11" aria-hidden="true" tabindex="-1"></a><span class="co"> (eine Matrixbedingung statt S einzelner Constraints - deutlich schneller)</span></span>
<span id="cb6-12"><a href="#cb6-12" aria-hidden="true" tabindex="-1"></a><span class="co"> * Vergleich CVaR- gegen Varianz-Optimierung</span></span>
<span id="cb6-13"><a href="#cb6-13" aria-hidden="true" tabindex="-1"></a><span class="co"> * Nachrechnung von VaR/CVaR aus den realisierten Szenarien</span></span>
<span id="cb6-14"><a href="#cb6-14" aria-hidden="true" tabindex="-1"></a><span class="co">&quot;&quot;&quot;</span></span>
<span id="cb6-15"><a href="#cb6-15" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-16"><a href="#cb6-16" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> time</span>
<span id="cb6-17"><a href="#cb6-17" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-18"><a href="#cb6-18" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> cvxpy <span class="im">as</span> cp</span>
<span id="cb6-19"><a href="#cb6-19" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> numpy <span class="im">as</span> np</span>
<span id="cb6-20"><a href="#cb6-20" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> pandas <span class="im">as</span> pd</span>
<span id="cb6-21"><a href="#cb6-21" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> yfinance <span class="im">as</span> yf</span>
<span id="cb6-22"><a href="#cb6-22" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-23"><a href="#cb6-23" aria-hidden="true" tabindex="-1"></a>TICKER <span class="op">=</span> [<span class="st">&quot;AAPL&quot;</span>, <span class="st">&quot;MSFT&quot;</span>, <span class="st">&quot;NVDA&quot;</span>, <span class="st">&quot;AMZN&quot;</span>, <span class="st">&quot;JNJ&quot;</span>, <span class="st">&quot;PFE&quot;</span>, <span class="st">&quot;JPM&quot;</span>, <span class="st">&quot;GS&quot;</span>, <span class="st">&quot;XOM&quot;</span>, <span class="st">&quot;CVX&quot;</span>]</span>
<span id="cb6-24"><a href="#cb6-24" aria-hidden="true" tabindex="-1"></a>ALPHA <span class="op">=</span> <span class="fl">0.95</span> <span class="co"># Konfidenzniveau: schlechteste 5 % der Tage</span></span>
<span id="cb6-25"><a href="#cb6-25" aria-hidden="true" tabindex="-1"></a>MAX_GEWICHT <span class="op">=</span> <span class="fl">0.25</span></span>
<span id="cb6-26"><a href="#cb6-26" aria-hidden="true" tabindex="-1"></a>GEBUEHRENSATZ <span class="op">=</span> <span class="fl">0.002</span> <span class="co"># 0,2 % je Einheit Turnover (Spread + Brokerage)</span></span>
<span id="cb6-27"><a href="#cb6-27" aria-hidden="true" tabindex="-1"></a>RISIKOAVERSION <span class="op">=</span> <span class="fl">1.5</span> <span class="co"># bezogen auf TAEGLICHE Groessen</span></span>
<span id="cb6-28"><a href="#cb6-28" aria-hidden="true" tabindex="-1"></a>HANDELSTAGE <span class="op">=</span> <span class="dv">252</span></span>
<span id="cb6-29"><a href="#cb6-29" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-30"><a href="#cb6-30" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-31"><a href="#cb6-31" aria-hidden="true" tabindex="-1"></a><span class="kw">def</span> lade_renditen():</span>
<span id="cb6-32"><a href="#cb6-32" aria-hidden="true" tabindex="-1"></a> ende <span class="op">=</span> pd.Timestamp.today().normalize()</span>
<span id="cb6-33"><a href="#cb6-33" aria-hidden="true" tabindex="-1"></a> start <span class="op">=</span> ende <span class="op">-</span> pd.DateOffset(years<span class="op">=</span><span class="dv">2</span>)</span>
<span id="cb6-34"><a href="#cb6-34" aria-hidden="true" tabindex="-1"></a> roh <span class="op">=</span> yf.download(TICKER, start<span class="op">=</span>start, end<span class="op">=</span>ende, auto_adjust<span class="op">=</span><span class="va">True</span>, progress<span class="op">=</span><span class="va">False</span>)</span>
<span id="cb6-35"><a href="#cb6-35" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> roh.empty:</span>
<span id="cb6-36"><a href="#cb6-36" aria-hidden="true" tabindex="-1"></a> <span class="cf">raise</span> <span class="pp">SystemExit</span>(<span class="st">&quot;Download fehlgeschlagen (Netz, Ticker oder Rate-Limit pruefen).&quot;</span>)</span>
<span id="cb6-37"><a href="#cb6-37" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-38"><a href="#cb6-38" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="bu">isinstance</span>(roh.columns, pd.MultiIndex):</span>
<span id="cb6-39"><a href="#cb6-39" aria-hidden="true" tabindex="-1"></a> kurse <span class="op">=</span> roh[<span class="st">&quot;Close&quot;</span>][TICKER].dropna() <span class="co"># erzwingt eigene Spaltenreihenfolge</span></span>
<span id="cb6-40"><a href="#cb6-40" aria-hidden="true" tabindex="-1"></a> <span class="cf">else</span>:</span>
<span id="cb6-41"><a href="#cb6-41" aria-hidden="true" tabindex="-1"></a> kurse <span class="op">=</span> roh[[<span class="st">&quot;Close&quot;</span>]].dropna()</span>
<span id="cb6-42"><a href="#cb6-42" aria-hidden="true" tabindex="-1"></a> kurse.columns <span class="op">=</span> TICKER</span>
<span id="cb6-43"><a href="#cb6-43" aria-hidden="true" tabindex="-1"></a> <span class="cf">assert</span> <span class="bu">list</span>(kurse.columns) <span class="op">==</span> TICKER, <span class="st">&quot;Spaltenreihenfolge weicht ab!&quot;</span></span>
<span id="cb6-44"><a href="#cb6-44" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> kurse.pct_change().dropna()</span>
<span id="cb6-45"><a href="#cb6-45" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-46"><a href="#cb6-46" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-47"><a href="#cb6-47" aria-hidden="true" tabindex="-1"></a><span class="kw">def</span> optimiere_cvar(R, w_alt, vektorisiert<span class="op">=</span><span class="va">True</span>):</span>
<span id="cb6-48"><a href="#cb6-48" aria-hidden="true" tabindex="-1"></a> <span class="co">&quot;&quot;&quot;</span></span>
<span id="cb6-49"><a href="#cb6-49" aria-hidden="true" tabindex="-1"></a><span class="co"> Maximiere: taegliche Rendite - lambda * CVaR - Transaktionskosten</span></span>
<span id="cb6-50"><a href="#cb6-50" aria-hidden="true" tabindex="-1"></a><span class="co"> Alle Groessen TAEGLICH.</span></span>
<span id="cb6-51"><a href="#cb6-51" aria-hidden="true" tabindex="-1"></a><span class="co"> &quot;&quot;&quot;</span></span>
<span id="cb6-52"><a href="#cb6-52" aria-hidden="true" tabindex="-1"></a> S, N <span class="op">=</span> R.shape</span>
<span id="cb6-53"><a href="#cb6-53" aria-hidden="true" tabindex="-1"></a> mu_taeglich <span class="op">=</span> R.mean(axis<span class="op">=</span><span class="dv">0</span>)</span>
<span id="cb6-54"><a href="#cb6-54" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-55"><a href="#cb6-55" aria-hidden="true" tabindex="-1"></a> w <span class="op">=</span> cp.Variable(N, nonneg<span class="op">=</span><span class="va">True</span>)</span>
<span id="cb6-56"><a href="#cb6-56" aria-hidden="true" tabindex="-1"></a> gamma <span class="op">=</span> cp.Variable() <span class="co"># wird im Optimum zum VaR</span></span>
<span id="cb6-57"><a href="#cb6-57" aria-hidden="true" tabindex="-1"></a> u <span class="op">=</span> cp.Variable(S, nonneg<span class="op">=</span><span class="va">True</span>) <span class="co"># Ueberschuss ueber die Schwelle</span></span>
<span id="cb6-58"><a href="#cb6-58" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-59"><a href="#cb6-59" aria-hidden="true" tabindex="-1"></a> cvar <span class="op">=</span> gamma <span class="op">+</span> (<span class="fl">1.0</span> <span class="op">/</span> (S <span class="op">*</span> (<span class="fl">1.0</span> <span class="op">-</span> ALPHA))) <span class="op">*</span> cp.<span class="bu">sum</span>(u)</span>
<span id="cb6-60"><a href="#cb6-60" aria-hidden="true" tabindex="-1"></a> turnover <span class="op">=</span> cp.norm1(w <span class="op">-</span> w_alt)</span>
<span id="cb6-61"><a href="#cb6-61" aria-hidden="true" tabindex="-1"></a> kosten <span class="op">=</span> GEBUEHRENSATZ <span class="op">*</span> turnover</span>
<span id="cb6-62"><a href="#cb6-62" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-63"><a href="#cb6-63" aria-hidden="true" tabindex="-1"></a> ziel <span class="op">=</span> cp.Maximize(mu_taeglich <span class="op">@</span> w <span class="op">-</span> RISIKOAVERSION <span class="op">*</span> cvar <span class="op">-</span> kosten)</span>
<span id="cb6-64"><a href="#cb6-64" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-65"><a href="#cb6-65" aria-hidden="true" tabindex="-1"></a> bedingungen <span class="op">=</span> [cp.<span class="bu">sum</span>(w) <span class="op">==</span> <span class="dv">1</span>, w <span class="op">&lt;=</span> MAX_GEWICHT]</span>
<span id="cb6-66"><a href="#cb6-66" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> vektorisiert:</span>
<span id="cb6-67"><a href="#cb6-67" aria-hidden="true" tabindex="-1"></a> <span class="co"># EINE Matrixbedingung statt S einzelner - deutlich schneller</span></span>
<span id="cb6-68"><a href="#cb6-68" aria-hidden="true" tabindex="-1"></a> bedingungen.append(u <span class="op">&gt;=</span> <span class="op">-</span>(R <span class="op">@</span> w) <span class="op">-</span> gamma)</span>
<span id="cb6-69"><a href="#cb6-69" aria-hidden="true" tabindex="-1"></a> <span class="cf">else</span>:</span>
<span id="cb6-70"><a href="#cb6-70" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> s <span class="kw">in</span> <span class="bu">range</span>(S): <span class="co"># Alternative: S einzelne Constraints (langsamer)</span></span>
<span id="cb6-71"><a href="#cb6-71" aria-hidden="true" tabindex="-1"></a> bedingungen.append(u[s] <span class="op">&gt;=</span> <span class="op">-</span>R[s] <span class="op">@</span> w <span class="op">-</span> gamma)</span>
<span id="cb6-72"><a href="#cb6-72" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-73"><a href="#cb6-73" aria-hidden="true" tabindex="-1"></a> problem <span class="op">=</span> cp.Problem(ziel, bedingungen)</span>
<span id="cb6-74"><a href="#cb6-74" aria-hidden="true" tabindex="-1"></a> problem.solve()</span>
<span id="cb6-75"><a href="#cb6-75" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> problem.status <span class="kw">not</span> <span class="kw">in</span> (<span class="st">&quot;optimal&quot;</span>, <span class="st">&quot;optimal_inaccurate&quot;</span>):</span>
<span id="cb6-76"><a href="#cb6-76" aria-hidden="true" tabindex="-1"></a> <span class="cf">raise</span> <span class="pp">SystemExit</span>(<span class="ss">f&quot;CVaR-Problem nicht loesbar: </span><span class="sc">{</span>problem<span class="sc">.</span>status<span class="sc">}</span><span class="ss">&quot;</span>)</span>
<span id="cb6-77"><a href="#cb6-77" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> w.value, <span class="bu">float</span>(gamma.value), <span class="bu">float</span>(cvar.value), <span class="bu">float</span>(turnover.value)</span>
<span id="cb6-78"><a href="#cb6-78" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-79"><a href="#cb6-79" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-80"><a href="#cb6-80" aria-hidden="true" tabindex="-1"></a><span class="kw">def</span> optimiere_varianz(R, w_alt):</span>
<span id="cb6-81"><a href="#cb6-81" aria-hidden="true" tabindex="-1"></a> <span class="co">&quot;&quot;&quot;Klassisches Mean-Variance zum Vergleich - ebenfalls taeglich gerechnet.</span></span>
<span id="cb6-82"><a href="#cb6-82" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-83"><a href="#cb6-83" aria-hidden="true" tabindex="-1"></a><span class="co"> ACHTUNG, DCP-Falle: Die Standardabweichung ist hier NICHT als</span></span>
<span id="cb6-84"><a href="#cb6-84" aria-hidden="true" tabindex="-1"></a><span class="co"> cp.sqrt(cp.quad_form(w, sigma)) formulierbar. cp.sqrt ist konkav und</span></span>
<span id="cb6-85"><a href="#cb6-85" aria-hidden="true" tabindex="-1"></a><span class="co"> verlangt ein konkaves Argument; quad_form ist konvex - CVXPY lehnt den</span></span>
<span id="cb6-86"><a href="#cb6-86" aria-hidden="true" tabindex="-1"></a><span class="co"> Ausdruck mit einem DCPError ab, und zwar voellig zu Recht (Anhang</span></span>
<span id="cb6-87"><a href="#cb6-87" aria-hidden="true" tabindex="-1"></a><span class="co"> Fehlerdiagnose). cp.psd_wrap() hilft dagegen nicht: Es behebt eine</span></span>
<span id="cb6-88"><a href="#cb6-88" aria-hidden="true" tabindex="-1"></a><span class="co"> NUMERISCHE Beanstandung an sigma, keine Regelverletzung im Aufbau.</span></span>
<span id="cb6-89"><a href="#cb6-89" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-90"><a href="#cb6-90" aria-hidden="true" tabindex="-1"></a><span class="co"> Der Standardweg ist die Cholesky-Zerlegung sigma = L L^T. Damit gilt</span></span>
<span id="cb6-91"><a href="#cb6-91" aria-hidden="true" tabindex="-1"></a><span class="co"> w&#39; sigma w = ||L^T w||^2, also ist die Standardabweichung die 2-Norm</span></span>
<span id="cb6-92"><a href="#cb6-92" aria-hidden="true" tabindex="-1"></a><span class="co"> eines AFFINEN Ausdrucks - konvex und damit regelkonform.</span></span>
<span id="cb6-93"><a href="#cb6-93" aria-hidden="true" tabindex="-1"></a><span class="co"> &quot;&quot;&quot;</span></span>
<span id="cb6-94"><a href="#cb6-94" aria-hidden="true" tabindex="-1"></a> N <span class="op">=</span> R.shape[<span class="dv">1</span>]</span>
<span id="cb6-95"><a href="#cb6-95" aria-hidden="true" tabindex="-1"></a> mu_taeglich <span class="op">=</span> R.mean(axis<span class="op">=</span><span class="dv">0</span>)</span>
<span id="cb6-96"><a href="#cb6-96" aria-hidden="true" tabindex="-1"></a> sigma <span class="op">=</span> np.cov(R, rowvar<span class="op">=</span><span class="va">False</span>, ddof<span class="op">=</span><span class="dv">1</span>)</span>
<span id="cb6-97"><a href="#cb6-97" aria-hidden="true" tabindex="-1"></a> <span class="co"># Der winzige Diagonalzuschlag faengt den Fall ab, dass sigma numerisch</span></span>
<span id="cb6-98"><a href="#cb6-98" aria-hidden="true" tabindex="-1"></a> <span class="co"># nur halbdefinit ist (mehr Titel als Handelstage, doppelte Spalten).</span></span>
<span id="cb6-99"><a href="#cb6-99" aria-hidden="true" tabindex="-1"></a> L <span class="op">=</span> np.linalg.cholesky(sigma <span class="op">+</span> <span class="fl">1e-12</span> <span class="op">*</span> np.eye(N))</span>
<span id="cb6-100"><a href="#cb6-100" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-101"><a href="#cb6-101" aria-hidden="true" tabindex="-1"></a> w <span class="op">=</span> cp.Variable(N, nonneg<span class="op">=</span><span class="va">True</span>)</span>
<span id="cb6-102"><a href="#cb6-102" aria-hidden="true" tabindex="-1"></a> ziel <span class="op">=</span> cp.Maximize(mu_taeglich <span class="op">@</span> w</span>
<span id="cb6-103"><a href="#cb6-103" aria-hidden="true" tabindex="-1"></a> <span class="op">-</span> RISIKOAVERSION <span class="op">*</span> cp.norm2(L.T <span class="op">@</span> w)</span>
<span id="cb6-104"><a href="#cb6-104" aria-hidden="true" tabindex="-1"></a> <span class="op">-</span> GEBUEHRENSATZ <span class="op">*</span> cp.norm1(w <span class="op">-</span> w_alt))</span>
<span id="cb6-105"><a href="#cb6-105" aria-hidden="true" tabindex="-1"></a> problem <span class="op">=</span> cp.Problem(ziel, [cp.<span class="bu">sum</span>(w) <span class="op">==</span> <span class="dv">1</span>, w <span class="op">&lt;=</span> MAX_GEWICHT])</span>
<span id="cb6-106"><a href="#cb6-106" aria-hidden="true" tabindex="-1"></a> problem.solve()</span>
<span id="cb6-107"><a href="#cb6-107" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> problem.status <span class="kw">not</span> <span class="kw">in</span> (<span class="st">&quot;optimal&quot;</span>, <span class="st">&quot;optimal_inaccurate&quot;</span>):</span>
<span id="cb6-108"><a href="#cb6-108" aria-hidden="true" tabindex="-1"></a> <span class="cf">raise</span> <span class="pp">SystemExit</span>(<span class="ss">f&quot;Varianz-Problem nicht loesbar: </span><span class="sc">{</span>problem<span class="sc">.</span>status<span class="sc">}</span><span class="ss">&quot;</span>)</span>
<span id="cb6-109"><a href="#cb6-109" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> w.value</span>
<span id="cb6-110"><a href="#cb6-110" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-111"><a href="#cb6-111" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-112"><a href="#cb6-112" aria-hidden="true" tabindex="-1"></a><span class="kw">def</span> realisierte_kennzahlen(w, R):</span>
<span id="cb6-113"><a href="#cb6-113" aria-hidden="true" tabindex="-1"></a> <span class="co">&quot;&quot;&quot;VaR und CVaR direkt aus den Szenarien - unabhaengige Gegenprobe.&quot;&quot;&quot;</span></span>
<span id="cb6-114"><a href="#cb6-114" aria-hidden="true" tabindex="-1"></a> portfoliorenditen <span class="op">=</span> R <span class="op">@</span> w</span>
<span id="cb6-115"><a href="#cb6-115" aria-hidden="true" tabindex="-1"></a> verluste <span class="op">=</span> <span class="op">-</span>portfoliorenditen</span>
<span id="cb6-116"><a href="#cb6-116" aria-hidden="true" tabindex="-1"></a> var <span class="op">=</span> <span class="bu">float</span>(np.quantile(verluste, ALPHA))</span>
<span id="cb6-117"><a href="#cb6-117" aria-hidden="true" tabindex="-1"></a> cvar <span class="op">=</span> <span class="bu">float</span>(verluste[verluste <span class="op">&gt;=</span> var].mean())</span>
<span id="cb6-118"><a href="#cb6-118" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> var, cvar, <span class="bu">float</span>(portfoliorenditen.mean()), <span class="bu">float</span>(portfoliorenditen.std(ddof<span class="op">=</span><span class="dv">1</span>))</span>
<span id="cb6-119"><a href="#cb6-119" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-120"><a href="#cb6-120" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-121"><a href="#cb6-121" aria-hidden="true" tabindex="-1"></a><span class="cf">if</span> <span class="va">__name__</span> <span class="op">==</span> <span class="st">&quot;__main__&quot;</span>:</span>
<span id="cb6-122"><a href="#cb6-122" aria-hidden="true" tabindex="-1"></a> renditen <span class="op">=</span> lade_renditen()</span>
<span id="cb6-123"><a href="#cb6-123" aria-hidden="true" tabindex="-1"></a> R <span class="op">=</span> renditen.values</span>
<span id="cb6-124"><a href="#cb6-124" aria-hidden="true" tabindex="-1"></a> S, N <span class="op">=</span> R.shape</span>
<span id="cb6-125"><a href="#cb6-125" aria-hidden="true" tabindex="-1"></a> w_alt <span class="op">=</span> np.ones(N) <span class="op">/</span> N <span class="co"># Ausgangslage: Gleichgewichtung</span></span>
<span id="cb6-126"><a href="#cb6-126" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-127"><a href="#cb6-127" aria-hidden="true" tabindex="-1"></a> t0 <span class="op">=</span> time.perf_counter()</span>
<span id="cb6-128"><a href="#cb6-128" aria-hidden="true" tabindex="-1"></a> w_cvar, var_modell, cvar_modell, turnover <span class="op">=</span> optimiere_cvar(R, w_alt, vektorisiert<span class="op">=</span><span class="va">True</span>)</span>
<span id="cb6-129"><a href="#cb6-129" aria-hidden="true" tabindex="-1"></a> dauer_vektor <span class="op">=</span> time.perf_counter() <span class="op">-</span> t0</span>
<span id="cb6-130"><a href="#cb6-130" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-131"><a href="#cb6-131" aria-hidden="true" tabindex="-1"></a> w_var <span class="op">=</span> optimiere_varianz(R, w_alt)</span>
<span id="cb6-132"><a href="#cb6-132" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-133"><a href="#cb6-133" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">&quot;=&quot;</span> <span class="op">*</span> <span class="dv">90</span>)</span>
<span id="cb6-134"><a href="#cb6-134" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">&quot; CVaR-PORTFOLIO-OPTIMIERUNG MIT TRANSAKTIONSKOSTEN&quot;</span>)</span>
<span id="cb6-135"><a href="#cb6-135" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">&quot;=&quot;</span> <span class="op">*</span> <span class="dv">90</span>)</span>
<span id="cb6-136"><a href="#cb6-136" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f&quot;Datenbasis: </span><span class="sc">{</span>S<span class="sc">}</span><span class="ss"> Handelstage, </span><span class="sc">{</span>N<span class="sc">}</span><span class="ss"> Titel | Konfidenzniveau &quot;</span></span>
<span id="cb6-137"><a href="#cb6-137" aria-hidden="true" tabindex="-1"></a> <span class="ss">f&quot;</span><span class="sc">{</span>ALPHA<span class="op">*</span><span class="dv">100</span><span class="sc">:.0f}</span><span class="ss"> % | Loesungszeit </span><span class="sc">{</span>dauer_vektor<span class="sc">:.2f}</span><span class="ss"> s</span><span class="ch">\n</span><span class="ss">&quot;</span>)</span>
<span id="cb6-138"><a href="#cb6-138" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-139"><a href="#cb6-139" aria-hidden="true" tabindex="-1"></a> <span class="co"># --- Gegenprobe: Modellwerte gegen realisierte Szenariowerte ---------</span></span>
<span id="cb6-140"><a href="#cb6-140" aria-hidden="true" tabindex="-1"></a> var_real, cvar_real, mu_real, sd_real <span class="op">=</span> realisierte_kennzahlen(w_cvar, R)</span>
<span id="cb6-141"><a href="#cb6-141" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">&quot;--- Gegenprobe: stimmen Modell und Szenarien ueberein? ---&quot;</span>)</span>
<span id="cb6-142"><a href="#cb6-142" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f&quot; VaR aus dem Modell (gamma): </span><span class="sc">{</span>var_modell<span class="op">*</span><span class="dv">100</span><span class="sc">:7.4f}</span><span class="ss"> % | &quot;</span></span>
<span id="cb6-143"><a href="#cb6-143" aria-hidden="true" tabindex="-1"></a> <span class="ss">f&quot;aus den Szenarien: </span><span class="sc">{</span>var_real<span class="op">*</span><span class="dv">100</span><span class="sc">:7.4f}</span><span class="ss"> %&quot;</span>)</span>
<span id="cb6-144"><a href="#cb6-144" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f&quot; CVaR aus dem Modell: </span><span class="sc">{</span>cvar_modell<span class="op">*</span><span class="dv">100</span><span class="sc">:7.4f}</span><span class="ss"> % | &quot;</span></span>
<span id="cb6-145"><a href="#cb6-145" aria-hidden="true" tabindex="-1"></a> <span class="ss">f&quot;aus den Szenarien: </span><span class="sc">{</span>cvar_real<span class="op">*</span><span class="dv">100</span><span class="sc">:7.4f}</span><span class="ss"> %&quot;</span>)</span>
<span id="cb6-146"><a href="#cb6-146" aria-hidden="true" tabindex="-1"></a> <span class="cf">assert</span> <span class="bu">abs</span>(cvar_modell <span class="op">-</span> cvar_real) <span class="op">&lt;</span> <span class="fl">1e-4</span>, <span class="st">&quot;CVaR stimmt nicht mit den Szenarien!&quot;</span></span>
<span id="cb6-147"><a href="#cb6-147" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">&quot; -&gt; Der Rockafellar-Uryasev-Trick liefert exakt den empirischen CVaR.&quot;</span>)</span>
<span id="cb6-148"><a href="#cb6-148" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-149"><a href="#cb6-149" aria-hidden="true" tabindex="-1"></a> <span class="co"># --- Kennzahlen beider Portfolios ------------------------------------</span></span>
<span id="cb6-150"><a href="#cb6-150" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f&quot;</span><span class="ch">\n</span><span class="sc">{</span><span class="st">&#39;Portfolio&#39;</span><span class="sc">:&lt;24}</span><span class="ss"> </span><span class="sc">{</span><span class="st">&#39;Rendite p.a.&#39;</span><span class="sc">:&gt;13}</span><span class="ss"> </span><span class="sc">{</span><span class="st">&#39;Vola p.a.&#39;</span><span class="sc">:&gt;11}</span><span class="ss"> &quot;</span></span>
<span id="cb6-151"><a href="#cb6-151" aria-hidden="true" tabindex="-1"></a> <span class="ss">f&quot;</span><span class="sc">{</span><span class="st">&#39;VaR 95% (Tag)&#39;</span><span class="sc">:&gt;15}</span><span class="ss"> </span><span class="sc">{</span><span class="st">&#39;CVaR 95% (Tag)&#39;</span><span class="sc">:&gt;16}</span><span class="ss"> </span><span class="sc">{</span><span class="st">&#39;Turnover&#39;</span><span class="sc">:&gt;10}</span><span class="ss">&quot;</span>)</span>
<span id="cb6-152"><a href="#cb6-152" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">&quot;-&quot;</span> <span class="op">*</span> <span class="dv">90</span>)</span>
<span id="cb6-153"><a href="#cb6-153" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> name, w <span class="kw">in</span> [(<span class="st">&quot;CVaR-optimiert&quot;</span>, w_cvar), (<span class="st">&quot;Varianz-optimiert&quot;</span>, w_var),</span>
<span id="cb6-154"><a href="#cb6-154" aria-hidden="true" tabindex="-1"></a> (<span class="st">&quot;Gleichgewichtung&quot;</span>, w_alt)]:</span>
<span id="cb6-155"><a href="#cb6-155" aria-hidden="true" tabindex="-1"></a> v, c, m, s <span class="op">=</span> realisierte_kennzahlen(w, R)</span>
<span id="cb6-156"><a href="#cb6-156" aria-hidden="true" tabindex="-1"></a> to <span class="op">=</span> <span class="bu">float</span>(np.<span class="bu">abs</span>(w <span class="op">-</span> w_alt).<span class="bu">sum</span>())</span>
<span id="cb6-157"><a href="#cb6-157" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f&quot;</span><span class="sc">{</span>name<span class="sc">:&lt;24}</span><span class="ss"> </span><span class="sc">{</span>m<span class="op">*</span>HANDELSTAGE<span class="op">*</span><span class="dv">100</span><span class="sc">:&gt;12.2f}</span><span class="ss"> % &quot;</span></span>
<span id="cb6-158"><a href="#cb6-158" aria-hidden="true" tabindex="-1"></a> <span class="ss">f&quot;</span><span class="sc">{</span>s<span class="op">*</span>np<span class="sc">.</span>sqrt(HANDELSTAGE)<span class="op">*</span><span class="dv">100</span><span class="sc">:&gt;10.2f}</span><span class="ss"> % </span><span class="sc">{</span>v<span class="op">*</span><span class="dv">100</span><span class="sc">:&gt;14.3f}</span><span class="ss"> % &quot;</span></span>
<span id="cb6-159"><a href="#cb6-159" aria-hidden="true" tabindex="-1"></a> <span class="ss">f&quot;</span><span class="sc">{</span>c<span class="op">*</span><span class="dv">100</span><span class="sc">:&gt;15.3f}</span><span class="ss"> % </span><span class="sc">{</span>to<span class="op">*</span><span class="dv">100</span><span class="sc">:&gt;9.1f}</span><span class="ss"> %&quot;</span>)</span>
<span id="cb6-160"><a href="#cb6-160" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-161"><a href="#cb6-161" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">&quot;</span><span class="ch">\n</span><span class="st">Hinweis zur Annualisierung: Renditen werden mit 252 skaliert,&quot;</span>)</span>
<span id="cb6-162"><a href="#cb6-162" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">&quot;Volatilitaeten mit sqrt(252). Fuer VaR/CVaR ist eine solche Skalierung&quot;</span>)</span>
<span id="cb6-163"><a href="#cb6-163" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">&quot;nur unter starken Annahmen (Unabhaengigkeit, kein Drift) zulaessig -&quot;</span>)</span>
<span id="cb6-164"><a href="#cb6-164" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">&quot;sie werden hier deshalb bewusst als TAGESwerte ausgewiesen.&quot;</span>)</span>
<span id="cb6-165"><a href="#cb6-165" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-166"><a href="#cb6-166" aria-hidden="true" tabindex="-1"></a> <span class="co"># --- Allokationstabelle ------------------------------------------------</span></span>
<span id="cb6-167"><a href="#cb6-167" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">&quot;</span><span class="ch">\n</span><span class="st">--- Allokation ---&quot;</span>)</span>
<span id="cb6-168"><a href="#cb6-168" aria-hidden="true" tabindex="-1"></a> tabelle <span class="op">=</span> pd.DataFrame({</span>
<span id="cb6-169"><a href="#cb6-169" aria-hidden="true" tabindex="-1"></a> <span class="st">&quot;Ticker&quot;</span>: TICKER,</span>
<span id="cb6-170"><a href="#cb6-170" aria-hidden="true" tabindex="-1"></a> <span class="st">&quot;vorher&quot;</span>: [<span class="ss">f&quot;</span><span class="sc">{</span>v<span class="op">*</span><span class="dv">100</span><span class="sc">:5.1f}</span><span class="ss"> %&quot;</span> <span class="cf">for</span> v <span class="kw">in</span> w_alt],</span>
<span id="cb6-171"><a href="#cb6-171" aria-hidden="true" tabindex="-1"></a> <span class="st">&quot;CVaR-opt.&quot;</span>: [<span class="ss">f&quot;</span><span class="sc">{</span>v<span class="op">*</span><span class="dv">100</span><span class="sc">:5.1f}</span><span class="ss"> %&quot;</span> <span class="cf">for</span> v <span class="kw">in</span> w_cvar],</span>
<span id="cb6-172"><a href="#cb6-172" aria-hidden="true" tabindex="-1"></a> <span class="st">&quot;Handel&quot;</span>: [<span class="ss">f&quot;</span><span class="sc">{</span>(w_cvar[i]<span class="op">-</span>w_alt[i])<span class="op">*</span><span class="dv">100</span><span class="sc">:+6.1f}</span><span class="ss"> %&quot;</span> <span class="cf">for</span> i <span class="kw">in</span> <span class="bu">range</span>(N)],</span>
<span id="cb6-173"><a href="#cb6-173" aria-hidden="true" tabindex="-1"></a> <span class="st">&quot;Varianz-opt.&quot;</span>: [<span class="ss">f&quot;</span><span class="sc">{</span>v<span class="op">*</span><span class="dv">100</span><span class="sc">:5.1f}</span><span class="ss"> %&quot;</span> <span class="cf">for</span> v <span class="kw">in</span> w_var],</span>
<span id="cb6-174"><a href="#cb6-174" aria-hidden="true" tabindex="-1"></a> })</span>
<span id="cb6-175"><a href="#cb6-175" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(tabelle.to_string(index<span class="op">=</span><span class="va">False</span>))</span>
<span id="cb6-176"><a href="#cb6-176" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f&quot;</span><span class="ch">\n</span><span class="ss">Turnover </span><span class="sc">{</span>turnover<span class="op">*</span><span class="dv">100</span><span class="sc">:.1f}</span><span class="ss"> % -&gt; Transaktionskosten &quot;</span></span>
<span id="cb6-177"><a href="#cb6-177" aria-hidden="true" tabindex="-1"></a> <span class="ss">f&quot;</span><span class="sc">{</span>GEBUEHRENSATZ<span class="op">*</span>turnover<span class="op">*</span><span class="dv">100</span><span class="sc">:.3f}</span><span class="ss"> % des Portfoliowerts&quot;</span>)</span>
<span id="cb6-178"><a href="#cb6-178" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-179"><a href="#cb6-179" aria-hidden="true" tabindex="-1"></a> <span class="co"># --- Laufzeitvergleich vektorisiert vs. Schleife ----------------------</span></span>
<span id="cb6-180"><a href="#cb6-180" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> S <span class="op">&lt;=</span> <span class="dv">600</span>: <span class="co"># bei sehr vielen Szenarien zu langsam</span></span>
<span id="cb6-181"><a href="#cb6-181" aria-hidden="true" tabindex="-1"></a> t0 <span class="op">=</span> time.perf_counter()</span>
<span id="cb6-182"><a href="#cb6-182" aria-hidden="true" tabindex="-1"></a> optimiere_cvar(R, w_alt, vektorisiert<span class="op">=</span><span class="va">False</span>)</span>
<span id="cb6-183"><a href="#cb6-183" aria-hidden="true" tabindex="-1"></a> dauer_schleife <span class="op">=</span> time.perf_counter() <span class="op">-</span> t0</span>
<span id="cb6-184"><a href="#cb6-184" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f&quot;</span><span class="ch">\n</span><span class="ss">--- Laufzeit: </span><span class="sc">{</span>S<span class="sc">}</span><span class="ss"> Nebenbedingungen aufbauen ---&quot;</span>)</span>
<span id="cb6-185"><a href="#cb6-185" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f&quot; vektorisiert (u &gt;= -(R @ w) - gamma): </span><span class="sc">{</span>dauer_vektor<span class="sc">:6.2f}</span><span class="ss"> s&quot;</span>)</span>
<span id="cb6-186"><a href="#cb6-186" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f&quot; Schleife ueber Szenarien (V01): </span><span class="sc">{</span>dauer_schleife<span class="sc">:6.2f}</span><span class="ss"> s &quot;</span></span>
<span id="cb6-187"><a href="#cb6-187" aria-hidden="true" tabindex="-1"></a> <span class="ss">f&quot;(</span><span class="sc">{</span>dauer_schleife<span class="op">/</span>dauer_vektor<span class="sc">:.1f}</span><span class="ss">x langsamer)&quot;</span>)</span>
<span id="cb6-188"><a href="#cb6-188" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">&quot;=&quot;</span> <span class="op">*</span> <span class="dv">90</span>)</span></code></pre></div>
<blockquote>
<p><strong>💻 Code-Durchgang: Vektorisierung</strong></p>
<p>Die entscheidende Zeile ist</p>
<div class="sourceCode" id="cb7"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a>bedingungen.append(u <span class="op">&gt;=</span> <span class="op">-</span>(R <span class="op">@</span> w) <span class="op">-</span> gamma) <span class="co"># EINE Matrixbedingung</span></span></code></pre></div>
<p>statt</p>
<div class="sourceCode" id="cb8"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="cf">for</span> s <span class="kw">in</span> <span class="bu">range</span>(S):</span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a> bedingungen.append(u[s] <span class="op">&gt;=</span> <span class="op">-</span>R[s] <span class="op">@</span> w <span class="op">-</span> gamma) <span class="co"># S einzelne Bedingungen</span></span></code></pre></div>
<p>Beide beschreiben <strong>dasselbe Modell</strong>. Der Unterschied liegt im Aufbau: CVXPY muss im zweiten Fall 500 einzelne Ausdrucksbäume erzeugen, prüfen und zusammensetzen. Bei einem Backtest mit 60 Rebalancings (<a href="handelsmaschine.html#kap-handelsmaschine">Kapitel 21</a>) summiert sich das erheblich.</p>
<p><strong>Die allgemeine Regel:</strong> Wenn Sie in einer Modellierungssprache eine Python-Schleife über Datenzeilen schreiben, prüfen Sie, ob sich dasselbe als Matrixoperation ausdrücken lässt. Der Solver rechnet ohnehin mit Matrizen — der Umweg über einzelne Ausdrücke kostet nur Aufbauzeit.</p>
</blockquote>
<blockquote>
<p><strong>⚠️ Die Standardabweichung ist in CVXPY keine Wurzel</strong></p>
<p>Im Vergleichsmodell <code>optimiere_varianz()</code> steht die Standardabweichung als</p>
<div class="sourceCode" id="cb9"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a>L <span class="op">=</span> np.linalg.cholesky(sigma <span class="op">+</span> <span class="fl">1e-12</span> <span class="op">*</span> np.eye(N))</span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a>risiko <span class="op">=</span> cp.norm2(L.T <span class="op">@</span> w) <span class="co"># = sqrt(w&#39; sigma w)</span></span></code></pre></div>
<p>und <strong>nicht</strong> als das Naheliegende, <code>cp.sqrt(cp.quad_form(w, sigma))</code>. Der naheliegende Ausdruck ist nicht DCP und wird von CVXPY mit einem <code>DCPError</code> abgelehnt: <code>cp.sqrt</code> ist konkav und verlangt deshalb ein <strong>konkaves</strong> Argument, <code>quad_form</code> ist aber konvex. Die Regel wird verletzt, obwohl die Funktion als ganze mathematisch völlig harmlos ist — <span class="math inline">\sqrt{w^\top \Sigma w}</span> ist konvex, DCP kann es nur nicht <em>sehen</em>.</p>
<p>Wichtig ist die Fehlerdiagnose dahinter, weil sie leicht in die Irre geht: <code>cp.psd_wrap(sigma)</code> sieht nach der Lösung aus und ist keine. Es unterdrückt die <strong>numerische</strong> Beanstandung, dass <span class="math inline">\Sigma</span> nicht als positiv semidefinit erkannt wird — gegen die <strong>strukturelle</strong> Regelverletzung im Aufbau hilft es nicht.</p>
<p>Der Ausweg ist immer derselbe: Zerlegen Sie <span class="math inline">\Sigma = LL^\top</span> (Cholesky). Dann ist <span class="math inline">w^\top \Sigma w = \lVert L^\top w\rVert_2^2</span>, und die Standardabweichung wird zur 2-Norm eines <strong>affinen</strong> Ausdrucks — konvex, regelkonform und für den Solver sogar die bessere Formulierung, weil sie direkt ein Kegelproblem ist. Der winzige Diagonalzuschlag <span class="math inline">10^{-12}</span> fängt den Fall ab, dass <span class="math inline">\Sigma</span> numerisch nur halbdefinit ist (mehr Titel als Handelstage, duplizierte Spalten). Die vollständige Fehlertabelle steht in <a href="anhang-fehlerdiagnose.html#anhang-fehlerdiagnose">Anhang C</a>.</p>
</blockquote>
<blockquote>
<p><strong>💡 Zur Annualisierung von VaR und CVaR</strong> Ein häufiger Fehler skaliert den täglichen CVaR mit <span class="math inline">\sqrt{252}</span>. Diese <strong>Wurzel-Zeit-Regel</strong> gilt streng nur für <strong>Standardabweichungen</strong> unabhängig identisch verteilter Größen ohne Drift. Der CVaR ist ein Erwartungswert über einen Verteilungsrand — für ihn ist die Regel eine grobe Näherung, die bei fetten Rändern und Autokorrelation systematisch danebenliegt.</p>
<p><strong>Dieses Buch weist VaR und CVaR deshalb als Tageswerte aus</strong> und benennt die Skalierungsproblematik ausdrücklich. Wer Mehrtageshorizonte braucht, simuliert sie (Monte-Carlo aus <a href="unsicherheit.html#kap-unsicherheit">Kapitel 12</a>) statt zu skalieren.</p>
</blockquote>
<hr />
<h2 id="sec:cvar-uebungsaufgaben">20.7 Übungsaufgaben</h2>
<blockquote>
<p>Lösungen: <a href="anhang-loesungen.html#sec:loesungen-cvar">Abschnitt A.20</a>.</p>
</blockquote>
<p><strong>Aufgabe 20.1 ⭐ — VaR und CVaR ablesen.</strong> Zehn Tagesverluste (in %): <span class="math inline">-1{,}2</span>, <span class="math inline">0{,}3</span>, <span class="math inline">2{,}1</span>, <span class="math inline">-0{,}8</span>, <span class="math inline">5{,}4</span>, <span class="math inline">1{,}1</span>, <span class="math inline">-2{,}0</span>, <span class="math inline">0{,}6</span>, <span class="math inline">8{,}9</span>, <span class="math inline">-0{,}4</span> (positiv = Verlust). Bestimmen Sie <span class="math inline">\text{VaR}_{80\%}</span> und <span class="math inline">\text{CVaR}_{80\%}</span> von Hand.</p>
<p><strong>Aufgabe 20.2 ⭐ — Warum kohärent?</strong> Erklären Sie in eigenen Worten, warum ein Risikomaß subadditiv sein sollte. Was bedeutet es wirtschaftlich, wenn diese Eigenschaft verletzt ist?</p>
<p><strong>Aufgabe 20.3 ⭐⭐ — Rockafellar-Uryasev nachvollziehen.</strong> Zeigen Sie für die drei Szenarien mit Verlusten <span class="math inline">(1, 4, 9)</span> und <span class="math inline">\alpha = 2/3</span>: (a) Was ist der empirische CVaR? (b) Werten Sie <span class="math inline">\gamma + \frac{1}{S(1-\alpha)}\sum_s \max(\text{Verlust}_s-\gamma, 0)</span> für <span class="math inline">\gamma \in \{0, 1, 4, 5, 9\}</span> aus. (c) Bei welchem <span class="math inline">\gamma</span> ist der Ausdruck minimal, und stimmt das Minimum mit (a) überein?</p>
<p><strong>Aufgabe 20.4 ⭐⭐ — Einheiten prüfen.</strong> Angenommen, ein Modell verrechnet Jahresrendite gegen Tages-CVaR (siehe die Warnung in <a href="#sec:cvar-implementierung-cvar-portfolio-mit-reibung">Abschnitt 20.6</a>). Berechnen Sie: Welchem „effektiven“ täglichen <span class="math inline">\lambda</span> entspräche <code>lambda_risk = 1.5</code> dadurch? Welchen Wert müsste man stattdessen setzen, um dieselbe Wirkung wie <code>RISIKOAVERSION = 1.5</code> im konsistenten Tagesmodell zu erzielen?</p>
<p><strong>Aufgabe 20.5 ⭐⭐⭐ — Risikoaversion kalibrieren.</strong> Variieren Sie <code>RISIKOAVERSION</code> von 0 bis 20 und tragen Sie Rendite, Volatilität, CVaR und Turnover gegeneinander auf. (a) Wie sieht die „Effizienzgrenze“ im Rendite-CVaR-Raum aus? (b) Bei welchem Wert entspricht das CVaR-Portfolio ungefähr dem Varianz-Portfolio? (c) Welchen Wert würden Sie einem konservativen Stiftungsfonds empfehlen — und wie begründen Sie ihn ohne Fachjargon?</p>
<p><strong>Aufgabe 20.6 ⭐⭐⭐ — Turnover-Grenze statt Strafe.</strong> Ersetzen Sie den Kostenterm durch eine <strong>harte Grenze</strong> <span class="math inline">\lVert\mathbf{w}-\mathbf{w}_{\text{alt}}\rVert_1 \le \tau</span> und variieren Sie <span class="math inline">\tau \in \{0{,}05;\ 0{,}1;\ 0{,}25;\ 0{,}5;\ 1{,}0\}</span>. (a) Wie verändert sich die erreichbare Rendite? (b) Was ist der Vorteil einer Grenze gegenüber einer Strafe — und was der Nachteil? (c) Wann würden Sie was einsetzen?</p>
<hr />
<h2 id="sec:cvar-denkfehler">20.8 Finde den Denkfehler</h2>
<div class="card card-denkfehler">
<blockquote>
<p><strong>🐛 Finde den Denkfehler 13.1: Das Risikobudget, das durch Diversifikation stieg</strong></p>
<p>Eine Bank vergibt Risikobudgets je Abteilung. Zwei Kreditabteilungen halten je eine Unternehmensanleihe über 100 € Nominal mit <strong>4 % Ausfallwahrscheinlichkeit</strong> (bei Ausfall Totalverlust, sonst 2 € Kupon). Der Risikocontroller misst für jede einzeln:</p>
<p><span class="math display">\text{VaR}_{95}(\text{A}) = -2{,}00\,€, \qquad \text{VaR}_{95}(\text{B}) = -2{,}00\,€</span></p>
<p>Ein <em>negativer</em> Verlust, also ein Gewinn. Auf dem 95-%-Niveau erscheint jede Anleihe risikolos, beide Abteilungen bekommen grünes Licht. Der Controller notiert als Gesamtrisiko die Summe: <span class="math inline">-4{,}00\,€</span>.</p>
<p>Dann werden die Positionen in einem gemeinsamen Buch zusammengelegt. Der VaR des Gesamtbuchs beträgt <strong>+98,00 €</strong>.</p>
<p><strong>Ihre Aufgabe:</strong></p>
<ol type="a">
<li><p>Wie kann die Zusammenlegung zweier <strong>unabhängiger</strong> Positionen das gemessene Risiko von <span class="math inline">-4\,€</span> auf <span class="math inline">+98\,€</span> treiben? Rechnen Sie die entscheidende Wahrscheinlichkeit aus.</p></li>
<li><p>Warum meldet der VaR für eine einzelne Anleihe einen Gewinn, obwohl sie mit 4 % Wahrscheinlichkeit vollständig ausfällt?</p></li>
<li><p>Welche Eigenschaft eines Risikomaßes wird hier verletzt? Was bedeutet das konkret für ein Unternehmen, das Risikobudgets auf Abteilungen verteilt und wieder zusammenzählt?</p></li>
<li><p>Der CVaR liefert 79,59 € und 79,66 € einzeln, aber nur 101,33 € zusammen — statt der Summe von 159,24 €. Warum kann ihm das Verhalten des VaR nicht passieren?</p></li>
</ol>
<p><em>Die Zahlen stammen aus Teil 2 von <code>VaR_CVaR_Demo.py</code> oben. Auflösung:</em> <em><a href="anhang-loesungen.html#sec:loesungen-cvar">Abschnitt A.20</a>.</em></p>
</blockquote>
</div>
<blockquote>
<p><strong>⚠️ Eine Falle beim Nachrechnen</strong></p>
<p>Wenn Sie den CVaR selbst nachrechnen wollen: Der naheliegende Weg <code>verluste[verluste &gt;= var].mean()</code> ist <strong>falsch</strong>, sobald die Verteilung Atome hat — und hier hat sie genau zwei mögliche Werte. Der VaR liegt dann selbst auf einem Atom, und der Vergleich <code>&gt;=</code> erfasst weit mehr Wahrscheinlichkeitsmasse als die vorgesehenen 5 %.</p>
<p>Deshalb verwendet <code>cvar_rockafellar()</code> oben die Optimierungsformel statt der naiven Mittelung. Wer stattdessen exakt abzählt, muss die schlechtesten <span class="math inline">\lceil (1-\alpha)\,N \rceil</span> Szenarien nehmen — nicht alle, die eine Schwelle überschreiten.</p>
<p>Diese Falle ist besonders unangenehm, weil das falsche Ergebnis plausibel aussieht. Sie fällt nur auf, wenn man wie hier eine <strong>unabhängige Gegenprobe</strong> hat: Ein CVaR, der die Subadditivität verletzt, kann nicht stimmen.</p>
</blockquote>
<blockquote>
<p><strong>🎯 Merksatz</strong> Ein Risikomaß, dessen Werte man nicht addieren darf, ist als Steuerungsgröße unbrauchbar — denn genau das tut jede Organisation mit Kennzahlen: Sie verteilt sie auf Einheiten und zählt sie wieder zusammen. Der CVaR ist <strong>kohärent</strong> und erlaubt das; der VaR nicht. Aus diesem Grund hat die Bankenaufsicht mit Basel III vom VaR auf den <em>Expected Shortfall</em> umgestellt — dieselbe Größe, die hier CVaR heißt.</p>
</blockquote>
<hr />
<h2 id="sec:cvar-quiz">20.9 Micro-Quiz</h2>
<div class="card card-quiz">
<blockquote>
<p><strong>❓ Micro-Quiz 13: Drei Fragen zum Selbstcheck</strong></p>
<p>Genau eine Antwort ist jeweils richtig. Auflösung in <a href="anhang-loesungen.html#quiz-loesung-cvar">Anhang A</a>.</p>
<p><strong>1. Zwei Anlagen haben denselben VaR(95) von 3 %. Was wissen Sie über ihre Extremverluste?</strong> (a) Sie sind gleich hoch — der VaR misst genau das. (b) <strong>Nichts.</strong> Der VaR ist ein Quantil: Er markiert die Schwelle und sagt nichts darüber, was dahinter liegt. Die eine kann dort 3 %, die andere 40 % haben. (c) Die Anlage mit der höheren Schwankung hat auch die höheren Extremverluste.</p>
<p><strong>2. Warum lässt sich der CVaR als lineares Programm minimieren, der VaR aber nicht?</strong> (a) Der VaR ist nicht differenzierbar. (b) Der CVaR lässt sich nach Rockafellar/Uryasev über eine Hilfsvariable und Schlupfterme als konvexes — sogar lineares — Problem schreiben. Die VaR-Minimierung ist dagegen nicht konvex und hat viele lokale Optima. (c) Der CVaR ist immer größer als der VaR.</p>
<p><strong>3. Sie sollen das Risiko von drei Handelsbüchern zu einer Gesamtkennzahl zusammenfassen. Welches Maß nehmen Sie?</strong> (a) VaR — er ist in der Praxis verbreiteter und leichter zu erklären. (b) CVaR, weil er <strong>subadditiv</strong> ist: Die Gesamtkennzahl kann nie größer werden als die Summe der Einzelkennzahlen, Diversifikation wird also korrekt belohnt. (c) Beide liefern dasselbe, solange die Bücher unabhängig sind.</p>
</blockquote>
</div>
<hr />
<h2 id="sec:cvar-selbsttest">20.10 Selbsttest</h2>
<blockquote>
<p>Antworten: <a href="anhang-loesungen.html#selbsttest-loesung-cvar">Anhang A</a>.</p>
</blockquote>
<ol type="1">
<li>Was misst der CVaR, was der VaR nicht misst?</li>
<li>Warum ist der CVaR konvex, aber nicht streng konvex?</li>
<li>Welche Rolle spielt die Hilfsvariable <span class="math inline">\gamma</span> bei Rockafellar/Uryasev?</li>
<li>Warum bevorzugt die <span class="math inline">L_1</span>-Strafe wenige große statt vieler kleiner Umschichtungen?</li>
<li>Warum sollte man tägliche und annualisierte Größen nicht in einer Zielfunktion mischen?</li>
</ol>
<hr />
<h2 id="sec:cvar-zusammenfassung">20.11 Zusammenfassung</h2>
<ul>
<li><strong>Reale Renditen haben fette Ränder.</strong> Ein 5-Sigma-Tag ist unter Normalverteilung ein Jahrtausendereignis — an echten Märkten passiert er alle paar Jahre.</li>
<li><strong>Der VaR ist ein Quantil und schaut nicht dahinter.</strong> Zwei Anlagen mit identischem VaR können Extremverluste von 3 % und 40 % haben. Der VaR sagt, <strong>wie oft</strong> es schiefgeht; der CVaR, <strong>wie schlimm</strong> es dann ist.</li>
<li><strong>Der VaR ist nicht kohärent:</strong> Er kann Diversifikation als Risikoerhöhung ausweisen. Deshalb die regulatorische Umstellung auf den Expected Shortfall. Praktische Folge: Man darf VaR-Kennzahlen <strong>nicht über Einheiten addieren</strong> — und genau das tut jede Organisation mit Kennzahlen.</li>
<li><strong>Das bessere Maß ist hier zugleich das leichter optimierbare</strong> — ein seltener Glücksfall. Der CVaR wird zum LP, die VaR-Minimierung bleibt nicht-konvex.</li>
<li><strong>Rockafellar/Uryasev</strong> machen den CVaR über eine Hilfsvariable <span class="math inline">\gamma</span> linear optimierbar, ohne den VaR vorher zu kennen.</li>
<li><strong>Transaktionskosten gehören ins Modell</strong>, nicht in eine nachgelagerte Rechnung — sonst schichtet der Optimierer bei jedem Rauschen um.</li>
<li><strong>Einheiten konsistent halten.</strong> Tägliche Renditen zu täglichem Risiko; annualisiert wird erst in der Ausgabe.</li>
<li><strong>Vektorisieren Sie Szenario-Bedingungen</strong> — das spart bei wiederholten Läufen erheblich Zeit.</li>
</ul>
<p><strong>Ausblick.</strong> <a href="handelsmaschine.html#kap-handelsmaschine">Kapitel 21</a> fügt alles zusammen: Datenpipeline, Signal, Optimierung, Rebalancing und ein Walk-Forward-Backtest ohne Lookahead-Bias.</p>
</article>
<button type="button" class="fortschritt-knopf" data-kapitel="cvar.html"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg> <span>Als gelesen markieren</span></button>
<nav class="prev-next"><a class="prev-next-knopf prev-next-prev" href="markowitz.html"><svg class="icon" aria-hidden="true"><use href="#icon-chevron-left"></use></svg><span><small>Zurück</small>Kapitel 19: Die moderne Portfoliotheorie nach Markowitz</span></a><a class="prev-next-knopf prev-next-next" href="handelsmaschine.html"><span><small>Weiter</small>Kapitel 21: Die vollständige quantitative Handelsmaschine</span><svg class="icon" aria-hidden="true"><use href="#icon-chevron-right"></use></svg></a></nav>
</main>
</div>
<footer class="site-footer">
<p>© Dieter Schlüter · <a href="gesamtdokument.html">Gesamtdokument</a> ·
<a href="programme.html">Beispielprogramme</a></p>
</footer>
<script defer src="assets/search-index.js"></script>
<script defer src="assets/programme.js"></script>
<script defer src="assets/site.js"></script>
</body>
</html>