Der Eintrag stand direkt unter "Download Notebooks als ZIP"; ohne das Wort "Buch" liess sich nicht auf einen Blick sehen, was da heruntergeladen wird. Geaendert an der einen Stelle in baue_sidebar_html(), von dort auf alle 41 Seiten. Veroeffentlicht: 151 Dateien uebertragen, 0 geloescht, alle vierzehn HTTP-Proben richtig. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
975 lines
133 KiB
HTML
Generated
975 lines
133 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 18: Finanzdaten-Modellierung — Renditen, Kovarianz und Shrinkage · Optimierte Entscheidungsfindung mit Python</title>
|
||
<script>
|
||
(function () {
|
||
try {
|
||
var t = localStorage.getItem("or-theme");
|
||
if (t) document.documentElement.setAttribute("data-theme", t);
|
||
} catch (e) {}
|
||
})();
|
||
</script>
|
||
<link rel="stylesheet" href="assets/highlight.css" />
|
||
<link rel="stylesheet" href="katex/katex.min.css" />
|
||
<script defer="" src="katex/katex.min.js"></script>
|
||
<script>document.addEventListener("DOMContentLoaded", function () {
|
||
var mathElements = document.getElementsByClassName("math");
|
||
var macros = [];
|
||
for (var i = 0; i < mathElements.length; i++) {
|
||
var texText = mathElements[i].firstChild;
|
||
if (mathElements[i].tagName == "SPAN") {
|
||
katex.render(texText.data, mathElements[i], {
|
||
displayMode: mathElements[i].classList.contains('display'),
|
||
throwOnError: false,
|
||
macros: macros,
|
||
fleqn: false
|
||
});
|
||
}}
|
||
// Der Browser springt zu einem #anker in der URL schon beim ersten Rendern
|
||
// an, BEVOR die KaTeX-Formeln oben im Text ihre finale Hoehe bekommen -
|
||
// durch den Reflow landet der Anker danach zu weit unten. Nach dem
|
||
// Formel-Rendering hier erneut zum Anker springen, das behebt es.
|
||
if (location.hash) {
|
||
var ziel = document.getElementById(decodeURIComponent(location.hash.slice(1)));
|
||
if (ziel) ziel.scrollIntoView({behavior: "instant", block: "start"});
|
||
}
|
||
});
|
||
</script>
|
||
<link rel="stylesheet" href="assets/site.css" />
|
||
</head>
|
||
<body>
|
||
<svg style="display:none" aria-hidden="true"><symbol id="icon-menu" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round">
|
||
<line x1="3" y1="6" x2="21" y2="6"/><line x1="3" y1="12" x2="21" y2="12"/><line x1="3" y1="18" x2="21" y2="18"/>
|
||
</symbol>
|
||
<symbol id="icon-search" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round">
|
||
<circle cx="11" cy="11" r="7"/><line x1="21" y1="21" x2="16.2" y2="16.2"/>
|
||
</symbol>
|
||
<symbol id="icon-sun" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round">
|
||
<circle cx="12" cy="12" r="4.5"/>
|
||
<line x1="12" y1="1.5" x2="12" y2="4"/><line x1="12" y1="20" x2="12" y2="22.5"/>
|
||
<line x1="1.5" y1="12" x2="4" y2="12"/><line x1="20" y1="12" x2="22.5" y2="12"/>
|
||
<line x1="4.5" y1="4.5" x2="6.2" y2="6.2"/><line x1="17.8" y1="17.8" x2="19.5" y2="19.5"/>
|
||
<line x1="19.5" y1="4.5" x2="17.8" y2="6.2"/><line x1="6.2" y1="17.8" x2="4.5" y2="19.5"/>
|
||
</symbol>
|
||
<symbol id="icon-moon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||
<path d="M20 14.5A8.5 8.5 0 1 1 9.5 4a6.8 6.8 0 0 0 10.5 10.5z"/>
|
||
</symbol>
|
||
<symbol id="icon-chevron-left" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||
<polyline points="15 4 7 12 15 20"/>
|
||
</symbol>
|
||
<symbol id="icon-chevron-right" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||
<polyline points="9 4 17 12 9 20"/>
|
||
</symbol>
|
||
<symbol id="icon-check" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||
<polyline points="4 13 9.5 18.5 20 6"/>
|
||
</symbol>
|
||
<symbol id="icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||
<path d="M18 13.5V19a1.5 1.5 0 0 1-1.5 1.5H5A1.5 1.5 0 0 1 3.5 19V7A1.5 1.5 0 0 1 5 5.5h5.5"/>
|
||
<polyline points="14.5 3.5 20.5 3.5 20.5 9.5"/><line x1="11" y1="13" x2="20" y2="4"/>
|
||
</symbol>
|
||
<symbol id="icon-book" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||
<path d="M4 5.5A2 2 0 0 1 6 4h6v16H6a2 2 0 0 0-2 1.5z"/>
|
||
<path d="M20 5.5A2 2 0 0 0 18 4h-6v16h6a2 2 0 0 1 2 1.5z"/>
|
||
</symbol>
|
||
<symbol id="icon-copy" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||
<rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/>
|
||
</symbol>
|
||
<symbol id="icon-download" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||
<path d="M12 3v12"/><polyline points="7 10 12 15 17 10"/><path d="M4 19.5h16"/>
|
||
</symbol></svg>
|
||
<header class="site-header">
|
||
<button type="button" class="icon-btn" id="sidebar-toggle" aria-label="Menü öffnen"><svg class="icon" aria-hidden="true"><use href="#icon-menu"></use></svg></button>
|
||
<a class="brand" href="index.html"><svg class="icon" aria-hidden="true"><use href="#icon-book"></use></svg> <span>Optimierte Entscheidungsfindung mit Python</span></a>
|
||
<div class="site-search">
|
||
<input id="suche-eingabe" type="search" placeholder="Suchen …" aria-label="Suche" autocomplete="off" />
|
||
<svg class="icon such-icon" aria-hidden="true"><use href="#icon-search"></use></svg>
|
||
<div id="suche-ergebnisse" class="suche-ergebnisse" hidden></div>
|
||
</div>
|
||
<button type="button" class="icon-btn" id="theme-toggle" aria-label="Darstellung umschalten">
|
||
<svg class="icon icon-sun" aria-hidden="true"><use href="#icon-sun"></use></svg><svg class="icon icon-moon" aria-hidden="true"><use href="#icon-moon"></use></svg>
|
||
</button>
|
||
</header>
|
||
<div class="site-body">
|
||
<div class="sidebar-overlay" id="sidebar-overlay" hidden></div>
|
||
<nav class="sidebar" id="sidebar" aria-label="Kapitelnavigation"><div class="sidebar-inhalt"><details class="sidebar-gruppe"><summary>Einstieg</summary><ul><li data-kapitel="vorwort.html"><a href="vorwort.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Vorwort & Lesehilfe</span></a></li><li data-kapitel="notation.html"><a href="notation.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Notation & Abkürzungen</span></a></li></ul></details><details class="sidebar-gruppe"><summary>Teil I: Grundlagen des Operations Research</summary><ul><li data-kapitel="einfuehrung.html"><a href="einfuehrung.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 1: Einführung in Operations Research — Vom Ursprung zur mathematischen Entscheidungsfindung</span></a></li><li data-kapitel="fundament.html"><a href="fundament.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 2: Das mathematische Fundament — Vektoren, Matrizen, Konvexität</span></a></li><li data-kapitel="oekosystem.html"><a href="oekosystem.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 3: Das Python-Ökosystem für OR — Solver, Bindings und Modellierungsschichten</span></a></li><li data-kapitel="modellierung.html"><a href="modellierung.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 4: Vom Management-Wunsch zum Modell</span></a></li><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</span></a></li><li data-kapitel="cpsat.html"><a href="cpsat.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 7: Constraint Programming mit CP-SAT — Logik, Scheduling und Zuweisung</span></a></li><li data-kapitel="graphen.html"><a href="graphen.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 8: Graphen, Flüsse und Touren — Min-Cost-Flow, Matching und VRP</span></a></li><li data-kapitel="metaheuristiken.html"><a href="metaheuristiken.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 9: Metaheuristiken — wenn der exakte Solver aussteigt</span></a></li><li data-kapitel="dekomposition.html"><a href="dekomposition.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 10: Spaltengenerierung — das Modell umbauen statt die Lösung raten</span></a></li><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 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 — 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" class="aktiv"><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"><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</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 class="sidebar-unterpunkt"><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 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 18: Finanzdaten-Modellierung — Renditen, Kovarianz und Shrinkage</span></nav>
|
||
<nav class="prev-next"><a class="prev-next-knopf prev-next-prev" href="supplychain.html"><svg class="icon" aria-hidden="true"><use href="#icon-chevron-left"></use></svg><span><small>Zurück</small>Kapitel 17: Supply-Chain und Energieeinsatz unter Unsicherheit</span></a><a class="prev-next-knopf prev-next-next" href="markowitz.html"><span><small>Weiter</small>Kapitel 19: Die moderne Portfoliotheorie nach Markowitz</span><svg class="icon" aria-hidden="true"><use href="#icon-chevron-right"></use></svg></a></nav>
|
||
<article>
|
||
<h1 id="kap-finanzdaten">Kapitel 18: Finanzdaten-Modellierung — Renditen, Kovarianz und Shrinkage</h1>
|
||
<div class="card card-blick">
|
||
<blockquote>
|
||
<p><strong>📌 Kapitel auf einen Blick</strong></p>
|
||
<p><strong>Worum geht es?</strong> Um die Eingangsdaten der Portfoliooptimierung — und darum, warum sie trügerisch sind. Wer historische Kovarianzen ungefiltert in einen Optimierer gibt, optimiert Rauschen.</p>
|
||
<p><strong>Voraussetzungen:</strong> <a href="qp-nlp.html#kap-qp-nlp">Kapitel 11</a> (Eigenwerte, positive Definitheit), Grundlagen der Statistik.</p>
|
||
<p><strong>Danach können Sie:</strong> Kursdaten korrekt laden, diskrete und logarithmische Renditen unterscheiden, das Schätzfehlerproblem erklären, Ledoit-Wolf-Shrinkage anwenden — und erkennen, wann eine Kovarianzmatrix aus zu wenigen Beobachtungen stammt.</p>
|
||
<p><strong>Zeitbedarf:</strong> ca. 5 Stunden.</p>
|
||
<p><strong>Programme:</strong><br />
|
||
<code>Renditen_Vergleich.py</code><br />
|
||
<code>Schaetzrauschen_Demo.py</code><br />
|
||
<code>Finanzdaten_Ledoit_Wolf.py</code><br />
|
||
<code>Kovarianz_Falle.py</code></p>
|
||
<p><strong>⚠️ Überspringen Sie dieses Kapitel nicht.</strong> Wer direkt bei Markowitz (<a href="markowitz.html#kap-markowitz">Kapitel 19</a>) einsteigt, erhält absurde Portfoliogewichte und weiß nicht, warum.</p>
|
||
<p><strong>Notebook:</strong> <a href="Notebooks_04/finanzdaten.ipynb">finanzdaten.ipynb</a> — herunterladen und in Jupyter öffnen, in Colab hochladen oder mit dem Kurs-Image starten</p>
|
||
</blockquote>
|
||
</div>
|
||
<hr />
|
||
<h2 id="sec:finanzdaten-schnellstart">18.1 In 5 Minuten gelöst</h2>
|
||
<div class="card card-schnellstart">
|
||
<blockquote>
|
||
<p><strong>🚀 In 5 Minuten gelöst: Die durchschnittliche Rendite, die es nicht gibt</strong></p>
|
||
<p>Eine Anlage wurde über vier Perioden beobachtet. Der Kurs stand bei 100, dann bei 50, 75, 150 und schließlich bei <strong>120</strong>.</p>
|
||
<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>kurse <span class="op">=</span> np.array([<span class="fl">100.0</span>, <span class="fl">50.0</span>, <span class="fl">75.0</span>, <span class="fl">150.0</span>, <span class="fl">120.0</span>])</span>
|
||
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a>diskret <span class="op">=</span> kurse[<span class="dv">1</span>:] <span class="op">/</span> kurse[:<span class="op">-</span><span class="dv">1</span>] <span class="op">-</span> <span class="dv">1</span> <span class="co"># (neu - alt) / alt</span></span>
|
||
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a>log <span class="op">=</span> np.log(kurse[<span class="dv">1</span>:] <span class="op">/</span> kurse[:<span class="op">-</span><span class="dv">1</span>]) <span class="co"># ln(neu / alt)</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="bu">print</span>(<span class="st">"diskret:"</span>, np.<span class="bu">round</span>(diskret <span class="op">*</span> <span class="dv">100</span>, <span class="dv">2</span>), <span class="st">"%"</span>)</span>
|
||
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a><span class="bu">print</span>(<span class="st">"log :"</span>, np.<span class="bu">round</span>(log <span class="op">*</span> <span class="dv">100</span>, <span class="dv">2</span>), <span class="st">"%"</span>)</span>
|
||
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a><span class="bu">print</span>(<span class="ss">f"Mittelwert diskret </span><span class="sc">{</span>diskret<span class="sc">.</span>mean()<span class="op">*</span><span class="dv">100</span><span class="sc">:5.2f}</span><span class="ss"> % -> hochgerechnet "</span></span>
|
||
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a> <span class="ss">f"</span><span class="sc">{</span><span class="dv">100</span> <span class="op">*</span> (<span class="dv">1</span> <span class="op">+</span> diskret.mean())<span class="op">**</span><span class="dv">4</span><span class="sc">:6.2f}</span><span class="ss">"</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"Mittelwert log </span><span class="sc">{</span>log<span class="sc">.</span>mean()<span class="op">*</span><span class="dv">100</span><span class="sc">:5.2f}</span><span class="ss"> % -> hochgerechnet "</span></span>
|
||
<span id="cb1-12"><a href="#cb1-12" aria-hidden="true" tabindex="-1"></a> <span class="ss">f"</span><span class="sc">{</span><span class="dv">100</span> <span class="op">*</span> np<span class="sc">.</span>exp(log.mean() <span class="op">*</span> <span class="dv">4</span>)<span class="sc">:6.2f}</span><span class="ss">"</span>)</span></code></pre></div>
|
||
<p><strong>Ausgabe:</strong></p>
|
||
<pre><code>diskret: [-50. 50. 100. -20.] %
|
||
log : [-69.31 40.55 69.31 -22.31] %
|
||
Mittelwert diskret 20.00 % -> hochgerechnet 207.36
|
||
Mittelwert log 4.56 % -> hochgerechnet 120.00</code></pre>
|
||
</blockquote>
|
||
</div>
|
||
<p><strong>Die durchschnittliche Rendite beträgt 20 % pro Periode — bei einer Anlage, die insgesamt 20 % gewonnen hat.</strong> Wer damit vier Perioden hochrechnet, landet bei 207,36 statt bei den tatsächlichen 120,00.</p>
|
||
<p>Der Grund steckt in der ersten Zeile: Ein Verlust von 50 % und ein Gewinn von 50 % heben sich <strong>nicht</strong> auf. Aus 100 werden 50, daraus 75 — nicht wieder 100. Diskrete Renditen darf man deshalb nicht mitteln und nicht addieren; sie multiplizieren sich.</p>
|
||
<p>Logarithmische Renditen dagegen <strong>addieren</strong> sich. Ihre Summe beträgt hier 18,23 %, und <span class="math inline">100 \cdot e^{0{,}1823} = 120{,}00</span> — exakt der beobachtete Endkurs.</p>
|
||
<table>
|
||
<colgroup>
|
||
<col style="width: 33%" />
|
||
<col style="width: 33%" />
|
||
<col style="width: 33%" />
|
||
</colgroup>
|
||
<thead>
|
||
<tr class="header">
|
||
<th></th>
|
||
<th>diskrete Rendite</th>
|
||
<th>logarithmische Rendite</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr class="odd">
|
||
<td>Verknüpfung über die Zeit</td>
|
||
<td>multiplikativ: <span class="math inline">\prod(1+r_t)</span></td>
|
||
<td><strong>additiv</strong>: <span class="math inline">\sum \ln(1+r_t)</span></td>
|
||
</tr>
|
||
<tr class="even">
|
||
<td>Mitteln zulässig?</td>
|
||
<td>nein — führt systematisch zu hoch</td>
|
||
<td>ja</td>
|
||
</tr>
|
||
<tr class="odd">
|
||
<td>Verknüpfung über Anlagen</td>
|
||
<td><strong>additiv</strong>: <span class="math inline">\sum w_i r_i</span></td>
|
||
<td>nein (Summe von Logs ≠ Log der Summe)</td>
|
||
</tr>
|
||
<tr class="even">
|
||
<td>Wofür also</td>
|
||
<td>Portfoliogewichtung, Kennzahlen je Periode</td>
|
||
<td>Zeitreihenanalyse, Volatilität, Modelle</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<blockquote>
|
||
<p><strong>🎯 Merksatz</strong> Beide Renditearten sind richtig — für <strong>verschiedene Richtungen</strong>. Diskrete Renditen addieren sich über die <strong>Anlagen</strong> eines Portfolios, logarithmische über die <strong>Zeit</strong>. Wer sie verwechselt, bekommt keine Fehlermeldung, sondern eine plausible falsche Zahl.</p>
|
||
</blockquote>
|
||
<p><strong>Warum funktioniert das?</strong> Weil der Logarithmus aus einem Produkt eine Summe macht: <span class="math inline">\ln(a \cdot b) = \ln a + \ln b</span>. Genau diese Eigenschaft braucht man, wenn sich Renditen über die Zeit aufmultiplizieren. Der Preis dafür: Über mehrere Anlagen hinweg funktioniert es nicht mehr, denn der Logarithmus einer Summe ist nicht die Summe der Logarithmen. Der Rest dieses Kapitels behandelt die zweite große Fehlerquelle bei Finanzdaten — die <strong>Kovarianzmatrix</strong>, deren Schätzung noch weit trügerischer ist als die Rendite selbst.</p>
|
||
<hr />
|
||
<h2 id="sec:finanzdaten-lernziele">18.2 Lernziele</h2>
|
||
<p>Nach diesem Kapitel können Sie …</p>
|
||
<ol type="1">
|
||
<li>… erklären, wann man diskrete und wann logarithmische Renditen verwendet.</li>
|
||
<li>… beschreiben, warum die Stichproben-Kovarianzmatrix bei vielen Titeln unbrauchbar wird.</li>
|
||
<li>… den <strong>Error-Maximizer-Effekt</strong> an einem Experiment nachweisen.</li>
|
||
<li>… Ledoit-Wolf-Shrinkage anwenden und ihre Wirkung an Eigenwerten und Konditionszahl messen.</li>
|
||
<li>… Kursdaten so laden, dass die Spaltenreihenfolge garantiert stimmt.</li>
|
||
<li>… begründen, warum eine Schätzung aus <span class="math inline">T < N</span> Beobachtungen dem Optimierer risikofreie Richtungen vorgaukelt — und welche drei Gegenmittel es gibt.</li>
|
||
<li>… ein Portfolio <strong>außerhalb</strong> des Schätzzeitraums bewerten statt darin.</li>
|
||
</ol>
|
||
<hr />
|
||
<h2 id="sec:finanzdaten-diskrete-und-logarithmische-renditen">18.3 Diskrete und logarithmische Renditen</h2>
|
||
<p>Sei <span class="math inline">P_{i,t}</span> der <strong>bereinigte</strong> Schlusskurs (<em>adjusted close</em>) von Titel <span class="math inline">i</span> zum Zeitpunkt <span class="math inline">t</span>. „Bereinigt“ heißt: um Dividenden und Aktiensplits korrigiert — sonst erscheint jede Dividendenzahlung als Kurssturz.</p>
|
||
<h3 id="diskrete-rendite">Diskrete Rendite</h3>
|
||
<p><span class="math display">
|
||
R_{i,t} = \frac{P_{i,t} - P_{i,t-1}}{P_{i,t-1}} = \frac{P_{i,t}}{P_{i,t-1}} - 1
|
||
</span></p>
|
||
<p><strong>Eigenschaft — über Titel additiv:</strong></p>
|
||
<p><span class="math display">
|
||
R_{p,t} = \sum_{i=1}^n w_i R_{i,t} = \mathbf{w}^\top\mathbf{R}_t
|
||
</span></p>
|
||
<h3 id="logarithmische-rendite">Logarithmische Rendite</h3>
|
||
<p><span class="math display">
|
||
r_{i,t} = \ln\!\left(\frac{P_{i,t}}{P_{i,t-1}}\right) = \ln P_{i,t} - \ln P_{i,t-1}
|
||
</span></p>
|
||
<p><strong>Eigenschaft — über die Zeit additiv:</strong></p>
|
||
<p><span class="math display">
|
||
r_{i,0\to T} = \sum_{t=1}^T r_{i,t}
|
||
</span></p>
|
||
<blockquote>
|
||
<p><strong>🎯 Die Merkregel</strong> <strong>Diskrete Renditen addieren sich über das Portfolio</strong> (mehrere Titel, ein Zeitpunkt) — deshalb braucht man sie für die <strong>Allokation</strong>. <strong>Logarithmische Renditen addieren sich über die Zeit</strong> (ein Titel, mehrere Perioden) — deshalb braucht man sie für <strong>Zeitreihenanalyse und Volatilitätsschätzung</strong>.</p>
|
||
<p>Man kann nicht beides gleichzeitig haben: Die gewichtete Summe von Log-Renditen ist <strong>nicht</strong> die Log-Rendite des Portfolios.</p>
|
||
</blockquote>
|
||
<blockquote>
|
||
<p><strong>✏️ Handrechnung 18.1: Der Unterschied in Zahlen</strong></p>
|
||
<p>Ein Kurs steigt von 100 auf 150, dann fällt er zurück auf 100.</p>
|
||
<table>
|
||
<colgroup>
|
||
<col style="width: 20%" />
|
||
<col style="width: 20%" />
|
||
<col style="width: 20%" />
|
||
<col style="width: 20%" />
|
||
<col style="width: 20%" />
|
||
</colgroup>
|
||
<thead>
|
||
<tr class="header">
|
||
<th></th>
|
||
<th>Periode 1</th>
|
||
<th>Periode 2</th>
|
||
<th>Summe</th>
|
||
<th>Wahrheit</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr class="odd">
|
||
<td><strong>Diskret</strong></td>
|
||
<td><span class="math inline">+50{,}0\,\%</span></td>
|
||
<td><span class="math inline">-33{,}3\,\%</span></td>
|
||
<td><span class="math inline">+16{,}7\,\%</span> ✗</td>
|
||
<td><span class="math inline">0\,\%</span></td>
|
||
</tr>
|
||
<tr class="even">
|
||
<td><strong>Logarithmisch</strong></td>
|
||
<td><span class="math inline">+0{,}4055</span></td>
|
||
<td><span class="math inline">-0{,}4055</span></td>
|
||
<td><span class="math inline">0{,}0000</span> ✓</td>
|
||
<td><span class="math inline">0\,\%</span></td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<p>Die diskreten Renditen <strong>suggerieren einen Gewinn von 16,7 %</strong>, obwohl der Kurs exakt dort steht, wo er begann. Die Log-Renditen heben sich korrekt auf.</p>
|
||
<p><strong>Deshalb ist die Aussage „im Mittel 5 % Rendite“ mehrdeutig.</strong> Das arithmetische Mittel diskreter Renditen überschätzt systematisch, was ein Anleger tatsächlich verdient hätte. Für Wachstumsaussagen nimmt man das <strong>geometrische</strong> Mittel — oder rechnet gleich in Log-Renditen.</p>
|
||
</blockquote>
|
||
<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"># Renditen_Vergleich.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 Finanzdaten: Diskrete vs. logarithmische Renditen.</span></span>
|
||
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a><span class="co">Zeigt an einem simulierten Kursverlauf, welche Eigenschaft wo gilt -</span></span>
|
||
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a><span class="co">und warum das arithmetische Mittel diskreter Renditen in die Irre fuehrt.</span></span>
|
||
<span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a><span class="co">"""</span></span>
|
||
<span id="cb3-9"><a href="#cb3-9" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb3-10"><a href="#cb3-10" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> numpy <span class="im">as</span> np</span>
|
||
<span id="cb3-11"><a href="#cb3-11" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> pandas <span class="im">as</span> pd</span>
|
||
<span id="cb3-12"><a href="#cb3-12" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb3-13"><a href="#cb3-13" 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-14"><a href="#cb3-14" aria-hidden="true" tabindex="-1"></a> kurse <span class="op">=</span> np.array([<span class="fl">100.0</span>, <span class="fl">150.0</span>, <span class="fl">100.0</span>, <span class="fl">120.0</span>, <span class="fl">90.0</span>, <span class="fl">135.0</span>])</span>
|
||
<span id="cb3-15"><a href="#cb3-15" aria-hidden="true" tabindex="-1"></a> tage <span class="op">=</span> [<span class="ss">f"t</span><span class="sc">{</span>i<span class="sc">}</span><span class="ss">"</span> <span class="cf">for</span> i <span class="kw">in</span> <span class="bu">range</span>(<span class="bu">len</span>(kurse))]</span>
|
||
<span id="cb3-16"><a href="#cb3-16" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb3-17"><a href="#cb3-17" aria-hidden="true" tabindex="-1"></a> diskret <span class="op">=</span> kurse[<span class="dv">1</span>:] <span class="op">/</span> kurse[:<span class="op">-</span><span class="dv">1</span>] <span class="op">-</span> <span class="fl">1.0</span></span>
|
||
<span id="cb3-18"><a href="#cb3-18" aria-hidden="true" tabindex="-1"></a> logarithmisch <span class="op">=</span> np.log(kurse[<span class="dv">1</span>:] <span class="op">/</span> kurse[:<span class="op">-</span><span class="dv">1</span>])</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="bu">print</span>(<span class="st">"="</span> <span class="op">*</span> <span class="dv">74</span>)</span>
|
||
<span id="cb3-21"><a href="#cb3-21" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">" DISKRETE UND LOGARITHMISCHE RENDITEN IM VERGLEICH"</span>)</span>
|
||
<span id="cb3-22"><a href="#cb3-22" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"="</span> <span class="op">*</span> <span class="dv">74</span>)</span>
|
||
<span id="cb3-23"><a href="#cb3-23" aria-hidden="true" tabindex="-1"></a> tabelle <span class="op">=</span> pd.DataFrame({</span>
|
||
<span id="cb3-24"><a href="#cb3-24" aria-hidden="true" tabindex="-1"></a> <span class="st">"Periode"</span>: [<span class="ss">f"</span><span class="sc">{</span>tage[i]<span class="sc">}</span><span class="ss"> -> </span><span class="sc">{</span>tage[i<span class="op">+</span><span class="dv">1</span>]<span class="sc">}</span><span class="ss">"</span> <span class="cf">for</span> i <span class="kw">in</span> <span class="bu">range</span>(<span class="bu">len</span>(diskret))],</span>
|
||
<span id="cb3-25"><a href="#cb3-25" aria-hidden="true" tabindex="-1"></a> <span class="st">"Kurs von"</span>: kurse[:<span class="op">-</span><span class="dv">1</span>],</span>
|
||
<span id="cb3-26"><a href="#cb3-26" aria-hidden="true" tabindex="-1"></a> <span class="st">"Kurs bis"</span>: kurse[<span class="dv">1</span>:],</span>
|
||
<span id="cb3-27"><a href="#cb3-27" aria-hidden="true" tabindex="-1"></a> <span class="st">"diskret R"</span>: [<span class="ss">f"</span><span class="sc">{</span>r<span class="op">*</span><span class="dv">100</span><span class="sc">:+7.2f}</span><span class="ss"> %"</span> <span class="cf">for</span> r <span class="kw">in</span> diskret],</span>
|
||
<span id="cb3-28"><a href="#cb3-28" aria-hidden="true" tabindex="-1"></a> <span class="st">"log r"</span>: [<span class="ss">f"</span><span class="sc">{</span>r<span class="sc">:+8.4f}</span><span class="ss">"</span> <span class="cf">for</span> r <span class="kw">in</span> logarithmisch],</span>
|
||
<span id="cb3-29"><a href="#cb3-29" aria-hidden="true" tabindex="-1"></a> })</span>
|
||
<span id="cb3-30"><a href="#cb3-30" 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="cb3-31"><a href="#cb3-31" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb3-32"><a href="#cb3-32" aria-hidden="true" tabindex="-1"></a> <span class="co"># --- Zeitliche Aggregation ------------------------------------------</span></span>
|
||
<span id="cb3-33"><a href="#cb3-33" aria-hidden="true" tabindex="-1"></a> gesamt_wahr <span class="op">=</span> kurse[<span class="op">-</span><span class="dv">1</span>] <span class="op">/</span> kurse[<span class="dv">0</span>] <span class="op">-</span> <span class="fl">1.0</span></span>
|
||
<span id="cb3-34"><a href="#cb3-34" aria-hidden="true" tabindex="-1"></a> summe_log <span class="op">=</span> logarithmisch.<span class="bu">sum</span>()</span>
|
||
<span id="cb3-35"><a href="#cb3-35" aria-hidden="true" tabindex="-1"></a> aus_log_zurueck <span class="op">=</span> np.exp(summe_log) <span class="op">-</span> <span class="fl">1.0</span></span>
|
||
<span id="cb3-36"><a href="#cb3-36" aria-hidden="true" tabindex="-1"></a> summe_diskret <span class="op">=</span> diskret.<span class="bu">sum</span>()</span>
|
||
<span id="cb3-37"><a href="#cb3-37" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb3-38"><a href="#cb3-38" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"</span><span class="ch">\n</span><span class="st">--- Aggregation ueber die Zeit ---"</span>)</span>
|
||
<span id="cb3-39"><a href="#cb3-39" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f" Tatsaechliche Gesamtrendite: </span><span class="sc">{</span>gesamt_wahr<span class="op">*</span><span class="dv">100</span><span class="sc">:+8.2f}</span><span class="ss"> %"</span>)</span>
|
||
<span id="cb3-40"><a href="#cb3-40" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f" Summe der Log-Renditen -> exp()-1: </span><span class="sc">{</span>aus_log_zurueck<span class="op">*</span><span class="dv">100</span><span class="sc">:+8.2f}</span><span class="ss"> % "</span></span>
|
||
<span id="cb3-41"><a href="#cb3-41" aria-hidden="true" tabindex="-1"></a> <span class="ss">f"</span><span class="sc">{</span><span class="st">'KORREKT'</span> <span class="cf">if</span> <span class="bu">abs</span>(aus_log_zurueck <span class="op">-</span> gesamt_wahr) <span class="op"><</span> <span class="fl">1e-9</span> <span class="cf">else</span> <span class="st">'falsch'</span><span class="sc">}</span><span class="ss">"</span>)</span>
|
||
<span id="cb3-42"><a href="#cb3-42" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f" Summe der diskreten Renditen: </span><span class="sc">{</span>summe_diskret<span class="op">*</span><span class="dv">100</span><span class="sc">:+8.2f}</span><span class="ss"> % FALSCH"</span>)</span>
|
||
<span id="cb3-43"><a href="#cb3-43" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb3-44"><a href="#cb3-44" aria-hidden="true" tabindex="-1"></a> <span class="co"># --- Mittelwerte ------------------------------------------------------</span></span>
|
||
<span id="cb3-45"><a href="#cb3-45" aria-hidden="true" tabindex="-1"></a> arithmetisch <span class="op">=</span> diskret.mean()</span>
|
||
<span id="cb3-46"><a href="#cb3-46" aria-hidden="true" tabindex="-1"></a> geometrisch <span class="op">=</span> np.prod(<span class="dv">1</span> <span class="op">+</span> diskret) <span class="op">**</span> (<span class="dv">1</span> <span class="op">/</span> <span class="bu">len</span>(diskret)) <span class="op">-</span> <span class="dv">1</span></span>
|
||
<span id="cb3-47"><a href="#cb3-47" aria-hidden="true" tabindex="-1"></a> aus_log <span class="op">=</span> np.exp(logarithmisch.mean()) <span class="op">-</span> <span class="dv">1</span></span>
|
||
<span id="cb3-48"><a href="#cb3-48" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb3-49"><a href="#cb3-49" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"</span><span class="ch">\n</span><span class="st">--- Welcher Mittelwert ist der richtige? ---"</span>)</span>
|
||
<span id="cb3-50"><a href="#cb3-50" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f" Arithmetisches Mittel (diskret): </span><span class="sc">{</span>arithmetisch<span class="op">*</span><span class="dv">100</span><span class="sc">:+8.2f}</span><span class="ss"> % "</span></span>
|
||
<span id="cb3-51"><a href="#cb3-51" aria-hidden="true" tabindex="-1"></a> <span class="ss">f"-> ueberschaetzt"</span>)</span>
|
||
<span id="cb3-52"><a href="#cb3-52" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f" Geometrisches Mittel: </span><span class="sc">{</span>geometrisch<span class="op">*</span><span class="dv">100</span><span class="sc">:+8.2f}</span><span class="ss"> % -> korrekt"</span>)</span>
|
||
<span id="cb3-53"><a href="#cb3-53" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f" exp(Mittel der Log-Renditen) - 1: </span><span class="sc">{</span>aus_log<span class="op">*</span><span class="dv">100</span><span class="sc">:+8.2f}</span><span class="ss"> % "</span></span>
|
||
<span id="cb3-54"><a href="#cb3-54" aria-hidden="true" tabindex="-1"></a> <span class="ss">f"-> identisch zum geometrischen"</span>)</span>
|
||
<span id="cb3-55"><a href="#cb3-55" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb3-56"><a href="#cb3-56" aria-hidden="true" tabindex="-1"></a> <span class="co"># Probe: Endkapital mit dem jeweiligen Mittelwert hochgerechnet</span></span>
|
||
<span id="cb3-57"><a href="#cb3-57" aria-hidden="true" tabindex="-1"></a> n <span class="op">=</span> <span class="bu">len</span>(diskret)</span>
|
||
<span id="cb3-58"><a href="#cb3-58" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f"</span><span class="ch">\n</span><span class="ss"> Probe - Startkapital 100 EUR ueber </span><span class="sc">{</span>n<span class="sc">}</span><span class="ss"> Perioden:"</span>)</span>
|
||
<span id="cb3-59"><a href="#cb3-59" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f" tatsaechlich: </span><span class="sc">{</span>kurse[<span class="op">-</span><span class="dv">1</span>]<span class="sc">:8.2f}</span><span class="ss"> EUR"</span>)</span>
|
||
<span id="cb3-60"><a href="#cb3-60" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f" mit arithm. Mittel hochgerechnet: </span><span class="sc">{</span><span class="dv">100</span><span class="op">*</span>(<span class="dv">1</span><span class="op">+</span>arithmetisch)<span class="op">**</span>n<span class="sc">:8.2f}</span><span class="ss"> EUR"</span>)</span>
|
||
<span id="cb3-61"><a href="#cb3-61" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f" mit geom. Mittel hochgerechnet: </span><span class="sc">{</span><span class="dv">100</span><span class="op">*</span>(<span class="dv">1</span><span class="op">+</span>geometrisch)<span class="op">**</span>n<span class="sc">:8.2f}</span><span class="ss"> EUR"</span>)</span>
|
||
<span id="cb3-62"><a href="#cb3-62" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb3-63"><a href="#cb3-63" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"</span><span class="ch">\n</span><span class="st">--- Annualisierung (252 Handelstage) ---"</span>)</span>
|
||
<span id="cb3-64"><a href="#cb3-64" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f" Volatilitaet aus Log-Renditen: "</span></span>
|
||
<span id="cb3-65"><a href="#cb3-65" aria-hidden="true" tabindex="-1"></a> <span class="ss">f"</span><span class="sc">{</span>logarithmisch<span class="sc">.</span>std(ddof<span class="op">=</span><span class="dv">1</span>)<span class="op">*</span>np<span class="sc">.</span>sqrt(<span class="dv">252</span>)<span class="op">*</span><span class="dv">100</span><span class="sc">:.2f}</span><span class="ss"> % p.a."</span>)</span>
|
||
<span id="cb3-66"><a href="#cb3-66" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">" (Die Wurzel-Zeit-Regel gilt nur bei unabhaengigen Renditen -"</span>)</span>
|
||
<span id="cb3-67"><a href="#cb3-67" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">" fuer reale Maerkte ist sie eine Naeherung.)"</span>)</span>
|
||
<span id="cb3-68"><a href="#cb3-68" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"="</span> <span class="op">*</span> <span class="dv">74</span>)</span></code></pre></div>
|
||
<hr />
|
||
<h2 id="sec:finanzdaten-das-schaetzfehler-problem">18.4 Das Schätzfehler-Problem</h2>
|
||
<p>Sei <span class="math inline">\mathbf{X}\in\mathbb{R}^{T\times N}</span> die Matrix zentrierter Renditen von <span class="math inline">N</span> Titeln über <span class="math inline">T</span> Handelstage. Die <strong>Stichproben-Kovarianzmatrix</strong> lautet:</p>
|
||
<p><span class="math display">
|
||
\mathbf{S} = \frac{1}{T-1}\mathbf{X}^\top\mathbf{X}
|
||
</span></p>
|
||
<p>Das Problem: <span class="math inline">\mathbf{S}</span> hat <span class="math inline">\frac{N(N+1)}{2}</span> zu schätzende Parameter, aber nur <span class="math inline">T \cdot N</span> Datenpunkte. Bei <span class="math inline">N = 50</span> Titeln sind das <strong>1275 Parameter</strong> — geschätzt aus einem Jahr Daten (<span class="math inline">T = 252</span>).</p>
|
||
<figure>
|
||
<img src="bilder_04/kap11_ledoit_wolf_shrinkage.svg" alt="Abb. 18.1: Ledoit-Wolf-Kovarianz-Shrinkage" />
|
||
<figcaption aria-hidden="true">Abb. 18.1: Ledoit-Wolf-Kovarianz-Shrinkage</figcaption>
|
||
</figure>
|
||
<table>
|
||
<colgroup>
|
||
<col style="width: 50%" />
|
||
<col style="width: 50%" />
|
||
</colgroup>
|
||
<thead>
|
||
<tr class="header">
|
||
<th>Verhältnis</th>
|
||
<th>Folge</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr class="odd">
|
||
<td><span class="math inline">T \gg N</span></td>
|
||
<td><span class="math inline">\mathbf{S}</span> ist brauchbar</td>
|
||
</tr>
|
||
<tr class="even">
|
||
<td><span class="math inline">T \approx N</span></td>
|
||
<td>Extrem instabil; Eigenwerte streuen weit</td>
|
||
</tr>
|
||
<tr class="odd">
|
||
<td><span class="math inline">T < N</span></td>
|
||
<td><span class="math inline">\mathbf{S}</span> ist <strong>singulär</strong> — nicht invertierbar, Rang <span class="math inline">< N</span></td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<p>Die <strong>Zufallsmatrizentheorie</strong> (<em>Random Matrix Theory</em>, Marchenko-Pastur-Gesetz) zeigt: Die kleinsten Eigenwerte von <span class="math inline">\mathbf{S}</span> werden <strong>systematisch unterschätzt</strong>, die größten überschätzt. Und genau das ist fatal, denn:</p>
|
||
<blockquote>
|
||
<p><strong>🎯 Der Error-Maximizer-Effekt</strong> Ein Risikominimierer sucht die Richtungen mit der <strong>kleinsten</strong> Varianz — also genau jene Eigenrichtungen, deren Eigenwerte am stärksten <strong>nach unten verzerrt</strong> sind. Die Optimierung greift damit zielsicher in das Schätzrauschen hinein. Markowitz-Optimierung ist deshalb kein Fehlerdämpfer, sondern ein <strong>Fehlerverstärker</strong>.</p>
|
||
</blockquote>
|
||
<div class="sourceCode" id="cb4"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="co">#!/usr/bin/env python3</span></span>
|
||
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a><span class="co"># Schaetzrauschen_Demo.py</span></span>
|
||
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a><span class="co">"""</span></span>
|
||
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a><span class="co">Kapitel Finanzdaten: Der Error-Maximizer-Effekt im Experiment.</span></span>
|
||
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a><span class="co">Aufbau: Wir KENNEN die wahre Kovarianzmatrix, weil wir die Daten selbst</span></span>
|
||
<span id="cb4-8"><a href="#cb4-8" aria-hidden="true" tabindex="-1"></a><span class="co">erzeugen. Dann schaetzen wir sie aus endlich vielen Beobachtungen und</span></span>
|
||
<span id="cb4-9"><a href="#cb4-9" aria-hidden="true" tabindex="-1"></a><span class="co">vergleichen, wie gut das daraus optimierte Portfolio in der WAHREN Welt</span></span>
|
||
<span id="cb4-10"><a href="#cb4-10" aria-hidden="true" tabindex="-1"></a><span class="co">abschneidet - mit und ohne Shrinkage.</span></span>
|
||
<span id="cb4-11"><a href="#cb4-11" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb4-12"><a href="#cb4-12" aria-hidden="true" tabindex="-1"></a><span class="co">Das ist der einzige saubere Weg, Schaetzfehler zu messen: Man braucht eine</span></span>
|
||
<span id="cb4-13"><a href="#cb4-13" aria-hidden="true" tabindex="-1"></a><span class="co">Wahrheit zum Vergleich, und die gibt es nur in der Simulation.</span></span>
|
||
<span id="cb4-14"><a href="#cb4-14" aria-hidden="true" tabindex="-1"></a><span class="co">"""</span></span>
|
||
<span id="cb4-15"><a href="#cb4-15" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb4-16"><a href="#cb4-16" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> numpy <span class="im">as</span> np</span>
|
||
<span id="cb4-17"><a href="#cb4-17" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> sklearn.covariance <span class="im">import</span> LedoitWolf</span>
|
||
<span id="cb4-18"><a href="#cb4-18" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb4-19"><a href="#cb4-19" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb4-20"><a href="#cb4-20" aria-hidden="true" tabindex="-1"></a><span class="kw">def</span> erzeuge_wahre_kovarianz(n, rng):</span>
|
||
<span id="cb4-21"><a href="#cb4-21" aria-hidden="true" tabindex="-1"></a> <span class="co">"""Ein-Faktor-Modell: gemeinsamer Marktfaktor plus titelspezifisches Rauschen."""</span></span>
|
||
<span id="cb4-22"><a href="#cb4-22" aria-hidden="true" tabindex="-1"></a> beta <span class="op">=</span> rng.uniform(<span class="fl">0.6</span>, <span class="fl">1.4</span>, size<span class="op">=</span>n) <span class="co"># Marktsensitivitaeten</span></span>
|
||
<span id="cb4-23"><a href="#cb4-23" aria-hidden="true" tabindex="-1"></a> var_markt <span class="op">=</span> <span class="fl">0.04</span> <span class="co"># Marktvarianz p.a.</span></span>
|
||
<span id="cb4-24"><a href="#cb4-24" aria-hidden="true" tabindex="-1"></a> var_spezifisch <span class="op">=</span> rng.uniform(<span class="fl">0.01</span>, <span class="fl">0.09</span>, size<span class="op">=</span>n) <span class="co"># idiosynkratische Varianz</span></span>
|
||
<span id="cb4-25"><a href="#cb4-25" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> np.outer(beta, beta) <span class="op">*</span> var_markt <span class="op">+</span> np.diag(var_spezifisch)</span>
|
||
<span id="cb4-26"><a href="#cb4-26" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb4-27"><a href="#cb4-27" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb4-28"><a href="#cb4-28" aria-hidden="true" tabindex="-1"></a><span class="kw">def</span> minimum_varianz_gewichte(sigma):</span>
|
||
<span id="cb4-29"><a href="#cb4-29" aria-hidden="true" tabindex="-1"></a> <span class="co">"""Analytische GMV-Loesung: w = Sigma^-1 1 / (1' Sigma^-1 1). Ohne Restriktionen."""</span></span>
|
||
<span id="cb4-30"><a href="#cb4-30" aria-hidden="true" tabindex="-1"></a> eins <span class="op">=</span> np.ones(<span class="bu">len</span>(sigma))</span>
|
||
<span id="cb4-31"><a href="#cb4-31" aria-hidden="true" tabindex="-1"></a> <span class="cf">try</span>:</span>
|
||
<span id="cb4-32"><a href="#cb4-32" aria-hidden="true" tabindex="-1"></a> loesung <span class="op">=</span> np.linalg.solve(sigma, eins)</span>
|
||
<span id="cb4-33"><a href="#cb4-33" aria-hidden="true" tabindex="-1"></a> <span class="cf">except</span> np.linalg.LinAlgError:</span>
|
||
<span id="cb4-34"><a href="#cb4-34" aria-hidden="true" tabindex="-1"></a> loesung <span class="op">=</span> np.linalg.pinv(sigma) <span class="op">@</span> eins <span class="co"># falls singulaer</span></span>
|
||
<span id="cb4-35"><a href="#cb4-35" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> loesung <span class="op">/</span> loesung.<span class="bu">sum</span>()</span>
|
||
<span id="cb4-36"><a href="#cb4-36" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb4-37"><a href="#cb4-37" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb4-38"><a href="#cb4-38" aria-hidden="true" tabindex="-1"></a><span class="kw">def</span> portfoliovolatilitaet(w, sigma):</span>
|
||
<span id="cb4-39"><a href="#cb4-39" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> <span class="bu">float</span>(np.sqrt(w <span class="op">@</span> sigma <span class="op">@</span> w))</span>
|
||
<span id="cb4-40"><a href="#cb4-40" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb4-41"><a href="#cb4-41" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb4-42"><a href="#cb4-42" 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="cb4-43"><a href="#cb4-43" aria-hidden="true" tabindex="-1"></a> rng <span class="op">=</span> np.random.default_rng(<span class="dv">2026</span>)</span>
|
||
<span id="cb4-44"><a href="#cb4-44" aria-hidden="true" tabindex="-1"></a> N <span class="op">=</span> <span class="dv">40</span> <span class="co"># Anzahl Titel</span></span>
|
||
<span id="cb4-45"><a href="#cb4-45" aria-hidden="true" tabindex="-1"></a> WIEDERHOLUNGEN <span class="op">=</span> <span class="dv">200</span></span>
|
||
<span id="cb4-46"><a href="#cb4-46" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb4-47"><a href="#cb4-47" aria-hidden="true" tabindex="-1"></a> sigma_wahr <span class="op">=</span> erzeuge_wahre_kovarianz(N, rng)</span>
|
||
<span id="cb4-48"><a href="#cb4-48" aria-hidden="true" tabindex="-1"></a> w_ideal <span class="op">=</span> minimum_varianz_gewichte(sigma_wahr)</span>
|
||
<span id="cb4-49"><a href="#cb4-49" aria-hidden="true" tabindex="-1"></a> vola_ideal <span class="op">=</span> portfoliovolatilitaet(w_ideal, sigma_wahr)</span>
|
||
<span id="cb4-50"><a href="#cb4-50" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb4-51"><a href="#cb4-51" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"="</span> <span class="op">*</span> <span class="dv">92</span>)</span>
|
||
<span id="cb4-52"><a href="#cb4-52" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">" ERROR-MAXIMIZER: WIE TEUER IST SCHAETZRAUSCHEN?"</span>)</span>
|
||
<span id="cb4-53"><a href="#cb4-53" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"="</span> <span class="op">*</span> <span class="dv">92</span>)</span>
|
||
<span id="cb4-54"><a href="#cb4-54" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f"Aufbau: </span><span class="sc">{</span>N<span class="sc">}</span><span class="ss"> Titel, wahre Kovarianz bekannt (Ein-Faktor-Modell)."</span>)</span>
|
||
<span id="cb4-55"><a href="#cb4-55" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f"Bestmoegliche Volatilitaet bei perfektem Wissen: "</span></span>
|
||
<span id="cb4-56"><a href="#cb4-56" aria-hidden="true" tabindex="-1"></a> <span class="ss">f"</span><span class="sc">{</span>vola_ideal<span class="op">*</span><span class="dv">100</span><span class="sc">:.2f}</span><span class="ss"> % p.a.</span><span class="ch">\n</span><span class="ss">"</span>)</span>
|
||
<span id="cb4-57"><a href="#cb4-57" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb4-58"><a href="#cb4-58" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f"</span><span class="sc">{</span><span class="st">'T (Tage)'</span><span class="sc">:>9}</span><span class="ss"> | </span><span class="sc">{</span><span class="st">'T/N'</span><span class="sc">:>5}</span><span class="ss"> | </span><span class="sc">{</span><span class="st">'Stichprobe'</span><span class="sc">:>22}</span><span class="ss"> | </span><span class="sc">{</span><span class="st">'Ledoit-Wolf'</span><span class="sc">:>22}</span><span class="ss"> | "</span></span>
|
||
<span id="cb4-59"><a href="#cb4-59" aria-hidden="true" tabindex="-1"></a> <span class="ss">f"</span><span class="sc">{</span><span class="st">'Shrink'</span><span class="sc">:>7}</span><span class="ss">"</span>)</span>
|
||
<span id="cb4-60"><a href="#cb4-60" 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">:>9}</span><span class="ss"> | </span><span class="sc">{</span><span class="st">''</span><span class="sc">:>5}</span><span class="ss"> | </span><span class="sc">{</span><span class="st">'Vola Aufschlag'</span><span class="sc">:>22}</span><span class="ss"> | "</span></span>
|
||
<span id="cb4-61"><a href="#cb4-61" aria-hidden="true" tabindex="-1"></a> <span class="ss">f"</span><span class="sc">{</span><span class="st">'Vola Aufschlag'</span><span class="sc">:>22}</span><span class="ss"> | </span><span class="sc">{</span><span class="st">'delta'</span><span class="sc">:>7}</span><span class="ss">"</span>)</span>
|
||
<span id="cb4-62"><a href="#cb4-62" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"-"</span> <span class="op">*</span> <span class="dv">92</span>)</span>
|
||
<span id="cb4-63"><a href="#cb4-63" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb4-64"><a href="#cb4-64" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> T <span class="kw">in</span> [<span class="dv">60</span>, <span class="dv">120</span>, <span class="dv">252</span>, <span class="dv">504</span>, <span class="dv">1260</span>]:</span>
|
||
<span id="cb4-65"><a href="#cb4-65" aria-hidden="true" tabindex="-1"></a> vola_stichprobe, vola_lw, deltas <span class="op">=</span> [], [], []</span>
|
||
<span id="cb4-66"><a href="#cb4-66" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb4-67"><a href="#cb4-67" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> _ <span class="kw">in</span> <span class="bu">range</span>(WIEDERHOLUNGEN):</span>
|
||
<span id="cb4-68"><a href="#cb4-68" aria-hidden="true" tabindex="-1"></a> <span class="co"># Daten aus der WAHREN Verteilung ziehen (taeglich)</span></span>
|
||
<span id="cb4-69"><a href="#cb4-69" aria-hidden="true" tabindex="-1"></a> daten <span class="op">=</span> rng.multivariate_normal(np.zeros(N), sigma_wahr <span class="op">/</span> <span class="dv">252</span>, size<span class="op">=</span>T)</span>
|
||
<span id="cb4-70"><a href="#cb4-70" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb4-71"><a href="#cb4-71" aria-hidden="true" tabindex="-1"></a> <span class="co"># (a) Stichproben-Kovarianz</span></span>
|
||
<span id="cb4-72"><a href="#cb4-72" aria-hidden="true" tabindex="-1"></a> s_stich <span class="op">=</span> np.cov(daten, rowvar<span class="op">=</span><span class="va">False</span>, ddof<span class="op">=</span><span class="dv">1</span>) <span class="op">*</span> <span class="dv">252</span></span>
|
||
<span id="cb4-73"><a href="#cb4-73" aria-hidden="true" tabindex="-1"></a> w_stich <span class="op">=</span> minimum_varianz_gewichte(s_stich)</span>
|
||
<span id="cb4-74"><a href="#cb4-74" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb4-75"><a href="#cb4-75" aria-hidden="true" tabindex="-1"></a> <span class="co"># (b) Ledoit-Wolf-Shrinkage</span></span>
|
||
<span id="cb4-76"><a href="#cb4-76" aria-hidden="true" tabindex="-1"></a> lw <span class="op">=</span> LedoitWolf().fit(daten)</span>
|
||
<span id="cb4-77"><a href="#cb4-77" aria-hidden="true" tabindex="-1"></a> s_lw <span class="op">=</span> lw.covariance_ <span class="op">*</span> <span class="dv">252</span></span>
|
||
<span id="cb4-78"><a href="#cb4-78" aria-hidden="true" tabindex="-1"></a> w_lw <span class="op">=</span> minimum_varianz_gewichte(s_lw)</span>
|
||
<span id="cb4-79"><a href="#cb4-79" aria-hidden="true" tabindex="-1"></a> deltas.append(lw.shrinkage_)</span>
|
||
<span id="cb4-80"><a href="#cb4-80" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb4-81"><a href="#cb4-81" aria-hidden="true" tabindex="-1"></a> <span class="co"># Bewertung IMMER mit der wahren Kovarianz - das ist der Punkt</span></span>
|
||
<span id="cb4-82"><a href="#cb4-82" aria-hidden="true" tabindex="-1"></a> vola_stichprobe.append(portfoliovolatilitaet(w_stich, sigma_wahr))</span>
|
||
<span id="cb4-83"><a href="#cb4-83" aria-hidden="true" tabindex="-1"></a> vola_lw.append(portfoliovolatilitaet(w_lw, sigma_wahr))</span>
|
||
<span id="cb4-84"><a href="#cb4-84" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb4-85"><a href="#cb4-85" aria-hidden="true" tabindex="-1"></a> m_stich, m_lw <span class="op">=</span> np.mean(vola_stichprobe), np.mean(vola_lw)</span>
|
||
<span id="cb4-86"><a href="#cb4-86" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f"</span><span class="sc">{</span>T<span class="sc">:>9}</span><span class="ss"> | </span><span class="sc">{</span>T<span class="op">/</span>N<span class="sc">:>5.1f}</span><span class="ss"> | </span><span class="sc">{</span>m_stich<span class="op">*</span><span class="dv">100</span><span class="sc">:>8.2f}</span><span class="ss"> % "</span></span>
|
||
<span id="cb4-87"><a href="#cb4-87" aria-hidden="true" tabindex="-1"></a> <span class="ss">f"</span><span class="sc">{</span>(m_stich<span class="op">/</span>vola_ideal<span class="op">-</span><span class="dv">1</span>)<span class="op">*</span><span class="dv">100</span><span class="sc">:>+9.1f}</span><span class="ss"> % | "</span></span>
|
||
<span id="cb4-88"><a href="#cb4-88" aria-hidden="true" tabindex="-1"></a> <span class="ss">f"</span><span class="sc">{</span>m_lw<span class="op">*</span><span class="dv">100</span><span class="sc">:>8.2f}</span><span class="ss"> % </span><span class="sc">{</span>(m_lw<span class="op">/</span>vola_ideal<span class="op">-</span><span class="dv">1</span>)<span class="op">*</span><span class="dv">100</span><span class="sc">:>+9.1f}</span><span class="ss"> % | "</span></span>
|
||
<span id="cb4-89"><a href="#cb4-89" aria-hidden="true" tabindex="-1"></a> <span class="ss">f"</span><span class="sc">{</span>np<span class="sc">.</span>mean(deltas)<span class="sc">:>7.3f}</span><span class="ss">"</span>)</span>
|
||
<span id="cb4-90"><a href="#cb4-90" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb4-91"><a href="#cb4-91" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"-"</span> <span class="op">*</span> <span class="dv">92</span>)</span>
|
||
<span id="cb4-92"><a href="#cb4-92" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"'Aufschlag' = wie viel mehr Risiko das Portfolio in der WAHREN Welt traegt,"</span>)</span>
|
||
<span id="cb4-93"><a href="#cb4-93" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"verglichen mit dem Portfolio bei perfektem Wissen."</span>)</span>
|
||
<span id="cb4-94"><a href="#cb4-94" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"Lesart: Je kleiner T/N, desto teurer das Schaetzrauschen - und desto mehr"</span>)</span>
|
||
<span id="cb4-95"><a href="#cb4-95" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"schrumpft Ledoit-Wolf (delta steigt)."</span>)</span>
|
||
<span id="cb4-96"><a href="#cb4-96" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"="</span> <span class="op">*</span> <span class="dv">92</span>)</span></code></pre></div>
|
||
<hr />
|
||
<p><strong>Erwartete Ausgabe:</strong></p>
|
||
<pre><code>============================================================================================
|
||
ERROR-MAXIMIZER: WIE TEUER IST SCHAETZRAUSCHEN?
|
||
============================================================================================
|
||
Aufbau: 40 Titel, wahre Kovarianz bekannt (Ein-Faktor-Modell).
|
||
Bestmoegliche Volatilitaet bei perfektem Wissen: 11.84 % p.a.
|
||
|
||
T (Tage) | T/N | Stichprobe | Ledoit-Wolf | Shrink
|
||
| | Vola Aufschlag | Vola Aufschlag | delta
|
||
--------------------------------------------------------------------------------------------
|
||
60 | 1.5 | 20.78 % +75.5 % | 15.44 % +30.4 % | 0.093
|
||
120 | 3.0 | 14.42 % +21.8 % | 13.79 % +16.5 % | 0.048
|
||
252 | 6.3 | 12.86 % +8.7 % | 12.76 % +7.8 % | 0.024
|
||
504 | 12.6 | 12.33 % +4.1 % | 12.30 % +3.9 % | 0.012
|
||
1260 | 31.5 | 12.03 % +1.6 % | 12.02 % +1.6 % | 0.005
|
||
--------------------------------------------------------------------------------------------</code></pre>
|
||
<p><strong>Diese Tabelle ist das Kernargument des ganzen Kapitels.</strong> Lesen Sie die erste Zeile: Bei nur 60 Beobachtungen für 40 Titel trägt das „risikominimale“ Portfolio in Wahrheit <strong>75,5 % mehr Risiko</strong> als nötig. Der Optimierer hat nicht das Risiko minimiert, sondern das <strong>geschätzte</strong> Risiko — und die Differenz ist der Schätzfehler, in den er hineinoptimiert hat.</p>
|
||
<p>Drei Beobachtungen:</p>
|
||
<ol type="1">
|
||
<li><strong>Der Schaden wächst dramatisch, je knapper die Daten.</strong> Von <span class="math inline">T/N = 31{,}5</span> (+1,6 %) bis <span class="math inline">T/N = 1{,}5</span> (+75,5 %) ist es kein gleitender Übergang, sondern eine Explosion.</li>
|
||
<li><strong>Shrinkage halbiert den Schaden dort, wo er groß ist</strong> (75,5 % → 30,4 %) und schadet dort nichts, wo er klein ist (1,6 % → 1,6 %). Sie ist damit praktisch risikolos einzusetzen.</li>
|
||
<li><strong><span class="math inline">\delta</span> passt sich automatisch an:</strong> viel Schrumpfung bei wenig Daten (0,093), fast keine bei vielen (0,005). Man muss nichts von Hand einstellen.</li>
|
||
</ol>
|
||
<blockquote>
|
||
<p><strong>🎯 Die Praxisregel</strong> Faustregel für Aktienportfolios: <strong><span class="math inline">T \ge 5N</span></strong> sollte man mindestens haben, besser <span class="math inline">T \ge 10N</span>. Bei 50 Titeln sind das 250 bis 500 Handelstage — ein bis zwei Jahre. Wer weniger hat, sollte entweder das Universum verkleinern oder mit Shrinkage arbeiten. Am besten beides.</p>
|
||
</blockquote>
|
||
<h2 id="sec:finanzdaten-ledoit-wolf-shrinkage">18.5 Ledoit-Wolf-Shrinkage</h2>
|
||
<p>Olivier Ledoit und Michael Wolf lösten das Dilemma durch <strong>lineare Schrumpfung</strong>:</p>
|
||
<p><span class="math display">
|
||
\boldsymbol{\Sigma}_{\text{LW}} = (1-\delta)\,\mathbf{S} + \delta\,\mathbf{F}
|
||
</span></p>
|
||
<blockquote>
|
||
<p><strong>📐 Formel-Lesehilfe</strong> * <span class="math inline">\mathbf{S}</span> — die Stichprobenmatrix: <strong>unverzerrt</strong>, aber verrauscht. * <span class="math inline">\mathbf{F}</span> — das <strong>Schrumpfungsziel</strong>: verzerrt, aber stabil und rauschfrei. * <span class="math inline">\delta \in [0,1]</span> — wie weit man vom Rauschen zur Struktur zieht.</p>
|
||
<p><strong>Ohne Formel gesagt:</strong> Man mischt eine zappelige, aber im Mittel richtige Schätzung mit einer ruhigen, aber etwas schiefen. Die Mischung ist besser als beide Bestandteile einzeln — ein klassischer <strong>Bias-Varianz-Kompromiss</strong>. Ledoit und Wolf berechnen dabei dasjenige <span class="math inline">\delta</span>, das den erwarteten quadratischen Fehler zur unbekannten wahren Matrix <strong>minimiert</strong> — analytisch, ohne Kreuzvalidierung.</p>
|
||
</blockquote>
|
||
<h3 id="welches-ziel-mathbff">Welches Ziel <span class="math inline">\mathbf{F}</span>?</h3>
|
||
<p>Ein häufiges Missverständnis: Es gibt nämlich <strong>mehrere</strong> Ledoit-Wolf-Varianten, und Text und Code müssen sich konsistent auf dieselbe beziehen:</p>
|
||
<table>
|
||
<colgroup>
|
||
<col style="width: 15%" />
|
||
<col style="width: 25%" />
|
||
<col style="width: 14%" />
|
||
<col style="width: 43%" />
|
||
</colgroup>
|
||
<thead>
|
||
<tr class="header">
|
||
<th>Ziel <span class="math inline">\mathbf{F}</span></th>
|
||
<th>Formel</th>
|
||
<th>Quelle</th>
|
||
<th>Wer benutzt es</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr class="odd">
|
||
<td><strong>Skalierte Einheitsmatrix</strong></td>
|
||
<td><span class="math inline">\mathbf{F} = \frac{\operatorname{tr}(\mathbf{S})}{N}\,\mathbf{I}</span></td>
|
||
<td>Ledoit/Wolf 2004, <em>„A well-conditioned estimator“</em></td>
|
||
<td><strong><code>sklearn.covariance.LedoitWolf</code></strong></td>
|
||
</tr>
|
||
<tr class="even">
|
||
<td><strong>Konstante Korrelation</strong></td>
|
||
<td><span class="math inline">f_{ii} = s_{ii}</span>, <span class="math inline">f_{ij} = \bar{r}\sqrt{s_{ii}s_{jj}}</span></td>
|
||
<td>Ledoit/Wolf 2003, <em>„Honey, I shrunk the sample covariance matrix“</em></td>
|
||
<td>oft in der Praxis, z. B. <code>PyPortfolioOpt</code></td>
|
||
</tr>
|
||
<tr class="odd">
|
||
<td><strong>Ein-Faktor-Modell</strong></td>
|
||
<td>aus Marktbeta geschätzt</td>
|
||
<td>Ledoit/Wolf 2003</td>
|
||
<td>Faktormodell-Ansätze</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<p><strong>Wichtig ist, Text und Code konsistent auf dieselbe Variante zu beziehen</strong> — zum Beispiel <code>sklearn.covariance.LedoitWolf</code>, das die skalierte Einheitsmatrix verwendet, versus eine manuelle Implementierung des Konstant-Korrelations-Ziels. Dieses Buch nennt beide und macht transparent, welches wo zum Einsatz kommt.</p>
|
||
<blockquote>
|
||
<p><strong>💡 Welches Ziel ist besser?</strong> Es kommt darauf an. Die <strong>Einheitsmatrix</strong> unterstellt, dass alle Titel gleich riskant und unkorreliert sind — eine starke, aber sehr stabile Annahme. Das <strong>Konstant-Korrelations-Ziel</strong> behält die geschätzten Einzelvarianzen und glättet nur die Korrelationen; das ist bei Aktien meist realistischer, weil Titel tatsächlich sehr unterschiedliche Volatilitäten haben. In der Aufgabe <em>Beide Shrinkage-Ziele vergleichen</em> (<a href="#sec:finanzdaten-uebungsaufgaben">Abschnitt 18.7</a>) implementieren Sie es selbst und vergleichen.</p>
|
||
</blockquote>
|
||
<p>Das Ergebnis ist in jedem Fall garantiert <strong>positiv definit</strong>, wohlkonditioniert und stabil invertierbar.</p>
|
||
<hr />
|
||
<h2 id="sec:finanzdaten-praxis-datenpipeline-mit-korrekter-spaltenreihenfolge">18.6 Praxis: Datenpipeline mit korrekter Spaltenreihenfolge</h2>
|
||
<blockquote>
|
||
<p><strong>⚠️ Die wichtigste Zeile dieses Kapitels</strong></p>
|
||
<p><code>yfinance</code> liefert die Kursspalten <strong>alphabetisch sortiert</strong>, nicht in der Reihenfolge Ihrer Ticker-Liste:</p>
|
||
<pre><code>Ihre Liste: ['AAPL', 'MSFT', 'NVDA', 'AMZN', 'JNJ', 'PFE', 'JPM', 'GS', 'XOM', 'CVX']
|
||
prices.columns: ['AAPL', 'AMZN', 'CVX', 'GS', 'JNJ', 'JPM', 'MSFT', 'NVDA', 'PFE', 'XOM']</code></pre>
|
||
<p>Wer danach mit Positionsindizes arbeitet, beschriftet Ergebnisse falsch und beschränkt falsche Sektoren. <strong>Die Abhilfe ist eine Zeile:</strong></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>prices <span class="op">=</span> raw[<span class="st">"Close"</span>][tickers].dropna() <span class="co"># erzwingt die eigene Reihenfolge</span></span>
|
||
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a><span class="cf">assert</span> <span class="bu">list</span>(prices.columns) <span class="op">==</span> tickers</span></code></pre></div>
|
||
</blockquote>
|
||
<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="co">#!/usr/bin/env python3</span></span>
|
||
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a><span class="co"># Finanzdaten_Ledoit_Wolf.py</span></span>
|
||
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a><span class="co">"""</span></span>
|
||
<span id="cb8-5"><a href="#cb8-5" aria-hidden="true" tabindex="-1"></a><span class="co">Kapitel Finanzdaten: Automatisierte Finanzdaten-Pipeline und Kovarianz-Shrinkage.</span></span>
|
||
<span id="cb8-6"><a href="#cb8-6" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb8-7"><a href="#cb8-7" aria-hidden="true" tabindex="-1"></a><span class="co">Eigenschaften:</span></span>
|
||
<span id="cb8-8"><a href="#cb8-8" aria-hidden="true" tabindex="-1"></a><span class="co"> * Spaltenreihenfolge wird erzwungen und per assert geprueft</span></span>
|
||
<span id="cb8-9"><a href="#cb8-9" aria-hidden="true" tabindex="-1"></a><span class="co"> * beide Shrinkage-Ziele werden berechnet und verglichen</span></span>
|
||
<span id="cb8-10"><a href="#cb8-10" aria-hidden="true" tabindex="-1"></a><span class="co"> * Datenqualitaetspruefungen (Luecken, Ausreisser, Mindestlaenge)</span></span>
|
||
<span id="cb8-11"><a href="#cb8-11" aria-hidden="true" tabindex="-1"></a><span class="co"> * Eigenwertspektrum wird ausgewiesen, nicht nur die Konditionszahl</span></span>
|
||
<span id="cb8-12"><a href="#cb8-12" aria-hidden="true" tabindex="-1"></a><span class="co">"""</span></span>
|
||
<span id="cb8-13"><a href="#cb8-13" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb8-14"><a href="#cb8-14" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> numpy <span class="im">as</span> np</span>
|
||
<span id="cb8-15"><a href="#cb8-15" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> pandas <span class="im">as</span> pd</span>
|
||
<span id="cb8-16"><a href="#cb8-16" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> yfinance <span class="im">as</span> yf</span>
|
||
<span id="cb8-17"><a href="#cb8-17" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> sklearn.covariance <span class="im">import</span> LedoitWolf</span>
|
||
<span id="cb8-18"><a href="#cb8-18" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb8-19"><a href="#cb8-19" aria-hidden="true" tabindex="-1"></a>HANDELSTAGE <span class="op">=</span> <span class="dv">252</span></span>
|
||
<span id="cb8-20"><a href="#cb8-20" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb8-21"><a href="#cb8-21" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb8-22"><a href="#cb8-22" aria-hidden="true" tabindex="-1"></a><span class="kw">def</span> lade_kurse(tickers: <span class="bu">list</span>[<span class="bu">str</span>], start, ende) <span class="op">-></span> pd.DataFrame:</span>
|
||
<span id="cb8-23"><a href="#cb8-23" aria-hidden="true" tabindex="-1"></a> <span class="co">"""Laedt bereinigte Schlusskurse und garantiert die Spaltenreihenfolge."""</span></span>
|
||
<span id="cb8-24"><a href="#cb8-24" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f"Lade </span><span class="sc">{</span><span class="bu">len</span>(tickers)<span class="sc">}</span><span class="ss"> Ticker von </span><span class="sc">{</span>start<span class="sc">}</span><span class="ss"> bis </span><span class="sc">{</span>ende<span class="sc">}</span><span class="ss"> ..."</span>)</span>
|
||
<span id="cb8-25"><a href="#cb8-25" aria-hidden="true" tabindex="-1"></a> roh <span class="op">=</span> yf.download(tickers, 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="cb8-26"><a href="#cb8-26" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> roh.empty:</span>
|
||
<span id="cb8-27"><a href="#cb8-27" 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="cb8-28"><a href="#cb8-28" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb8-29"><a href="#cb8-29" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="bu">isinstance</span>(roh.columns, pd.MultiIndex):</span>
|
||
<span id="cb8-30"><a href="#cb8-30" aria-hidden="true" tabindex="-1"></a> <span class="co"># [tickers] erzwingt die gewuenschte Spaltenreihenfolge</span></span>
|
||
<span id="cb8-31"><a href="#cb8-31" aria-hidden="true" tabindex="-1"></a> kurse <span class="op">=</span> roh[<span class="st">"Close"</span>][tickers].dropna()</span>
|
||
<span id="cb8-32"><a href="#cb8-32" aria-hidden="true" tabindex="-1"></a> <span class="cf">else</span>:</span>
|
||
<span id="cb8-33"><a href="#cb8-33" aria-hidden="true" tabindex="-1"></a> kurse <span class="op">=</span> roh[[<span class="st">"Close"</span>]].dropna()</span>
|
||
<span id="cb8-34"><a href="#cb8-34" aria-hidden="true" tabindex="-1"></a> kurse.columns <span class="op">=</span> tickers</span>
|
||
<span id="cb8-35"><a href="#cb8-35" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb8-36"><a href="#cb8-36" aria-hidden="true" tabindex="-1"></a> <span class="cf">assert</span> <span class="bu">list</span>(kurse.columns) <span class="op">==</span> tickers, (</span>
|
||
<span id="cb8-37"><a href="#cb8-37" aria-hidden="true" tabindex="-1"></a> <span class="ss">f"Spaltenreihenfolge weicht ab!</span><span class="ch">\n</span><span class="ss"> erwartet: </span><span class="sc">{</span>tickers<span class="sc">}</span><span class="ch">\n</span><span class="ss">"</span></span>
|
||
<span id="cb8-38"><a href="#cb8-38" aria-hidden="true" tabindex="-1"></a> <span class="ss">f" erhalten: </span><span class="sc">{</span><span class="bu">list</span>(kurse.columns)<span class="sc">}</span><span class="ss">"</span>)</span>
|
||
<span id="cb8-39"><a href="#cb8-39" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> kurse</span>
|
||
<span id="cb8-40"><a href="#cb8-40" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb8-41"><a href="#cb8-41" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb8-42"><a href="#cb8-42" aria-hidden="true" tabindex="-1"></a><span class="kw">def</span> pruefe_datenqualitaet(kurse: pd.DataFrame, mindest_tage: <span class="bu">int</span> <span class="op">=</span> <span class="dv">200</span>) <span class="op">-></span> <span class="va">None</span>:</span>
|
||
<span id="cb8-43"><a href="#cb8-43" aria-hidden="true" tabindex="-1"></a> <span class="co">"""Faengt die haeufigsten Datenprobleme ab, bevor sie ins Modell gelangen."""</span></span>
|
||
<span id="cb8-44"><a href="#cb8-44" aria-hidden="true" tabindex="-1"></a> T, N <span class="op">=</span> kurse.shape</span>
|
||
<span id="cb8-45"><a href="#cb8-45" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f"</span><span class="ch">\n</span><span class="ss">Datenqualitaet: </span><span class="sc">{</span>T<span class="sc">}</span><span class="ss"> Handelstage, </span><span class="sc">{</span>N<span class="sc">}</span><span class="ss"> Titel (T/N = </span><span class="sc">{</span>T<span class="op">/</span>N<span class="sc">:.1f}</span><span class="ss">)"</span>)</span>
|
||
<span id="cb8-46"><a href="#cb8-46" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> T <span class="op"><</span> mindest_tage:</span>
|
||
<span id="cb8-47"><a href="#cb8-47" aria-hidden="true" tabindex="-1"></a> <span class="cf">raise</span> <span class="pp">SystemExit</span>(<span class="ss">f"Zu wenige Beobachtungen (</span><span class="sc">{</span>T<span class="sc">}</span><span class="ss"> < </span><span class="sc">{</span>mindest_tage<span class="sc">}</span><span class="ss">)."</span>)</span>
|
||
<span id="cb8-48"><a href="#cb8-48" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> T <span class="op"><</span> N:</span>
|
||
<span id="cb8-49"><a href="#cb8-49" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">" WARNUNG: T < N - die Stichprobenkovarianz ist singulaer!"</span>)</span>
|
||
<span id="cb8-50"><a href="#cb8-50" aria-hidden="true" tabindex="-1"></a> <span class="cf">elif</span> T <span class="op"><</span> <span class="dv">3</span> <span class="op">*</span> N:</span>
|
||
<span id="cb8-51"><a href="#cb8-51" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">" WARNUNG: T < 3N - erhebliches Schaetzrauschen zu erwarten."</span>)</span>
|
||
<span id="cb8-52"><a href="#cb8-52" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb8-53"><a href="#cb8-53" aria-hidden="true" tabindex="-1"></a> renditen <span class="op">=</span> kurse.pct_change().dropna()</span>
|
||
<span id="cb8-54"><a href="#cb8-54" aria-hidden="true" tabindex="-1"></a> extreme <span class="op">=</span> (renditen.<span class="bu">abs</span>() <span class="op">></span> <span class="fl">0.25</span>).<span class="bu">sum</span>().<span class="bu">sum</span>()</span>
|
||
<span id="cb8-55"><a href="#cb8-55" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> extreme:</span>
|
||
<span id="cb8-56"><a href="#cb8-56" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f" Hinweis: </span><span class="sc">{</span>extreme<span class="sc">}</span><span class="ss"> Tagesrenditen ueber 25 % "</span></span>
|
||
<span id="cb8-57"><a href="#cb8-57" aria-hidden="true" tabindex="-1"></a> <span class="ss">f"(Splits, Sondersituationen oder Datenfehler pruefen)."</span>)</span>
|
||
<span id="cb8-58"><a href="#cb8-58" aria-hidden="true" tabindex="-1"></a> luecken <span class="op">=</span> kurse.isna().<span class="bu">sum</span>().<span class="bu">sum</span>()</span>
|
||
<span id="cb8-59"><a href="#cb8-59" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f" Fehlende Werte nach dropna: </span><span class="sc">{</span>luecken<span class="sc">}</span><span class="ss">"</span>)</span>
|
||
<span id="cb8-60"><a href="#cb8-60" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb8-61"><a href="#cb8-61" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb8-62"><a href="#cb8-62" aria-hidden="true" tabindex="-1"></a><span class="kw">def</span> ziel_konstante_korrelation(renditen: np.ndarray) <span class="op">-></span> np.ndarray:</span>
|
||
<span id="cb8-63"><a href="#cb8-63" aria-hidden="true" tabindex="-1"></a> <span class="co">"""</span></span>
|
||
<span id="cb8-64"><a href="#cb8-64" aria-hidden="true" tabindex="-1"></a><span class="co"> Shrinkage-Ziel nach Ledoit/Wolf 2003: Einzelvarianzen behalten,</span></span>
|
||
<span id="cb8-65"><a href="#cb8-65" aria-hidden="true" tabindex="-1"></a><span class="co"> alle Korrelationen durch ihren Mittelwert ersetzen.</span></span>
|
||
<span id="cb8-66"><a href="#cb8-66" aria-hidden="true" tabindex="-1"></a><span class="co"> (sklearn nutzt stattdessen die skalierte Einheitsmatrix - siehe oben.)</span></span>
|
||
<span id="cb8-67"><a href="#cb8-67" aria-hidden="true" tabindex="-1"></a><span class="co"> """</span></span>
|
||
<span id="cb8-68"><a href="#cb8-68" aria-hidden="true" tabindex="-1"></a> S <span class="op">=</span> np.cov(renditen, rowvar<span class="op">=</span><span class="va">False</span>, ddof<span class="op">=</span><span class="dv">1</span>)</span>
|
||
<span id="cb8-69"><a href="#cb8-69" aria-hidden="true" tabindex="-1"></a> d <span class="op">=</span> np.sqrt(np.diag(S))</span>
|
||
<span id="cb8-70"><a href="#cb8-70" aria-hidden="true" tabindex="-1"></a> korrelation <span class="op">=</span> S <span class="op">/</span> np.outer(d, d)</span>
|
||
<span id="cb8-71"><a href="#cb8-71" aria-hidden="true" tabindex="-1"></a> n <span class="op">=</span> <span class="bu">len</span>(S)</span>
|
||
<span id="cb8-72"><a href="#cb8-72" aria-hidden="true" tabindex="-1"></a> r_quer <span class="op">=</span> (korrelation.<span class="bu">sum</span>() <span class="op">-</span> n) <span class="op">/</span> (n <span class="op">*</span> (n <span class="op">-</span> <span class="dv">1</span>)) <span class="co"># Mittel ohne Diagonale</span></span>
|
||
<span id="cb8-73"><a href="#cb8-73" aria-hidden="true" tabindex="-1"></a> F <span class="op">=</span> r_quer <span class="op">*</span> np.outer(d, d)</span>
|
||
<span id="cb8-74"><a href="#cb8-74" aria-hidden="true" tabindex="-1"></a> np.fill_diagonal(F, np.diag(S))</span>
|
||
<span id="cb8-75"><a href="#cb8-75" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> F</span>
|
||
<span id="cb8-76"><a href="#cb8-76" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb8-77"><a href="#cb8-77" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb8-78"><a href="#cb8-78" aria-hidden="true" tabindex="-1"></a><span class="kw">def</span> analysiere(kurse: pd.DataFrame):</span>
|
||
<span id="cb8-79"><a href="#cb8-79" aria-hidden="true" tabindex="-1"></a> renditen <span class="op">=</span> kurse.pct_change().dropna()</span>
|
||
<span id="cb8-80"><a href="#cb8-80" aria-hidden="true" tabindex="-1"></a> T, N <span class="op">=</span> renditen.shape</span>
|
||
<span id="cb8-81"><a href="#cb8-81" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb8-82"><a href="#cb8-82" aria-hidden="true" tabindex="-1"></a> mu <span class="op">=</span> renditen.mean().values <span class="op">*</span> HANDELSTAGE</span>
|
||
<span id="cb8-83"><a href="#cb8-83" aria-hidden="true" tabindex="-1"></a> sigma_stichprobe <span class="op">=</span> renditen.cov().values <span class="op">*</span> HANDELSTAGE</span>
|
||
<span id="cb8-84"><a href="#cb8-84" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb8-85"><a href="#cb8-85" aria-hidden="true" tabindex="-1"></a> lw <span class="op">=</span> LedoitWolf(assume_centered<span class="op">=</span><span class="va">False</span>).fit(renditen.values)</span>
|
||
<span id="cb8-86"><a href="#cb8-86" aria-hidden="true" tabindex="-1"></a> sigma_lw <span class="op">=</span> lw.covariance_ <span class="op">*</span> HANDELSTAGE</span>
|
||
<span id="cb8-87"><a href="#cb8-87" aria-hidden="true" tabindex="-1"></a> delta <span class="op">=</span> lw.shrinkage_</span>
|
||
<span id="cb8-88"><a href="#cb8-88" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb8-89"><a href="#cb8-89" 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">84</span>)</span>
|
||
<span id="cb8-90"><a href="#cb8-90" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">" FINANZDATEN-PIPELINE UND MATRIX-KONDITIONIERUNG"</span>)</span>
|
||
<span id="cb8-91"><a href="#cb8-91" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"="</span> <span class="op">*</span> <span class="dv">84</span>)</span>
|
||
<span id="cb8-92"><a href="#cb8-92" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f"Beobachtungen T: </span><span class="sc">{</span>T<span class="sc">}</span><span class="ss">"</span>)</span>
|
||
<span id="cb8-93"><a href="#cb8-93" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f"Titel N: </span><span class="sc">{</span>N<span class="sc">}</span><span class="ss">"</span>)</span>
|
||
<span id="cb8-94"><a href="#cb8-94" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f"Optimales Shrinkage delta: </span><span class="sc">{</span>delta<span class="sc">:.4f}</span><span class="ss"> "</span></span>
|
||
<span id="cb8-95"><a href="#cb8-95" aria-hidden="true" tabindex="-1"></a> <span class="ss">f"(</span><span class="sc">{</span>delta<span class="op">*</span><span class="dv">100</span><span class="sc">:.1f}</span><span class="ss"> % Gewicht auf dem strukturierten Ziel)"</span>)</span>
|
||
<span id="cb8-96"><a href="#cb8-96" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb8-97"><a href="#cb8-97" aria-hidden="true" tabindex="-1"></a> eig_stich <span class="op">=</span> np.linalg.eigvalsh(sigma_stichprobe)</span>
|
||
<span id="cb8-98"><a href="#cb8-98" aria-hidden="true" tabindex="-1"></a> eig_lw <span class="op">=</span> np.linalg.eigvalsh(sigma_lw)</span>
|
||
<span id="cb8-99"><a href="#cb8-99" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb8-100"><a href="#cb8-100" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"</span><span class="ch">\n</span><span class="st">--- Eigenwertspektrum (annualisiert) ---"</span>)</span>
|
||
<span id="cb8-101"><a href="#cb8-101" 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">:<14}</span><span class="ss"> </span><span class="sc">{</span><span class="st">'kleinster'</span><span class="sc">:>12}</span><span class="ss"> </span><span class="sc">{</span><span class="st">'Median'</span><span class="sc">:>12}</span><span class="ss"> </span><span class="sc">{</span><span class="st">'groesster'</span><span class="sc">:>12}</span><span class="ss"> "</span></span>
|
||
<span id="cb8-102"><a href="#cb8-102" aria-hidden="true" tabindex="-1"></a> <span class="ss">f"</span><span class="sc">{</span><span class="st">'Kondition'</span><span class="sc">:>12}</span><span class="ss">"</span>)</span>
|
||
<span id="cb8-103"><a href="#cb8-103" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> name, eig <span class="kw">in</span> [(<span class="st">"Stichprobe"</span>, eig_stich), (<span class="st">"Ledoit-Wolf"</span>, eig_lw)]:</span>
|
||
<span id="cb8-104"><a href="#cb8-104" aria-hidden="true" tabindex="-1"></a> kondition <span class="op">=</span> eig.<span class="bu">max</span>() <span class="op">/</span> <span class="bu">max</span>(eig.<span class="bu">min</span>(), <span class="fl">1e-12</span>)</span>
|
||
<span id="cb8-105"><a href="#cb8-105" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f"</span><span class="sc">{</span>name<span class="sc">:<14}</span><span class="ss"> </span><span class="sc">{</span>eig<span class="sc">.</span><span class="bu">min</span>()<span class="sc">:>12.6f}</span><span class="ss"> </span><span class="sc">{</span>np<span class="sc">.</span>median(eig)<span class="sc">:>12.6f}</span><span class="ss"> "</span></span>
|
||
<span id="cb8-106"><a href="#cb8-106" aria-hidden="true" tabindex="-1"></a> <span class="ss">f"</span><span class="sc">{</span>eig<span class="sc">.</span><span class="bu">max</span>()<span class="sc">:>12.6f}</span><span class="ss"> </span><span class="sc">{</span>kondition<span class="sc">:>12.1f}</span><span class="ss">"</span>)</span>
|
||
<span id="cb8-107"><a href="#cb8-107" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb8-108"><a href="#cb8-108" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"</span><span class="ch">\n</span><span class="st">Die Konditionszahl misst, wie stark sich kleine Datenaenderungen auf"</span>)</span>
|
||
<span id="cb8-109"><a href="#cb8-109" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"die Inverse auswirken. Je kleiner, desto stabiler die Portfoliogewichte."</span>)</span>
|
||
<span id="cb8-110"><a href="#cb8-110" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb8-111"><a href="#cb8-111" aria-hidden="true" tabindex="-1"></a> <span class="co"># --- Vergleich der beiden Shrinkage-Ziele ----------------------------</span></span>
|
||
<span id="cb8-112"><a href="#cb8-112" aria-hidden="true" tabindex="-1"></a> S_taeglich <span class="op">=</span> np.cov(renditen.values, rowvar<span class="op">=</span><span class="va">False</span>, ddof<span class="op">=</span><span class="dv">1</span>)</span>
|
||
<span id="cb8-113"><a href="#cb8-113" aria-hidden="true" tabindex="-1"></a> F_identitaet <span class="op">=</span> np.eye(N) <span class="op">*</span> np.trace(S_taeglich) <span class="op">/</span> N</span>
|
||
<span id="cb8-114"><a href="#cb8-114" aria-hidden="true" tabindex="-1"></a> F_korrelation <span class="op">=</span> ziel_konstante_korrelation(renditen.values)</span>
|
||
<span id="cb8-115"><a href="#cb8-115" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb8-116"><a href="#cb8-116" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"</span><span class="ch">\n</span><span class="st">--- Die beiden Shrinkage-Ziele im Vergleich ---"</span>)</span>
|
||
<span id="cb8-117"><a href="#cb8-117" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> name, F <span class="kw">in</span> [(<span class="st">"skalierte Einheitsmatrix (sklearn)"</span>, F_identitaet),</span>
|
||
<span id="cb8-118"><a href="#cb8-118" aria-hidden="true" tabindex="-1"></a> (<span class="st">"konstante Korrelation (LW 2003)"</span>, F_korrelation)]:</span>
|
||
<span id="cb8-119"><a href="#cb8-119" aria-hidden="true" tabindex="-1"></a> gemischt <span class="op">=</span> ((<span class="dv">1</span> <span class="op">-</span> delta) <span class="op">*</span> S_taeglich <span class="op">+</span> delta <span class="op">*</span> F) <span class="op">*</span> HANDELSTAGE</span>
|
||
<span id="cb8-120"><a href="#cb8-120" aria-hidden="true" tabindex="-1"></a> eig <span class="op">=</span> np.linalg.eigvalsh(gemischt)</span>
|
||
<span id="cb8-121"><a href="#cb8-121" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f" </span><span class="sc">{</span>name<span class="sc">:<36}</span><span class="ss">: Kondition </span><span class="sc">{</span>eig<span class="sc">.</span><span class="bu">max</span>()<span class="op">/</span><span class="bu">max</span>(eig.<span class="bu">min</span>(),<span class="fl">1e-12</span>)<span class="sc">:8.1f}</span><span class="ss">, "</span></span>
|
||
<span id="cb8-122"><a href="#cb8-122" aria-hidden="true" tabindex="-1"></a> <span class="ss">f"kleinster EW </span><span class="sc">{</span>eig<span class="sc">.</span><span class="bu">min</span>()<span class="sc">:.6f}</span><span class="ss">"</span>)</span>
|
||
<span id="cb8-123"><a href="#cb8-123" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb8-124"><a href="#cb8-124" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"</span><span class="ch">\n</span><span class="st">--- Erwartete Renditen (annualisiert) ---"</span>)</span>
|
||
<span id="cb8-125"><a href="#cb8-125" aria-hidden="true" tabindex="-1"></a> uebersicht <span class="op">=</span> pd.DataFrame({</span>
|
||
<span id="cb8-126"><a href="#cb8-126" aria-hidden="true" tabindex="-1"></a> <span class="st">"Ticker"</span>: kurse.columns,</span>
|
||
<span id="cb8-127"><a href="#cb8-127" aria-hidden="true" tabindex="-1"></a> <span class="st">"Rendite p.a."</span>: [<span class="ss">f"</span><span class="sc">{</span>r<span class="op">*</span><span class="dv">100</span><span class="sc">:+7.2f}</span><span class="ss"> %"</span> <span class="cf">for</span> r <span class="kw">in</span> mu],</span>
|
||
<span id="cb8-128"><a href="#cb8-128" aria-hidden="true" tabindex="-1"></a> <span class="st">"Volatilitaet p.a."</span>: [<span class="ss">f"</span><span class="sc">{</span>np<span class="sc">.</span>sqrt(sigma_lw[i, i])<span class="op">*</span><span class="dv">100</span><span class="sc">:6.2f}</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="cb8-129"><a href="#cb8-129" aria-hidden="true" tabindex="-1"></a> })</span>
|
||
<span id="cb8-130"><a href="#cb8-130" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(uebersicht.to_string(index<span class="op">=</span><span class="va">False</span>))</span>
|
||
<span id="cb8-131"><a href="#cb8-131" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"="</span> <span class="op">*</span> <span class="dv">84</span>)</span>
|
||
<span id="cb8-132"><a href="#cb8-132" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> renditen, mu, sigma_stichprobe, sigma_lw</span>
|
||
<span id="cb8-133"><a href="#cb8-133" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb8-134"><a href="#cb8-134" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb8-135"><a href="#cb8-135" 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="cb8-136"><a href="#cb8-136" aria-hidden="true" tabindex="-1"></a> UNIVERSUM <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="co"># Technologie</span></span>
|
||
<span id="cb8-137"><a href="#cb8-137" aria-hidden="true" tabindex="-1"></a> <span class="st">"JNJ"</span>, <span class="st">"PFE"</span>, <span class="co"># Gesundheit</span></span>
|
||
<span id="cb8-138"><a href="#cb8-138" aria-hidden="true" tabindex="-1"></a> <span class="st">"JPM"</span>, <span class="st">"GS"</span>, <span class="co"># Banken</span></span>
|
||
<span id="cb8-139"><a href="#cb8-139" aria-hidden="true" tabindex="-1"></a> <span class="st">"XOM"</span>, <span class="st">"CVX"</span>] <span class="co"># Energie</span></span>
|
||
<span id="cb8-140"><a href="#cb8-140" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb8-141"><a href="#cb8-141" aria-hidden="true" tabindex="-1"></a> <span class="co"># Relatives 2-Jahres-Fenster, damit das Beispiel nicht "altert"</span></span>
|
||
<span id="cb8-142"><a href="#cb8-142" aria-hidden="true" tabindex="-1"></a> ende <span class="op">=</span> pd.Timestamp.today().normalize()</span>
|
||
<span id="cb8-143"><a href="#cb8-143" 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="cb8-144"><a href="#cb8-144" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb8-145"><a href="#cb8-145" aria-hidden="true" tabindex="-1"></a> kurse <span class="op">=</span> lade_kurse(UNIVERSUM, start.strftime(<span class="st">"%Y-%m-</span><span class="sc">%d</span><span class="st">"</span>), ende.strftime(<span class="st">"%Y-%m-</span><span class="sc">%d</span><span class="st">"</span>))</span>
|
||
<span id="cb8-146"><a href="#cb8-146" aria-hidden="true" tabindex="-1"></a> pruefe_datenqualitaet(kurse)</span>
|
||
<span id="cb8-147"><a href="#cb8-147" aria-hidden="true" tabindex="-1"></a> analysiere(kurse)</span></code></pre></div>
|
||
<blockquote>
|
||
<p><strong>⚠️ Zur Reproduzierbarkeit</strong> Dieses Programm lädt <strong>Live-Daten</strong>. Ihre Zahlen werden von den hier abgedruckten abweichen — je nach Abrufdatum. Das ist beabsichtigt und selbst eine Lektion: Wenn sich das optimale Portfolio zwischen zwei Abrufen deutlich ändert, obwohl nur ein paar Tage vergangen sind, sehen Sie den Schätzfehler direkt. Prüfen Sie das ruhig einmal.</p>
|
||
</blockquote>
|
||
<hr />
|
||
<h2 id="sec:finanzdaten-uebungsaufgaben">18.7 Übungsaufgaben</h2>
|
||
<blockquote>
|
||
<p>Lösungen: <a href="anhang-loesungen.html#sec:loesungen-finanzdaten">Abschnitt A.18</a>.</p>
|
||
</blockquote>
|
||
<p><strong>Aufgabe 18.1 ⭐ — Renditeart wählen.</strong> Welche Renditeart nehmen Sie und warum? (a) Portfoliorendite aus Einzelrenditen berechnen. (b) Volatilität über 5 Jahre schätzen. (c) Kumulierte Wertentwicklung über 10 Jahre darstellen. (d) Korrelationen zwischen Titeln schätzen.</p>
|
||
<p><strong>Aufgabe 18.2 ⭐ — Mittelwertfalle.</strong> Ein Fonds meldet Jahresrenditen von <span class="math inline">+60\,\%</span>, <span class="math inline">-40\,\%</span>, <span class="math inline">+60\,\%</span>, <span class="math inline">-40\,\%</span>. (a) Wie hoch ist das arithmetische Mittel? (b) Wie viel Kapital hat ein Anleger nach 4 Jahren aus 10 000 €? (c) Welche jährliche Rendite entspricht dem tatsächlich?</p>
|
||
<p><strong>Aufgabe 18.3 ⭐⭐ — Konditionszahl verstehen.</strong> Erzeugen Sie eine Kovarianzmatrix für <span class="math inline">N = 30</span> Titel aus <span class="math inline">T = 40</span>, <span class="math inline">T = 100</span> und <span class="math inline">T = 1000</span> simulierten Beobachtungen. Berechnen Sie jeweils kleinsten Eigenwert und Konditionszahl. Ab welchem <span class="math inline">T</span> wird die Matrix brauchbar?</p>
|
||
<p><strong>Aufgabe 18.4 ⭐⭐ — Spaltenreihenfolge prüfen.</strong> Laden Sie fünf Ticker in einer bewusst unsortierten Reihenfolge. Zeigen Sie, dass <code>raw["Close"].columns</code> abweicht, und dass <code>raw["Close"][tickers]</code> das behebt. Was passiert, wenn ein Ticker nicht existiert?</p>
|
||
<p><strong>Aufgabe 18.5 ⭐⭐⭐ — Beide Shrinkage-Ziele vergleichen.</strong> Implementieren Sie das Konstant-Korrelations-Ziel vollständig (inklusive eigener Berechnung von <span class="math inline">\delta</span> nach Ledoit/Wolf 2003 oder per Kreuzvalidierung). Vergleichen Sie mit <code>sklearn</code> anhand: (a) der Konditionszahl, (b) der Out-of-Sample-Volatilität eines GMV-Portfolios (nach dem Muster von <code>Schaetzrauschen_Demo.py</code>), (c) der Stabilität der Gewichte über rollierende Fenster.</p>
|
||
<p><strong>Aufgabe 18.6 ⭐⭐⭐ — Error-Maximizer selbst messen.</strong> Erweitern Sie <code>Schaetzrauschen_Demo.py</code> um eine dritte Variante: die <strong>Gleichgewichtung</strong> (<span class="math inline">w_i = 1/N</span>), die überhaupt keine Schätzung benötigt. (a) Ab welchem <span class="math inline">T/N</span> schlägt die Stichproben-Optimierung die Gleichgewichtung? (b) Ab welchem <span class="math inline">T/N</span> schlägt Ledoit-Wolf sie? (c) Was folgt daraus für die Praxis?</p>
|
||
<hr />
|
||
<h2 id="sec:finanzdaten-denkfehler">18.8 Finde den Denkfehler</h2>
|
||
<div class="card card-denkfehler">
|
||
<blockquote>
|
||
<p><strong>🐛 Finde den Denkfehler: Das risikofreie Portfolio</strong></p>
|
||
<p>Ein Analyst stellt ein Portfolio aus <strong>30 Titeln</strong> zusammen. Für die Kovarianzmatrix nimmt er das letzte Quartal — bei Wochendaten sind das <strong>20 Beobachtungen</strong>. Dann minimiert er die Varianz.</p>
|
||
<p>Das Ergebnis begeistert ihn: Das Portfolio hat ein Risiko von <strong>0,000 %</strong>. Er hat ein risikofreies Aktienportfolio gefunden.</p>
|
||
<p><strong>Ihre Aufgabe:</strong> (a) Wie hoch ist der Rang einer Kovarianzmatrix, die aus <span class="math inline">T</span> Beobachtungen für <span class="math inline">N > T</span> Anlagen geschätzt wurde — und was folgt daraus geometrisch? (b) Warum findet ausgerechnet ein <strong>Minimum</strong>-Varianz-Optimierer diese Stelle so zuverlässig? (c) Sehen Sie sich unten die Spalte „Hebel“ an. Was sagt ein Wert von 3,8 über das Portfolio aus? (d) Warum schlägt die simple Gleichgewichtung den Optimierer — und was folgt daraus für Ihre eigenen Modelle, auch außerhalb der Finanzwelt?</p>
|
||
<p><em>Auflösung: <a href="anhang-loesungen.html#sec:loesungen-finanzdaten">Abschnitt A.18</a>.</em></p>
|
||
</blockquote>
|
||
</div>
|
||
<p>Das folgende Programm führt den Fall vor. Es arbeitet mit <strong>synthetischen</strong> Daten, damit das Ergebnis reproduzierbar ist und kein Internetzugang nötig wird — mit echten Kursdaten sieht es genauso aus.</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><span class="co">#!/usr/bin/env python3</span></span>
|
||
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a><span class="co"># Kovarianz_Falle.py</span></span>
|
||
<span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a><span class="co">"""</span></span>
|
||
<span id="cb9-5"><a href="#cb9-5" aria-hidden="true" tabindex="-1"></a><span class="co">Kapitel Finanzdaten: Warum die historische Kovarianzmatrix den Optimierer belaeugt.</span></span>
|
||
<span id="cb9-6"><a href="#cb9-6" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb9-7"><a href="#cb9-7" aria-hidden="true" tabindex="-1"></a><span class="co">Ein Portfolio aus 30 Anlagen soll das Risiko minimieren. Geschaetzt wird die</span></span>
|
||
<span id="cb9-8"><a href="#cb9-8" aria-hidden="true" tabindex="-1"></a><span class="co">Kovarianzmatrix aus 20 Beobachtungen - in der Praxis ein voellig ueblicher</span></span>
|
||
<span id="cb9-9"><a href="#cb9-9" aria-hidden="true" tabindex="-1"></a><span class="co">Fall (30 Titel, ein Quartal Wochendaten).</span></span>
|
||
<span id="cb9-10"><a href="#cb9-10" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb9-11"><a href="#cb9-11" aria-hidden="true" tabindex="-1"></a><span class="co">Das Ergebnis ist ein Portfolio mit einem gemessenen Risiko von 0,000 %. Der</span></span>
|
||
<span id="cb9-12"><a href="#cb9-12" aria-hidden="true" tabindex="-1"></a><span class="co">Optimierer haelt es fuer risikofrei. Ausserhalb des Schaetzzeitraums ist es</span></span>
|
||
<span id="cb9-13"><a href="#cb9-13" aria-hidden="true" tabindex="-1"></a><span class="co">das schlechteste der drei untersuchten Portfolios - schlechter sogar als</span></span>
|
||
<span id="cb9-14"><a href="#cb9-14" aria-hidden="true" tabindex="-1"></a><span class="co">blosse Gleichgewichtung.</span></span>
|
||
<span id="cb9-15"><a href="#cb9-15" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb9-16"><a href="#cb9-16" aria-hidden="true" tabindex="-1"></a><span class="co">Der Grund ist nicht Zufall, sondern Struktur: Bei N Anlagen und T < N</span></span>
|
||
<span id="cb9-17"><a href="#cb9-17" aria-hidden="true" tabindex="-1"></a><span class="co">Beobachtungen hat die Stichproben-Kovarianzmatrix hoechstens Rang T-1. Es gibt</span></span>
|
||
<span id="cb9-18"><a href="#cb9-18" aria-hidden="true" tabindex="-1"></a><span class="co">dann ganze Richtungen im Gewichtsraum, in denen sie exakt null Varianz misst -</span></span>
|
||
<span id="cb9-19"><a href="#cb9-19" aria-hidden="true" tabindex="-1"></a><span class="co">Richtungen, die es in Wirklichkeit nicht gibt. Der Optimierer findet sie</span></span>
|
||
<span id="cb9-20"><a href="#cb9-20" aria-hidden="true" tabindex="-1"></a><span class="co">zuverlaessig, denn er sucht ja genau danach.</span></span>
|
||
<span id="cb9-21"><a href="#cb9-21" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb9-22"><a href="#cb9-22" aria-hidden="true" tabindex="-1"></a><span class="co">Die Daten sind synthetisch (ein Marktfaktor plus Eigenrauschen), damit das</span></span>
|
||
<span id="cb9-23"><a href="#cb9-23" aria-hidden="true" tabindex="-1"></a><span class="co">Ergebnis reproduzierbar ist und kein Internetzugang noetig wird. Mit echten</span></span>
|
||
<span id="cb9-24"><a href="#cb9-24" aria-hidden="true" tabindex="-1"></a><span class="co">Kursdaten sieht es genauso aus.</span></span>
|
||
<span id="cb9-25"><a href="#cb9-25" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb9-26"><a href="#cb9-26" aria-hidden="true" tabindex="-1"></a><span class="co">Benoetigt: numpy, cvxpy, scikit-learn</span></span>
|
||
<span id="cb9-27"><a href="#cb9-27" aria-hidden="true" tabindex="-1"></a><span class="co">"""</span></span>
|
||
<span id="cb9-28"><a href="#cb9-28" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb9-29"><a href="#cb9-29" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> __future__ <span class="im">import</span> annotations</span>
|
||
<span id="cb9-30"><a href="#cb9-30" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb9-31"><a href="#cb9-31" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> numpy <span class="im">as</span> np</span>
|
||
<span id="cb9-32"><a href="#cb9-32" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> cvxpy <span class="im">as</span> cp</span>
|
||
<span id="cb9-33"><a href="#cb9-33" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> sklearn.covariance <span class="im">import</span> LedoitWolf</span>
|
||
<span id="cb9-34"><a href="#cb9-34" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb9-35"><a href="#cb9-35" aria-hidden="true" tabindex="-1"></a>ANZAHL_ANLAGEN <span class="op">=</span> <span class="dv">30</span></span>
|
||
<span id="cb9-36"><a href="#cb9-36" aria-hidden="true" tabindex="-1"></a>BEOBACHTUNGEN_SCHAETZUNG <span class="op">=</span> <span class="dv">20</span> <span class="co"># weniger als Anlagen - genau darum geht es</span></span>
|
||
<span id="cb9-37"><a href="#cb9-37" aria-hidden="true" tabindex="-1"></a>BEOBACHTUNGEN_TEST <span class="op">=</span> <span class="dv">2000</span> <span class="co"># der "spaetere Verlauf"</span></span>
|
||
<span id="cb9-38"><a href="#cb9-38" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb9-39"><a href="#cb9-39" aria-hidden="true" tabindex="-1"></a>RNG <span class="op">=</span> np.random.default_rng(<span class="dv">11</span>)</span>
|
||
<span id="cb9-40"><a href="#cb9-40" aria-hidden="true" tabindex="-1"></a><span class="co"># Jede Anlage reagiert unterschiedlich stark auf den Gesamtmarkt.</span></span>
|
||
<span id="cb9-41"><a href="#cb9-41" aria-hidden="true" tabindex="-1"></a>BETA <span class="op">=</span> RNG.uniform(<span class="fl">0.6</span>, <span class="fl">1.4</span>, ANZAHL_ANLAGEN)</span>
|
||
<span id="cb9-42"><a href="#cb9-42" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb9-43"><a href="#cb9-43" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb9-44"><a href="#cb9-44" aria-hidden="true" tabindex="-1"></a><span class="kw">def</span> erzeuge_renditen(perioden: <span class="bu">int</span>) <span class="op">-></span> np.ndarray:</span>
|
||
<span id="cb9-45"><a href="#cb9-45" aria-hidden="true" tabindex="-1"></a> <span class="co">"""Ein Marktfaktor, auf den alle reagieren, plus Eigenrauschen je Anlage."""</span></span>
|
||
<span id="cb9-46"><a href="#cb9-46" aria-hidden="true" tabindex="-1"></a> markt <span class="op">=</span> RNG.normal(<span class="fl">0.0</span>, <span class="fl">0.010</span>, perioden)</span>
|
||
<span id="cb9-47"><a href="#cb9-47" aria-hidden="true" tabindex="-1"></a> eigen <span class="op">=</span> RNG.normal(<span class="fl">0.0</span>, <span class="fl">0.012</span>, (perioden, ANZAHL_ANLAGEN))</span>
|
||
<span id="cb9-48"><a href="#cb9-48" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> np.outer(markt, BETA) <span class="op">+</span> eigen</span>
|
||
<span id="cb9-49"><a href="#cb9-49" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb9-50"><a href="#cb9-50" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb9-51"><a href="#cb9-51" aria-hidden="true" tabindex="-1"></a><span class="kw">def</span> minimales_risiko(kovarianz: np.ndarray) <span class="op">-></span> <span class="bu">tuple</span>[np.ndarray, <span class="bu">float</span>]:</span>
|
||
<span id="cb9-52"><a href="#cb9-52" aria-hidden="true" tabindex="-1"></a> <span class="co">"""Minimum-Varianz-Portfolio: Gewichte summieren sich zu 1, sonst frei.</span></span>
|
||
<span id="cb9-53"><a href="#cb9-53" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb9-54"><a href="#cb9-54" aria-hidden="true" tabindex="-1"></a><span class="co"> cp.psd_wrap() sagt CVXPY: 'Ich weiss, dass diese Matrix numerisch nicht</span></span>
|
||
<span id="cb9-55"><a href="#cb9-55" aria-hidden="true" tabindex="-1"></a><span class="co"> exakt positiv semidefinit ist - rechne trotzdem.' Das ist hier bewusst so</span></span>
|
||
<span id="cb9-56"><a href="#cb9-56" aria-hidden="true" tabindex="-1"></a><span class="co"> gewaehlt, denn genau diese Eigenschaft wollen wir vorfuehren. Im</span></span>
|
||
<span id="cb9-57"><a href="#cb9-57" aria-hidden="true" tabindex="-1"></a><span class="co"> Produktivbetrieb waere die DCP-Fehlermeldung das Warnsignal, dem man</span></span>
|
||
<span id="cb9-58"><a href="#cb9-58" aria-hidden="true" tabindex="-1"></a><span class="co"> nachgehen muss (siehe den Denkfehler im Kapitel Quadratische und</span></span>
|
||
<span id="cb9-59"><a href="#cb9-59" aria-hidden="true" tabindex="-1"></a><span class="co"> nichtlineare Optimierung).</span></span>
|
||
<span id="cb9-60"><a href="#cb9-60" aria-hidden="true" tabindex="-1"></a><span class="co"> """</span></span>
|
||
<span id="cb9-61"><a href="#cb9-61" aria-hidden="true" tabindex="-1"></a> gewichte <span class="op">=</span> cp.Variable(ANZAHL_ANLAGEN)</span>
|
||
<span id="cb9-62"><a href="#cb9-62" aria-hidden="true" tabindex="-1"></a> problem <span class="op">=</span> cp.Problem(cp.Minimize(cp.quad_form(gewichte, cp.psd_wrap(kovarianz))),</span>
|
||
<span id="cb9-63"><a href="#cb9-63" aria-hidden="true" tabindex="-1"></a> [cp.<span class="bu">sum</span>(gewichte) <span class="op">==</span> <span class="dv">1</span>])</span>
|
||
<span id="cb9-64"><a href="#cb9-64" aria-hidden="true" tabindex="-1"></a> problem.solve()</span>
|
||
<span id="cb9-65"><a href="#cb9-65" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> np.array(gewichte.value).ravel(), <span class="bu">max</span>(problem.value, <span class="fl">0.0</span>)</span>
|
||
<span id="cb9-66"><a href="#cb9-66" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb9-67"><a href="#cb9-67" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb9-68"><a href="#cb9-68" 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="cb9-69"><a href="#cb9-69" aria-hidden="true" tabindex="-1"></a> schaetzzeitraum <span class="op">=</span> erzeuge_renditen(BEOBACHTUNGEN_SCHAETZUNG)</span>
|
||
<span id="cb9-70"><a href="#cb9-70" aria-hidden="true" tabindex="-1"></a> spaeterer_verlauf <span class="op">=</span> erzeuge_renditen(BEOBACHTUNGEN_TEST)</span>
|
||
<span id="cb9-71"><a href="#cb9-71" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb9-72"><a href="#cb9-72" aria-hidden="true" tabindex="-1"></a> stichprobe <span class="op">=</span> np.cov(schaetzzeitraum, rowvar<span class="op">=</span><span class="va">False</span>)</span>
|
||
<span id="cb9-73"><a href="#cb9-73" aria-hidden="true" tabindex="-1"></a> ledoit_wolf <span class="op">=</span> LedoitWolf().fit(schaetzzeitraum)</span>
|
||
<span id="cb9-74"><a href="#cb9-74" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb9-75"><a href="#cb9-75" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"="</span> <span class="op">*</span> <span class="dv">78</span>)</span>
|
||
<span id="cb9-76"><a href="#cb9-76" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">" DIE KOVARIANZ-FALLE"</span>)</span>
|
||
<span id="cb9-77"><a href="#cb9-77" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"="</span> <span class="op">*</span> <span class="dv">78</span>)</span>
|
||
<span id="cb9-78"><a href="#cb9-78" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f"</span><span class="sc">{</span>ANZAHL_ANLAGEN<span class="sc">}</span><span class="ss"> Anlagen, geschaetzt aus </span><span class="sc">{</span>BEOBACHTUNGEN_SCHAETZUNG<span class="sc">}</span><span class="ss"> "</span></span>
|
||
<span id="cb9-79"><a href="#cb9-79" aria-hidden="true" tabindex="-1"></a> <span class="ss">f"Beobachtungen."</span>)</span>
|
||
<span id="cb9-80"><a href="#cb9-80" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f"Rang der Stichprobenmatrix: "</span></span>
|
||
<span id="cb9-81"><a href="#cb9-81" aria-hidden="true" tabindex="-1"></a> <span class="ss">f"</span><span class="sc">{</span>np<span class="sc">.</span>linalg<span class="sc">.</span>matrix_rank(stichprobe)<span class="sc">}</span><span class="ss"> - noetig waeren </span><span class="sc">{</span>ANZAHL_ANLAGEN<span class="sc">}</span><span class="ss">."</span>)</span>
|
||
<span id="cb9-82"><a href="#cb9-82" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f"Kleinster Eigenwert: </span><span class="sc">{</span>np<span class="sc">.</span>linalg<span class="sc">.</span>eigvalsh(stichprobe)<span class="sc">.</span><span class="bu">min</span>()<span class="sc">:.2e}</span><span class="ss">"</span>)</span>
|
||
<span id="cb9-83"><a href="#cb9-83" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>()</span>
|
||
<span id="cb9-84"><a href="#cb9-84" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"Es gibt also Richtungen, in denen diese Matrix EXAKT null Varianz"</span>)</span>
|
||
<span id="cb9-85"><a href="#cb9-85" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"misst. Genau dort sucht ein Minimum-Varianz-Optimierer."</span>)</span>
|
||
<span id="cb9-86"><a href="#cb9-86" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>()</span>
|
||
<span id="cb9-87"><a href="#cb9-87" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb9-88"><a href="#cb9-88" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f"</span><span class="sc">{</span><span class="st">'Schaetzer'</span><span class="sc">:<26}</span><span class="ss"> </span><span class="sc">{</span><span class="st">'Risiko im Zeitraum'</span><span class="sc">:>19}</span><span class="ss"> "</span></span>
|
||
<span id="cb9-89"><a href="#cb9-89" aria-hidden="true" tabindex="-1"></a> <span class="ss">f"</span><span class="sc">{</span><span class="st">'Risiko spaeter'</span><span class="sc">:>16}</span><span class="ss"> </span><span class="sc">{</span><span class="st">'Hebel'</span><span class="sc">:>7}</span><span class="ss">"</span>)</span>
|
||
<span id="cb9-90"><a href="#cb9-90" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"-"</span> <span class="op">*</span> <span class="dv">78</span>)</span>
|
||
<span id="cb9-91"><a href="#cb9-91" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb9-92"><a href="#cb9-92" aria-hidden="true" tabindex="-1"></a> ergebnisse <span class="op">=</span> {}</span>
|
||
<span id="cb9-93"><a href="#cb9-93" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> name, matrix <span class="kw">in</span> [</span>
|
||
<span id="cb9-94"><a href="#cb9-94" aria-hidden="true" tabindex="-1"></a> (<span class="st">"Stichprobe (roh)"</span>, stichprobe),</span>
|
||
<span id="cb9-95"><a href="#cb9-95" aria-hidden="true" tabindex="-1"></a> (<span class="ss">f"Ledoit-Wolf (d=</span><span class="sc">{</span>ledoit_wolf<span class="sc">.</span>shrinkage_<span class="sc">:.2f}</span><span class="ss">)"</span>, ledoit_wolf.covariance_)]:</span>
|
||
<span id="cb9-96"><a href="#cb9-96" aria-hidden="true" tabindex="-1"></a> gewichte, varianz_intern <span class="op">=</span> minimales_risiko(matrix)</span>
|
||
<span id="cb9-97"><a href="#cb9-97" aria-hidden="true" tabindex="-1"></a> risiko_spaeter <span class="op">=</span> <span class="bu">float</span>(np.std(spaeterer_verlauf <span class="op">@</span> gewichte))</span>
|
||
<span id="cb9-98"><a href="#cb9-98" aria-hidden="true" tabindex="-1"></a> hebel <span class="op">=</span> <span class="bu">float</span>(np.<span class="bu">abs</span>(gewichte).<span class="bu">sum</span>())</span>
|
||
<span id="cb9-99"><a href="#cb9-99" aria-hidden="true" tabindex="-1"></a> ergebnisse[name] <span class="op">=</span> (risiko_spaeter, gewichte)</span>
|
||
<span id="cb9-100"><a href="#cb9-100" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f"</span><span class="sc">{</span>name<span class="sc">:<26}</span><span class="ss"> </span><span class="sc">{</span>np<span class="sc">.</span>sqrt(varianz_intern) <span class="op">*</span> <span class="dv">100</span><span class="sc">:>18.3f}</span><span class="ss"> % "</span></span>
|
||
<span id="cb9-101"><a href="#cb9-101" aria-hidden="true" tabindex="-1"></a> <span class="ss">f"</span><span class="sc">{</span>risiko_spaeter <span class="op">*</span> <span class="dv">100</span><span class="sc">:>15.3f}</span><span class="ss"> % </span><span class="sc">{</span>hebel<span class="sc">:>7.1f}</span><span class="ss">"</span>)</span>
|
||
<span id="cb9-102"><a href="#cb9-102" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb9-103"><a href="#cb9-103" aria-hidden="true" tabindex="-1"></a> gleich <span class="op">=</span> np.full(ANZAHL_ANLAGEN, <span class="fl">1.0</span> <span class="op">/</span> ANZAHL_ANLAGEN)</span>
|
||
<span id="cb9-104"><a href="#cb9-104" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f"</span><span class="sc">{</span><span class="st">'Gleichgewichtung 1/N'</span><span class="sc">:<26}</span><span class="ss"> "</span></span>
|
||
<span id="cb9-105"><a href="#cb9-105" aria-hidden="true" tabindex="-1"></a> <span class="ss">f"</span><span class="sc">{</span><span class="bu">float</span>(np.std(schaetzzeitraum <span class="op">@</span> gleich)) <span class="op">*</span> <span class="dv">100</span><span class="sc">:>18.3f}</span><span class="ss"> % "</span></span>
|
||
<span id="cb9-106"><a href="#cb9-106" aria-hidden="true" tabindex="-1"></a> <span class="ss">f"</span><span class="sc">{</span><span class="bu">float</span>(np.std(spaeterer_verlauf <span class="op">@</span> gleich)) <span class="op">*</span> <span class="dv">100</span><span class="sc">:>15.3f}</span><span class="ss"> % </span><span class="sc">{</span><span class="fl">1.0</span><span class="sc">:>7.1f}</span><span class="ss">"</span>)</span>
|
||
<span id="cb9-107"><a href="#cb9-107" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"-"</span> <span class="op">*</span> <span class="dv">78</span>)</span>
|
||
<span id="cb9-108"><a href="#cb9-108" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb9-109"><a href="#cb9-109" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"</span><span class="ch">\n</span><span class="st">Drei Beobachtungen:"</span>)</span>
|
||
<span id="cb9-110"><a href="#cb9-110" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"1. Die rohe Schaetzung meldet 0,000 % Risiko - und liefert spaeter das"</span>)</span>
|
||
<span id="cb9-111"><a href="#cb9-111" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">" SCHLECHTESTE Ergebnis der drei. Sie hat kein Portfolio optimiert,"</span>)</span>
|
||
<span id="cb9-112"><a href="#cb9-112" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">" sondern eine Luecke in den eigenen Daten gefunden."</span>)</span>
|
||
<span id="cb9-113"><a href="#cb9-113" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"2. Die Gleichgewichtung, die gar nicht optimiert, schlaegt den rohen"</span>)</span>
|
||
<span id="cb9-114"><a href="#cb9-114" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">" Optimierer deutlich. Das ist kein Zufallsbefund, sondern in der"</span>)</span>
|
||
<span id="cb9-115"><a href="#cb9-115" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">" Literatur breit belegt."</span>)</span>
|
||
<span id="cb9-116"><a href="#cb9-116" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"3. Ledoit-Wolf ist im Schaetzzeitraum EHRLICHER (0,441 statt 0,000 %)"</span>)</span>
|
||
<span id="cb9-117"><a href="#cb9-117" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">" und spaeter am besten. Der Hebel faellt von 3,8 auf 1,8 - das"</span>)</span>
|
||
<span id="cb9-118"><a href="#cb9-118" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">" Portfolio wird auch praktisch handelbarer."</span>)</span>
|
||
<span id="cb9-119"><a href="#cb9-119" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>()</span>
|
||
<span id="cb9-120"><a href="#cb9-120" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"Merksatz: Ein Optimierer glaubt seinen Eingabedaten vollstaendig."</span>)</span>
|
||
<span id="cb9-121"><a href="#cb9-121" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"Je mehr Freiheit Sie ihm geben, desto gruendlicher findet er deren"</span>)</span>
|
||
<span id="cb9-122"><a href="#cb9-122" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"Fehler. Das gilt fuer Kovarianzmatrizen wie fuer Lieferzeiten,"</span>)</span>
|
||
<span id="cb9-123"><a href="#cb9-123" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"Ausfallraten und jede andere geschaetzte Groesse."</span>)</span>
|
||
<span id="cb9-124"><a href="#cb9-124" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"="</span> <span class="op">*</span> <span class="dv">78</span>)</span></code></pre></div>
|
||
<p><strong>Erwartete Ausgabe:</strong></p>
|
||
<pre><code>==============================================================================
|
||
DIE KOVARIANZ-FALLE
|
||
==============================================================================
|
||
30 Anlagen, geschaetzt aus 20 Beobachtungen.
|
||
Rang der Stichprobenmatrix: 19 - noetig waeren 30.
|
||
Kleinster Eigenwert: -6.47e-20
|
||
|
||
Es gibt also Richtungen, in denen diese Matrix EXAKT null Varianz
|
||
misst. Genau dort sucht ein Minimum-Varianz-Optimierer.
|
||
|
||
Schaetzer Risiko im Zeitraum Risiko spaeter Hebel
|
||
------------------------------------------------------------------------------
|
||
Stichprobe (roh) 0.000 % 1.287 % 3.8
|
||
Ledoit-Wolf (d=0.34) 0.441 % 0.974 % 1.8
|
||
Gleichgewichtung 1/N 0.808 % 1.026 % 1.0
|
||
------------------------------------------------------------------------------
|
||
|
||
Drei Beobachtungen:
|
||
1. Die rohe Schaetzung meldet 0,000 % Risiko - und liefert spaeter das
|
||
SCHLECHTESTE Ergebnis der drei. Sie hat kein Portfolio optimiert,
|
||
sondern eine Luecke in den eigenen Daten gefunden.
|
||
2. Die Gleichgewichtung, die gar nicht optimiert, schlaegt den rohen
|
||
Optimierer deutlich. Das ist kein Zufallsbefund, sondern in der
|
||
Literatur breit belegt.
|
||
3. Ledoit-Wolf ist im Schaetzzeitraum EHRLICHER (0,441 statt 0,000 %)
|
||
und spaeter am besten. Der Hebel faellt von 3,8 auf 1,8 - das
|
||
Portfolio wird auch praktisch handelbarer.
|
||
|
||
Merksatz: Ein Optimierer glaubt seinen Eingabedaten vollstaendig.
|
||
Je mehr Freiheit Sie ihm geben, desto gruendlicher findet er deren
|
||
Fehler. Das gilt fuer Kovarianzmatrizen wie fuer Lieferzeiten,
|
||
Ausfallraten und jede andere geschaetzte Groesse.
|
||
==============================================================================</code></pre>
|
||
<div class="card card-formel">
|
||
<blockquote>
|
||
<p><strong>🔤 Formel-Übersetzer: warum <span class="math inline">N > T</span> alles kaputt macht</strong></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">\mathbf{S} = \frac{1}{T-1}\sum_{t}(\mathbf{r}_t - \bar{\mathbf{r}})(\mathbf{r}_t - \bar{\mathbf{r}})^\top</span></td>
|
||
<td>„Wie stark schwanken die Anlagen — und wie sehr gemeinsam?“</td>
|
||
</tr>
|
||
<tr class="even">
|
||
<td><span class="math inline">\operatorname{rang}(\mathbf{S}) \le T - 1</span></td>
|
||
<td>„Aus 20 Beobachtungen lassen sich höchstens 19 unabhängige Richtungen ablesen.“</td>
|
||
</tr>
|
||
<tr class="odd">
|
||
<td><span class="math inline">N = 30 > 19</span></td>
|
||
<td>„Es bleiben 11 Richtungen übrig, über die die Daten <strong>nichts</strong> sagen.“</td>
|
||
</tr>
|
||
<tr class="even">
|
||
<td>$,</td>
|
||
<td></td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</blockquote>
|
||
</div>
|
||
<p>e 0: ^ op = 0$ | „In genau diesen Richtungen misst die Matrix null Risiko — nicht weil keines da ist, sondern weil sie blind ist.“ | > | <span class="math inline">\min_{\mathbf{w}} \mathbf{w}^ op\mathbf{S}\mathbf{w}</span> | „Und der Optimierer sucht zielsicher genau dort.“ | > > <strong>Die Faustregel:</strong> Für eine halbwegs verlässliche Kovarianzschätzung braucht man <span class="math inline">T \gtrsim 10 \cdot N</span> Beobachtungen. Bei 30 Titeln also rund 300 Perioden — mehr als ein Jahr Tagesdaten. Wer weniger hat, <strong>muss</strong> schrumpfen.</p>
|
||
<hr />
|
||
<h2 id="sec:finanzdaten-quiz">18.9 Micro-Quiz</h2>
|
||
<div class="card card-quiz">
|
||
<blockquote>
|
||
<p><strong>❓ Micro-Quiz 18: Drei Fragen zum Selbstcheck</strong></p>
|
||
<p>Genau eine Antwort ist jeweils richtig. Auflösung in <a href="anhang-loesungen.html#quiz-loesung-finanzdaten">Anhang A</a>.</p>
|
||
<p><strong>1. Ein Kurs fällt um 50 % und steigt danach um 50 %. Wo steht er?</strong> (a) Wieder beim Ausgangswert — die Prozente heben sich auf. (b) Bei 75 % des Ausgangswerts. Diskrete Renditen verknüpfen sich multiplikativ, nicht additiv: <span class="math inline">1{,}0 \cdot 0{,}5 \cdot 1{,}5 = 0{,}75</span>. (c) Bei 25 % des Ausgangswerts.</p>
|
||
<p><strong>2. Wofür nimmt man logarithmische Renditen, wofür diskrete?</strong> (a) Logarithmische sind grundsätzlich genauer und daher immer vorzuziehen. (b) Logarithmische addieren sich über die <strong>Zeit</strong>, diskrete über die <strong>Anlagen</strong> eines Portfolios. Man wählt nach der Richtung, in der summiert wird. (c) Diskrete für kurze, logarithmische für lange Zeiträume.</p>
|
||
<p><strong>3. Sie schätzen eine Kovarianzmatrix für 50 Anlagen aus 40 Wochenrenditen. Was ist zu tun?</strong> (a) Nichts — 40 Beobachtungen sind eine ordentliche Stichprobe. (b) Die Matrix ist singulär und gaukelt dem Optimierer risikofreie Richtungen vor. Entweder mehr Daten beschaffen oder einen Shrinkage-Schätzer verwenden, der positive Definitheit garantiert. (c) Die Anzahl der Anlagen auf 40 reduzieren, dann passt es.</p>
|
||
</blockquote>
|
||
</div>
|
||
<hr />
|
||
<h2 id="sec:finanzdaten-selbsttest">18.10 Selbsttest</h2>
|
||
<blockquote>
|
||
<p>Antworten: <a href="anhang-loesungen.html#selbsttest-loesung-finanzdaten">Anhang A</a>.</p>
|
||
</blockquote>
|
||
<ol type="1">
|
||
<li>Warum addieren sich Log-Renditen über die Zeit, diskrete aber über das Portfolio?</li>
|
||
<li>Was besagt der Error-Maximizer-Effekt?</li>
|
||
<li>Warum ist <span class="math inline">\mathbf{S}</span> bei <span class="math inline">T < N</span> singulär, und was folgt daraus praktisch?</li>
|
||
<li>Was mischt Ledoit-Wolf, und wie wird <span class="math inline">\delta</span> bestimmt?</li>
|
||
<li>Welche zwei Shrinkage-Ziele gibt es, und welches verwendet <code>scikit-learn</code>?</li>
|
||
</ol>
|
||
<hr />
|
||
<h2 id="sec:finanzdaten-zusammenfassung">18.11 Zusammenfassung</h2>
|
||
<ul>
|
||
<li><strong>Diskret über das Portfolio, logarithmisch über die Zeit</strong> — die Wahl der Renditeart ist keine Geschmacksfrage.</li>
|
||
<li><strong>Das arithmetische Mittel diskreter Renditen überschätzt</strong> die tatsächliche Wertentwicklung systematisch.</li>
|
||
<li><strong>Die Stichprobenkovarianz ist bei <span class="math inline">T \approx N</span> unbrauchbar</strong> und bei <span class="math inline">T < N</span> singulär.</li>
|
||
<li><strong>Markowitz verstärkt Schätzfehler</strong>, statt sie auszugleichen — der Error-Maximizer-Effekt.</li>
|
||
<li><strong>Shrinkage</strong> mischt Rauschen mit Struktur und liefert eine stabil invertierbare Matrix. Es gibt mehrere Ziele; <code>sklearn</code> verwendet die skalierte Einheitsmatrix.</li>
|
||
<li><strong>Erzwingen Sie die Spaltenreihenfolge</strong> nach jedem Datenimport und prüfen Sie sie per <code>assert</code>.</li>
|
||
<li><strong>Faustregel für die Datenmenge:</strong> <span class="math inline">T \gtrsim 10 \cdot N</span>. Bei 30 Titeln also rund 300 Perioden. Wer weniger hat, muss schrumpfen — oder die Freiheit des Optimierers begrenzen.</li>
|
||
<li><strong>Bewerten Sie außerhalb des Schätzzeitraums.</strong> Ein Portfolio, das im eigenen Datenfenster 0,000 % Risiko meldet, ist kein gutes Portfolio, sondern ein Beleg dafür, dass die Daten nicht ausreichen.</li>
|
||
<li><strong>Das gilt weit über Finanzdaten hinaus.</strong> Bearbeitungszeiten, Ausfallraten, Nachfrageprognosen: Ein Optimierer sucht nicht die beste Lösung, sondern den größten Fehler in Ihren Schätzungen.</li>
|
||
</ul>
|
||
<p><strong>Ausblick.</strong> Mit stabilen Schätzungen können wir in <a href="markowitz.html#kap-markowitz">Kapitel 19</a> endlich optimieren: die Markowitz-Effizienzgrenze mit realistischen institutionellen Restriktionen.</p>
|
||
|
||
</article>
|
||
<button type="button" class="fortschritt-knopf" data-kapitel="finanzdaten.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="supplychain.html"><svg class="icon" aria-hidden="true"><use href="#icon-chevron-left"></use></svg><span><small>Zurück</small>Kapitel 17: Supply-Chain und Energieeinsatz unter Unsicherheit</span></a><a class="prev-next-knopf prev-next-next" href="markowitz.html"><span><small>Weiter</small>Kapitel 19: Die moderne Portfoliotheorie nach Markowitz</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>
|