σμ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 Academy学习路线
Ctrl K
AO
+1.2k 位学习者
登录加入 ↗
学习路线
AO
+1.2k 位学习者
登录
  • English
  • Français
  • Español
  • العربية
  • Português
  • Deutsch
  • 日本語
  • 中文
Python 学习路线›模块 11 · 生产系统与前沿模型›主题 11.7·~1小时 30分钟专家

Heston 模型

路线进度模块 11/11 · 主题 7/13
11.7 Heston 模型
—实验得分— / 100总 XP—连续天数—

当波动率也在变化时

Black-Scholes 假设波动率恒定,但真实的波动率在暴跌时升高、平静时消退,期权市场也体现了这一点:隐含波动率随行权价而异(微笑或偏斜)。Heston 模型保留几何的价格过程,但同时让*方差* v 也随机:它以速度 kappa 被拉向长期水平 theta,受到大小为 xi、随 sqrt(v) 缩放的噪声扰动,且价格与方差的冲击有相关性 rho。负的 rho(波动率上升时价格下跌,即杠杆效应)产生了股票期权中常见的向下偏斜。

# 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

模拟:截断与相关性

模拟时按小区间 dt 逐步推进。方差更新为 v + kappa * (theta - v) * dt + xi * sqrt(v * dt) * dz,但朴素的欧拉步可能把 v 推到零以下,此时平方根就失败了。完全截断方案在右侧出现 v 的每处都使用 max(v, 0)(负值当作零),并为下一步保留原始结果。Feller 条件 2 * kappa * theta >= xi^2 是真实过程永远不会触及零的参数区域;若不满足,截断就更重要。两个冲击必须相关:抽取独立的正态数 z1、z2,令 dz = z1、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

完整路径与合理性检查

一步同时更新两个状态变量:价格使用步*开始时*的方差,S * exp((mu - v/2) * dt + sqrt(v * dt) * dw),然后方差再变动。按期限内的步数重复,就得到一条路径;许多路径给出终端价格的分布,对其贴现收益取平均就能给期权定价。一个很好的合理性检查:在漂移 mu 下,无论波动率参数如何,终端价格的平均值都应接近 S0 * exp(mu * T)。否则价格步里有 bug。把 kappa, theta, xi, rho 校准到期权价格,将在后面的章节出现。

# 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
欧拉法简单但不精确欧拉格式带有离散化误差,随 dt 减小而缩小,粗糙的网格会使期权价格产生偏差。要用足够多的步数和足够多的路径(标准误差按路径数平方根的倒数下降)。用已知答案检查模拟:令 xi = 0,模型就退化为波动率为 sqrt(theta) 的 Black-Scholes。在生产中,通过特征函数的半解析 Heston 定价更快更精确;当收益依赖路径时,模拟才是灵活的工具。
  • Heston 让方差随机:它以速度 kappa 回归到 theta,噪声为 xi * sqrt(v),与价格的相关性为 rho(股票为负)。
  • 用完全截断(右侧用 max(v, 0))模拟,用 dw = rho z1 + sqrt(1 - rho^2) z2 让冲击相关,并检查 Feller 条件 2 kappa theta >= xi^2。
  • 价格步使用步开始时的方差;检查终端价格均值是否遵循 S0 * exp(mu * T),以及 xi = 0 是否还原 Black-Scholes。

下一节:局部波动率,依赖价格与时间的波动率曲面。

实验:评分内容

  • 用 feller_condition 保持方差为正25 分
  • 用 variance_step 推进方差25 分
  • 用 correlated_normals 让冲击相关25 分
  • 用 heston_step 推进价格与方差25 分
资源管理器 · lab-136-1
▾ lab-136-1
…
bash · 浏览器内
learner@quantcraft:~/lab-136-1$
Python 尚未加载PythonLn 1, Col 1Spaces: 4UTF-8

要重置此主题吗?

lab-136-1 中的所有内容将恢复为初始文件,终端也会被清空。你当前的解答将丢失,且无法撤销。

将被重置
  • main.py → 初始代码
  • 终端历史与测试输出
  • 未提交的更改
将被保留
  • 实验最高得分
  • 你的 XP 与连续天数
  • 讲解进度与笔记

登录后即可运行你的代码。

所有讲解均可免费阅读。创建账户或登录后,即可运行代码、运行测试并提交此实验。

  • 浏览器内 IDE 与 bash 终端,无需安装
  • 即时评分、XP 以及你在学习路线中的位置
创建账户登录
或
使用 GitHub 继续