σμimplied vol · KKmax(S−K,0)udβρᵢⱼfat tailsPnL · drawdownyield · TdSₜ = μSₜ dt + σSₜ dWₜC = S·N(d₁) − K·e⁻ʳᵀ·N(d₂)σₚ² = wᵀΣwd₁ = [ln(S/K) + (r + σ²⁄2)T] ⁄ σ√T∂V/∂t + ½σ²S²·∂²V/∂S² + rS·∂V/∂S − rV = 0Sharpe = (Rₚ − R_f) ⁄ σₚVaR₉₉ = μ − 2.33σρ = Cov(X,Y) ⁄ σₓσᵧE[Rₚ] = Σ wᵢ·E[Rᵢ]φ(x) = e^(−x²/2) ⁄ √2πE[Rᵢ] = R_f + βᵢ(E[Rₘ] − R_f)dXₜ = θ(μ − Xₜ)dt + σ dWₜσ²ₜ = ω + α·ε²ₜ₋₁ + β·σ²ₜ₋₁C − P = S − K·e⁻ʳᵀΔ = ∂V/∂S Γ = ∂²V/∂S²p = (e^(rΔt) − d) ⁄ (u − d)rₜ = ln(Pₜ ⁄ Pₜ₋₁)E[Xₜ₊₁ | ℱₜ] = Xₜf* = (bp − q) ⁄ bz = (x − μ) ⁄ σP(N=k) = λᵏe^(−λ) ⁄ k!Θ = −∂V/∂Tν = S·φ(d₁)·√Tmin wᵀΣw s.t. wᵀμ = μ*∫Σ∂∞λ
σμimplied vol · KKmax(S−K,0)udβρᵢⱼfat tailsPnL · drawdownyield · TdSₜ = μSₜ dt + σSₜ dWₜC = S·N(d₁) − K·e⁻ʳᵀ·N(d₂)σₚ² = wᵀΣwd₁ = [ln(S/K) + (r + σ²⁄2)T] ⁄ σ√T∂V/∂t + ½σ²S²·∂²V/∂S² + rS·∂V/∂S − rV = 0Sharpe = (Rₚ − R_f) ⁄ σₚVaR₉₉ = μ − 2.33σρ = Cov(X,Y) ⁄ σₓσᵧE[Rₚ] = Σ wᵢ·E[Rᵢ]φ(x) = e^(−x²/2) ⁄ √2πE[Rᵢ] = R_f + βᵢ(E[Rₘ] − R_f)dXₜ = θ(μ − Xₜ)dt + σ dWₜσ²ₜ = ω + α·ε²ₜ₋₁ + β·σ²ₜ₋₁C − P = S − K·e⁻ʳᵀΔ = ∂V/∂S Γ = ∂²V/∂S²p = (e^(rΔt) − d) ⁄ (u − d)rₜ = ln(Pₜ ⁄ Pₜ₋₁)E[Xₜ₊₁ | ℱₜ] = Xₜf* = (bp − q) ⁄ bz = (x − μ) ⁄ σP(N=k) = λᵏe^(−λ) ⁄ k!Θ = −∂V/∂Tν = S·φ(d₁)·√Tmin wᵀΣw s.t. wᵀμ = μ*∫Σ∂∞λ
uantCraft AcademySkills
Ctrl K
AO
+1,2 Tsd. Lernende
AnmeldenBeitreten ↗
Skills
AO
+1,2 Tsd. Lernende
Anmelden
  • English
  • Français
  • Español
  • العربية
  • Português
  • Deutsch
  • 日本語
  • 中文
Python-Skill›Modul 5 · Portfoliooptimierung›Thema 5.3·~50 Min.Mittelstufe

Minimum-Varianz-Portfolio

Position in der SkillModul 5 von 11 · Thema 3 von 5
5.3 Minimum-Varianz-Portfolio
—Lab-Punkte— / 100XP gesamt—Serie—

Die sicherste Mischung

Das Kombinieren von Assets senkt das Risiko, aber wie stark, hängt von den Gewichten ab. Das Minimum-Varianz-Portfolio ist die Wahl der Gewichte mit Summe 1, die die kleinstmögliche Varianz hat. Es braucht keine Renditeprognose, nur die Kovarianzmatrix, was es beliebt macht: Erwartete Renditen sind sehr schwer zu schätzen, Kovarianzen deutlich weniger. Für zwei Assets ist die Antwort eine Formel, für viele die Lösung eines linearen Gleichungssystems.

# Two assets: volatility 20% and 10%, correlation 0.3
def variance(w, vol1, vol2, rho):
    return w * w * vol1 ** 2 + (1 - w) ** 2 * vol2 ** 2 + 2 * w * (1 - w) * rho * vol1 * vol2

vol1, vol2, rho = 0.20, 0.10, 0.3
w = (vol2 ** 2 - rho * vol1 * vol2) / (vol1 ** 2 + vol2 ** 2 - 2 * rho * vol1 * vol2)
print(round(w, 4), round(variance(w, vol1, vol2, rho) ** 0.5, 4))        # 0.1053 0.0979
print(round(variance(0.0, vol1, vol2, rho) ** 0.5, 4))                   # 0.1      all in the safe asset: riskier than the mix

Viele Assets: ein lineares System

Um w @ cov @ w unter der Nebenbedingung sum(w) = 1 zu minimieren, setzt man die Ableitung der Lagrange-Funktion null. Das Ergebnis ist w = cov^-1 * 1 / (1' cov^-1 1): Man löst das System cov @ x = ones und skaliert x, sodass die Gewichte sich zu 1 summieren. Die minimale Varianz selbst ist 1 / (1' cov^-1 1). Im Code nimmt man np.linalg.solve(cov, ones), nicht np.linalg.inv(cov) @ ones: schneller und genauer, weil die Inverse nie gebildet wird.

