σμ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 11 · Produktivsysteme und Spitzenmodelle›Thema 11.7·~1 Std. 30 Min.Experte

Das Heston-Modell

Position in der SkillModul 11 von 11 · Thema 7 von 13
11.7 Das Heston-Modell
—Lab-Punkte— / 100XP gesamt—Serie—

Wenn auch die Volatilität sich bewegt

Black-Scholes nimmt konstante Volatilität an, aber die echte Volatilität steigt in Crashs und verblasst in ruhigen Zeiten, und der Optionsmarkt zeigt das: Die implizite Volatilität unterscheidet sich je Strike (das Smile oder der Skew). Das Heston-Modell behält den geometrischen Preisprozess bei, macht aber auch die *Varianz* v zufällig: Sie wird mit Geschwindigkeit kappa zu einem langfristigen Niveau theta zurückgezogen, von Rauschen der Größe xi geschüttelt, das mit sqrt(v) skaliert, und die Schocks von Preis und Varianz haben die Korrelation rho. Ein negatives rho (der Preis fällt, wenn die Volatilität steigt, der Leverage-Effekt) erzeugt den abwärts gerichteten Skew bei Aktienoptionen.

# The Heston equations, in words:  dS = mu S dt + sqrt(v) S dW      dv = kappa (theta - v) dt + xi sqrt(v) dZ      corr(dW, dZ) = rho
kappa, theta, xi = 2.0, 0.04, 0.3             # reversion speed, long-run variance (a 20% volatility), volatility of variance
print(round(theta ** 0.5, 2))                 # 0.2    the long-run volatility
print(2 * kappa * theta, xi ** 2)             # 0.16 0.09   the Feller condition 2 kappa theta >= xi^2 holds: the variance stays positive

Simulation: Abschneiden und Korrelation

Zur Simulation geht man in kleinen Intervallen dt voran. Das Varianz-Update lautet v + kappa * (theta - v) * dt + xi * sqrt(v * dt) * dz, aber ein einfacher Euler-Schritt kann v unter null drücken, wo die Wurzel versagt. Das Schema der vollen Abschneidung nutzt max(v, 0) überall, wo v rechts vorkommt (ein negativer Wert wirkt wie null), und behält das Rohergebnis für den nächsten Schritt. Die Feller-Bedingung 2 * kappa * theta >= xi^2 ist der Parameterbereich, in dem der wahre Prozess nie null erreicht; scheitert sie, zählt das Abschneiden noch mehr. Die beiden Schocks müssen korreliert sein: Ziehen Sie unabhängige Normalen z1, z2, setzen Sie dz = z1 und dw = rho * z1 + sqrt(1 - rho^2) * z2.

# One variance step with full truncation, and the correlated shocks for the price
import math

def variance_step(v, kappa, theta, xi, dz, dt):
    vp = max(v, 0.0)
    return v + kappa * (theta - vp) * dt + xi * math.sqrt(vp * dt) * dz

def correlated_normals(z1, z2, rho):
    return z1, rho * z1 + math.sqrt(1 - rho ** 2) * z2

print(round(variance_step(0.04, 2.0, 0.04, 0.3, 0.5, 1 / 252), 6))      # 0.04189   at the long-run level only the noise moves it
dz, dw = correlated_normals(1.0, 1.0, -0.7)
print(round(dz, 4), round(dw, 4))             # 1.0 0.0141   a negative rho: the price shock pulls against the variance shock
print(variance_step(-0.01, 2.0, 0.04, 0.3, 1.0, 1 / 252))               # -0.00968...   still negative, but it moved up by kappa * theta * dt: the negative value acted as 0

Ein ganzer Pfad und eine Plausibilitätsprüfung

Ein Schritt aktualisiert beide Zustandsvariablen gemeinsam: Der Preis nutzt die Varianz zu *Beginn* des Schritts, S * exp((mu - v/2) * dt + sqrt(v * dt) * dw), danach bewegt sich die Varianz. Wiederholen Sie das für die Zahl der Schritte im Horizont, und Sie haben einen Pfad; viele Pfade ergeben eine Verteilung von Endpreisen, und der Mittelwert eines abgezinsten Payoffs darüber bewertet eine Option. Eine gute Plausibilitätsprüfung: Mit der Drift mu sollte der mittlere Endpreis nahe S0 * exp(mu * T) liegen, egal welche Volatilitätsparameter gelten. Andernfalls steckt ein Fehler im Preisschritt. Die Kalibrierung von kappa, theta, xi, rho an Optionspreise folgt in den kommenden Themen.

