σμ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 3 · Wahrscheinlichkeit & Monte-Carlo-Simulation›Thema 3.3·~45 Min.Mittelstufe

Fat Tails und Normalitätstests

Position in der SkillModul 3 von 11 · Thema 3 von 12
3.3 Fat Tails und Normalitätstests
—Lab-Punkte— / 100XP gesamt—Serie—

Was die Glockenkurve verspricht

Viele Risikomodelle nehmen normalverteilte Renditen an, weil sich damit alles mit Mittelwert und Standardabweichung berechnen lässt. Die Normalverteilung ist bei Extremen sehr präzise. Die Wahrscheinlichkeit, mehr als k Standardabweichungen vom Mittel entfernt zu sein, in beide Richtungen, ist erfc(k / sqrt(2)): 31,7 % für 1, 4,55 % für 2, 0,27 % für 3, 0,0063 % für 4. Ein 4-Sigma-Tag träte danach etwa einmal in 15.800 Handelstagen auf, also ungefähr einmal in 63 Jahren, ein 5-Sigma-Tag einmal in mehreren tausend Jahren.

import math
import numpy as np

for k in (1, 2, 3, 4, 5):
    probability = math.erfc(k / math.sqrt(2))      # P(|Z| > k) for a normal variable
    print(k, f"{probability:.2e}")
# 1 3.17e-01
# 2 4.55e-02
# 3 2.70e-03
# 4 6.33e-05
# 5 5.73e-07

print(round(1 / math.erfc(4 / math.sqrt(2))))                  # 15787   trading days between 4-sigma days, if returns were normal
print(round(1 / math.erfc(5 / math.sqrt(2)) / 252))            # 6922    years between 5-sigma days

Märkte haben schwere Ränder

Echte Märkte erzeugen 4- und 5-Sigma-Tage in einer Karriere viele Male, 1987, 2008, 2020. Ihre Renditeverteilungen haben schwere Ränder: mehr Extremtage, als die Glocke zulässt (und eine höhere, schmalere Mitte). Einfach sichtbar wird das am Tail Ratio: der beobachtete Anteil der Renditen jenseits von k Standardabweichungen geteilt durch den Anteil, den eine Normalverteilung ergäbe. Ein Verhältnis nahe 1 bedeutet normale Ränder; 5 bedeutet fünfmal zu häufige Extreme; bei Tagesdaten und k = 4 kann es in die Hunderte gehen. Risikomodelle mit Normalitätsannahme unterschätzen genau die Tage, die am meisten zählen.

returns = np.array([0.010, 0.012, 0.008, 0.011, 0.009, 0.010, 0.012, -0.060, 0.010, 0.009])

def tail_ratio(x, k):
    observed = np.mean(np.abs(x - x.mean()) > k * x.std(ddof=1))     # share beyond k standard deviations
    return observed / math.erfc(k / math.sqrt(2))                    # divided by what a normal would give

print(round(float(tail_ratio(returns, 2)), 2))    # 2.2   the one crash is 2.2 times too frequent at 2 sigma (a tiny sample, though)

Der Jarque-Bera-Test

Ein formaler Test fragt, ob die Stichprobe plausibel aus einer Normalverteilung stammen kann. Die Jarque-Bera-Statistik kombiniert die beiden Formmaße des vorigen Themas: JB = n / 6 * (S² + K² / 4), mit S der Schiefe und K der Exzess-Kurtosis. Bei einer normalen Stichprobe sind beide nahe 0, JB ist also klein. Unter Normalität folgt JB einer Chi-Quadrat-Verteilung mit 2 Freiheitsgraden, deren Rand die geschlossene Form exp(-JB / 2) hat: Das ist der p-Wert. Liegt er unter 0,05, wird die Normalität verworfen. Der kritische Wert ist JB = 5,99. Unsere 10-Tage-Stichprobe mit einem Crash hat JB = 22,4 und einen p-Wert von 0,00001.

x = returns
n = len(x)
deviations = x - x.mean()
m2, m3, m4 = (np.mean(deviations ** k) for k in (2, 3, 4))
skew, kurt = m3 / m2 ** 1.5, m4 / m2 ** 2 - 3

jb = n / 6 * (skew ** 2 + kurt ** 2 / 4)
p_value = math.exp(-jb / 2)
print(round(float(jb), 2), p_value < 0.05)     # 22.37 True   normality rejected
print(f"{p_value:.1e}")                         # 1.4e-05
# The p-value falls fast as the statistic grows: 5.99 is the 5% critical value
for jb in (0, 2, 5.99, 10, 22.37):
    print(jb, round(math.exp(-jb / 2), 5))
# 0 1.0
# 2 0.36788
# 5.99 0.05004
# 10 0.00674
# 22.37 1e-05
Die Normalität zu verwerfen ist nicht das EndeBei Hunderten täglicher Renditen verwirft der Test die Normalität für fast jeden Wert, eine Ablehnung ist also zu erwarten. Wichtig ist, wie stark die Ränder abweichen: Nutzen Sie das Tail Ratio, um das Problem zu bemessen, und machen Sie dann Stresstests mit echten Crashs, einer Verteilung mit schwereren Rändern wie der Student-t oder historische Simulation, statt einer Glockenkurve zu vertrauen.
  • Eine Normalvariable liegt mit Wahrscheinlichkeit erfc(k / sqrt(2)) mehr als k Standardabweichungen entfernt: 4,55 % bei 2, 0,0063 % bei 4.
  • Das Tail Ratio, beobachteter Anteil geteilt durch den normalen, zeigt schwere Ränder: Märkte liegen bei 4 Sigma weit über 1.
  • Jarque-Bera: n / 6 * (S**2 + K**2 / 4); der p-Wert ist exp(-JB / 2); unter 0,05 wird die Normalität verworfen (JB über 5,99).

Als Nächstes: Hypothesentests: der t-Test, um zu entscheiden, ob eine mittlere Rendite wirklich von null verschieden ist.

Lab: Was bewertet wird

  • Mit jarque_bera messen, wie weit eine Stichprobe von der Normalverteilung abweicht25 Pkt.
  • Mit normality_p_value die Prüfgröße in einen p-Wert umrechnen25 Pkt.
  • Mit normal_tail_probability berechnen, was die Glockenkurve verspricht25 Pkt.
  • Mit tail_ratio zählen, wie viel schwerer die Ränder sind25 Pkt.
Explorer · lab-56-1
▾ lab-56-1
…
bash · im Browser
learner@quantcraft:~/lab-56-1$
Python noch nicht geladenPythonLn 1, Col 1Spaces: 4UTF-8

Dieses Thema zurücksetzen?

Alles in lab-56-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