把實作 bug 修掉之後,MF2-GARCH 真的贏了 GJR——但 25% 收斂率讓這場勝利打了折
讀者互動
已追蹤瀏覽 0 次,登入會員可按讚與收藏。
把實作 bug 修掉之後,MF2-GARCH 真的贏了 GJR——但 25% 收斂率讓這場勝利打了折
一句話結論
我們在 K621 跑了一版 MF2-GARCH(一個被 2025 年 Journal of Applied Econometrics 介紹、把波動率拆成「短週期」與「長週期」兩塊的新模型),表面上有點優勢;但 Codex 代碼審查抓出三個實作層級的 bug,等於 那一版的數字本來就不該採信 。K623 是把三個 bug 全部修正後的重估版,結論有兩面: 好消息是 ——在 SPY 美股 2023–2024 兩年的樣本外測試中,修正版 MF2-GARCH 在波動率預測的標準損失函數(QLIKE)上, 真的小幅勝過 GJR-GARCH(1.503 vs 1.530),而且這個差距達到了統計上的兩模型比較顯著水準。 壞消息是 ——這個模型在重複再估計的過程中, 24 次裡只有 6 次(25%)真正收斂 ,剩下 75% 都是用前一次的參數硬撐下去。所以雖然數字贏了,但這個贏法 離「可以放心上線」還有一段距離 ——這是一個「方法論成立、但工程穩定性不足」的中間結果,本文會誠實寫清楚兩面。
故事的起點:為什麼會想做這個模型?
GARCH 家族的模型在波動率預測這個領域已經被研究 30 多年。最常被當作 baseline 的 GJR-GARCH 加入了「壞消息對波動衝擊比好消息大」的不對稱效應,這一點抓得相當好。但 GJR 有一個結構上的限制—— 它只用一條方程式 處理波動,把「今天的盤中震盪」和「整個牛熊週期的長期變動」 揉在同一個 persistence 參數裡 。
直觀上這不太合理。市場的高波動其實有兩種來源:
- 短週期 ——某些天剛好新聞多、籌碼鬆動、盤中跳動大,但這種能量幾天就消散
- 長週期 ——景氣循環、信用週期、政策環境改變帶來的「整段時期都比較波動」的常態漂移
如果用同一條方程式抓兩件事,模型估出來的 persistence 參數通常會被拉到接近 1(IGARCH 邊界),長期預測就變成「過去高波動會無限延續」——這顯然不真實。
Conrad & Engle 在 2025 年發表的 MF2-GARCH(Multiplicative Factor 2-component GARCH) 就是針對這件事提出的解法。它把總波動率拆成兩塊乘起來:
總變異 h_t = g_t(短週期成分)× τ_t(長週期成分)
這樣一來:
- 短週期 g_t 是一個 單位均值 的 GJR 結構,專門抓「相對於長期水準的瞬時偏離」
- 長週期 τ_t 是一個 MEM filter,輸入是過去 m 天的「標準化波動」滾動平均,專門抓「長期水準本身的緩慢移動」
理論很漂亮 ,論文上也展示了在多個資產上 QLIKE 改善的證據。所以 K621 試圖把它端到端複製出來。
K621 的失敗——以及 Codex 為什麼救了我們
K621 跑出來的結果其實 看起來還不錯 ,但代碼進到 Codex 審查階段時被點出了 三個 HIGH 等級的 bug :
- 短週期方程式寫錯了 — 原本實作的 g_t 變成了標準的 GJR-GARCH(吃原始報酬平方、有自由 omega 參數),但這違反 Conrad & Engle 設計的「g_t 必須是單位均值、無量綱」約束。正確版本是吃 r²/τ(標準化後的訊號)、且截距項要被約束為 (1 − α − γ/2 − β),沒有 omega 自由度。
- V_t 的分母用錯了 — V_t(餵給長週期 filter 的那個量)原本被算成 ε²/σ²,但 σ² 是中間量、不是模型完整變異。正確版本必須用 V_t = (r − μ)²/(g_t × τ_t),也就是 用兩個成分相乘的完整變異 做分母。
- BIC 比較不公平 — 原本 K621 對不同 m 候選值(22、44、66、126、252)做 BIC 比較時, 有效樣本數會跟著 m 變化 ——大 m 等於丟掉更多前期資料、樣本更小。這樣的 BIC 不能直接比。正確版本是 所有 m 都用相同 burn-in(max(m_candidates) = 252) ,把所有候選 m 拉到同一條起跑線再比較。
這三個 bug 任一個都足以讓 K621 的數字失去意義。所以 K623 從頭重寫一遍,三個都修掉,然後重跑。
這也是「先讓 Codex 審代碼、再信結果」這條規範的具體案例——很多時候模型在紙上對、但實作層級錯掉一個小細節,整個結論就站不住。
K623 修正後的數字
樣本:SPY,2006-01-01 到 2026-03-27,共 5,088 個交易日。
樣本外(OOS)測試:2023-01-01 到 2024-12-31,共 502 個交易日。
估計窗口 2,000 天,每 21 個交易日重新估計一次。
比較對象:GJR-GARCH(baseline)、MF2-GARCH(修正版)、EWMA(簡單對照)。
主要損失函數:QLIKE
QLIKE 是波動率預測領域 首選 的損失函數——對於用「報酬平方」當代理變數的 noisy 波動率代理量來說,QLIKE 的排序穩定性遠勝 MSE。
| 模型 | OOS QLIKE | 與 MF2 比較 |
|---|---|---|
| MF2-GARCH(修正版) | 1.5030 | — |
| GJR-GARCH | 1.5303 | 兩模型比較顯著(達顯著水準) |
| EWMA(λ=0.94) | 1.5623 | 兩模型比較顯著(達顯著水準) |
MF2-GARCH 是 QLIKE 維度的贏家 ,且兩個對照組都通過嚴格統計檢驗門檻。
對照損失函數:MSE
| 模型 | OOS MSE |
|---|---|
| GJR-GARCH | 1.1522 |
| MF2-GARCH | 1.1329 |
| EWMA | 1.1213 |
MSE 的排序剛好顛倒——EWMA 反而最低。這個現象在波動率預測文獻很常見:MSE 對極端日(高波動 outlier)過度敏感,而 EWMA 因為「平滑而保守」的本性會在 MSE 上佔便宜,但平時的預測力其實偏弱。所以 主結論看 QLIKE,不看 MSE ——這是 Patton (2011) 那條經典守則。
那「打折」在哪裡?——25% 收斂率
把上面的數字單獨拿出來,會以為這是個漂亮的勝利。但 K623 有一個 不能掩蓋的工程問題 :
在 OOS 期間總共 24 次重新估計中,MF2-GARCH 只有 6 次(25%)真正收斂到 numerical optimizer 接受的 stationary point 。
剩下 18 次(75%)optimizer 都沒能達到收斂條件,模型只能 fall back 用前一次估到的參數繼續往前推。從 results JSON 看 mf2_params_log 也佐證——5 次有紀錄的成功估計,參數高度一致(α≈0.058、γ≈0.247、β≈0.760、λ₃≈0.959),這表示 模型在能收斂的時候是穩的 ;但「能收斂的時候」不是大多數時候,這是嚴重的工程缺口。
這意味著什麼?
- 學術角度 :模型在「狀態穩定」時表現可接受,QLIKE 改善是真的,這個發現可以寫進方法論討論。
- 實務角度 :要把這個模型放到生產環境(每天自動跑、自動下單) 還不行 ——因為 25% 收斂率代表 75% 的時候你不知道參數有沒有飄掉 ,下游風險管理沒法依賴。
- 未來方向 :這個結果指出 問題不在模型本身,在 numerical optimization 的初值與設定 。後續實驗(K970 等)已經改用 VIX 當作外生 τ 訊號繞開這個 numerical bottleneck,初步看來收斂率大幅改善,QLIKE 改善幅度也更穩定。
兩個附加觀察
觀察 1:MF2 和 GJR 的預測 走勢非常像
MF2 與 GJR 的 OOS 預測序列 相關係數 0.986 ——肉眼幾乎重合。這代表 MF2 的勝出 不是來自「在哪些日子預測完全不同」 ,而是來自「在大部分日子上微幅偏好較高/較低」這種 邊際差異累積 。
這也呼應我們先前 K970 系列的觀察:MF2 的長週期 τ 通常變動很慢(K623 中 τ 跨 refit 標準差只有 0.005,幾乎不動),所以 短期的 g_t 才是真正在做工 。換句話說,「兩成分分解」這個架構 目前仍未發揮預想的長週期 alpha 。
觀察 2:最佳 m = 66 對應的是約 3 個月
在 [22, 44, 66, 126, 252] 這幾個候選裡,BIC 選出 m = 66 ——對應大約 3 個月 的長週期記憶長度。
這個結果有方法論意義:m = 22(一個月)太短、m = 252(一年)太長,最佳的「長週期」其實落在 中段 ——3 個月的滾動平均剛好夠濾掉日波動雜訊、又不會過度平滑。這也跟 Conrad & Engle 原論文在多個美股資產上選出 m ≈ 60–80 的範圍一致。
誠實的整體判定
把這些湊在一起的判定是:
| 維度 | 狀態 |
|---|---|
| 方法論複製忠實度 | ✅ 三個 K621 bug 全部修正,與 Conrad & Engle 設計一致 |
| QLIKE 樣本外勝出 | ✅ vs GJR / vs EWMA 都達兩模型比較顯著水準 |
| MSE 樣本外勝出 | ❌ EWMA 反而最低(但 MSE 不適合波動率代理量) |
| 收斂率 | ⚠️ 25%(24 次中 6 次)— 工程穩定性不足 |
| 上線就緒 | ❌ 收斂率太低不能直接放生產 |
| 方法論貢獻 | ✅ 證明在「能收斂時」MF2 確實微幅勝 GJR |
換句話說: 這是一個有貢獻的 null-leaning result。 我們確實複製出了 Conrad & Engle 2025 的部分發現(QLIKE 維度勝出),但同時揭露了「直接照論文 spec 實作」會撞上的 numerical bottleneck(收斂率)。後續方向是用 K970 那套「VIX 做 τ 的代理訊號」繞過 numerical 問題,把整個架構推進到能上線的階段。
為什麼這篇值得一讀?
讀者大多時候只看到「某模型贏了某模型」這種乾淨的標題;但實際的研究過程 從來不乾淨 :
- K621 看起來贏了,但 bug 撤回
- K623 修完 bug 真的贏了,但工程上不穩定
- K970 才開始走向「可上線」
把這個過程寫出來,比直接報「MF2 在 SPY 上 QLIKE 改善 1.8%」更接近研究實況——也更有助於讀者判斷 什麼時候該信數字、什麼時候該打折扣 。
我們認為這種「中間態誠實報告」是這個平台願意持續做的——比起永遠端出「完美勝利」, 揭露收斂率這類工程缺口、把每一個 caveat 寫清楚 ,才是研究真正能累積信任的方式。
資料來源
- 市場資料 :yfinance 提供的 SPY ETF 日線收盤價,期間 2006-01-01 至 2026-03-27(共 5,088 觀察值)
- 波動率代理量 :日報酬率平方(r²,百分比尺度)
- 樣本外期間 :2023-01-01 至 2024-12-31(共 502 觀察值)
- 估計設定 :rolling window = 2,000 天、每 21 交易日重估、共 24 次 refit
- 比較對象 :GJR-GARCH(arch 套件實作)、EWMA(λ = 0.94,RiskMetrics 標準)
- 參考文獻 :Conrad, C. & Engle, R. F. (2025). Modelling Volatility Cycles: The MF2-GARCH Model. Journal of Applied Econometrics, 40(4), 438–454.
- 實驗代碼與完整 results :本平台 K623 實驗目錄
- 修正脈絡 :本實驗修正了 K621 由 Codex code review 識別的三個 HIGH 等級實作 bug(短週期方程式形式、V_t 分母、BIC burn-in 統一),詳見實驗 README
本研究記錄於 K623。後續方向見 K970 系列(用 VIX 做 τ 代理訊號繞開 numerical bottleneck)。
詳情
- experiment_refs
- K623
相關文章
先讀正式關聯,若無則使用標籤與主題相似度補齊