Lab 4 · Backtest Settings

策略回測實驗室

風險平價、GMV 這些策略,「紙上算」都很漂亮。一旦你把「多久再平衡一次?要付多少手續費?用多少歷史資料估計風險?」 這三件事考慮進去,績效就開始被磨掉。在這個 Lab,你會親眼看到「小決策」的累積效果。

1確認策略
2基準 vs 自訂
3看績效差異

開始之前

🕹️ 你要做什麼

  1. 策略鎖定為「風險平價」(5 檔:VTI / VEA / VWO / TLT / GLD),別糾結建構法。
  2. 左邊「基準卡」固定(月再平衡、5bp 成本、36 個月 Cov 窗口)。
  3. 右邊「自訂卡」動三個旋鈕:再平衡頻率(never/年/季/月)、成本(0/5/15/50 bps)、Cov 窗口(12/24/36/60m)。
  4. 看三張圖並排:權益曲線、回撤、成本拖累。
  5. 讀「教學洞見」——理解 walk-forward、turnover、估計誤差對回測的影響。
  6. 進階:打開 Colab 區塊,用 pandas 自己手刻一個 walk-forward 回測器。

🧠 要建立的觀念

  • 「紙上績效」跟「真實績效」的差距,常常不在策略本身,而在實作細節
  • 再平衡是「紀律」,但每次動都要付 turnover × 成本。
  • 交易成本是「無聲的複利殺手」——小數字、長時間、會蠶食掉 Sharpe。
  • 短 Cov 窗口對近期敏感,長窗口穩定但反應慢——沒有絕對最佳。

🛠️ 會學到的方法

  • Walk-forward 回測的正確寫法(每期用「過去」估計、在「未來」執行)。
  • 權重 drift 公式:w_j ← w_j · (1+r_j) / (1+r_p)
  • Turnover = Σ|Δw|/2,單邊計算。
  • 成本扣除:equity × (1 − turnover × 2 × bps/10000)

1確認策略

固定策略是「風險平價(Risk Parity)」,資產池:美股、已開發、新興、長債、黃金。
Risk Parity · 5 資產
VTI
動態
VEA
動態
VWO
動態
TLT
動態
GLD
動態
權重由「估計 Cov + 風險平價」動態計算。回測區間 2015-01-02 ~ 2026-04-17(約 11 年)。

2基準 vs 自訂

左邊是教科書基準設定;右邊讓你自由調整。兩個組合會同時跑,結果即時比較。

📘 基準設定

再平衡頻率
每月
交易成本
5 bp
估計窗口
36 個月

「月再平衡、5bp、3 年窗口」是多數研究論文的默認。

🧪 你的設定

3看績效差異

兩組設定下的權益曲線、績效比較、成本影響視覺化。

權益曲線(起始 = 1)

Drawdown 比較

成本吃掉多少終值?

左邊:零成本回測的終值。右邊:你的成本設定下的終值。差異 = 「摩擦」。

🔍 教學洞見 · 回測的四大陷阱

Lab 4 的核心論點是「細節會吃 Sharpe」。這四張卡解釋為什麼, 以及在 Colab 裡要怎麼寫才能避免這些陷阱。

🔁

Walk-Forward:嚴格隔開「估計」與「執行」

常見錯誤:用 整段期間 的 Σ 估出權重,再套回整段期間算 Sharpe。 這叫 look-ahead bias——你用未來資料當訓練。 正確做法:每個再平衡日只用「當下為止」的 36 個月歷史估計, 下個月才開始拿這個權重產生報酬。

親手驗:Colab 區塊的 for t in rebalance_dates 迴圈裡, 注意 cov = rets.loc[t-36m : t-1d].cov(),切口不能包含 t。

🔁 切口絕不能碰到 t
for t in rebal_dates:
    hist = rets.loc[:t - pd.Timedelta(days=1)]   # 不含 t
    hist = hist.tail(36 * 21)                    # 36 個月
    Σ    = hist.cov().values * 252
💸

交易成本:turnover × bps 的無聲複利殺手

單次成本只有 5bp 看起來很小,但月再平衡一年 12 次、10 年 120 次, 如果每次 turnover 約 15%,累積成本 ≈ 120 × 0.15 × 0.05% = 0.9%/年。 這會直接從 CAGR 裡扣掉——一個 8% 的策略會變 7.1%,Sharpe 掉 10%+。

親手驗:調整右邊成本旋鈕 0 → 50bp,看「成本吃掉多少終值」長條圖。 台股散戶的 50bp 真的會把多數策略打成平盤。

💸 成本扣除
turnover = np.abs(w_new - w).sum() / 2
cost     = turnover * 2 * cost_bps / 10000
equity  *= (1 - cost)                            # 每次再平衡扣一次
w        = w_new
📅

估計窗口:短敏感長穩定,12m vs 60m 差很多

12 個月窗口對近期變動反應快,但估計誤差大(只有 252 筆日報酬估 n×n 矩陣)。 60 個月穩定,但遇到政策/景氣轉折會反應慢。 實務經驗:股債混合組合 36~48 個月是甜蜜點;純股票策略可以短一點(24m)。

親手驗:把窗口從 12 拉到 60,看「自訂卡」Sharpe 的變化。 12m 通常 Sharpe 較高但 MDD 也較大——那是估計雜訊的代價。

📅 窗口長度對比
Σ_12m = rets.tail(12 * 21).cov() * 252            # 短視野
Σ_60m = rets.tail(60 * 21).cov() * 252            # 長視野
# 比條件數:np.linalg.cond(Σ_12m) vs cond(Σ_60m)
# 短窗口常不良,解答會抖
⚖️

再平衡頻率:紀律 vs 成本的平衡點

買入持有 (never) 沒有成本,但權重會自然漂移成「過去贏家越來越重」的狀態, 失去分散效果。每月再平衡把權重拉回目標,但付最多成本。 多數實證:每季再平衡是多數組合的最佳平衡點——年 turnover 約 4 次, 足以恢復分散又不至於被成本吃光。

親手驗:固定其他參數,比較 never / yearly / quarterly / monthly 四組的「終值 - 成本」。你會看到一個 U 型:中間最優。

⚖️ 再平衡日的生成
freq = {"monthly": "ME", "quarterly": "QE", "yearly": "YE"}
rebal_dates = rets.resample(freq["quarterly"]).last().index
# buy-and-hold:rebal_dates = [rets.index[0]]
📓
想看完整 walk-forward 回測器?
上方每張洞見卡都附 3~4 行對應程式碼。完整版 notebook 把它們串成: 資料下載 → risk-parity 權重 → walk-forward 迴圈(drift + cost)→ 成本敏感度對比圖。 在 lab4_backtest.ipynb 一鍵重現本頁所有曲線。
在 Colab 開啟 →