Glossar-Links: Fachbegriffe im Fließtext automatisch verlinken
Auto-Linking im Build: Glossar-Begriffe werden im Fließtext automatisch
erkannt und als Link auf den Glossar-Eintrag gesetzt — erste Nennung je
Begriff je Datei, dezent gestrichelte Unterstreichung im HTML, hyperref
im PDF. Kein manuelles Markieren bei Textänderungen nötig.
Neue Infrastruktur:
- glossar_eintraege_04.py: glossar_slug() + LINK_TEXTE-Map (automatisch
generiert aus EINTRAEGEN + Abkürzungs-Extraktion)
- erzeuge_glossar_04.py: jeder Eintrag bekommt {#gloss:<slug>}-Anchor
- build_version_04.py: resolve_glossar() — Auto-Linking + {gl:}-Marke
- web_04/site.css: .glossar-link (dezent, nicht wie Navigationslink)
5 neue Glossar-Einträge (waren als Begriff im Text, aber nicht im Glossar):
Solver, Scheduling, Graphen, Backtest, DCP (Disciplined Convex Programming)
Schutzmechanismen:
- Code-Blöcke, Inline-Code, {idx:}/{ref:}-Marken, Markdown-Links und
Überschriften werden nicht verlinkt
- Verschachtelung verhindert: 'CP-SAT-Solver' als Ganzes, nicht 'CP'+[
-'SAT'+[-'Solver'
- 'OR' als 2-Zeichen-Abkürzung nicht auto-verlinkt (False Positive in
'OR-Tools'); {gl:OR} als manuelle Marke
- Glossar selbst nicht auto-verlinkt (sonst Self-Links)
- reflow_markdown(): ::: als Block-Grenze (sonst kollabiert fenced div)
619 Glossar-Links im Gesamtdokument, 239 Anchor im Glossar, 34 im Vorwort.
This commit is contained in:
parent
81ddb02d5c
commit
e8abb66d75
52 changed files with 4316 additions and 1921 deletions
20
OR_HTML_04/dynamische-programmierung.html
generated
20
OR_HTML_04/dynamische-programmierung.html
generated
|
|
@ -103,9 +103,9 @@
|
|||
<div class="card card-blick">
|
||||
<blockquote>
|
||||
<p><strong>📌 Kapitel auf einen Blick</strong></p>
|
||||
<p><strong>Worum geht es?</strong> Um Entscheidungsketten: Was heute klug ist, hängt davon ab, was morgen noch möglich sein wird. Die Bellman-Gleichung löst solche Probleme durch Rückwärtsrechnen.</p>
|
||||
<p><strong>Worum geht es?</strong> Um Entscheidungsketten: Was heute klug ist, hängt davon ab, was morgen noch möglich sein wird. Die <a href="anhang-glossar.md#gloss:bellman-gleichung" class="glossar-link">Bellman-Gleichung</a> löst solche Probleme durch Rückwärtsrechnen.</p>
|
||||
<p><strong>Voraussetzungen:</strong> <a href="unsicherheit.html#kap-unsicherheit">Kapitel 12</a> (Erwartungswerte). Rekursion in Python.</p>
|
||||
<p><strong>Danach können Sie:</strong> Ein mehrperiodiges Problem in Zustände und Stufen zerlegen, die Wertfunktion durch Rückwärtsinduktion berechnen, die optimale Strategie ableiten — und prüfen, ob Ihr Zustand vollständig genug ist.</p>
|
||||
<p><strong>Danach können Sie:</strong> Ein mehrperiodiges Problem in Zustände und Stufen zerlegen, die Wertfunktion durch <a href="anhang-glossar.md#gloss:rueckwaertsinduktion" class="glossar-link">Rückwärtsinduktion</a> berechnen, die optimale Strategie ableiten — und prüfen, ob Ihr Zustand vollständig genug ist.</p>
|
||||
<p><strong>Zeitbedarf:</strong> ca. 5 Stunden.</p>
|
||||
<p><strong>Programme:</strong><br />
|
||||
<code>Bellman_Minimalbeispiel.py</code><br />
|
||||
|
|
@ -225,7 +225,7 @@ Restkosten je Ort: {'Ziel': 0, 'Ost': 5, 'West': 8, '
|
|||
<blockquote>
|
||||
<p><strong>🎯 Merksatz</strong> Eine Entscheidung ist nie für sich zu bewerten, sondern nur <strong>zusammen mit allem, was danach kommt</strong>. Genau das leistet die Wertfunktion: Sie fasst die gesamte Zukunft eines Zustands in einer einzigen Zahl zusammen. Und weil man die Zukunft kennen muss, bevor man die Gegenwart bewerten kann, rechnet dynamische Programmierung <strong>rückwärts</strong>.</p>
|
||||
</blockquote>
|
||||
<p><strong>Warum funktioniert das?</strong> Weil man den Rest des Weges nicht neu durchdenken muss, sobald man einmal an einem Ort steht: Wie man dorthin gekommen ist, ist für die Zukunft egal. Diese Eigenschaft heißt <strong>Bellmansches Optimalitätsprinzip</strong> und ist der Grund, warum aus einem Problem mit exponentiell vielen Wegen eine Rechnung mit wenigen Zeilen wird. Bei fünf Orten fällt das kaum auf — bei fünfzig ist es der Unterschied zwischen Sekunden und Jahren.</p>
|
||||
<p><strong>Warum funktioniert das?</strong> Weil man den Rest des Weges nicht neu durchdenken muss, sobald man einmal an einem Ort steht: Wie man dorthin gekommen ist, ist für die Zukunft egal. Diese Eigenschaft heißt <strong>Bellmansches <a href="anhang-glossar.md#gloss:optimalitaetsprinzip" class="glossar-link">Optimalitätsprinzip</a></strong> und ist der Grund, warum aus einem Problem mit exponentiell vielen Wegen eine Rechnung mit wenigen Zeilen wird. Bei fünf Orten fällt das kaum auf — bei fünfzig ist es der Unterschied zwischen Sekunden und Jahren.</p>
|
||||
<hr />
|
||||
<h2 id="sec:dynamische-programmierung-lernziele">13.2 Lernziele</h2>
|
||||
<p>Nach diesem Kapitel können Sie …</p>
|
||||
|
|
@ -234,9 +234,9 @@ Restkosten je Ort: {'Ziel': 0, 'Ost': 5, 'West': 8, '
|
|||
<li>… Zustand, Stufe, Aktion und Wertfunktion für ein gegebenes Problem benennen.</li>
|
||||
<li>… eine Rückwärtsinduktion von Hand für ein kleines Problem durchführen.</li>
|
||||
<li>… das Almgren-Chriss-Ausführungsproblem lösen und die Lösung interpretieren.</li>
|
||||
<li>… einschätzen, wann DP funktioniert und wann der „Fluch der Dimensionalität“ zuschlägt.</li>
|
||||
<li>… einschätzen, wann <a href="anhang-glossar.md#gloss:dynamische-programmierung-dp" class="glossar-link">DP</a> funktioniert und wann der „<a href="anhang-glossar.md#gloss:fluch-der-dimensionalitaet" class="glossar-link">Fluch der Dimensionalität</a>“ zuschlägt.</li>
|
||||
<li>… die Wertfunktion als <strong>Nachschlagetabelle</strong> lesen: Sie liefert keine Planfolge, sondern eine Regel, die auch bei Abweichungen gilt.</li>
|
||||
<li>… einen Zustandsraum auf Vollständigkeit prüfen und erkennen, wann eine Kostenart Vorgeschichte erfordert.</li>
|
||||
<li>… einen <a href="anhang-glossar.md#gloss:zustandsraum" class="glossar-link">Zustandsraum</a> auf Vollständigkeit prüfen und erkennen, wann eine Kostenart Vorgeschichte erfordert.</li>
|
||||
</ol>
|
||||
<hr />
|
||||
<h2 id="sec:dynamische-programmierung-das-bellmansche-optimalitaetsprinzip">13.3 Das Bellmansche Optimalitätsprinzip</h2>
|
||||
|
|
@ -553,7 +553,7 @@ V_t(S_t) = \min_{a_t\in\mathcal{A}(S_t)}\Big\{\,C(S_t,a_t) \;+\; \gamma\cdot\mat
|
|||
C(n_t, X_t) = \underbrace{\eta\,n_t^2}_{\text{Marktauswirkung}} \;+\; \underbrace{\lambda\,\sigma^2 X_t^2}_{\text{Risiko des Restbestands}}
|
||||
</span></p>
|
||||
<blockquote>
|
||||
<p><strong>📐 Formel-Lesehilfe</strong> * <span class="math inline">n_t</span> — in Periode <span class="math inline">t</span> verkaufte Stückzahl. Quadriert, weil doppelte Menge mehr als doppelten Preisdruck erzeugt. * <span class="math inline">\eta</span> („eta“) — Slippage-Koeffizient. Wie stark reagiert der Markt auf Volumen? * <span class="math inline">X_t</span> — Restbestand <strong>nach</strong> dem Verkauf. Quadriert, weil Varianz quadratisch mit der Positionsgröße wächst. * <span class="math inline">\lambda</span> — Risikoaversion: Wie sehr stört mich Schwankung im Vergleich zu Slippage? * <span class="math inline">\sigma</span> — Volatilität je Periode.</p>
|
||||
<p><strong>📐 Formel-Lesehilfe</strong> * <span class="math inline">n_t</span> — in Periode <span class="math inline">t</span> verkaufte Stückzahl. Quadriert, weil doppelte Menge mehr als doppelten Preisdruck erzeugt. * <span class="math inline">\eta</span> („eta“) — Slippage-Koeffizient. Wie stark reagiert der Markt auf Volumen? * <span class="math inline">X_t</span> — Restbestand <strong>nach</strong> dem Verkauf. Quadriert, weil Varianz quadratisch mit der Positionsgröße wächst. * <span class="math inline">\lambda</span> — Risikoaversion: Wie sehr stört mich Schwankung im Vergleich zu Slippage? * <span class="math inline">\sigma</span> — <a href="anhang-glossar.md#gloss:volatilitaet" class="glossar-link">Volatilität</a> je Periode.</p>
|
||||
<p><strong>Ohne Formel gesagt:</strong> „Schnell verkaufen kostet Preisabschlag. Langsam verkaufen kostet Nervenkitzel. Finde die Mitte.“</p>
|
||||
<p><strong>Die zwei Extremfälle:</strong> * <span class="math inline">\lambda \to 0</span> (risikoneutral): gleichmäßiges Aufteilen auf alle Perioden minimiert <span class="math inline">\sum n_t^2</span> bei fester Summe. * <span class="math inline">\lambda \to \infty</span> (extrem risikoscheu): sofort alles verkaufen, um kein Risiko zu tragen.</p>
|
||||
</blockquote>
|
||||
|
|
@ -561,7 +561,7 @@ C(n_t, X_t) = \underbrace{\eta\,n_t^2}_{\text{Marktauswirkung}} \;+\; \underbrac
|
|||
<p><strong>⚠️ Zur Kalibrierung des Risikoparameters</strong></p>
|
||||
<p>Ein häufiger Fehler ist ein undokumentierter Skalierungsfaktor im Risikoterm, etwa:</p>
|
||||
<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>holding_risk <span class="op">=</span> risk_aversion <span class="op">*</span> (sigma_period <span class="op">**</span> <span class="dv">2</span>) <span class="op">*</span> (remaining <span class="op">**</span> <span class="dv">2</span>) <span class="op">*</span> <span class="fl">1e5</span></span></code></pre></div>
|
||||
<p>Woher eine solche Zahl kommt, bleibt dann unklar. Faktisch wirkt sie als versteckte Erhöhung der Risikoaversion um fünf Größenordnungen — ein Parameter wie <code>risk_aversion = 1e-6</code> würde dann in Wahrheit <span class="math inline">0{,}1</span> bedeuten. Solche „magischen Zahlen“ machen ein Modell unkalibrierbar: Niemand kann sagen, ob 1e-6 viel oder wenig ist.</p>
|
||||
<p>Woher eine solche Zahl kommt, bleibt dann unklar. Faktisch wirkt sie als versteckte Erhöhung der Risikoaversion um fünf Größenordnungen — ein <a href="anhang-glossar.md#gloss:parameter" class="glossar-link">Parameter</a> wie <code>risk_aversion = 1e-6</code> würde dann in Wahrheit <span class="math inline">0{,}1</span> bedeuten. Solche „magischen Zahlen“ machen ein Modell unkalibrierbar: Niemand kann sagen, ob 1e-6 viel oder wenig ist.</p>
|
||||
<p><strong>Der Parameter lässt sich stattdessen herleiten.</strong> Beide Kostenterme werden in <strong>Euro</strong> gerechnet: * Marktauswirkung: <span class="math inline">\eta \cdot n_t^2</span> mit <span class="math inline">\eta</span> in €/Stück². * Risiko: <span class="math inline">\tfrac{\lambda}{2}\cdot \sigma_{\text{Periode}}^2 \cdot P_0^2 \cdot X_t^2</span> — die Varianz des Werts der offenen Position, multipliziert mit der Risikoaversion.</p>
|
||||
<p>Durch die Multiplikation mit <span class="math inline">P_0^2</span> (dem Quadrat des Aktienkurses) stimmen die Einheiten, und <span class="math inline">\lambda</span> wird interpretierbar: Es ist der Preis, den man je Einheit Wertvarianz zu zahlen bereit ist.</p>
|
||||
</blockquote>
|
||||
|
|
@ -819,7 +819,7 @@ Abweichung DP zur analytischen Loesung: 5.788 % (Diskretisierung: 1000 Stueck)
|
|||
1e-03 | 97,000 ( 97.0 %) | fast alles sofort
|
||||
====================================================================================</code></pre>
|
||||
<p><strong>Die Lösung ist <em>front-loaded</em>:</strong> 41 % im ersten Schritt, dann fallend (25 %, 16 %, 10 %, 8 %). Das ist die typische Form — man baut Risiko früh ab, aber nicht abrupt. Die Sensitivitätstabelle zeigt, wie <span class="math inline">\lambda</span> zwischen den beiden Extremen steuert: Bei <span class="math inline">\lambda = 10^{-7}</span> verkauft das Modell gleichmäßig (Risiko ist egal), bei <span class="math inline">\lambda = 10^{-3}</span> praktisch alles sofort (Risiko dominiert).</p>
|
||||
<p>Der Vergleich beziffert den Nutzen: Gegenüber der naiven TWAP-Strategie (gleiche Tranchen) spart die optimierte Ausführung <strong>2 976 €</strong> oder 6 Basispunkte — bei einer Position von 5 Mio. €. Gegenüber „alles sofort“ sind es 14 734 €.</p>
|
||||
<p>Der Vergleich beziffert den Nutzen: Gegenüber der naiven <a href="anhang-glossar.md#gloss:twap" class="glossar-link">TWAP</a>-Strategie (gleiche Tranchen) spart die optimierte Ausführung <strong>2 976 €</strong> oder 6 Basispunkte — bei einer Position von 5 Mio. €. Gegenüber „alles sofort“ sind es 14 734 €.</p>
|
||||
<blockquote>
|
||||
<p><strong>💻 Code-Durchgang: die analytische Gegenprobe und was ihre Abweichung bedeutet</strong></p>
|
||||
<p>Das Almgren-Chriss-Problem hat eine <strong>geschlossene Lösung</strong>: <span class="math display">X_t = X_0\,\frac{\sinh(\kappa(T-t))}{\sinh(\kappa T)}, \qquad \kappa = \operatorname{arcosh}\!\Big(\tfrac{\tilde\kappa^2}{2}+1\Big),\qquad \tilde\kappa^2 = \frac{\lambda\,\sigma^2 P_0^2}{\eta}</span></p>
|
||||
|
|
@ -876,7 +876,7 @@ Abweichung DP zur analytischen Loesung: 5.788 % (Diskretisierung: 1000 Stueck)
|
|||
</tbody>
|
||||
</table>
|
||||
<p><strong>Das ist der Fluch der Dimensionalität</strong> (Bellmans eigener Begriff): Jede zusätzliche Zustandsvariable <strong>multipliziert</strong> den Aufwand.</p>
|
||||
<p><strong>Gegenmittel:</strong> * <strong>Zustandsraum</strong> <strong>verkleinern:</strong> gröber diskretisieren, irrelevante Variablen weglassen. * <strong>Approximate Dynamic Programming</strong><strong>:</strong> <span class="math inline">V_t</span> durch eine parametrische Funktion annähern statt tabellarisch zu speichern. * <strong>Reinforcement Learning</strong><strong>:</strong> dieselbe Bellman-Gleichung, aber <span class="math inline">V</span> wird aus Erfahrung gelernt (Q-Learning) statt vollständig berechnet. * <strong>Nach geschlossenen Lösungen suchen</strong> — wie bei Almgren-Chriss. Wo eine Formel existiert, ist sie unschlagbar.</p>
|
||||
<p><strong>Gegenmittel:</strong> * <strong>Zustandsraum</strong> <strong>verkleinern:</strong> gröber diskretisieren, irrelevante Variablen weglassen. * <strong><a href="anhang-glossar.md#gloss:approximate-dynamic-programming" class="glossar-link">Approximate Dynamic Programming</a></strong><strong>:</strong> <span class="math inline">V_t</span> durch eine parametrische Funktion annähern statt tabellarisch zu speichern. * <strong><a href="anhang-glossar.md#gloss:reinforcement-learning" class="glossar-link">Reinforcement Learning</a></strong><strong>:</strong> dieselbe Bellman-Gleichung, aber <span class="math inline">V</span> wird aus Erfahrung gelernt (<a href="anhang-glossar.md#gloss:q-learning" class="glossar-link">Q-Learning</a>) statt vollständig berechnet. * <strong>Nach geschlossenen Lösungen suchen</strong> — wie bei Almgren-Chriss. Wo eine Formel existiert, ist sie unschlagbar.</p>
|
||||
<hr />
|
||||
<h2 id="sec:dynamische-programmierung-uebungsaufgaben">13.6 Übungsaufgaben</h2>
|
||||
<blockquote>
|
||||
|
|
@ -885,7 +885,7 @@ Abweichung DP zur analytischen Loesung: 5.788 % (Diskretisierung: 1000 Stueck)
|
|||
<p><strong>Aufgabe 13.1 ⭐ — Bausteine benennen.</strong> Ein Wanderer plant eine 5-Tages-Tour und muss täglich entscheiden, wie weit er läuft. Bestimmen Sie Stufe, Zustand, Aktion und Wertfunktion. Was gehört <strong>nicht</strong> in den Zustand?</p>
|
||||
<p><strong>Aufgabe 13.2 ⭐ — Optimalitätsprinzip anwenden.</strong> Warum folgt aus dem Optimalitätsprinzip, dass man rückwärts rechnen darf? Was würde schiefgehen, wenn die Kosten einer Periode auch von <strong>früheren</strong> Aktionen abhängen (und nicht nur vom aktuellen Zustand)?</p>
|
||||
<p><strong>Aufgabe 13.3 ⭐⭐ — Rückwärtsinduktion von Hand.</strong> 5 Einheiten in 3 Perioden, Kosten <span class="math inline">C(n) = n^2 + 2n</span>. Erstellen Sie die vollständige Wertfunktionstabelle und bestimmen Sie den optimalen Pfad. Prüfen Sie mit <code>Bellman_Minimalbeispiel.py</code> (angepasst).</p>
|
||||
<p><strong>Aufgabe 13.4 ⭐⭐ — Rucksackproblem als DP.</strong> Lösen Sie das Rucksackproblem aus <a href="milp.html#kap-milp">Kapitel 6</a> mit dynamischer Programmierung statt MILP. (Zustand: verbleibende Kapazität; Stufe: betrachteter Gegenstand.) Vergleichen Sie Laufzeit und Ergebnis mit dem MILP-Solver.</p>
|
||||
<p><strong>Aufgabe 13.4 ⭐⭐ — <a href="anhang-glossar.md#gloss:rucksackproblem" class="glossar-link">Rucksackproblem</a> als DP.</strong> Lösen Sie das Rucksackproblem aus <a href="milp.html#kap-milp">Kapitel 6</a> mit dynamischer Programmierung statt <a href="anhang-glossar.md#gloss:gemischt-ganzzahlige-optimierung-milp" class="glossar-link">MILP</a>. (Zustand: verbleibende Kapazität; Stufe: betrachteter Gegenstand.) Vergleichen Sie Laufzeit und Ergebnis mit dem MILP-<a href="anhang-glossar.md#gloss:solver" class="glossar-link">Solver</a>.</p>
|
||||
<p><strong>Aufgabe 13.5 ⭐⭐⭐ — Risikoaversion kalibrieren.</strong> Untersuchen Sie mit <code>Mehrperiodige_Order_Execution.py</code>: (a) Bei welchem <span class="math inline">\lambda</span> verkauft das Modell in der ersten Periode mehr als 50 %? (b) Stellen Sie den Zusammenhang zwischen <span class="math inline">\lambda</span> und den erwarteten Gesamtkosten dar. (c) Ein Händler sagt: „Ich will höchstens 20 % Marktauswirkungskosten und den Rest an Risiko.“ Welches <span class="math inline">\lambda</span> setzen Sie?</p>
|
||||
<p><strong>Aufgabe 13.6 ⭐⭐⭐ — Zustandsraum erweitern.</strong> Erweitern Sie das Ausführungsmodell um einen zweiten Zustand: die aktuelle <strong>Orderbuchtiefe</strong> (3 Stufen: dünn/normal/tief), die mit gegebenen Übergangswahrscheinlichkeiten wechselt und <span class="math inline">\eta</span> um Faktor 2 / 1 / 0,5 skaliert. Wie ändert sich die Strategie? Wie stark wächst die Rechenzeit?</p>
|
||||
<hr />
|
||||
|
|
|
|||
Loading…
Reference in a new issue