Lab 3 · Mean-Variance Efficient Frontier

平均變異數效率前緣

馬可維茲告訴我們:理性投資人應該只待在「效率前緣」上。這條曲線是什麼形狀?由哪些量決定? 本 Lab 帶你從 $\Sigma$、$\Sigma^{-1}$ 開始,用 CH6 的三大係數 $A$、$B$、$C$ 推出 $\sigma^2 = (C\mu^2 - 2B\mu + A)/D$ 這條雙曲線,並用解析解算出 GMV 權重。

對應 CH6 問題集 P1–P5 資料期間 2016-01-01 ~ 2025-12-31

開始之前

🕹️ 你要做什麼

  1. 挑 2~6 檔資產(預選 SPY/QQQ/KO/AAPL)。
  2. 看 Step 2:$E$、$\Sigma$、$\Sigma^{-1}$ 三張表(年化後的數字)。
  3. 看 Step 3:$A$、$B$、$C$、$D$ 四個係數與 GMV 權重 — 這些就是問題集會叫你算的東西。
  4. 看 Step 4:把個別資產、GMV、效率前緣畫在 $(\sigma, \mu)$ 平面上。
  5. 寫三題反思 → 匯出 Markdown 報告(含 numpy 實作碼可貼到 Colab)。

🧠 要建立的觀念

  • 共變異數矩陣 $\Sigma$:對角線是變異數,非對角線是共變異數 — 兩兩資產「一起動」的程度。
  • 效率前緣是一條雙曲線。GMV 在頂點左側,其上方的弧段才是「效率的」(相同風險下最高報酬)。
  • GMV 權重 $w_{GMV} \propto \Sigma^{-1}\mathbf{1}$,完全不用到 $E$ — 因此在實務上對平均報酬的估計誤差最不敏感。
  • 當兩檔資產高度共線時,$\Sigma$ 接近奇異,GMV 不穩定 — 這就是為什麼實務上會用收縮法(shrinkage)。

🛠️ 會學到的方法

  • pct_changerets.cov() 得到 $\Sigma$。
  • np.linalg.inv 算 $\Sigma^{-1}$。
  • 以向量/矩陣運算算 $A = E^\top \Sigma^{-1} E$、$B$、$C$、$D$。
  • 用 $w_{GMV} = \Sigma^{-1}\mathbf{1}/C$ 與 $\sigma^2 = (C\mu^2-2B\mu+A)/D$ 直接畫出前緣。

📐 本 Lab 的核心公式(CH6)

$$A = E^\top \Sigma^{-1} E,\quad B = E^\top \Sigma^{-1}\mathbf{1},\quad C = \mathbf{1}^\top \Sigma^{-1}\mathbf{1},\quad D = AC - B^2$$ $$w_{GMV} = \dfrac{\Sigma^{-1}\mathbf{1}}{C}, \quad \mu_{GMV} = \dfrac{B}{C}, \quad \sigma^2_{GMV} = \dfrac{1}{C}$$ $$\boxed{\ \sigma^2 \;=\; \dfrac{1}{D}\bigl(C\mu^2 - 2B\mu + A\bigr)\ }$$

最後一式是 $(\sigma, \mu)$ 平面上的雙曲線;切一刀 $\mu \ge \mu_{GMV}$ 的部分就是效率前緣。

1選擇資產(2–6 檔)

建議混合「不同資產類別」(大盤 + 個股 + 防禦股)才能看到真正的分散效果。
資料期間固定為 2016-01-01 ~ 2025-12-31;本 Lab 允許做空(權重可為負),純做多需要 QP 數值解,屬於進階延伸。

2平均向量 $E$ 與共變異數矩陣 $\Sigma$

對應 CH6 問題集 P1:估計 $E$、$\Sigma$(本 Lab 使用年化日報酬)。
🐍 Python 程式碼($E$、$\Sigma$、$\Sigma^{-1}$,點擊展開)
import yfinance as yf, pandas as pd, numpy as np

tickers = ["SPY", "QQQ", "KO", "AAPL"]               # 可加 "2330.TW" / "0050.TW"
data = yf.download(tickers, start="2016-01-01", end="2025-12-31",
                   auto_adjust=False)["Adj Close"].dropna()
rets = data.pct_change().dropna()

E     = rets.mean().values * 252
Sigma = rets.cov().values  * 252
inv   = np.linalg.inv(Sigma)

print("E =", dict(zip(data.columns, E.round(4))))
print("Sigma =\n", pd.DataFrame(Sigma, index=data.columns, columns=data.columns).round(4))
print("Sigma^-1 =\n", pd.DataFrame(inv, index=data.columns, columns=data.columns).round(4))

3GMV 解析解與效率前緣係數

對應 CH6 問題集 P2/P3:代公式,驗證 GMV 與雙曲線方程。
🐍 Python 程式碼($A, B, C, D$ 與 GMV,點擊展開)
ones = np.ones_like(E)
A = E  @ inv @ E
B = E  @ inv @ ones
C = ones @ inv @ ones
D = A * C - B ** 2
print(f"A={A:.4f}  B={B:.4f}  C={C:.4f}  D={D:.4f}")

w_gmv  = inv @ ones / C
mu_gmv = B / C
var_gmv = 1 / C
print("w_GMV =", dict(zip(data.columns, w_gmv.round(4))))
print(f"μ_GMV={mu_gmv:.4f}  σ_GMV={np.sqrt(var_gmv):.4f}")

4效率前緣 $(\sigma, \mu)$ 散佈圖

對應 CH6 問題集 P4/P5:畫出雙曲線,觀察 GMV 位置與個別資產的相對位置。

效率前緣

綠實線 = 效率前緣($\mu \ge \mu_{GMV}$);綠虛線 = 最小變異前緣的下半;三角 = GMV;圓點 = 個別資產。效率前緣「吞掉」所有個別資產 — 這就是分散化帶來的免費午餐。

🐍 Python 程式碼(畫出效率前緣,點擊展開)
import matplotlib.pyplot as plt

mus = np.linspace(mu_gmv, E.max() * 1.2, 50)
sig = np.sqrt((C * mus ** 2 - 2 * B * mus + A) / D)

plt.plot(sig, mus, label="Efficient frontier")
plt.scatter(np.sqrt(np.diag(Sigma)), E, label="Assets")
plt.scatter([np.sqrt(var_gmv)], [mu_gmv], s=120, marker="^", label="GMV")
plt.xlabel("σ"); plt.ylabel("μ"); plt.legend(); plt.grid(alpha=0.3)
plt.show()

5反思與匯出

答完這三題,你就能回答 CH6 問題集 P2/P3/P5 的「財務意涵」子題。
下一個:Lab 4 · 回測實驗室 →