# A short Monte Carlo: simulate many paths, and check the average terminal price against S0 * exp(mu * T)
import math
import random

def simulate(s0, v0, mu, kappa, theta, xi, rho, steps, years, rng):
    dt = years / steps
    s, v = s0, v0
    for _ in range(steps):
        z1, z2 = rng.gauss(0, 1), rng.gauss(0, 1)
        dz, dw = z1, rho * z1 + math.sqrt(1 - rho ** 2) * z2
        vp = max(v, 0.0)
        s *= math.exp((mu - vp / 2) * dt + math.sqrt(vp * dt) * dw)
        v = v + kappa * (theta - vp) * dt + xi * math.sqrt(vp * dt) * dz
    return s

rng = random.Random(11)
finals = [simulate(100.0, 0.04, 0.05, 2.0, 0.04, 0.3, -0.7, 50, 1.0, rng) for _ in range(4000)]
mean = sum(finals) / len(finals)
print(abs(mean / (100.0 * math.exp(0.05)) - 1) < 0.02)       # True   the average terminal price follows S0 * exp(mu * T)
print(min(finals) > 0)                                       # True   prices stay positive
# A check that costs nothing: with xi = 0 and v0 = theta the variance never moves (Black-Scholes with volatility sqrt(theta))
import math

kappa, theta, xi = 2.0, 0.04, 0.0
v = theta
for z in (1.5, -2.0, 0.3, 0.9):
    vp = max(v, 0.0)
    v = v + kappa * (theta - vp) * (1 / 252) + xi * math.sqrt(vp / 252) * z
print(v == theta)                                    # True   no noise and already at the long-run level
print(round(math.sqrt(v), 2))                        # 0.2    a constant 20% volatility
Euler ist einfach, nicht exaktEuler-Schemata tragen einen Diskretisierungsfehler, der mit dt schrumpft, und ein grobes Gitter verzerrt Optionspreise. Nutzen Sie genug Schritte und viele Pfade (der Standardfehler fällt wie eins durch die Wurzel der Pfadzahl). Prüfen Sie die Simulation an einer bekannten Antwort: Setzen Sie xi = 0, und das Modell fällt auf Black-Scholes mit Volatilität sqrt(theta) zusammen. In der Produktion ist die semi-analytische Heston-Bewertung über die charakteristische Funktion schneller und exakt; Simulation ist das flexible Werkzeug, wenn Payoffs vom Pfad abhängen.
  • Heston macht die Varianz zufällig: Sie kehrt mit Geschwindigkeit kappa zu theta zurück, hat Rauschen xi * sqrt(v) und ist über rho mit dem Preis korreliert (bei Aktien negativ).
  • Simulieren Sie mit voller Abschneidung (max(v, 0) rechts), korrelieren Sie die Schocks mit dw = rho z1 + sqrt(1 - rho^2) z2 und prüfen Sie die Feller-Bedingung 2 kappa theta >= xi^2.
  • Der Preisschritt nutzt die Varianz zu Beginn des Schritts; prüfen Sie, dass der mittlere Endpreis S0 * exp(mu * T) folgt und xi = 0 Black-Scholes reproduziert.

Als Nächstes: lokale Volatilität, eine Volatilitätsfläche, die von Preis und Zeit abhängt.

Lab: Was bewertet wird

  • Die Varianz mit feller_condition positiv halten25 Pkt.
  • Die Varianz mit variance_step fortschreiben25 Pkt.
  • Die Schocks mit correlated_normals korrelieren25 Pkt.
  • Preis und Varianz mit heston_step bewegen25 Pkt.
Explorer · lab-136-1
▾ lab-136-1
…
bash · im Browser
learner@quantcraft:~/lab-136-1$
Python noch nicht geladenPythonLn 1, Col 1Spaces: 4UTF-8

Dieses Thema zurücksetzen?

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