策略回測實驗室
風險平價、GMV 這些策略,「紙上算」都很漂亮。一旦你把「多久再平衡一次?要付多少手續費?用多少歷史資料估計風險?」 這三件事考慮進去,績效就開始被磨掉。在這個 Lab,你會親眼看到「小決策」的累積效果。
開始之前
🕹️ 你要做什麼
- 策略鎖定為「風險平價」(5 檔:VTI / VEA / VWO / TLT / GLD),別糾結建構法。
- 左邊「基準卡」固定(月再平衡、5bp 成本、36 個月 Cov 窗口)。
- 右邊「自訂卡」動三個旋鈕:再平衡頻率(never/年/季/月)、成本(0/5/15/50 bps)、Cov 窗口(12/24/36/60m)。
- 看三張圖並排:權益曲線、回撤、成本拖累。
- 讀「教學洞見」——理解 walk-forward、turnover、估計誤差對回測的影響。
- 進階:打開 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)」,資產池:美股、已開發、新興、長債、黃金。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。
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]]
上方每張洞見卡都附 3~4 行對應程式碼。完整版 notebook 把它們串成: 資料下載 → risk-parity 權重 → walk-forward 迴圈(drift + cost)→ 成本敏感度對比圖。 在
lab4_backtest.ipynb 一鍵重現本頁所有曲線。