<aclass="brand"href="index.html"><svgclass="icon"aria-hidden="true"><usehref="#icon-book"></use></svg><span>Optimierte Entscheidungsfindung mit Python</span></a>
<navclass="sidebar"id="sidebar"aria-label="Kapitelnavigation"><divclass="sidebar-inhalt"><detailsclass="sidebar-gruppe"><summary>Einstieg</summary><ul><lidata-kapitel="vorwort.html"><ahref="vorwort.html"><spanclass="fortschritt-haken"><svgclass="icon"aria-hidden="true"><usehref="#icon-check"></use></svg></span><span>Vorwort & Lesehilfe</span></a></li><lidata-kapitel="notation.html"><ahref="notation.html"><spanclass="fortschritt-haken"><svgclass="icon"aria-hidden="true"><usehref="#icon-check"></use></svg></span><span>Notation & Abkürzungen</span></a></li></ul></details><detailsclass="sidebar-gruppe"><summary>Teil I: Grundlagen des Operations Research</summary><ul><lidata-kapitel="einfuehrung.html"><ahref="einfuehrung.html"><spanclass="fortschritt-haken"><svgclass="icon"aria-hidden="true"><usehref="#icon-check"></use></svg></span><span>Kapitel 1: Einführung in Operations Research — Vom Ursprung zur mathematischen Entscheidungsfindung</span></a></li><lidata-kapitel="fundament.html"><ahref="fundament.html"><spanclass="fortschritt-haken"><svgclass="icon"aria-hidden="true"><usehref="#icon-check"></use></svg></span><span>Kapitel 2: Das mathematische Fundament — Vektoren, Matrizen, Konvexität</span></a></li><lidata-kapitel="oekosystem.html"><ahref="oekosystem.html"><spanclass="fortschritt-haken"><svgclass="icon"aria-hidden="true"><usehref="#icon-check"></use></svg></span><span>Kapitel 3: Das Python-Ökosystem für OR — Solver, Bindings und Modellierungsschichten</span></a></li><lidata-kapitel="modellierung.html"><ahref="modellierung.html"><spanclass="fortschritt-haken"><svgclass="icon"aria-hidden="true"><usehref="#icon-check"></use></svg></span><span>Kapitel 4: Vom Management-Wunsch zum Modell</span></a></li></ul></details><detailsclass="sidebar-gruppe"><summary>Teil II: Die Kernverfahren der deterministischen Optimierung</summary><ul><lidata-kapitel="lp.html"><ahref="lp.html"><spanclass="fortschritt-haken"><svgclass="icon"aria-hidden="true"><usehref="#icon-check"></use></svg></span><span>Kapitel 5: Lineare Programmierung — Simplex, Dualität und Schattenpreise</span></a></li><lidata-kapitel="milp.html"><ahref="milp.html"><spanclass="fortschritt-haken"><svgclass="icon"aria-hidden="true"><usehref="#icon-check"></use></svg></span><span>Kapitel 6: Gemischt-ganzzahlige Optimierung — Diskrete Entscheidungen und Branch-and-Bound</span></a></li><lidata-kapitel="cpsat.html"><ahref="cpsat.html"><spanclass="fortschritt-haken"><svgclass="icon"aria-hidden="true"><usehref="#icon-check"></use></svg></span><span>Kapitel 7: Constraint Programming mit CP-SAT — Logik, Scheduling und Zuweisung</span></a></li><lidata-kapitel="graphen.html"><ahref="graphen.html"><spanclass="fortschritt-haken"><svgclass="icon"aria-hidden="true"><usehref="#icon-check"></use></svg></span><span>Kapitel 8: Graphen, Flüsse und Touren — Min-Cost-Flow, Matching und VRP</span></a></li><lidata-kapitel="metaheuristiken.html"><ahref="metaheuristiken.html"><spanclass="fortschritt-haken"><svgclass="icon"aria-hidden="true"><usehref="#icon-check"></use></svg></span><span>Kapitel 9: Metaheuristiken — wenn der exakte Solver aussteigt</span></a></li><lidata-kapitel="dekomposition.html"><ahref="dekomposition.html"><spanclass="fortschritt-haken"><svgclass="icon"aria-hidden="true"><usehref="#icon-check"></use></svg></span><span>Kapitel 10: Spaltengenerierung — das Modell umbauen statt die Lösung raten</span></a></li></ul></details><detailsclass="sidebar-gruppe"><summary>Teil III: Nichtlinearität, Unsicherheit und mehrperiodige Dynamik</summary><ul><lidata-kapitel="qp-nlp.html"><ahref="qp-nlp.html"><spanclass="fortschritt-haken"><svgclass="icon"aria-hidden="true"><usehref="#icon-check"></use></svg></span><span>Kapitel 11: Quadratische und nichtlineare Optimierung — KKT, Lagrange, Konvexität</span></a></li><lidata-kapitel="unsicherheit.html"><ahref="unsicherheit.html"><spanclass="fortschritt-haken"><svgclass="icon"aria-hidden="true"><usehref="#icon-check"></use></svg></
<mainclass="content">
<navclass="breadcrumb"aria-label="Breadcrumb"><ahref="index.html">Start</a>›<span>Teil IV</span>›<span>Kapitel 21: Die vollständige quantitative Handelsmaschine</span></nav>
<navclass="prev-next"><aclass="prev-next-knopf prev-next-prev"href="cvar.html"><svgclass="icon"aria-hidden="true"><usehref="#icon-chevron-left"></use></svg><span><small>Zurück</small>Kapitel 20: Tail-Risiko, CVaR und Transaktionskosten</span></a><aclass="prev-next-knopf prev-next-next"href="praxisfallen.html"><span><small>Weiter</small>Kapitel 22: Praxisfallen und der Weg zum produktiven Einsatz</span><svgclass="icon"aria-hidden="true"><usehref="#icon-chevron-right"></use></svg></a></nav>
<article>
<h1id="kap-handelsmaschine">Kapitel 21: Die vollständige quantitative Handelsmaschine</h1>
<divclass="card card-blick">
<blockquote>
<p><strong>📌 Kapitel auf einen Blick</strong></p>
<p><strong>Worum geht es?</strong> Um das Zusammenführen von allem: Datenpipeline, Signal, Optimierung, Rebalancing, Kostenverbuchung und ein Backtest, der nicht lügt.</p>
<p><strong>Voraussetzungen:</strong><ahref="finanzdaten.html#kap-finanzdaten">Kapitel 18</a> bis <ahref="cvar.html#kap-cvar">Kapitel 20</a>.</p>
<p><strong>Danach können Sie:</strong> Eine Walk-Forward-Backtest-Architektur bauen, Lookahead-Bias vermeiden, Ergebnisse gegen eine Benchmark bewerten und typische Backtest-Fallen erkennen.</p>
<p><strong>Zeitbedarf:</strong> ca. 6 Stunden.</p>
<p><strong>Programme:</strong><br/>
<code>QuantitativeTradingEngine.py</code><br/>
<code>Backtest_Fallen.py</code><br/>
<code>Data_Snooping.py</code></p>
<p><strong>⚠️ Keine Anlageberatung.</strong> Dieses Kapitel demonstriert Methodik an realen Daten, keine handelbare Strategie. <ahref="#sec:handelsmaschine-vom-backtest-zum-betrieb">Abschnitt 21.7</a> erklärt ausführlich, warum ein guter Backtest noch lange keine funktionierende Strategie ist.</p>
<ahref="https://colab.research.google.com/github/dschlueter/or-mit-python/blob/main/Notebooks_04/handelsmaschine.ipynb">In Google Colab öffnen</a></p>
</blockquote>
</div>
<hr/>
<h2id="sec:handelsmaschine-schnellstart">21.1 In 5 Minuten gelöst</h2>
<divclass="card card-schnellstart">
<blockquote>
<p><strong>🚀 In 5 Minuten gelöst: Dieselben Tage, ein anderes Schicksal</strong></p>
<p>Zwei Strategien über zehn Jahre. Sie bestehen aus <strong>exakt denselben Tagesrenditen</strong> — nur in anderer Reihenfolge. Bei der einen sind die 250 schlechtesten Tage über den ganzen Zeitraum verstreut, bei der anderen liegen sie am Stück.</p>
<spanid="cb1-4"><ahref="#cb1-4"aria-hidden="true"tabindex="-1"></a>tage <spanclass="op">=</span> rng.normal(<spanclass="fl">0.0005</span>, <spanclass="fl">0.010</span>, <spanclass="dv">2520</span>) <spanclass="co"># zehn Jahre Tagesrenditen</span></span>
<p><strong>Rendite und Sharpe-Kennzahl sind identisch</strong> — sie müssen es sein, denn beide Reihen enthalten dieselben Zahlen. Nur die Reihenfolge unterscheidet sich.</p>
<p>Der maximale Rückschlag beträgt trotzdem 19,0 % gegen <strong>98,7 %</strong>. Die zweite Strategie verliert zwischenzeitlich fast das gesamte Kapital und erholt sich danach wieder auf denselben Endstand.</p>
<p>Rechnerisch sind beide gleichwertig. Praktisch ist die zweite tot: Bei −98 % gibt es keinen Anleger mehr, kein Mandat und kein Handelsdesk, das die Erholung noch erlebt.</p>
<blockquote>
<p><strong>🎯 Merksatz</strong> Rendite und Sharpe-Kennzahl mitteln über die Zeit und verlieren dabei die <strong>Reihenfolge</strong>. Genau in der Reihenfolge steckt aber, ob eine Strategie überlebt. Der maximale Rückschlag misst nicht das statistische Risiko, sondern das menschliche: <em>Wie schlimm sah es zwischendurch aus?</em> Berichten Sie ihn immer mit — eine Rendite allein ist keine Aussage.</p>
</blockquote>
<p>Dasselbe gilt weit außerhalb der Finanzwelt. Ein Produktionsplan, der im Jahresmittel optimal ist, aber im März drei Wochen lang die Liefertreue reißt, wird im April abgeschaltet — bevor sich der Mittelwert einstellen kann. Wo immer Sie einen Durchschnitt berichten, berichten Sie auch den <strong>schlimmsten Zwischenzustand</strong>.</p>
<li>… die sechs Bausteine einer quantitativen Engine benennen und ihre Reihenfolge begründen.</li>
<li>… einen Walk-Forward-Backtest ohne Lookahead-Bias implementieren.</li>
<li>… Rebalancing-Termine korrekt auf Handelstage abbilden.</li>
<li>… Transaktionskosten und Gewichtsdrift realistisch verbuchen.</li>
<li>… Backtest-Ergebnisse kritisch prüfen und die typischen Selbsttäuschungen erkennen.</li>
<li>… den maximalen Rückschlag als eigenständige Kennzahl berichten und begründen, warum Rendite und Sharpe allein nichts über den Verlauf aussagen.</li>
<li>… die Zahl der ausprobierten Varianten protokollieren und die Signifikanzschwelle entsprechend korrigieren.</li>
</ol>
<hr/>
<h2id="sec:handelsmaschine-die-architektur">21.3 Die Architektur</h2>
<figure>
<imgsrc="bilder_04/kap14_engine_overview.svg"alt="Abb. 21.1: Überblick der quantitativen Engine"/>
<figcaptionaria-hidden="true">Abb. 21.1: Überblick der quantitativen Engine</figcaption>
<p><strong>🎯 Die goldene Regel des Backtestens</strong><strong>Zum Zeitpunkt <spanclass="math inline">t</span> darf ausschließlich Information verwendet werden, die zum Zeitpunkt <spanclass="math inline">t</span> tatsächlich vorlag.</strong> Jede Verletzung — und sei sie einen einzigen Tag groß — macht Ergebnisse systematisch zu gut. Der Fehler ist besonders tückisch, weil er keine Fehlermeldung erzeugt, sondern nur die Rendite verbessert.</p>
<p><code>resample("MS")</code> erzeugt <strong>Kalender-Monatsanfänge</strong> — den 1. Januar, den 1. Februar und so fort. Der Kursindex enthält aber nur <strong>Handelstage</strong>. Fällt der Monatserste auf ein Wochenende oder einen Feiertag, ist er kein Element des Index, die Bedingung wird nie wahr, und das Rebalancing <strong>entfällt kommentarlos</strong>.</p>
<p>Messung auf einem reinen Wochentagskalender über fünf Jahre:</p>
<p>Mit echten Börsenfeiertagen fallen weitere Termine aus. Der Backtest testete also eine <strong>andere Strategie als die beschriebene</strong> — und lieferte trotzdem plausibel aussehende Kennzahlen.</p>
<spanid="cb4-2"><ahref="#cb4-2"aria-hidden="true"tabindex="-1"></a><spanclass="va">self</span>.rebalancing_termine <spanclass="op">=</span><spanclass="va">self</span>.kurse.index[<spanclass="op">~</span>monat.duplicated()] <spanclass="co"># erster HANDELStag</span></span>
<p><code>~monat.duplicated()</code> markiert den jeweils <strong>ersten vorhandenen</strong> Tag jedes Monats — also garantiert einen Handelstag.</p>
</blockquote>
<blockquote>
<p><strong>🎯 Die allgemeine Lehre</strong><strong>Der gefährlichste Fehler ist der, der nichts kaputt macht.</strong> Ein Absturz wird bemerkt. Ein Backtest, der stillschweigend 28 % seiner Entscheidungen auslässt, wird gelobt. Bauen Sie deshalb in jeden Backtest <strong>Zähler</strong> ein: Wie viele Rebalancings waren geplant, wie viele wurden ausgeführt? Weichen die Zahlen ab, stimmt etwas nicht.</p>
</blockquote>
<hr/>
<h2id="sec:handelsmaschine-die-engine">21.5 Die Engine</h2>
<spanid="cb5-9"><ahref="#cb5-9"aria-hidden="true"tabindex="-1"></a><spanclass="co"> * Rebalancing-Termine sind garantiert Handelstage; die Zahl der</span></span>
<spanid="cb5-10"><ahref="#cb5-10"aria-hidden="true"tabindex="-1"></a><spanclass="co"> tatsaechlich ausgefuehrten Umschichtungen wird ausgewiesen</span></span>
<spanid="cb5-36"><ahref="#cb5-36"aria-hidden="true"tabindex="-1"></a><spanclass="co">"""Walk-Forward-Backtest mit CVaR-Optimierung und Transaktionskosten."""</span></span>
<spanid="cb5-59"><ahref="#cb5-59"aria-hidden="true"tabindex="-1"></a> ende <spanclass="op">=</span> pd.Timestamp.today().normalize()</span>
<spanid="cb5-60"><ahref="#cb5-60"aria-hidden="true"tabindex="-1"></a> start <spanclass="op">=</span> ende <spanclass="op">-</span> pd.DateOffset(years<spanclass="op">=</span><spanclass="va">self</span>.jahre)</span>
<spanid="cb5-61"><ahref="#cb5-61"aria-hidden="true"tabindex="-1"></a> alle <spanclass="op">=</span><spanclass="va">self</span>.universum <spanclass="op">+</span> [<spanclass="va">self</span>.benchmark]</span>
<spanid="cb5-63"><ahref="#cb5-63"aria-hidden="true"tabindex="-1"></a><spanclass="bu">print</span>(<spanclass="ss">f"Lade </span><spanclass="sc">{</span><spanclass="bu">len</span>(<spanclass="va">self</span>.universum)<spanclass="sc">}</span><spanclass="ss"> Titel + Benchmark (</span><spanclass="sc">{</span><spanclass="va">self</span><spanclass="sc">.</span>benchmark<spanclass="sc">}</span><spanclass="ss">) "</span></span>
<spanid="cb5-64"><ahref="#cb5-64"aria-hidden="true"tabindex="-1"></a><spanclass="ss">f"ueber </span><spanclass="sc">{</span><spanclass="va">self</span><spanclass="sc">.</span>jahre<spanclass="sc">}</span><spanclass="ss"> Jahre ..."</span>)</span>
<spanid="cb5-80"><ahref="#cb5-80"aria-hidden="true"tabindex="-1"></a><spanclass="co"># --- erster HANDELStag je Monat, nicht Kalendermonatsanfang -----</span></span>
<spanid="cb5-84"><ahref="#cb5-84"aria-hidden="true"tabindex="-1"></a><spanclass="st">"Rebalancing-Termine sind keine Handelstage!"</span></span>
<spanid="cb5-90"><ahref="#cb5-90"aria-hidden="true"tabindex="-1"></a><spanclass="co"># -- 2. Signal --------------------------------------------------------</span></span>
<spanid="cb5-93"><ahref="#cb5-93"aria-hidden="true"tabindex="-1"></a><spanclass="co"> 12-1-Momentum: Kursentwicklung der letzten 12 Monate unter Auslassung</span></span>
<spanid="cb5-94"><ahref="#cb5-94"aria-hidden="true"tabindex="-1"></a><spanclass="co"> des letzten Monats (kurzfristige Umkehr herausrechnen).</span></span>
<spanid="cb5-97"><ahref="#cb5-97"aria-hidden="true"tabindex="-1"></a> historie <spanclass="op">=</span><spanclass="va">self</span>.kurse.loc[:stichtag]</span>
<spanid="cb5-102"><ahref="#cb5-102"aria-hidden="true"tabindex="-1"></a> p_neu <spanclass="op">=</span> historie.iloc[<spanclass="op">-</span><spanclass="dv">21</span>] <spanclass="co"># vor ca. einem Monat</span></span>
<spanid="cb5-116"><ahref="#cb5-116"aria-hidden="true"tabindex="-1"></a> historie <spanclass="op">=</span><spanclass="va">self</span>.renditen.loc[:stichtag].iloc[<spanclass="op">-</span>rueckblick:]</span>
<spanid="cb5-124"><ahref="#cb5-124"aria-hidden="true"tabindex="-1"></a> w <spanclass="op">=</span> cp.Variable(N, nonneg<spanclass="op">=</span><spanclass="va">True</span>)</span>
<spanid="cb5-126"><ahref="#cb5-126"aria-hidden="true"tabindex="-1"></a> u <spanclass="op">=</span> cp.Variable(S, nonneg<spanclass="op">=</span><spanclass="va">True</span>)</span>
<spanid="cb5-150"><ahref="#cb5-150"aria-hidden="true"tabindex="-1"></a> N <spanclass="op">=</span><spanclass="bu">len</span>(<spanclass="va">self</span>.universum)</span>
<spanid="cb5-160"><ahref="#cb5-160"aria-hidden="true"tabindex="-1"></a><spanclass="cf">for</span> t <spanclass="kw">in</span><spanclass="bu">range</span>(<spanclass="va">self</span>.warmup, <spanclass="bu">len</span>(<spanclass="va">self</span>.renditen) <spanclass="op">-</span><spanclass="dv">1</span>):</span>
<spanid="cb5-161"><ahref="#cb5-161"aria-hidden="true"tabindex="-1"></a> heute <spanclass="op">=</span><spanclass="va">self</span>.renditen.index[t]</span>
<spanid="cb5-164"><ahref="#cb5-164"aria-hidden="true"tabindex="-1"></a> ist_termin <spanclass="op">=</span> heute <spanclass="kw">in</span><spanclass="va">self</span>.rebalancing_termine <spanclass="kw">or</span> t <spanclass="op">==</span><spanclass="va">self</span>.warmup</span>
<spanid="cb5-168"><ahref="#cb5-168"aria-hidden="true"tabindex="-1"></a> neue_gewichte, erfolg <spanclass="op">=</span><spanclass="va">self</span>.optimiere(heute, gewichte)</span>
<spanid="cb5-179"><ahref="#cb5-179"aria-hidden="true"tabindex="-1"></a><spanclass="co"># Rendite von MORGEN auf die HEUTE festgelegten Gewichte anwenden</span></span>
<spanid="cb5-222"><ahref="#cb5-222"aria-hidden="true"tabindex="-1"></a><spanclass="bu">print</span>(<spanclass="st">" LEISTUNGSREPORT DER QUANTITATIVEN ENGINE"</span>)</span>
<spanid="cb5-224"><ahref="#cb5-224"aria-hidden="true"tabindex="-1"></a><spanclass="bu">print</span>(<spanclass="ss">f"Zeitraum: </span><spanclass="sc">{</span>ergebnis<spanclass="sc">.</span>index[<spanclass="dv">0</span>]<spanclass="sc">:</span><spanclass="op">%</span>Y<spanclass="op">-%</span>m<spanclass="op">-%</span>d<spanclass="sc">}</span><spanclass="ss"> bis </span><spanclass="sc">{</span>ergebnis<spanclass="sc">.</span>index[<spanclass="op">-</span><spanclass="dv">1</span>]<spanclass="sc">:</span><spanclass="op">%</span>Y<spanclass="op">-%</span>m<spanclass="op">-%</span>d<spanclass="sc">}</span><spanclass="ss">"</span></span>
<spanid="cb5-250"><ahref="#cb5-250"aria-hidden="true"tabindex="-1"></a><spanclass="bu">print</span>(<spanclass="st">"Ohne diese Kosten waere die ausgewiesene Rendite entsprechend hoeher -"</span>)</span>
<spanid="cb5-251"><ahref="#cb5-251"aria-hidden="true"tabindex="-1"></a><spanclass="bu">print</span>(<spanclass="st">"genau deshalb gehoeren sie in den Backtest und nicht daneben."</span>)</span>
<spanid="cb5-267"><ahref="#cb5-267"aria-hidden="true"tabindex="-1"></a> ziel <spanclass="op">=</span> os.path.join(OUTPUT_DIR, <spanclass="st">"trading_engine_backtest.png"</span>)</span>
<spanid="cb5-269"><ahref="#cb5-269"aria-hidden="true"tabindex="-1"></a><spanclass="bu">print</span>(<spanclass="ss">f"Chart gespeichert unter '</span><spanclass="sc">{</span>ziel<spanclass="sc">}</span><spanclass="ss">'"</span>)</span>
<spanid="cb5-274"><ahref="#cb5-274"aria-hidden="true"tabindex="-1"></a><spanclass="co"> Prueft, dass das Signal zum Zeitpunkt t NUR Daten bis t verwendet.</span></span>
<spanid="cb5-275"><ahref="#cb5-275"aria-hidden="true"tabindex="-1"></a><spanclass="co"> Methode: kuenstlich die Zukunft veraendern und pruefen, ob sich das</span></span>
<spanid="cb5-276"><ahref="#cb5-276"aria-hidden="true"tabindex="-1"></a><spanclass="co"> Signal von heute dadurch aendert. Tut es das, liegt Lookahead vor.</span></span>
<spanid="cb5-288"><ahref="#cb5-288"aria-hidden="true"tabindex="-1"></a><spanclass="bu">print</span>(<spanclass="ss">f"Lookahead-Selbsttest: Signal bleibt bei manipulierter Zukunft "</span></span>
<spanid="cb5-290"><ahref="#cb5-290"aria-hidden="true"tabindex="-1"></a><spanclass="cf">assert</span> identisch, <spanclass="st">"Das Signal verwendet Zukunftsdaten!"</span></span>
<p><code>to_period("M")</code> bildet jeden Handelstag auf seinen Monat ab; <code>~duplicated()</code> behält jeweils den <strong>ersten</strong> — also garantiert einen realen Handelstag.</p>
<p><strong>2. Die Zeitachse im Backtest.</strong></p>
<spanid="cb7-2"><ahref="#cb7-2"aria-hidden="true"tabindex="-1"></a>portfoliorendite <spanclass="op">=</span> gewichte <spanclass="op">@</span> tagesrenditen <spanclass="co"># HEUTE festgelegt</span></span></code></pre></div>
<p>Die Gewichte werden am Tag <spanclass="math inline">t</span> aus Daten bis <spanclass="math inline">t</span> bestimmt und auf die Rendite von <spanclass="math inline">t+1</span> angewendet. <strong>Diese eine Indexverschiebung ist der Unterschied zwischen einem ehrlichen und einem geschönten Backtest.</strong></p>
<p><strong>3. Der Lookahead-Selbsttest.</strong> Er verdreifacht künstlich alle Kurse <strong>nach</strong> dem Stichtag und prüft, ob sich das Signal von <em>vor</em> dem Stichtag dadurch ändert. Ändert es sich, greift der Code auf die Zukunft zu. Dieser Test kostet zehn Zeilen und findet eine Fehlerklasse, die sonst praktisch unsichtbar bleibt. <strong>Übernehmen Sie ihn in jedes Backtest-Projekt.</strong></p>
<p>Zwischen zwei Rebalancings verändern sich die Gewichte von selbst — gestiegene Titel bekommen mehr Gewicht. Wer das weglässt, unterstellt implizit <strong>tägliches</strong> kostenloses Rebalancing und überschätzt die Strategie.</p>
</blockquote>
<blockquote>
<p><strong>⚠️ Zur Reproduzierbarkeit</strong> Dieses Programm lädt Live-Daten über ein relatives Fünfjahresfenster. <strong>Ihre Zahlen werden von jeder abgedruckten Zahl abweichen</strong> — je nach Abrufdatum und Marktlage. Bewerten Sie deshalb nicht die absoluten Werte, sondern die <strong>Struktur</strong>: Wurden alle Rebalancings ausgeführt? Besteht der Lookahead-Test? Sind die Transaktionskosten plausibel?</p>
</blockquote>
<hr/>
<h2id="sec:handelsmaschine-die-fuenf-selbsttaeuschungen-des-backtestens">21.6 Die fünf Selbsttäuschungen des Backtestens</h2>
<spanid="cb9-5"><ahref="#cb9-5"aria-hidden="true"tabindex="-1"></a><spanclass="co">Kapitel Handelsmaschine: Wie leicht man sich selbst betruegt.</span></span>
<spanid="cb9-7"><ahref="#cb9-7"aria-hidden="true"tabindex="-1"></a><spanclass="co">Demonstriert an SIMULIERTEN Daten (also ohne jede echte Prognosekraft),</span></span>
<spanid="cb9-8"><ahref="#cb9-8"aria-hidden="true"tabindex="-1"></a><spanclass="co">wie gross die scheinbare Ueberrendite durch typische Backtest-Fehler wird.</span></span>
<spanid="cb9-9"><ahref="#cb9-9"aria-hidden="true"tabindex="-1"></a><spanclass="co">Weil die Daten reines Rauschen sind, ist JEDE positive Ueberrendite ein Artefakt.</span></span>
<spanid="cb9-17"><ahref="#cb9-17"aria-hidden="true"tabindex="-1"></a><spanclass="co">"""Reines Rauschen: kein Titel hat echte Prognosekraft."""</span></span>
<spanid="cb9-20"><ahref="#cb9-20"aria-hidden="true"tabindex="-1"></a> index <spanclass="op">=</span> pd.bdate_range(<spanclass="st">"2020-01-01"</span>, periods<spanclass="op">=</span>tage)</span>
<spanid="cb9-22"><ahref="#cb9-22"aria-hidden="true"tabindex="-1"></a> columns<spanclass="op">=</span>[<spanclass="ss">f"T</span><spanclass="sc">{</span>i<spanclass="sc">:02d}</span><spanclass="ss">"</span><spanclass="cf">for</span> i <spanclass="kw">in</span><spanclass="bu">range</span>(titel)])</span>
<spanid="cb9-34"><ahref="#cb9-34"aria-hidden="true"tabindex="-1"></a><spanclass="co"># FEHLER: nur die im Nachhinein besten Titel ins Universum lassen</span></span>
<spanid="cb9-35"><ahref="#cb9-35"aria-hidden="true"tabindex="-1"></a> beste <spanclass="op">=</span> renditen.<spanclass="bu">sum</span>().nlargest(renditen.shape[<spanclass="dv">1</span>] <spanclass="op">//</span><spanclass="dv">2</span>).index</span>
<spanid="cb9-39"><ahref="#cb9-39"aria-hidden="true"tabindex="-1"></a><spanclass="cf">for</span> t <spanclass="kw">in</span><spanclass="bu">range</span>(fenster, <spanclass="bu">len</span>(daten) <spanclass="op">-</span><spanclass="dv">1</span>):</span>
<spanid="cb9-40"><ahref="#cb9-40"aria-hidden="true"tabindex="-1"></a><spanclass="cf">if</span> t <spanclass="op">%</span><spanclass="dv">21</span><spanclass="op">==</span><spanclass="dv">0</span>: <spanclass="co"># monatlich</span></span>
<spanid="cb9-42"><ahref="#cb9-42"aria-hidden="true"tabindex="-1"></a><spanclass="co"># FEHLER: Signal nutzt die Rendite von MORGEN</span></span>
<spanid="cb9-43"><ahref="#cb9-43"aria-hidden="true"tabindex="-1"></a> signal <spanclass="op">=</span> daten.iloc[t <spanclass="op">+</span><spanclass="dv">1</span>].values</span>
<spanid="cb9-47"><ahref="#cb9-47"aria-hidden="true"tabindex="-1"></a> neue <spanclass="op">=</span> (signal <spanclass="op">></span> np.median(signal)).astype(<spanclass="bu">float</span>)</span>
<spanid="cb9-48"><ahref="#cb9-48"aria-hidden="true"tabindex="-1"></a> neue <spanclass="op">=</span> neue <spanclass="op">/</span> neue.<spanclass="bu">sum</span>() <spanclass="cf">if</span> neue.<spanclass="bu">sum</span>() <spanclass="op">></span><spanclass="dv">0</span><spanclass="cf">else</span> gewichte</span>
<spanid="cb9-63"><ahref="#cb9-63"aria-hidden="true"tabindex="-1"></a> jahre <spanclass="op">=</span><spanclass="bu">len</span>(renditen) <spanclass="op">/</span><spanclass="dv">252</span></span>
<spanid="cb9-67"><ahref="#cb9-67"aria-hidden="true"tabindex="-1"></a><spanclass="bu">print</span>(<spanclass="st">" DIE FUENF SELBSTTAEUSCHUNGEN - GEMESSEN AN REINEM RAUSCHEN"</span>)</span>
<spanid="cb9-69"><ahref="#cb9-69"aria-hidden="true"tabindex="-1"></a><spanclass="bu">print</span>(<spanclass="st">"Die Daten sind zufaellig erzeugt. Es gibt KEINE echte Prognosekraft."</span>)</span>
<spanid="cb9-70"><ahref="#cb9-70"aria-hidden="true"tabindex="-1"></a><spanclass="bu">print</span>(<spanclass="st">"Jede Ueberrendite unten ist daher ein reines Artefakt.</span><spanclass="ch">\n</span><spanclass="st">"</span>)</span>
<spanid="cb9-79"><ahref="#cb9-79"aria-hidden="true"tabindex="-1"></a> (<spanclass="st">"Ehrlich: Signal aus Vergangenheit, mit Kosten"</span>, {}),</span>
<spanid="cb9-92"><ahref="#cb9-92"aria-hidden="true"tabindex="-1"></a><spanclass="bu">print</span>(<spanclass="st">"FEHLER 4 (Overfitting) und FEHLER 5 (Data Snooping) lassen sich so nicht"</span>)</span>
<spanid="cb9-93"><ahref="#cb9-93"aria-hidden="true"tabindex="-1"></a><spanclass="bu">print</span>(<spanclass="st">"zeigen - sie entstehen erst durch WIEDERHOLTES Probieren. Faustregel:"</span>)</span>
<spanid="cb9-94"><ahref="#cb9-94"aria-hidden="true"tabindex="-1"></a><spanclass="bu">print</span>(<spanclass="st">"Wer 20 Strategien testet, findet auch in reinem Rauschen eine mit"</span>)</span>
<spanid="cb9-95"><ahref="#cb9-95"aria-hidden="true"tabindex="-1"></a><spanclass="bu">print</span>(<spanclass="st">"Signifikanz auf dem 5-%-Niveau. Genau das ist der Punkt."</span>)</span>
<p><strong>Lesen Sie diese Tabelle sehr genau.</strong> Die zugrunde liegenden Daten sind <strong>reiner Zufall</strong> — es gibt keinerlei Prognosekraft, kein Signal, keine Struktur. Trotzdem:</p>
<ul>
<li><strong>Lookahead</strong> erzeugt eine scheinbare Überrendite von <strong>15,4 Prozentpunkten pro Jahr</strong>. Ein einziger falscher Index — <code>iloc[t+1]</code> statt <code>iloc[t]</code> — verwandelt Rauschen in eine scheinbar brillante Strategie.</li>
<li><strong>Survivorship-Bias</strong> liefert <strong>13,1 Prozentpunkte</strong> allein dadurch, dass man das Universum im Nachhinein auf die Gewinner beschränkt.</li>
<li>Selbst die <strong>ehrliche</strong> Variante zeigt noch +1,1 Prozentpunkte — reines Rauschen, das aber ohne Weiteres als „leichte Outperformance“ verkauft werden könnte.</li>
</ul>
<p><strong>Die Lehre:</strong> Wenn Sie in einem Backtest eine Überrendite von 15 % sehen, ist die erste Frage nicht „Wie kann ich das nutzen?“, sondern <strong>„Wo ist mein Fehler?“</strong>. Und wenn Sie keinen finden, suchen Sie weiter — die Wahrscheinlichkeit, dass Sie tatsächlich eine Goldader entdeckt haben, ist deutlich kleiner als die, dass ein Index verrutscht ist.</p>
<p>Die fünf Fallen im Einzelnen:</p>
<table>
<colgroup>
<colstyle="width: 25%"/>
<colstyle="width: 25%"/>
<colstyle="width: 25%"/>
<colstyle="width: 25%"/>
</colgroup>
<thead>
<trclass="header">
<th>#</th>
<th>Falle</th>
<th>Was passiert</th>
<th>Gegenmittel</th>
</tr>
</thead>
<tbody>
<trclass="odd">
<td>1</td>
<td><strong>Lookahead-Bias</strong></td>
<td>Entscheidungen nutzen Daten, die es noch nicht gab</td>
<td>Zeitindex prüfen; Selbsttest wie oben</td>
</tr>
<trclass="even">
<td>2</td>
<td><strong>Survivorship-Bias</strong></td>
<td>Nur heute existierende Titel im Universum</td>
<td>Viele Varianten getestet, beste berichtet</td>
<td>Zahl der Versuche protokollieren; Deflated Sharpe Ratio</td>
</tr>
</tbody>
</table>
<blockquote>
<p><strong>🎯 Die unbequeme Wahrheit</strong> Falle 5 ist die gefährlichste, weil sie sich nicht im Code zeigt, sondern im <strong>Arbeitsprozess</strong>. Wer zwanzig Parameterkombinationen durchprobiert und die beste berichtet, hat keine Strategie gefunden, sondern eine Zufallsschwankung ausgewählt. Marcos López de Prado hat gezeigt, dass die meisten veröffentlichten Backtests genau daran scheitern. <strong>Protokollieren Sie, wie viele Varianten Sie getestet haben</strong> — und berichten Sie diese Zahl mit.</p>
</blockquote>
<hr/>
<h2id="sec:handelsmaschine-vom-backtest-zum-betrieb">21.7 Vom Backtest zum Betrieb</h2>
<p>Ein guter Backtest ist eine <strong>notwendige</strong>, keine hinreichende Bedingung. Was zwischen Backtest und echtem Einsatz liegt:</p>
<table>
<colgroup>
<colstyle="width: 33%"/>
<colstyle="width: 33%"/>
<colstyle="width: 33%"/>
</colgroup>
<thead>
<trclass="header">
<th>Schritt</th>
<th>Frage</th>
<th>Typisches Ergebnis</th>
</tr>
</thead>
<tbody>
<trclass="odd">
<td><strong>Papierhandel</strong></td>
<td>Funktioniert es auf Live-Daten ohne Geld?</td>
<td>3–6 Monate, oft schlechter als der Backtest</td>
</tr>
<trclass="even">
<td><strong>Kapazitätsanalyse</strong></td>
<td>Bewegt meine eigene Order den Markt?</td>
<td>Begrenzt das einsetzbare Volumen</td>
</tr>
<trclass="odd">
<td><strong>Regimewechsel-Test</strong></td>
<td>Hält es in Krisen?</td>
<td>Backtest über 2008, 2020 separat auswerten</td>
</tr>
<trclass="even">
<td><strong>Betriebsrisiken</strong></td>
<td>Was, wenn der Datenfeed ausfällt?</td>
<td>Fallback-Strategie, Monitoring</td>
</tr>
<trclass="odd">
<td><strong>Regulatorik</strong></td>
<td>MiFID II, Best Execution, Dokumentation</td>
<td>Protokollpflichten</td>
</tr>
</tbody>
</table>
<blockquote>
<p><strong>⚠️ Der Realitätsabschlag</strong> Als Faustregel gilt: <strong>Die reale Performance liegt deutlich unter dem Backtest</strong> — durch Slippage, verzögerte Ausführung, Datenrevisionen und schlicht dadurch, dass die Zukunft nicht die Vergangenheit ist. Wer einen Backtest mit Sharpe 1,5 hat, sollte real mit deutlich weniger rechnen. Eine Strategie, die im Backtest nur knapp die Benchmark schlägt, wird es real nicht tun.</p>
<p><strong>Aufgabe 21.1 ⭐ — Lookahead erkennen.</strong> Welche dieser Zeilen enthalten Lookahead-Bias? Begründen Sie: (a) <code>signal = kurse.loc[:heute].pct_change().mean()</code> (b) <code>signal = kurse.pct_change().mean()</code> (c) <code>vola = renditen.std()</code> (berechnet einmal über den gesamten Zeitraum) (d) <code>w = optimiere(renditen.loc[:heute]); rendite = w @ renditen.loc[heute]</code> (e) <code>universum = [t for t in alle if kurse[t].notna().all()]</code></p>
<p><strong>Aufgabe 21.2 ⭐ — Kennzahlen deuten.</strong> Strategie A: CAGR 12 %, Vola 22 %, MaxDD −35 %. Strategie B: CAGR 8 %, Vola 9 %, MaxDD −12 %. Berechnen Sie Sharpe (bei <spanclass="math inline">r_f = 2\,\%</span>) und Calmar. Welche würden Sie einem Pensionsfonds empfehlen und warum?</p>
<p><strong>Aufgabe 21.3 ⭐⭐ — Rebalancing-Kalender prüfen.</strong> Bauen Sie den Fehler nach: Ersetzen Sie den korrigierten Kalender durch <code>resample("MS").first().index</code>. Zählen Sie, wie viele Rebalancings ausfallen, und vergleichen Sie die Backtest-Kennzahlen beider Varianten.</p>
<p><strong>Aufgabe 21.4 ⭐⭐ — Rebalancing-Frequenz.</strong> Variieren Sie die Frequenz: täglich, wöchentlich, monatlich, quartalsweise, jährlich. (a) Wie ändern sich Rendite, Turnover und Kosten? (b) Ab welcher Frequenz fressen die Kosten den Ertrag auf? (c) Was ist Ihre Empfehlung bei einem Gebührensatz von 0,15 %? Bei 0,5 %?</p>
<p><strong>Aufgabe 21.5 ⭐⭐⭐ — Krisenverhalten.</strong> Werten Sie den Backtest getrennt für Teilzeiträume aus (z. B. je Kalenderjahr). Erstellen Sie eine Tabelle mit CAGR, Vola und MaxDD je Jahr für Strategie und Benchmark. (a) In welchen Phasen schlägt die Strategie die Benchmark? (b) Ist das Muster stabil oder zufällig? (c) Was folgt daraus für die Beurteilung der Gesamtkennzahl?</p>
<p><strong>Aufgabe 21.6 ⭐⭐⭐ — Data Snooping messen.</strong> Testen Sie 30 Varianten Ihrer Strategie (verschiedene Rückblickfenster, Risikoaversionen, Positionsgrenzen). Berichten Sie: (a) die beste Sharpe Ratio, (b) die mittlere Sharpe Ratio über alle Varianten, (c) die Sharpe Ratio der besten Variante <strong>auf einem zurückgehaltenen Zeitraum</strong>. Was lernen Sie aus der Differenz zwischen (a) und (c)?</p>
<hr/>
<h2id="sec:handelsmaschine-denkfehler">21.9 Finde den Denkfehler</h2>
<p><code>Backtest_Fallen.py</code> zeigt drei Fehler, die <strong>im</strong> Backtest stecken: Lookahead, Survivorship, vergessene Kosten. Alle drei kann man einem Programm ansehen, wenn man es liest.</p>
<p>Die beiden übrigen Selbsttäuschungen sind anders gebaut. Sie entstehen nicht im Code, sondern in der <strong>Arbeitsweise davor</strong> — und hinterlassen im Programm keine Spur. Ein Backtest, der zwanzigmal nachjustiert wurde, sieht am Ende genauso sauber aus wie einer, der beim ersten Versuch funktioniert hat.</p>
<p>Eine Analystin entwickelt über mehrere Wochen eine Handelsstrategie. Sie probiert verschiedene Signalfenster, Schwellenwerte, Filter und Haltedauern durch — insgesamt rund <strong>hundert Varianten</strong>. Die beste testet sie sauber: kein Lookahead, korrektes Universum, Transaktionskosten berücksichtigt.</p>
<p>Das Ergebnis über fünf Jahre: <strong>Sharpe-Kennzahl 1,13</strong>, p-Wert <strong>0,0094</strong>. Der Backtest ist handwerklich einwandfrei — jede der drei Fallen aus <code>Backtest_Fallen.py</code> wurde vermieden. Sie stellt die Strategie vor.</p>
<p><strong>Ihre Aufgabe:</strong> (a) Der Backtest ist korrekt. Warum ist das Ergebnis trotzdem wertlos? (b) Sehen Sie sich unten die letzte Spalte der Tabelle an: Sie bleibt konstant bei 5 %, obwohl die Zahl der Versuche um das Tausendfache wächst. Wieso ist das kein Widerspruch, sondern der Kern des Problems? (c) Welche Zahl fehlt in ihrem Bericht — eine Zahl, die in keinem Backtest-Ergebnis steht und die sie selbst aufschreiben müsste? (d) Nennen Sie drei Gegenmittel und begründen Sie, warum das dritte nur <strong>einmal</strong> verwendbar ist.</p>
<p>Das folgende Programm macht den Effekt messbar. Es testet Strategien, die <strong>nachweislich</strong> keinerlei Vorteil haben — ihre Tagesergebnisse sind Zufallszahlen mit Erwartungswert exakt null — und zeigt, wie gut die jeweils beste davon aussieht, allein als Funktion der Anzahl der Versuche.</p>
<spanid="cb11-5"><ahref="#cb11-5"aria-hidden="true"tabindex="-1"></a><spanclass="co">Kapitel Handelsmaschine: Die Selbsttaeuschung, die man einem Backtest nicht ansieht.</span></span>
<spanid="cb11-7"><ahref="#cb11-7"aria-hidden="true"tabindex="-1"></a><spanclass="co">Backtest_Fallen.py zeigt drei Fehler, die IM Backtest stecken: Lookahead,</span></span>
<spanid="cb11-8"><ahref="#cb11-8"aria-hidden="true"tabindex="-1"></a><spanclass="co">Survivorship, vergessene Kosten. Alle drei kann man einem Programm ansehen,</span></span>
<spanid="cb11-9"><ahref="#cb11-9"aria-hidden="true"tabindex="-1"></a><spanclass="co">wenn man es liest.</span></span>
<spanid="cb11-11"><ahref="#cb11-11"aria-hidden="true"tabindex="-1"></a><spanclass="co">Die beiden anderen - Overfitting und Data Snooping - entstehen nicht im</span></span>
<spanid="cb11-12"><ahref="#cb11-12"aria-hidden="true"tabindex="-1"></a><spanclass="co">Backtest, sondern in der ARBEITSWEISE davor. Sie hinterlassen im Code keine</span></span>
<spanid="cb11-13"><ahref="#cb11-13"aria-hidden="true"tabindex="-1"></a><spanclass="co">Spur. Ein Backtest, der zwanzigmal angepasst wurde, sieht am Ende genauso</span></span>
<spanid="cb11-14"><ahref="#cb11-14"aria-hidden="true"tabindex="-1"></a><spanclass="co">sauber aus wie einer, der beim ersten Versuch funktioniert hat.</span></span>
<spanid="cb11-16"><ahref="#cb11-16"aria-hidden="true"tabindex="-1"></a><spanclass="co">Dieses Programm macht den Effekt messbar. Es testet Strategien, die</span></span>
<spanid="cb11-17"><ahref="#cb11-17"aria-hidden="true"tabindex="-1"></a><spanclass="co">NACHWEISLICH keinerlei Prognosekraft haben (ihre taeglichen Ergebnisse sind</span></span>
<spanid="cb11-18"><ahref="#cb11-18"aria-hidden="true"tabindex="-1"></a><spanclass="co">Zufallszahlen mit Erwartungswert exakt null), und zeigt, wie gut die jeweils</span></span>
<spanid="cb11-19"><ahref="#cb11-19"aria-hidden="true"tabindex="-1"></a><spanclass="co">BESTE davon aussieht - allein als Funktion der Anzahl der Versuche.</span></span>
<spanid="cb11-31"><ahref="#cb11-31"aria-hidden="true"tabindex="-1"></a>WIEDERHOLUNGEN <spanclass="op">=</span><spanclass="dv">300</span><spanclass="co"># damit die Tabelle nicht vom Zufall abhaengt</span></span>
<spanid="cb11-38"><ahref="#cb11-38"aria-hidden="true"tabindex="-1"></a><spanclass="co">"""Sharpe-Kennzahl und einseitiger p-Wert je Strategie.</span></span>
<spanid="cb11-40"><ahref="#cb11-40"aria-hidden="true"tabindex="-1"></a><spanclass="co"> ergebnisse hat die Form (Strategien, Handelstage). Der p-Wert prueft die</span></span>
<spanid="cb11-41"><ahref="#cb11-41"aria-hidden="true"tabindex="-1"></a><spanclass="co"> Nullhypothese 'mittleres Tagesergebnis ist null' - also genau die Frage,</span></span>
<spanid="cb11-42"><ahref="#cb11-42"aria-hidden="true"tabindex="-1"></a><spanclass="co"> die ein Backtest beantworten soll.</span></span>
<spanid="cb11-52"><ahref="#cb11-52"aria-hidden="true"tabindex="-1"></a><spanclass="co">"""Liefert (beste Sharpe, ihr p-Wert, Anteil scheinbar signifikanter,</span></span>
<spanid="cb11-53"><ahref="#cb11-53"aria-hidden="true"tabindex="-1"></a><spanclass="co"> Anteil, der auch die Bonferroni-Huerde nimmt) - gemittelt ueber</span></span>
<spanid="cb11-58"><ahref="#cb11-58"aria-hidden="true"tabindex="-1"></a><spanclass="co"># Der springende Punkt: Erwartungswert exakt 0. Keine dieser</span></span>
<spanid="cb11-59"><ahref="#cb11-59"aria-hidden="true"tabindex="-1"></a><spanclass="co"># Strategien hat einen echten Vorteil - per Konstruktion.</span></span>
<spanid="cb11-64"><ahref="#cb11-64"aria-hidden="true"tabindex="-1"></a> beste <spanclass="op">=</span><spanclass="bu">int</span>(sharpe.argmax())</span>
<spanid="cb11-68"><ahref="#cb11-68"aria-hidden="true"tabindex="-1"></a><spanclass="co"># Bonferroni: Wer n Tests macht, muss die Huerde durch n teilen.</span></span>
<spanid="cb11-70"><ahref="#cb11-70"aria-hidden="true"tabindex="-1"></a><spanclass="bu">float</span>((p_werte <spanclass="op"><</span> NIVEAU <spanclass="op">/</span> anzahl_strategien).mean()))</span>
<spanid="cb11-79"><ahref="#cb11-79"aria-hidden="true"tabindex="-1"></a><spanclass="bu">print</span>(<spanclass="st">" WIE GUT SIEHT DIE BESTE VON N STRATEGIEN AUS,"</span>)</span>
<spanid="cb11-80"><ahref="#cb11-80"aria-hidden="true"tabindex="-1"></a><spanclass="bu">print</span>(<spanclass="st">" WENN KEINE EINZIGE ETWAS TAUGT?"</span>)</span>
<spanid="cb11-84"><ahref="#cb11-84"aria-hidden="true"tabindex="-1"></a><spanclass="bu">print</span>(<spanclass="ss">f"Jede Zeile ist der Mittelwert aus </span><spanclass="sc">{</span>WIEDERHOLUNGEN<spanclass="sc">}</span><spanclass="ss"> unabhaengigen "</span></span>
<spanid="cb11-100"><ahref="#cb11-100"aria-hidden="true"tabindex="-1"></a><spanclass="bu">print</span>(<spanclass="st">"</span><spanclass="ch">\n</span><spanclass="st">Lesen Sie die dritte Spalte von unten nach oben:"</span>)</span>
<spanid="cb11-101"><ahref="#cb11-101"aria-hidden="true"tabindex="-1"></a><spanclass="bu">print</span>(<spanclass="ss">f" Wer </span><spanclass="sc">{</span><spanclass="dv">1000</span><spanclass="sc">}</span><spanclass="ss"> Varianten durchprobiert, findet eine mit p = </span><spanclass="sc">{</span>p_1000<spanclass="sc">:.4f}</span><spanclass="ss"> -"</span>)</span>
<spanid="cb11-102"><ahref="#cb11-102"aria-hidden="true"tabindex="-1"></a><spanclass="bu">print</span>(<spanclass="st">" ein Wert, den jede Zeitschrift als 'hochsignifikant' druckt."</span>)</span>
<spanid="cb11-103"><ahref="#cb11-103"aria-hidden="true"tabindex="-1"></a><spanclass="bu">print</span>(<spanclass="ss">f" Wer </span><spanclass="sc">{</span><spanclass="dv">100</span><spanclass="sc">}</span><spanclass="ss"> probiert, findet p = </span><spanclass="sc">{</span>p_100<spanclass="sc">:.4f}</span><spanclass="ss"> und eine Sharpe-Kennzahl"</span>)</span>
<spanid="cb11-104"><ahref="#cb11-104"aria-hidden="true"tabindex="-1"></a><spanclass="bu">print</span>(<spanclass="ss">f" von </span><spanclass="sc">{</span>sharpe_100<spanclass="sc">:.2f}</span><spanclass="ss"> - damit geht man zum Vorgesetzten."</span>)</span>
<spanid="cb11-105"><ahref="#cb11-105"aria-hidden="true"tabindex="-1"></a><spanclass="bu">print</span>(<spanclass="st">" Und keine dieser Strategien hat auch nur den Hauch eines Vorteils."</span>)</span>
<spanid="cb11-107"><ahref="#cb11-107"aria-hidden="true"tabindex="-1"></a><spanclass="bu">print</span>(<spanclass="st">"Die LETZTE Spalte bleibt dagegen konstant bei rund 5 %. Das ist kein"</span>)</span>
<spanid="cb11-108"><ahref="#cb11-108"aria-hidden="true"tabindex="-1"></a><spanclass="bu">print</span>(<spanclass="st">"Widerspruch, sondern die Definition: Ein Test zum 5-%-Niveau irrt in"</span>)</span>
<spanid="cb11-109"><ahref="#cb11-109"aria-hidden="true"tabindex="-1"></a><spanclass="bu">print</span>(<spanclass="st">"5 </span><spanclass="sc">% d</span><spanclass="st">er Faelle. Was sich aendert, ist nicht der Anteil, sondern die"</span>)</span>
<spanid="cb11-110"><ahref="#cb11-110"aria-hidden="true"tabindex="-1"></a><spanclass="bu">print</span>(<spanclass="st">"ANZAHL - und weil man nur die beste Strategie praesentiert, sieht man"</span>)</span>
<spanid="cb11-111"><ahref="#cb11-111"aria-hidden="true"tabindex="-1"></a><spanclass="bu">print</span>(<spanclass="st">"von allen Fehlversuchen genau einen: den erfolgreichsten."</span>)</span>
<spanid="cb11-114"><ahref="#cb11-114"aria-hidden="true"tabindex="-1"></a><spanclass="bu">print</span>(<spanclass="st">" WAS MAN DAGEGEN TUN KANN"</span>)</span>
<spanid="cb11-116"><ahref="#cb11-116"aria-hidden="true"tabindex="-1"></a><spanclass="bu">print</span>(<spanclass="st">"1. ZAEHLEN. Notieren Sie, wie viele Varianten Sie ausprobiert haben -"</span>)</span>
<spanid="cb11-117"><ahref="#cb11-117"aria-hidden="true"tabindex="-1"></a><spanclass="bu">print</span>(<spanclass="st">" auch die verworfenen, auch die 'nur mal schnell'. Ohne diese Zahl"</span>)</span>
<spanid="cb11-118"><ahref="#cb11-118"aria-hidden="true"tabindex="-1"></a><spanclass="bu">print</span>(<spanclass="st">" ist kein p-Wert und keine Sharpe-Kennzahl interpretierbar."</span>)</span>
<spanid="cb11-120"><ahref="#cb11-120"aria-hidden="true"tabindex="-1"></a><spanclass="bu">print</span>(<spanclass="st">"2. KORRIGIEREN. Die Bonferroni-Korrektur teilt die Huerde durch die"</span>)</span>
<spanid="cb11-121"><ahref="#cb11-121"aria-hidden="true"tabindex="-1"></a><spanclass="bu">print</span>(<spanclass="st">" Zahl der Versuche:"</span>)</span>
<spanid="cb11-123"><ahref="#cb11-123"aria-hidden="true"tabindex="-1"></a><spanclass="bu">print</span>(<spanclass="ss">f" bei </span><spanclass="sc">{</span>anzahl<spanclass="sc">:5d}</span><spanclass="ss"> Versuchen: p <</span><spanclass="sc">{</span>NIVEAU <spanclass="op">/</span> anzahl<spanclass="sc">:.5f}</span><spanclass="ss"> statt "</span></span>
<spanid="cb11-125"><ahref="#cb11-125"aria-hidden="true"tabindex="-1"></a><spanclass="bu">print</span>(<spanclass="st">" Sie ist konservativ, aber sie ist ehrlich. Fuer Handelsstrategien"</span>)</span>
<spanid="cb11-126"><ahref="#cb11-126"aria-hidden="true"tabindex="-1"></a><spanclass="bu">print</span>(<spanclass="st">" gibt es verfeinerte Varianten (Deflated Sharpe Ratio nach Bailey"</span>)</span>
<spanid="cb11-127"><ahref="#cb11-127"aria-hidden="true"tabindex="-1"></a><spanclass="bu">print</span>(<spanclass="st">" und Lopez de Prado), die dasselbe Prinzip verfolgen."</span>)</span>
<spanid="cb11-129"><ahref="#cb11-129"aria-hidden="true"tabindex="-1"></a><spanclass="bu">print</span>(<spanclass="st">"3. ZURUECKHALTEN. Legen Sie einen Zeitraum beiseite, BEVOR Sie"</span>)</span>
<spanid="cb11-130"><ahref="#cb11-130"aria-hidden="true"tabindex="-1"></a><spanclass="bu">print</span>(<spanclass="st">" anfangen, und ruehren Sie ihn bis zum Schluss nicht an. Er ist"</span>)</span>
<spanid="cb11-131"><ahref="#cb11-131"aria-hidden="true"tabindex="-1"></a><spanclass="bu">print</span>(<spanclass="st">" der einzige Test, den Sie nicht durch Probieren verderben koennen -"</span>)</span>
<spanid="cb11-132"><ahref="#cb11-132"aria-hidden="true"tabindex="-1"></a><spanclass="bu">print</span>(<spanclass="st">" und er ist genau einmal verwendbar."</span>)</span>
<p><strong>🎯 Merksatz</strong> Ein Backtest-Ergebnis ist ohne die Angabe <strong>„wie viele Varianten wurden probiert?“</strong> nicht interpretierbar. Diese Zahl steht in keinem Programm und in keiner Kennzahl — sie existiert nur im Kopf der Person, die die Arbeit gemacht hat. Genau deshalb ist sie die erste Frage, die man einem vorgelegten Backtest stellen sollte, und die erste Zahl, die man beim eigenen mitschreiben muss.</p>
<p>Genau eine Antwort ist jeweils richtig. Auflösung in <ahref="anhang-loesungen.html#quiz-loesung-handelsmaschine">Anhang A</a>.</p>
<p><strong>1. Zwei Strategien haben dieselbe Jahresrendite und dieselbe Sharpe-Kennzahl. Was wissen Sie über ihren Verlauf?</strong> (a) Er ist im Wesentlichen gleich — beide Kennzahlen zusammen beschreiben ihn vollständig. (b) <strong>Nichts.</strong> Beide Kennzahlen mitteln über die Zeit und verlieren die Reihenfolge. Dieselben Tagesrenditen können zu einem Rückschlag von 19 % oder von 98 % führen. (c) Die Strategie mit der höheren Schwankung hat den größeren Rückschlag.</p>
<p><strong>2. Sie haben 50 Strategievarianten getestet und die beste erreicht p = 0,01. Wie bewerten Sie das?</strong> (a) Hochsignifikant — die Wahrscheinlichkeit eines Zufallsbefunds liegt bei 1 %. (b) Bei 50 Versuchen ist ein p-Wert von 0,01 unauffällig: Schon rein zufällig erwartet man etwa 2,5 Treffer unter dem 5-%-Niveau. Die Bonferroni-Schwelle läge bei 0,001. (c) Der p-Wert ist für Handelsstrategien grundsätzlich ungeeignet.</p>
<p><strong>3. Warum ist ein zurückgehaltener Testzeitraum nur </strong>einmal** verwendbar?** (a) Weil die Daten danach veraltet sind. (b) Weil man ab dem Moment, in dem man das Ergebnis kennt und daraufhin etwas ändert, wieder anfängt zu probieren — der Zeitraum ist dann Teil der Suche geworden und nicht mehr unabhängig. (c) Weil sich die Kennzahlen bei wiederholter Berechnung numerisch verschlechtern.</p>
<li><strong>Die goldene Regel</strong><strong>:</strong> Zum Zeitpunkt <spanclass="math inline">t</span> nur Information von <spanclass="math inline">t</span>. Der Selbsttest mit manipulierter Zukunft prüft das automatisch.</li>
<li><strong>Rebalancing-Termine müssen Handelstage sein</strong> — sonst fallen bis zu 28 % still aus.</li>
<li><strong>Zählen Sie mit:</strong> geplante gegen ausgeführte Rebalancings, kumulierter Turnover, Gesamtkosten. Abweichungen sind Fehlerhinweise.</li>
<li><strong>Fünf Selbsttäuschungen:</strong> Lookahead, Survivorship, Kostenblindheit, Overfitting, Data Snooping. Die ersten drei stecken im Code und sind lesbar; die letzten beiden entstehen in der <strong>Arbeitsweise</strong> und hinterlassen im Programm keine Spur.</li>
<li><strong>Ohne die Zahl der ausprobierten Varianten ist kein Backtest-Ergebnis interpretierbar.</strong> Auf reinem Rauschen liefert die Beste von hundert Versuchen im Mittel Sharpe 1,13 bei p = 0,0094. Protokollieren Sie mit, korrigieren Sie die Schwelle (Bonferroni, Deflated Sharpe) — und halten Sie einen Zeitraum zurück, den Sie genau <strong>einmal</strong> verwenden.</li>
<li><strong>Rendite und Sharpe verlieren die Reihenfolge.</strong> Dieselben Tagesrenditen können zu einem Rückschlag von 19 % oder 98 % führen. Berichten Sie den maximalen Rückschlag immer mit.</li>
<li><strong>Ein guter Backtest ist notwendig, nicht hinreichend.</strong> Zwischen ihm und dem Betrieb liegen Papierhandel, Kapazitätsanalyse und Betriebsrisiken.</li>
</ul>
<p><strong>Ausblick.</strong><ahref="praxisfallen.html#kap-praxisfallen">Kapitel 22</a> zieht die Summe aus allen Teilen: die typischen Praxisfallen und der Weg vom Skript zum produktiven System.</p>
<navclass="prev-next"><aclass="prev-next-knopf prev-next-prev"href="cvar.html"><svgclass="icon"aria-hidden="true"><usehref="#icon-chevron-left"></use></svg><span><small>Zurück</small>Kapitel 20: Tail-Risiko, CVaR und Transaktionskosten</span></a><aclass="prev-next-knopf prev-next-next"href="praxisfallen.html"><span><small>Weiter</small>Kapitel 22: Praxisfallen und der Weg zum produktiven Einsatz</span><svgclass="icon"aria-hidden="true"><usehref="#icon-chevron-right"></use></svg></a></nav>