回測過擬合怎麼看出來?參數最佳化之後該做的三件事
你把參數掃了一輪,回測曲線漂亮到讓你想直接按 live trading——年化 120%、最大回撤 8%、勝率 62%。 接下來大概率會發生的事:實盤第一個月就吃掉回測三年淨利的一半。這不是壞運氣,是「過擬合」 (overfitting)留下的收據。
這篇不評論你用哪個策略邏輯——邏輯本身可能沒問題,問題往往出在參數怎麼挑的、用哪段資料挑的。 給你三件事,都是最佳化按下去之後、把策略搬上實盤之前該做的驗證,一件都不能省。
先講清楚:過擬合到底把「什麼」配給「什麼」
過擬合的機制很直接:你在同一段歷史資料上,同時做「選策略」與「調參數」兩件事, 最後挑到的那一組,本質上是對這段歷史的雜訊拿到滿分——不是對市場的 結構性行為拿到滿分。
把資料想成一張考卷。你先看完考卷再回頭挑答題方法,考出來當然全對——但那不能推論你 下一張考卷也會這樣。過擬合的核心就是這個:你用未來看過的資料回頭挑參數,然後用同一份 資料驗證挑得對不對,整個流程裡沒有任何資訊在告訴你這組參數對「沒見過的資料」有沒有效。
第一關:把資料切開,最佳化只能碰 in-sample
最基本、也最常被跳過的動作:資料一開始就切兩塊。一塊給你隨便玩—— 參數怎麼調、指標怎麼加、規則怎麼改都可以;另一塊鎖起來,最佳化跑完那一刻才第一次 拿出來看。這塊不能參與任何選擇,一旦拿出來看過就報廢,不能再用。
切法沒有唯一正解,看你手上有多少年資料。(本文寫作時整理的常見基準)
這裡有個很容易騙自己的做法:你把 out-of-sample 拿出來看,發現不理想,回頭改參數, 再看一次。這個當下 OOS 就報廢了——它已經被最佳化流程間接碰過, 跟本來的 in-sample 沒有本質差別。看第二次的 OOS 不叫 out-of-sample,叫另一段 in-sample。
想避開這個陷阱,可以再切第三塊叫 hold-out:整個開發過程完全不碰, 策略要交付給實盤那天才第一次看。這塊小一點沒關係(15% 到 20%),它的作用是給你 「這組參數在真的沒見過的資料上長什麼樣」一個誠實的參考。
第二關:walk-forward — 讓「最佳化」變成一直發生的事
切一次 in-sample/out-of-sample 有個弱點:你只驗證了「用前 70% 挑的參數, 在後 30% 上還有效」這一個切點。市場如果換了個模式,你這組挑三年前資料調出來的 參數,可能三年來都在慢慢失效,你只是還沒發現。
walk-forward 的想法很單純:把資料切成很多小段,每段都跑一次「用前面 N 個月調參數、 用接下來 M 個月驗證」,然後把「驗證段」全部拼起來當成一條連續的樣本外曲線。 這條曲線比較接近「真的照這個流程做的話,這幾年會拿到什麼」。
| 單次切樣本外 | walk-forward | ||
|---|---|---|---|
| 驗證了幾個時間點? | 1 個切點 | 很多個滾動視窗 | |
| 對「市場換模式」的抵抗力 | 低(用一段舊資料挑) | 高(每個視窗都重新挑) | |
| 設定複雜度 | 簡單 | 要決定視窗長度與滾動步長 | |
| 運算成本 | 跑 1 次最佳化 | 跑 N 次最佳化 | |
| 最像實盤的行為 | 不太像 | 接近你會怎麼定期重調 |
兩種驗證方式的取捨。walk-forward 較貴,但更接近「策略要定期重調」的現實。
walk-forward 有個副產品同樣重要:每個視窗挑到的「最佳參數」是什麼?如果十個視窗挑到十組差很多的值,那不是這個策略敏感——是這個策略沒有真的規律, 只是每次都在配當下那段雜訊。反過來,十個視窗挑到差不多的參數,那才是真的抓到什麼。
第三關:參數敏感度 — 你挑到的是山峰還是山脊?
同樣一組回測拿到 Sharpe 2.1,可能是兩種很不一樣的東西:山峰—— 你剛好挑到那唯一的高點,任何一個參數挪一格數字就掉到 Sharpe 0.5;山脊—— 你周圍一片參數都在 Sharpe 1.8~2.1,挪一格還是差不多。第一種是過擬合的教科書範例, 第二種才是可以搬上實盤的東西。
把「參數 vs 績效」的 3D 熱圖畫出來看是最直觀的做法。真的有規律的策略,圖看起來會是 一片緩坡;過擬合的策略看起來是幾根尖刺。這一步不需要新工具,用你已經在跑的最佳化 結果自己畫。
順帶一提:資料量夠不夠支撐你調的參數個數
參數愈多,過擬合愈容易——這句話幾乎是常識,但少有人講具體門檻。這裡列一個粗略的 經驗值,來自機器學習的一般原則(不是交易獨有):每多一個要調的參數,你需要的獨立 樣本數會加倍成長。把「回測跑過的交易筆數」當成樣本數來估:
這是粗略的健康檢查值,不是精確門檻。策略愈複雜,數字要往上抓。
如果你的策略跑三年只成交 40 筆,卻在調 5 個參數,那不是「策略太挑」——是資料量根本 不夠讓你分辨「真的有效」與「剛好配到」。這種情況下,唯一有意義的動作是換更高頻的 timeframe、或把參數個數砍到 2 個以內。
三關都過了:實盤上線前的最後兩步
就算前面三關全過,也不建議直接開正常倉。上線之後的兩件事同樣關鍵:
- 先開 1/3 或更小的部位跑一到兩個月。回測會漏算的東西——真實成交延遲、滑點、部分成交、交易所偶爾的拒單——只有實盤會告訴你。
- 紀錄每一筆回測 vs 實盤的偏差。同一根 K 棒的訊號、實際成交價、以及最終 PnL 有沒有系統性偏離回測預期。
- 設定一個停止線:實盤累積虧損超過 X% 或連續 N 筆偏離回測,就先停下來檢查——不要等到已經吃完 3 個月才發現不對。
- 要把部位放大之前,用實盤這一到兩個月的資料再跑一次
walk-forward驗證。這是最誠實的一份 out-of-sample 資料。
部位怎麼從小開始加大,跟策略邏輯是兩回事,屬於資金管理的問題。這一段可以另外看 Kelly 公式與部位大小 那篇,那邊有講「半 Kelly」為什麼是實務常用的折衷。
這三關都幫不了你的事
講完做得到什麼,也該講清楚做不到什麼——這是這篇最容易被誤解的地方。walk-forward 與參數敏感度都是「同一個市場環境」的驗證, 它們對付不了下面這幾種東西:
執行成本被低估:多數回測工具預設的手續費、滑點都是理想值, 真實的做市商庫存、taker 手續費、部分成交都會啃掉一部分理論淨利。
訊號稀疏度:一年只觸發 10 次的策略,就算 walk-forward 過關, 也可能只是這 10 次剛好對——樣本太少,統計上沒有意義。
你自己會不會關掉它:一組回測看起來能扛 40% 回撤,實盤跌到 20% 你就 睡不著關掉了——這是行為問題,測不出來。
誠實的一段:把回測數字放在該有的位置
這篇本身沒有貼任何具體的策略回測數字,是刻意的——沒有標的、期間、參數、樣本外設定 一起附上的績效數字,不管數字多漂亮,讀者拿去做決策都是危險的。過去績效不代表未來表現,這句話在回測結果上尤其成立: 回測是模擬,不是實單紀錄。
如果你要在自己的文章、Twitter 或給付費訂閱者的訊號裡放回測結果,最低限度該附上: 標的(例如 BTCUSDT.P)、時間範圍(例如 2023-01 至 2025-12)、 參數組(不要只寫「經最佳化」)、有沒有 walk-forward、以及一句「這是模擬結果, 不代表實盤獲利」。少一個都會讓別人沒辦法判斷這份績效值不值得跟。
這也是為什麼建議在做量化之前先看 散戶怎麼開始做量化交易 那篇——裡面有一整段在講「年化 500% 不是 overfitting 就是還沒崩」,可以當這篇的姊妹篇。
常見問題
walk-forward 的每個視窗都要重新挑參數嗎?那不是等於一直在最佳化?
為什麼參數敏感度要 ±10%,不是 ±20% 或 ±5%?
in-sample 表現太差,能不能回去換策略邏輯,再走一次流程?
什麼樣的策略最容易過擬合?
工具面上,這三關要怎麼跑?
backtesting.py、vectorbt)自己組。先去自己工具的設定裡找 「walk-forward」或「rolling window」的選項,沒有的話就得把資料匯出到別的工具做。Get started
TVSBot 是非託管的 TradingView → 交易所自動下單平台。把你驗過的策略接上 webhook,用你自己的 API key,先開 dry-run 或小部位跑一輪實盤——這是「三關通過之後」該接的下一段。
免費開始