Neues Skript erzeuge_stichwortregister_04.py:
- Sucht alle Glossarbegriffe (Anzeigename) in den Kapiteldateien
und markiert die erste Fundstelle je Datei mit {idx:Indexmarke}
- Termliste aus glossar_eintraege_04.py + vorhandenen {idx:...}-Markern
- Idempotent: erkennt vorhandene Marker und überspringt sie
- Überspringt Codeblöcke, Inline-Code und Math
- --check und --bericht Modi
- 605 Marker eingefügt (2 Durchläufe: 597 + 8)
Zusätzlich:
- titeltexte_04.py _saeubern(): entfernt {idx:...}-Marker vor
Titeltext-Vergleich (pruefe_titeltexte schlug sonst fehl)
784 lines
115 KiB
HTML
Generated
784 lines
115 KiB
HTML
Generated
<!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{idx: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{idx: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><li data-kapitel="synthese-grundlagen.html"><a href="synthese-grundlagen.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Synthese Teil I</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{idx: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{idx: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><li data-kapitel="synthese-kernverfahren.html"><a href="synthese-kernverfahren.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Synthese Teil II</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></span><span>Kapitel 12: Optimierung unter Unsicherheit — Monte-Carlo, Stochastik, Robustheit</span></a></li><li data-kapitel="dynamische-programmierung.html"><a href="dynamische-programmierung.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 13: Dynamische Programmierung — Die Bellman-Gleichung{idx:Bellman-Gleichung} und Order-Execution</span></a></li><li data-kapitel="mehrziel.html"><a href="mehrziel.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 14: Mehrere Ziele — Pareto-Fronten statt Gewichte</span></a></li><li data-kapitel="prognose.html"><a href="prognose.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 15: Predict-then-Optimize{idx:Predict-then-Optimize} — die bessere Prognose, die schlechtere Entscheidung</span></a></li><li data-kapitel="synthese-nichtlinear.html"><a href="synthese-nichtlinear.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Synthese Teil III</span></a></li></ul></details><details class="sidebar-gruppe" open><summary>Teil IV: Anwendungen — Energiewirtschaft und Finanzmärkte</summary><ul><li data-kapitel="bruecke.html"><a href="bruecke.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 16: Die Strukturbrücke — dieselbe Mathematik, zwei Welten</span></a></li><li data-kapitel="supplychain.html"><a href="supplychain.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 17: Supply-Chain und Energieeinsatz unter Unsicherheit</span></a></li><li data-kapitel="finanzdaten.html"><a href="finanzdaten.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 18: Finanzdaten-Modellierung — Renditen, Kovarianz und Shrinkage</span></a></li><li data-kapitel="markowitz.html"><a href="markowitz.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 19: Die moderne Portfoliotheorie nach Markowitz</span></a></li><li data-kapitel="cvar.html" class="aktiv"><a href="cvar.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 20: Tail-Risiko, CVaR und Transaktionskosten{idx:Transaktionskosten}</span></a></li><li data-kapitel="handelsmaschine.html"><a href="handelsmaschine.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 21: Die vollständige quantitative Handelsmaschine</span></a></li><li data-kapitel="synthese-anwendungen.html"><a href="synthese-anwendungen.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Synthese Teil IV</span></a></li></ul></details><details class="sidebar-gruppe"><summary>Teil V: Praxis</summary><ul><li data-kapitel="praxisfallen.html"><a href="praxisfallen.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 22: Praxisfallen und der Weg zum produktiven Einsatz</span></a></li><li data-kapitel="testing.html"><a href="testing.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 23: Testen, Messen, Ausliefern</span></a></li><li data-kapitel="synthese-praxis.html"><a href="synthese-praxis.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Synthese Teil V</span></a></li><li data-kapitel="projektwerkstatt.html"><a href="projektwerkstatt.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Projektwerkstatt</span></a></li></ul></details><details class="sidebar-gruppe"><summary>Anhänge</summary><ul><li data-kapitel="anhang-loesungen.html"><a href="anhang-loesungen.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Anhang A: Lösungen zu allen Übungsaufgaben</span></a></li><li data-kapitel="anhang-modellierungsmuster.html"><a href="anhang-modellierungsmuster.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Anhang B: Katalog der Modellierungsmuster</span></a></li><li data-kapitel="anhang-fehlerdiagnose.html"><a href="anhang-fehlerdiagnose.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Anhang C: Fehlerdiagnose-Handbuch</span></a></li><li data-kapitel="anhang-spickzettel.html"><a href="anhang-spickzettel.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Anhang D: Spickzettel der Solver</span></a></li><li data-kapitel="anhang-glossar.html"><a href="anhang-glossar.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Anhang E: Glossar</span></a></li><li data-kapitel="anhang-literatur.html"><a href="anhang-literatur.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Anhang F: Literaturverzeichnis</span></a></li></ul></details><ul class="sidebar-extra"><li><a href="programme.html"><svg class="icon" aria-hidden="true"><use href="#icon-book"></use></svg> Beispielprogramme</a></li><li><a href="notebooks.html"><svg class="icon" aria-hidden="true"><use href="#icon-book"></use></svg> Notebooks</a></li><li><a href="Notebooks_04.zip" download><svg class="icon" aria-hidden="true"><use href="#icon-download"></use></svg> Download Notebooks als ZIP</a></li><li><a href="anhang-glossar.html"><svg class="icon" aria-hidden="true"><use href="#icon-book"></use></svg> Glossar</a></li><li><a href="stichwortverzeichnis.html"><svg class="icon" aria-hidden="true"><use href="#icon-search"></use></svg> Stichwortverzeichnis</a></li><li><a href="gesamtdokument.html"><svg class="icon" aria-hidden="true"><use href="#icon-external-link"></use></svg> Gesamtdokument (eine HTML-Seite)</a></li><li><a href="Operations_Research_mit_Python_Version_04.pdf" download><svg class="icon" aria-hidden="true"><use href="#icon-download"></use></svg> Download Buch als PDF</a></li></ul></div></nav>
|
||
<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{idx: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> — herunterladen und in Jupyter öffnen, in Colab hochladen oder mit dem Kurs-Image starten</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">"Anlage A"</span>, A), (<span class="st">"Anlage B"</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"><=</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"</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"> %"</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">"""</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 "unmoegliche" 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">"""</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">-></span> <span class="bu">float</span>:</span>
|
||
<span id="cb3-16"><a href="#cb3-16" aria-hidden="true" tabindex="-1"></a> <span class="co">"""VaR = Quantil der Verlustverteilung (Verluste positiv, Gewinne negativ)."""</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">-></span> <span class="bu">float</span>:</span>
|
||
<span id="cb3-21"><a href="#cb3-21" aria-hidden="true" tabindex="-1"></a> <span class="co">"""</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 "Mittelwert aller Werte >= VaR" 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 '>=' 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 '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' optimieren.</span></span>
|
||
<span id="cb3-31"><a href="#cb3-31" aria-hidden="true" tabindex="-1"></a><span class="co"> """</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">"__main__"</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">"="</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">" TEIL 1: WIE OFT TRITT DAS 'UNMOEGLICHE' EIN?"</span>)</span>
|
||
<span id="cb3-43"><a href="#cb3-43" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"="</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">"Vergleich: Normalverteilung gegen t-Verteilung mit 3 Freiheitsgraden"</span>)</span>
|
||
<span id="cb3-45"><a href="#cb3-45" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"(beide auf Standardabweichung 1 normiert).</span><span class="ch">\n</span><span class="st">"</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"</span><span class="sc">{</span><span class="st">'Ereignis'</span><span class="sc">:<22}</span><span class="ss"> </span><span class="sc">{</span><span class="st">'Normal'</span><span class="sc">:>14}</span><span class="ss"> </span><span class="sc">{</span><span class="st">'t (df=3)'</span><span class="sc">:>14}</span><span class="ss"> </span><span class="sc">{</span><span class="st">'Faktor'</span><span class="sc">:>11}</span><span class="ss"> "</span></span>
|
||
<span id="cb3-51"><a href="#cb3-51" aria-hidden="true" tabindex="-1"></a> <span class="ss">f"</span><span class="sc">{</span><span class="st">'Normal: 1 Tag in'</span><span class="sc">:>18}</span><span class="ss">"</span>)</span>
|
||
<span id="cb3-52"><a href="#cb3-52" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"-"</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"Abweichung > </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">:>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">:>13.6f}</span><span class="ss"> % "</span></span>
|
||
<span id="cb3-57"><a href="#cb3-57" aria-hidden="true" tabindex="-1"></a> <span class="ss">f"</span><span class="sc">{</span>p_t<span class="op">/</span>p_normal<span class="sc">:>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">:>15,.0f}</span><span class="ss"> Jahre"</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">"</span><span class="ch">\n</span><span class="st">Deutung: Ein 5-Sigma-Tag ist unter Normalverteilung ein Ereignis von"</span>)</span>
|
||
<span id="cb3-60"><a href="#cb3-60" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"etwa einmal in 6.900 Jahren. Reale Aktienmaerkte liefern solche Tage"</span>)</span>
|
||
<span id="cb3-61"><a href="#cb3-61" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"mehrfach pro Jahrzehnt. Wer allein mit Varianz steuert, plant fuer"</span>)</span>
|
||
<span id="cb3-62"><a href="#cb3-62" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"eine Welt, in der Crashs praktisch nicht vorkommen."</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">"</span><span class="ch">\n</span><span class="st">"</span> <span class="op">+</span> <span class="st">"="</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">" TEIL 2: WARUM DER VaR KEIN KOHAERENTES RISIKOMASS IST"</span>)</span>
|
||
<span id="cb3-67"><a href="#cb3-67" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"="</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">"Zwei unabhaengige Anleihen, je 100 EUR Nominal."</span>)</span>
|
||
<span id="cb3-69"><a href="#cb3-69" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"Jede faellt mit 4 % Wahrscheinlichkeit aus (Verlust 100),"</span>)</span>
|
||
<span id="cb3-70"><a href="#cb3-70" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"sonst zahlt sie 2 EUR Kupon (Verlust -2).</span><span class="ch">\n</span><span class="st">"</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"><</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"><</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"</span><span class="sc">{</span><span class="st">''</span><span class="sc">:<28}</span><span class="ss"> </span><span class="sc">{</span><span class="st">'VaR 95%'</span><span class="sc">:>12}</span><span class="ss"> </span><span class="sc">{</span><span class="st">'CVaR 95%'</span><span class="sc">:>12}</span><span class="ss">"</span>)</span>
|
||
<span id="cb3-78"><a href="#cb3-78" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"-"</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">"Anleihe A allein"</span>, verlust_a),</span>
|
||
<span id="cb3-81"><a href="#cb3-81" aria-hidden="true" tabindex="-1"></a> (<span class="st">"Anleihe B allein"</span>, verlust_b),</span>
|
||
<span id="cb3-82"><a href="#cb3-82" aria-hidden="true" tabindex="-1"></a> (<span class="st">"Portfolio A+B"</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"</span><span class="sc">{</span>name<span class="sc">:<28}</span><span class="ss"> </span><span class="sc">{</span>werte[name][<span class="dv">0</span>]<span class="sc">:>12.2f}</span><span class="ss"> </span><span class="sc">{</span>werte[name][<span class="dv">1</span>]<span class="sc">:>12.2f}</span><span class="ss">"</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">"Anleihe A allein"</span>][<span class="dv">0</span>] <span class="op">+</span> werte[<span class="st">"Anleihe B allein"</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">"Anleihe A allein"</span>][<span class="dv">1</span>] <span class="op">+</span> werte[<span class="st">"Anleihe B allein"</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"</span><span class="sc">{</span><span class="st">'Summe der Einzelwerte'</span><span class="sc">:<28}</span><span class="ss"> </span><span class="sc">{</span>var_summe<span class="sc">:>12.2f}</span><span class="ss"> </span><span class="sc">{</span>cvar_summe<span class="sc">:>12.2f}</span><span class="ss">"</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">"Portfolio A+B"</span>]</span>
|
||
<span id="cb3-91"><a href="#cb3-91" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"-"</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"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"> -> "</span></span>
|
||
<span id="cb3-93"><a href="#cb3-93" aria-hidden="true" tabindex="-1"></a> <span class="ss">f"</span><span class="sc">{</span><span class="st">'VERLETZT die Subadditivitaet!'</span> <span class="cf">if</span> var_port <span class="op">></span> var_summe <span class="cf">else</span> <span class="st">'subadditiv'</span><span class="sc">}</span><span class="ss">"</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"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"> -> "</span></span>
|
||
<span id="cb3-95"><a href="#cb3-95" aria-hidden="true" tabindex="-1"></a> <span class="ss">f"</span><span class="sc">{</span><span class="st">'subadditiv (kohaerent)'</span> <span class="cf">if</span> cvar_port <span class="op"><=</span> cvar_summe <span class="op">+</span> <span class="fl">1e-6</span> <span class="cf">else</span> <span class="st">'verletzt'</span><span class="sc">}</span><span class="ss">"</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">"</span><span class="ch">\n</span><span class="st">Deutung: Einzeln betrachtet meldet der VaR fuer jede Anleihe einen"</span>)</span>
|
||
<span id="cb3-98"><a href="#cb3-98" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"GEWINN von 2 EUR - denn mit 96 % Wahrscheinlichkeit passiert nichts,"</span>)</span>
|
||
<span id="cb3-99"><a href="#cb3-99" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"und 4 </span><span class="sc">% li</span><span class="st">egen unterhalb der 5-%-Schwelle. Im Portfolio steigt die"</span>)</span>
|
||
<span id="cb3-100"><a href="#cb3-100" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"Wahrscheinlichkeit mindestens eines Ausfalls auf 7,8 </span><span class="sc">% u</span><span class="st">nd damit UEBER"</span>)</span>
|
||
<span id="cb3-101"><a href="#cb3-101" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"die Schwelle - der VaR springt auf 98. Er behauptet also, Streuung"</span>)</span>
|
||
<span id="cb3-102"><a href="#cb3-102" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"habe das Risiko erhoeht. Das ist oekonomisch unsinnig und der Grund,"</span>)</span>
|
||
<span id="cb3-103"><a href="#cb3-103" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"warum die Bankenaufsicht mit Basel III auf den Expected Shortfall"</span>)</span>
|
||
<span id="cb3-104"><a href="#cb3-104" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"umgestellt hat."</span>)</span>
|
||
<span id="cb3-105"><a href="#cb3-105" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"="</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 'UNMOEGLICHE' EIN?
|
||
========================================================================================
|
||
Ereignis Normal t (df=3) Faktor Normal: 1 Tag in
|
||
----------------------------------------------------------------------------------------
|
||
Abweichung > 3 Sigma 0.269980 % 1.384683 % 5.1x 1 Jahre
|
||
Abweichung > 4 Sigma 0.006334 % 0.616537 % 97.3x 63 Jahre
|
||
Abweichung > 5 Sigma 0.000057 % 0.323904 % 5649.8x 6,922 Jahre
|
||
Abweichung > 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 -> VERLETZT die Subadditivitaet!
|
||
CVaR: Portfolio 101.33 vs. Summe 159.24 -> 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>
|
||
<figure>
|
||
<img src="bilder_04/kap_cvar_subadditivitaet.svg" alt="Abb. 20.1: Dieselbe Tabelle als Bild, gerechnet mit denselben Ziehungen wie VaR_CVaR_Demo.py. Erzeugt von bilder_04/erzeuge_var_vs_cvar.py." />
|
||
<figcaption aria-hidden="true">Abb. 20.1: Dieselbe Tabelle als Bild, gerechnet mit denselben Ziehungen wie <code>VaR_CVaR_Demo.py</code>. Erzeugt von <code>bilder_04/erzeuge_var_vs_cvar.py</code>.</figcaption>
|
||
</figure>
|
||
<p><strong>Was Sie in der Abbildung sehen.</strong> Links wechselt der Balken über null das Vorzeichen: Aus zwei gemeldeten Gewinnen wird im Portfolio ein Verlust. Rechts passiert nichts dergleichen — der Portfoliobalken ist kürzer als der Summenbalken, und genau das heißt Subadditivität. Der Grund für den Sprung links ist keine Rechenungenauigkeit, sondern die Bauart des Maßes: Eine Schwelle bei 95 % sieht ein Ereignis mit 4 % Wahrscheinlichkeit nicht — bis zwei davon zusammenkommen.</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>>=</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.2: 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.2: 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> > <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 > rechnet weiter, nur eben über die falsche Menge. An 2 000 simulierten Tagesrenditen mit > Fat Tails gemessen: > > | Rechnung | gemittelt über | CVaR | > | — | — | — | > | richtig (<span class="math inline">\alpha = 0{,}95</span>, Rand 5 %) | 100 von 2 000 Szenarien | <strong>3,43 %</strong> | > | vertauscht (Rand 95 %) | 1 900 von 2 000 Szenarien | <strong>0,18 %</strong> | > > Ein Faktor <strong>19</strong> — und die zweite Zahl ist kein schlecht geschätztes Randrisiko, sondern > überhaupt kein Randmaß mehr: Sie mittelt über fast alle Tage und schließt die schlimmen > gerade nicht ein. Der größte Einzelverlust der Stichprobe beträgt 21,4 %. > > <strong>Die Gegenprobe kostet eine Zeile:</strong> Ist der berechnete CVaR nicht deutlich größer als > 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.3: CVaR-Zielfunktion mit Reibungs-Penalty" />
|
||
<figcaption aria-hidden="true">Abb. 20.3: 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">"""</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">"""</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">"AAPL"</span>, <span class="st">"MSFT"</span>, <span class="st">"NVDA"</span>, <span class="st">"AMZN"</span>, <span class="st">"JNJ"</span>, <span class="st">"PFE"</span>, <span class="st">"JPM"</span>, <span class="st">"GS"</span>, <span class="st">"XOM"</span>, <span class="st">"CVX"</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">"Download fehlgeschlagen (Netz, Ticker oder Rate-Limit pruefen)."</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">"Close"</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">"Close"</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">"Spaltenreihenfolge weicht ab!"</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">"""</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"> """</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"><=</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">>=</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">>=</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">"optimal"</span>, <span class="st">"optimal_inaccurate"</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"CVaR-Problem nicht loesbar: </span><span class="sc">{</span>problem<span class="sc">.</span>status<span class="sc">}</span><span class="ss">"</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">"""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' 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"> """</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"><=</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">"optimal"</span>, <span class="st">"optimal_inaccurate"</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"Varianz-Problem nicht loesbar: </span><span class="sc">{</span>problem<span class="sc">.</span>status<span class="sc">}</span><span class="ss">"</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">"""VaR und CVaR direkt aus den Szenarien - unabhaengige Gegenprobe."""</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">>=</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">"__main__"</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">"="</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">" CVaR-PORTFOLIO-OPTIMIERUNG MIT TRANSAKTIONSKOSTEN"</span>)</span>
|
||
<span id="cb6-135"><a href="#cb6-135" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"="</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"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 "</span></span>
|
||
<span id="cb6-137"><a href="#cb6-137" aria-hidden="true" tabindex="-1"></a> <span class="ss">f"</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">"</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">"--- Gegenprobe: stimmen Modell und Szenarien ueberein? ---"</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" 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"> % | "</span></span>
|
||
<span id="cb6-143"><a href="#cb6-143" aria-hidden="true" tabindex="-1"></a> <span class="ss">f"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"> %"</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" 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"> % | "</span></span>
|
||
<span id="cb6-145"><a href="#cb6-145" aria-hidden="true" tabindex="-1"></a> <span class="ss">f"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"> %"</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"><</span> <span class="fl">1e-4</span>, <span class="st">"CVaR stimmt nicht mit den Szenarien!"</span></span>
|
||
<span id="cb6-147"><a href="#cb6-147" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">" -> Der Rockafellar-Uryasev-Trick liefert exakt den empirischen CVaR."</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"</span><span class="ch">\n</span><span class="sc">{</span><span class="st">'Portfolio'</span><span class="sc">:<24}</span><span class="ss"> </span><span class="sc">{</span><span class="st">'Rendite p.a.'</span><span class="sc">:>13}</span><span class="ss"> </span><span class="sc">{</span><span class="st">'Vola p.a.'</span><span class="sc">:>11}</span><span class="ss"> "</span></span>
|
||
<span id="cb6-151"><a href="#cb6-151" aria-hidden="true" tabindex="-1"></a> <span class="ss">f"</span><span class="sc">{</span><span class="st">'VaR 95% (Tag)'</span><span class="sc">:>15}</span><span class="ss"> </span><span class="sc">{</span><span class="st">'CVaR 95% (Tag)'</span><span class="sc">:>16}</span><span class="ss"> </span><span class="sc">{</span><span class="st">'Turnover'</span><span class="sc">:>10}</span><span class="ss">"</span>)</span>
|
||
<span id="cb6-152"><a href="#cb6-152" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"-"</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">"CVaR-optimiert"</span>, w_cvar), (<span class="st">"Varianz-optimiert"</span>, w_var),</span>
|
||
<span id="cb6-154"><a href="#cb6-154" aria-hidden="true" tabindex="-1"></a> (<span class="st">"Gleichgewichtung"</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"</span><span class="sc">{</span>name<span class="sc">:<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">:>12.2f}</span><span class="ss"> % "</span></span>
|
||
<span id="cb6-158"><a href="#cb6-158" aria-hidden="true" tabindex="-1"></a> <span class="ss">f"</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">:>10.2f}</span><span class="ss"> % </span><span class="sc">{</span>v<span class="op">*</span><span class="dv">100</span><span class="sc">:>14.3f}</span><span class="ss"> % "</span></span>
|
||
<span id="cb6-159"><a href="#cb6-159" aria-hidden="true" tabindex="-1"></a> <span class="ss">f"</span><span class="sc">{</span>c<span class="op">*</span><span class="dv">100</span><span class="sc">:>15.3f}</span><span class="ss"> % </span><span class="sc">{</span>to<span class="op">*</span><span class="dv">100</span><span class="sc">:>9.1f}</span><span class="ss"> %"</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">"</span><span class="ch">\n</span><span class="st">Hinweis zur Annualisierung: Renditen werden mit 252 skaliert,"</span>)</span>
|
||
<span id="cb6-162"><a href="#cb6-162" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"Volatilitaeten mit sqrt(252). Fuer VaR/CVaR ist eine solche Skalierung"</span>)</span>
|
||
<span id="cb6-163"><a href="#cb6-163" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"nur unter starken Annahmen (Unabhaengigkeit, kein Drift) zulaessig -"</span>)</span>
|
||
<span id="cb6-164"><a href="#cb6-164" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"sie werden hier deshalb bewusst als TAGESwerte ausgewiesen."</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">"</span><span class="ch">\n</span><span class="st">--- Allokation ---"</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">"Ticker"</span>: TICKER,</span>
|
||
<span id="cb6-170"><a href="#cb6-170" aria-hidden="true" tabindex="-1"></a> <span class="st">"vorher"</span>: [<span class="ss">f"</span><span class="sc">{</span>v<span class="op">*</span><span class="dv">100</span><span class="sc">:5.1f}</span><span class="ss"> %"</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">"CVaR-opt."</span>: [<span class="ss">f"</span><span class="sc">{</span>v<span class="op">*</span><span class="dv">100</span><span class="sc">:5.1f}</span><span class="ss"> %"</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">"Handel"</span>: [<span class="ss">f"</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"> %"</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">"Varianz-opt."</span>: [<span class="ss">f"</span><span class="sc">{</span>v<span class="op">*</span><span class="dv">100</span><span class="sc">:5.1f}</span><span class="ss"> %"</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"</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"> % -> Transaktionskosten "</span></span>
|
||
<span id="cb6-177"><a href="#cb6-177" aria-hidden="true" tabindex="-1"></a> <span class="ss">f"</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"</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"><=</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"</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 ---"</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" vektorisiert (u >= -(R @ w) - gamma): </span><span class="sc">{</span>dauer_vektor<span class="sc">:6.2f}</span><span class="ss"> s"</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" Schleife ueber Szenarien (V01): </span><span class="sc">{</span>dauer_schleife<span class="sc">:6.2f}</span><span class="ss"> s "</span></span>
|
||
<span id="cb6-187"><a href="#cb6-187" aria-hidden="true" tabindex="-1"></a> <span class="ss">f"(</span><span class="sc">{</span>dauer_schleife<span class="op">/</span>dauer_vektor<span class="sc">:.1f}</span><span class="ss">x langsamer)"</span>)</span>
|
||
<span id="cb6-188"><a href="#cb6-188" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"="</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">>=</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">>=</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' 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: 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 >= 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>>=</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 20: 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>
|