σμ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 7 · Alpha-Forschung und Risiko›Thema 7.4·~50 Min.Fortgeschritten

Historischer VaR

Position in der SkillModul 7 von 11 · Thema 4 von 9
7.4 Historischer VaR
—Lab-Punkte— / 100XP gesamt—Serie—

Eine Verlustgrenze mit Konfidenzniveau

Der Value at Risk antwortet: Wie viel kann ich an einem schlechten Tag verlieren, aber nicht am schlechtesten? Ein 1-Tages-VaR mit 95 % von 2 % sagt, dass der Verlust an 95 von 100 Tagen 2 % nicht übersteigen sollte. Die historische Methode braucht kein Modell. Man nimmt die vergangenen Renditen, sortiert sie und liest den Verlust am 5. Perzentil ab: Der VaR ist minus dieses Quantil. Aufseher und Risikolimits nutzen ihn überall, weil er eine einzige Zahl ist, die ein Manager mit einem Limit vergleichen kann.

import numpy as np

rng = np.random.default_rng(3)
returns = rng.normal(0.0004, 0.012, size=500)           # two years of daily returns

var_95 = -np.quantile(returns, 0.05)                    # minus the 5th percentile
var_99 = -np.quantile(returns, 0.01)
print(round(float(var_95), 5), round(float(var_99), 5))  # 0.01928 0.027  the 99% loss limit is larger

Einen VaR testen: die Überschreitungen

Ein VaR ist eine Prognose, kann also überprüft werden. Eine Überschreitung ist ein Tag, an dem der Verlust den VaR überstieg, return < -VaR. Bei einem 95-%-VaR erwartet man etwa 5 % der Tage als Überschreitungen: viel mehr heißt, das Modell unterschätzt das Risiko, viel weniger, dass es zu vorsichtig ist. Aufseher zählen Überschreitungen über 250 Tage genau deshalb. Beachten Sie die strikte Ungleichung: Ein Verlust gleich dem VaR ist keine Überschreitung.

import numpy as np

rng = np.random.default_rng(3)
returns = rng.normal(0.0004, 0.012, size=500)
var_95 = -np.quantile(returns, 0.05)

exceptions = int(np.sum(returns < -var_95))
print(exceptions, "exceptions in", len(returns), "days; expected about", int(0.05 * len(returns)))     # 25 25

Längere Horizonte, und wie es geschah

Oft wird ein 10-Tages-VaR verlangt. Bei unabhängigen Tagesrenditen wächst die Volatilität mit der Wurzel der Zeit, daher skaliert die Wurzel-aus-Zeit-Regel: VaR_T = VaR_1 * sqrt(T). Sie ist eine Näherung, schwächer bei dicken Rändern und autokorrelierten Renditen. Ehrliche Backtests achten auch auf die Zeit: Der an Tag t verwendete VaR darf nur Renditen vor Tag t nutzen, dieselbe Disziplin wie beim Vermeiden von Look-ahead. Ein rollierender VaR macht das mit einem Fenster der letzten n Tage.

# The square-root-of-time rule for several horizons
import math

one_day = 0.0186
for days in (1, 5, 10, 20):
    print(days, round(one_day * math.sqrt(days), 4))        # 1: 0.0186, 5: 0.0416, 10: 0.0588, 20: 0.0832
import numpy as np

def historical_var(returns, confidence):
    return float(-np.quantile(returns, 1 - confidence))

def rolling_var(returns, window, confidence):
    out = np.full(len(returns), np.nan)
    for t in range(window, len(returns)):
        out[t] = historical_var(returns[t - window:t], confidence)      # the days BEFORE day t
    return out

rng = np.random.default_rng(3)
returns = rng.normal(0.0004, 0.012, size=500)
rolling = rolling_var(returns, 250, 0.99)
print(np.isnan(rolling[:250]).all(), round(float(rolling[250]), 5), round(float(rolling[-1]), 5))
exceptions = int(np.sum(returns[250:] < -rolling[250:]))
print(exceptions, "exceptions in", len(returns) - 250, "days (about 2 expected at 99%)")
print(round(historical_var(returns, 0.99) * np.sqrt(10), 5))                 # a 10-day figure by the square-root rule
Was der VaR nicht verrätVaR ist eine Schwelle, kein Worst Case: Er sagt nichts darüber, wie schlimm die Verluste jenseits davon sind, weshalb die nächsten Themen Expected Shortfall und Stresstests behandeln. Die historische Methode ist so gut wie ihr Fenster: Zwei ruhige Jahre ergeben kurz vor einer Krise einen kleinen VaR, und die 99-%-Zahl beruht auf nur wenigen Beobachtungen.
  • Der historische VaR ist minus das (1 - confidence)-Quantil vergangener Renditen (np.quantile): ein positiver Verlustanteil ohne Modell.
  • Testen Sie durch Zählen der Überschreitungen (return < -VaR): etwa 1 - confidence der Tage; mehr heißt, der VaR ist zu niedrig.
  • Skalieren Sie mit var * sqrt(days) auf einen Horizont; ein rollierendes Fenster nutzt nur frühere Tage; der VaR liefert eine Schwelle, nicht die Größe der Verluste darüber.

Als Nächstes: parametrischer VaR, dieselbe Schwelle aus einer Normalverteilung statt aus der Rohhistorie berechnen.

Lab: Was bewertet wird

  • Mit historical_var den Verlust aus der Historie ablesen25 Pkt.
  • Mit var_exceptions die Überschreitungen zählen25 Pkt.
  • Mit scale_var den Horizont dehnen25 Pkt.
  • Mit rolling_var so schätzen, wie es geschah25 Pkt.
Explorer · lab-96-1
▾ lab-96-1
…
bash · im Browser
learner@quantcraft:~/lab-96-1$
Python noch nicht geladenPythonLn 1, Col 1Spaces: 4UTF-8

Dieses Thema zurücksetzen?

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