σμ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 学习路线›模块 7 · Alpha 研究与风险›主题 7.5·~50分钟高级

参数法 VaR

路线进度模块 7/11 · 主题 5/9
7.5 参数法 VaR
—实验得分— / 100总 XP—连续天数—

用公式代替历史

历史 VaR 从过去的收益率中读出损失。参数化 VaR 假设收益率服从正态分布,只需要均值和标准差两个数。以概率 1 - confidence 被超过的损失就是 z * sigma - mu,其中 z 是标准正态分位数(95% 时为 1.645,99% 时为 2.326)。它快速、平滑,而且很容易推广到整个组合,因此几十年来是行业标准。

from statistics import NormalDist

def normal_var(mu, sigma, confidence):
    z = NormalDist().inv_cdf(confidence)
    return z * sigma - mu

print(round(NormalDist().inv_cdf(0.95), 4), round(NormalDist().inv_cdf(0.99), 4))
print(round(normal_var(0.0005, 0.012, 0.95), 5))        # a 95% one-day loss limit
print(round(normal_var(0.0005, 0.012, 0.99), 5))        # a higher confidence, a larger limit
# The multiplier z for common confidence levels
from statistics import NormalDist

for confidence in (0.90, 0.95, 0.975, 0.99, 0.999):
    print(confidence, round(NormalDist().inv_cdf(confidence), 3))       # 1.282, 1.645, 1.96, 2.326, 3.09

从单个资产到组合,再到十天

对于组合,均值是 weights @ mu,标准差是 sqrt(weights @ cov @ weights),正是组合方差那一节的量。分散化直接体现出来:相关性越低,标准差和 VaR 越小。期限更长时,均值随天数增长,标准差随其平方根增长,所以 10 日 VaR 是 z * sigma * sqrt(10) - mu * 10。

import numpy as np
from statistics import NormalDist

def normal_var(mu, sigma, confidence):
    return NormalDist().inv_cdf(confidence) * sigma - mu

weights = np.array([0.6, 0.4])
mu = np.array([0.0005, 0.0003])
cov = np.array([[0.00016, 0.00004], [0.00004, 0.00009]])             # volatilities 1.26% and 0.95%, correlation 0.33

mean, std = float(weights @ mu), float(np.sqrt(weights @ cov @ weights))
print(round(mean, 5), round(std, 5))
print(round(normal_var(mean, std, 0.99), 5))
print(round(normal_var(mean * 10, std * np.sqrt(10), 0.99), 5))      # the 10-day figure

正态假设失效之处

真实收益率有厚尾:极端的日子比正态分布允许的频繁得多。因此参数化 VaR 看起来太小,置信水平越高越明显。用同一份数据与历史 VaR 比较就能看出差距:为正说明正态模型低估了风险。95% 时两者往往接近,99% 时可能相差很大。

# Fat-tailed returns: the normal model understates the 99% loss
import numpy as np
from statistics import NormalDist

rng = np.random.default_rng(2)
returns = rng.standard_t(3, size=5000) * 0.008           # a fat-tailed distribution (3 degrees of freedom)

for confidence in (0.95, 0.99):
    historical = -np.quantile(returns, 1 - confidence)
    parametric = NormalDist().inv_cdf(confidence) * returns.std(ddof=1) - returns.mean()
    print(confidence, round(float(historical), 5), round(float(parametric), 5), round(float(historical - parametric), 5))
按问题选方法参数化 VaR 适合快速、平滑的数字,以及线性头寸的组合。对于收益相对风险因子并非线性的期权,以及对于尾部,它都是糟糕的向导。许多交易台会同时算参数化、历史和蒙特卡洛等多种 VaR,并把差异很大视为对模型的警告。
  • 参数化 VaR = z * sigma - mu,其中 z = NormalDist().inv_cdf(confidence):只需均值和标准差。
  • 组合使用 weights @ mu 和 sqrt(weights @ cov @ weights);期限把均值乘以 days、波动率乘以 sqrt(days)。
  • 真实收益有厚尾,所以与历史 VaR 比较:差值为正说明正态模型低估了风险。

下一节:预期损失(ES),VaR 被突破那些天的平均亏损。

实验:评分内容

  • 用 normal_var 把两个数变成损失上限25 分
  • 用 portfolio_normal_var 覆盖整个组合25 分
  • 用 horizon_var 看得更远25 分
  • 用 normality_gap 度量厚尾25 分
资源管理器 · lab-97-1
▾ lab-97-1
…
bash · 浏览器内
learner@quantcraft:~/lab-97-1$
Python 尚未加载PythonLn 1, Col 1Spaces: 4UTF-8

要重置此主题吗?

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

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

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

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

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