σμ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 学习路线›模块 8 · 随机模型与机器学习›主题 8.2·~55分钟高级

几何布朗运动

路线进度模块 8/11 · 主题 2/10
8.2 几何布朗运动
—实验得分— / 100总 XP—连续天数—

价格按百分比变动

算术布朗运动不论股价是 5 还是 500,都加上同样金额的噪声,而且可能降到零以下。股票的表现不同:1% 的变动在任何价格上都是 1%。几何布朗运动把随机性放在百分比变化上:dS = mu * S * dt + sigma * S * dW。这就是布莱克-斯科尔斯所用的模型,mu 是年化预期收益,sigma 是波动率,也就是市场报价的那个量。

import math

def gbm_step(s, mu, sigma, dt, z):
    return s * math.exp((mu - 0.5 * sigma ** 2) * dt + sigma * math.sqrt(dt) * z)

print(round(gbm_step(100.0, 0.08, 0.2, 1 / 252, 0.0), 4))     # a calm day: only the (mu - sigma^2/2) drift acts
print(round(gbm_step(100.0, 0.08, 0.2, 1 / 252, 1.0), 4))     # a one-sigma up day
print(round(gbm_step(100.0, 0.08, 0.2, 1 / 252, -50.0), 4))   # an absurd fall: still positive

精确解与负二分之一 σ 平方

解这个方程得到 S(t) = S(0) * exp((mu - sigma**2 / 2) * t + sigma * W(t))。为什么有这个奇怪的 - sigma**2 / 2?因为指数函数是凸的:由詹森不等式,噪声会抬高 exp(噪声) 的平均,减去 sigma**2 / 2 恰好抵消它,所以*期望*价格以速率 mu 增长。典型的*路径*增长更慢,速率为 mu - sigma**2 / 2,这就是股价中位数低于均值的原因。下一节的伊藤引理会推导这一项。

import numpy as np

def gbm_path(s0, mu, sigma, dt, z):
    log_moves = (mu - 0.5 * sigma ** 2) * dt + sigma * np.sqrt(dt) * z
    return s0 * np.exp(np.concatenate([[0.0], np.cumsum(log_moves)]))

rng = np.random.default_rng(1)
z = rng.standard_normal(252)
path = gbm_path(100.0, 0.08, 0.2, 1 / 252, z)
print(path[:4].round(3), round(float(path[-1]), 3))

大量路径:均值与中位数

模拟数千条一年期路径,看它们停在哪里。期末价格的*均值*接近 S0 * exp(mu * T),即期望价格的公式。*中位数*更低,为 S0 * exp((mu - sigma**2/2) * T),波动率高时差距很大:多数路径收在均值之下,均值被少数极高的路径拉高。这种右偏的对数正态分布,就是长期股价的形状。

import numpy as np

rng = np.random.default_rng(5)
s0, mu, sigma, T, steps, paths = 100.0, 0.08, 0.4, 1.0, 252, 20000
dt = T / steps
z = rng.standard_normal((paths, steps))
final = s0 * np.exp(np.sum((mu - 0.5 * sigma ** 2) * dt + sigma * np.sqrt(dt) * z, axis=1))

print(round(float(final.mean()), 1), round(s0 * np.exp(mu * T), 1))                      # close to each other: the expected price
print(round(float(np.median(final)), 1), round(s0 * np.exp((mu - 0.5 * sigma ** 2) * T), 1))   # the median is lower
print(round(float(np.mean(final < s0)), 3))                                              # the share of paths that lose money

估计 mu 和 sigma

对每隔 dt 年采样的价格,对数收益率 r = diff(log(prices)) 是均值为 (mu - sigma**2/2) * dt、标准差为 sigma * sqrt(dt) 的独立正态变量。所以 sigma = std(r) / sqrt(dt),mu = mean(r) / dt + sigma**2 / 2。波动率几百个点就估得不错;漂移则出了名地噪声大,因为它的标准误只随总*时间*缩小,而不是随观测数量缩小。

import numpy as np

def estimate_gbm(prices, dt):
    r = np.diff(np.log(prices))
    sigma = r.std(ddof=1) / np.sqrt(dt)
    return r.mean() / dt + 0.5 * sigma ** 2, sigma

rng = np.random.default_rng(8)
dt = 1 / 252
for years in (1, 10, 100):
    n = int(years * 252)
    log_moves = (0.10 - 0.5 * 0.25 ** 2) * dt + 0.25 * np.sqrt(dt) * rng.standard_normal(n)
    prices = 100 * np.exp(np.concatenate([[0.0], np.cumsum(log_moves)]))
    mu, sigma = estimate_gbm(prices, dt)
    print(years, "years:", round(float(mu), 3), round(float(sigma), 3))           # true mu 0.10 and sigma 0.25
几何布朗运动是个好开端,而非真理真实价格有厚尾、跳跃以及会变动的波动率(GARCH 一节),GBM 都不包含。它的优点是一切都很明确:价格服从对数正态,期望价格有公式,期权价格也由此得出。修正其缺陷的模型(跳跃、随机波动率)都是建立在它之上的。
  • GBM:S(t) = S(0) * exp((mu - sigma**2 / 2) * t + sigma * W(t));百分比变化是随机的,价格始终为正。
  • - sigma**2 / 2 抵消了 exp 的凸性:期望价格是 S0 * exp(mu * t),而中位路径以 mu - sigma**2 / 2 增长。
  • 由对数收益估计:sigma = std(r) / sqrt(dt),mu = mean(r) / dt + sigma**2 / 2;波动率估得准,漂移估得差。

下一节:伊藤引理,解释 - sigma**2 / 2 从何而来的链式法则。

实验:评分内容

  • 用 gbm_step 走精确的一步25 分
  • 用 gbm_path 模拟价格路径25 分
  • 用 gbm_expected 对所有未来取平均25 分
  • 用 estimate_gbm 反推参数25 分
资源管理器 · lab-103-1
▾ lab-103-1
…
bash · 浏览器内
learner@quantcraft:~/lab-103-1$
Python 尚未加载PythonLn 1, Col 1Spaces: 4UTF-8

要重置此主题吗?

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

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

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

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

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