# Minimum-variance weights of three assets
import numpy as np

cov = np.array([[0.0400, 0.0060, 0.0100],
                [0.0060, 0.0100, 0.0020],
                [0.0100, 0.0020, 0.0225]])

x = np.linalg.solve(cov, np.ones(3))
weights = x / x.sum()
print(np.round(weights, 4), round(float(weights.sum()), 4))        # [0.0192 0.7082 0.2726] 1.0
print(round(float(weights @ cov @ weights), 6), round(1 / float(x.sum()), 6))      # 0.007742 twice: the same number
# No other mix with weights summing to 1 does better: try 5000 random ones
import numpy as np

cov = np.array([[0.0400, 0.0060, 0.0100],
                [0.0060, 0.0100, 0.0020],
                [0.0100, 0.0020, 0.0225]])
x = np.linalg.solve(cov, np.ones(3))
best = x / x.sum()

rng = np.random.default_rng(0)
trial = rng.normal(size=(5000, 3))
trial = trial / trial.sum(axis=1, keepdims=True)                  # each row sums to 1
variances = np.einsum("ij,jk,ik->i", trial, cov, trial)            # w @ cov @ w for every row
print(round(float(variances.min()), 6), round(float(best @ cov @ best), 6))
print(bool(variances.min() >= best @ cov @ best))                  # True

Shorts und Nebenbedingungen

Die Formel erlaubt negative Gewichte: Sie kann ein Asset leerverkaufen, um ein anderes abzusichern. Viele Anleger können oder wollen das nicht und wollen Long-only-Gewichte. Negative Gewichte auf null zu setzen und neu zu skalieren ist eine schnelle Notlösung, die gültige Gewichte liefert, aber nicht das echte Long-only-Optimum, für das ein numerischer Löser (quadratische Programmierung) nötig ist, weil die Bedingung w >= 0 das Problem zu einem mit Ungleichungsnebenbedingungen macht. Das gekappte Portfolio ist immerhin haltbar und leicht mit dem freien zu vergleichen.

# The unconstrained solution shorts an asset; clip it and compare the risks
import numpy as np

cov = np.array([[0.04, 0.0342, 0.0],
                [0.0342, 0.0324, 0.0],
                [0.0, 0.0, 0.0225]])        # assets 1 and 2: volatility 20% and 18%, correlation 0.95

x = np.linalg.solve(cov, np.ones(3))
free = x / x.sum()
clipped = np.clip(free, 0, None)
clipped = clipped / clipped.sum()
print(np.round(free, 4), round(float(free @ cov @ free), 6))
print(np.round(clipped, 4), round(float(clipped @ cov @ clipped), 6))
In der Theorie optimal, in der Praxis fragilDie Gewichte nutzen die Inverse der Kovarianzmatrix, die Fehler verstärkt: Assets, die in der Stichprobe etwas weniger korreliert oder weniger volatil wirken, erhalten große Gewichte, oft mit großen Shorts, und die Gewichte springen, wenn sich das Datenfenster verschiebt. Praktiker schrumpfen die Kovarianzschätzung, begrenzen die Gewichte oder fügen eine Strafe hinzu. Ein Minimum-Varianz-Portfolio, das auf den Anpassungsdaten glänzt, testet man an späteren Daten, nicht an derselben Stichprobe.
  • Minimale Varianz braucht nur die Kovarianzmatrix: für zwei Assets (vol2**2 - rho * vol1 * vol2) / (vol1**2 + vol2**2 - 2 * rho * vol1 * vol2) in Asset 1.
  • Allgemein w = solve(cov, ones) / sum(...), die minimale Varianz ist 1 / (1' cov^-1 1); nehmen Sie np.linalg.solve, nicht die Inverse.
  • Die freie Lösung kann Assets leerverkaufen; Kappen auf null und Neuskalieren ist eine schnelle Notlösung, nicht das echte Optimum, und die Gewichte reagieren empfindlich auf Schätzfehler.

Als Nächstes: Mittelwert-Varianz-Optimierung, die erwarteten Renditen hinzunehmen und den besten Kompromiss zwischen Rendite und Risiko finden.

Lab: Was bewertet wird

  • Mit two_asset_weight zwei Assets risikoärmstmöglich mischen25 Pkt.
  • Mit min_variance_weights die sichersten Gewichte lösen25 Pkt.
  • Mit min_variance das geringste Risiko angeben25 Pkt.
  • Mit long_only_weights die Shorts entfernen25 Pkt.
Explorer · lab-84-1
▾ lab-84-1
…
bash · im Browser
learner@quantcraft:~/lab-84-1$
Python noch nicht geladenPythonLn 1, Col 1Spaces: 4UTF-8

Dieses Thema zurücksetzen?

Alles in lab-84-1 wird auf die Startdateien zurückgesetzt und das Terminal geleert. Ihre aktuelle Lösung geht verloren – das lässt sich nicht rückgängig machen.

Wird zurückgesetzt
  • main.py → Startcode
  • Terminal-Verlauf und Testausgabe
  • Nicht eingereichte Änderungen
Bleibt erhalten
  • Beste Lab-Punktzahl
  • Ihre XP und Ihre Serie
  • Vorlesungsfortschritt und Notizen

Melde dich an, um deinen Code auszuführen.

Alle Lektionen kannst du kostenlos lesen. Erstelle ein Konto oder melde dich an, um Code auszuführen, Tests zu starten und dieses Lab abzugeben.

  • IDE im Browser mit Bash-Terminal — nichts zu installieren
  • Sofortige Bewertung, XP und dein Platz auf der Skill
Konto erstellenAnmelden
ODER
Weiter mit GitHub