Lab 2 · Risk Measurement

風險衡量實驗室

VaR(Value at Risk)有三種常見算法——歷史模擬、參數法(常態)、蒙地卡羅。 三者給出的「明天最壞跌多少」可能差很多,在 2020 年三月、2022 年升息熊市的極端日子,誰預測得準?誰被市場教訓?

1選投資組合
2設定信心水準
3三法並排比較

開始之前

🕹️ 你要做什麼

  1. 挑 1 個預設投組,設定信心水準(95%/99%)、回望期(250/500/1000 日)、蒙地卡羅次數。
  2. 看中央「三張 VaR 卡」:歷史、參數、蒙地卡羅的預測值差多少。
  3. 看「報酬直方圖」的三條虛線(各方法的 VaR 線)在哪。
  4. 滑到「實際破線紀錄」,看 2020-03 / 2022 熊市哪些天被誰誤判。
  5. 寫反思 → 匯出報告。

🧠 要建立的觀念

  • VaR = 在某信心水準下,可能的最壞單日跌幅(95% VaR = -2% ≈ 100 天裡最慘的 5 天會超過這個跌幅)。
  • 參數法假設常態分配,遇到胖尾(fat tail)會嚴重低估風險。
  • 歷史模擬不假設分配,但「從沒發生過的事」它不會預測。
  • CVaR 告訴你「破線那天平均有多慘」,比 VaR 更能反映尾端風險。

🛠️ 會學到的方法

  • 歷史模擬:取日報酬的 (1−conf) 分位數。
  • 參數法:μ + z·σ(z 由 Acklam 逆常態近似算出)。
  • 蒙地卡羅:以 μ、σ 採樣 N 次,取分位數。
  • Backtesting:算實際破線次數 vs 理論預期次數的偏差。

1選投資組合

用 preset 先跑起來,這個 Lab 重點在「算風險的方法」不在建構。

2設定 VaR 參數

信心水準越高,VaR 越「極端」;窗口越長,對極端事件越鈍感。

🧪 參數

3三法並排比較

三種算法給出今日的 1-day VaR / CVaR。數字越負代表預測虧損越慘。

日報酬率分布 + 三條 VaR 預測線

直方圖是你選擇區間內的實際日報酬分布。三條垂直線是三種方法對「1-day VaR」的預測。超過線的左側就是 VaR 破線日。

Backtest:VaR 破線(Exceedance)時點

紅點 = 當日實際虧損超過歷史模擬 VaR 預測。在理想狀態下,破線比例應該接近 (1 − 信心水準)。

🎓 教學解讀:三種 VaR 該在什麼場景用?

每種方法都有假設。看出「哪個假設在哪個時候會爆掉」才是風控的核心素養。
📜

歷史模擬法的盲點

「取 (1−信心水準) 分位數」看似客觀,但假設了未來極端程度 ≤ 歷史。如果回溯窗口剛好錯過 2008 / 2020,今天的 VaR 會嚴重低估。

💡 試試看:切到「2019–2024」,用 252 日窗口;再切到「全段」,比較 99% VaR。

📜 Historical VaR
alpha    = 0.05
var_hist = ret.quantile(alpha)      # 第 5 百分位
# 沒見過的極端 → 永遠抓不到
🔔

參數法 = 常態假設

VaR = μ + z·σ 背後是報酬率服從常態。實際上日報酬是厚尾(G₂ ≫ 0)、偏左(G₁ < 0);在黑天鵝日子,常態法會顯著低估風險。

💡 試試看:切到 2020(COVID),看直方圖左尾怎麼「衝出」參數法那條虛線。

🔔 Parametric VaR
from scipy import stats
mu, sd  = ret.mean(), ret.std()
z       = stats.norm.ppf(0.05)      # ≈ -1.645
var_par = mu + z * sd               # 常態分位數
🎲

蒙地卡羅 vs 歷史模擬

MC 用 (μ, σ) 生成大量樣本取分位數 —— 本質上還是常態假設,只是給你信心區間。模擬次數從 1000 → 100000 變化,分位數會越來越穩定,但無法修正模型錯誤(厚尾仍然被漏掉)。

💡 試試看:在同一區間下,把模擬次數從 1,000 拉到 100,000,看 MC VaR 的抖動。

🎲 Monte Carlo VaR
sim    = np.random.normal(mu, sd, 100_000)
var_mc = np.quantile(sim, 0.05)
# 換厚尾:stats.t(df=4).rvs(100_000)*sd + mu
🩸

ES(CVaR)比 VaR 更完整

VaR 只告訴你「破線的門檻」,ES = 破線那天平均跌多慘。監管機構 Basel III 之所以從 VaR 改採 ES,就是為了抓「尾部有多厚」這件事。ES 絕對比 VaR 更負(更保守)。

💡 觀察:每張卡片的 ES 欄位,對比 VaR 欄位,差距在壓力情境會拉大。

🩸 Expected Shortfall
es_hist = ret[ret <= var_hist].mean()
# 常態封閉解:
es_par  = mu - sd * stats.norm.pdf(z) / 0.05

🧪 一個不能少的檢定:Kupiec 覆蓋率

VaR 是否可靠?實際破線次數應 ≈ (1 − 信心水準) × 天數。差太多就用卡方檢定拒絕。

把 $N$ 天報酬與 VaR 比對,記錄破線次數 $x$。理論上 $x/N \approx \alpha$。
對數概似比 $LR \sim \chi^2(1)$,$p < 0.05$ 代表 VaR 模型過度樂觀(破太多)或過度保守(破太少)。

🧪 Kupiec LR test
breach = (ret < var_hist).sum()
N, p   = len(ret), breach / len(ret)
LR = (-2 * (N - breach) * np.log(1 - 0.05)
      - 2 * breach      * np.log(0.05)
      + 2 * (N - breach) * np.log(1 - p)
      + 2 * breach      * np.log(p))
pval = 1 - stats.chi2.cdf(LR, df=1)
# pval < 0.05 → 拒絕 H₀,VaR 模型有問題
📓
完整 pipeline 在 notebook 裡
上方每張卡都附 3~5 行對應程式碼。想看三法的並排輸出、Kupiec p-value、 以及厚尾 t 分配的對比實驗,可以在 Colab 打開 lab2_var.ipynb
在 Colab 開啟 →