【數據騙局】你的回測為何總是「完美獲利」?揭密台股資料庫最致命的「倖存者偏差」:當下市的「壁紙股」被悄悄抹去,你的量化策略其實正踩在 1000 顆「隱形地雷」上裸奔
作者與來源揭露
- 作者
- 量子操盤手 (Quantum Trader)
- 審核
- 由 CULTIVATE 編輯團隊完成最終審閱
- 生成模型
- gemini-3-pro-preview
- 主要來源
- SYSTEM_CLI
許多量化新手的「聖杯策略」其實建立在有缺陷的數據上。本文深入解析台股回測中最致命的「倖存者偏差」,揭示當資料庫剔除下市股(如復興航空、樂陞)後,如何讓爛策略偽裝成高報酬神話,並提供正確構建 Point-in-Time 資料庫的實戰解法。
身為一名在台股市場打滾多年的量化交易員,我每週都會收到工程師寄來的「聖杯」策略報告。「年化報酬 40%」、「夏普比率 (Sharpe Ratio) 超過 3」……這些數字漂亮得令人眩目。但我通常只問一個問題,就能讓對方瞬間沉默:
「你的回測資料庫,包含已經下市的股票嗎?」
這就是量化交易中最經典、也最致命的陷阱——倖存者偏差 (Survivorship Bias)。
什麼是「倖存者偏差」?
二戰時期,美軍統計返航轟炸機的彈孔分佈,發現機翼和機身中彈最多,因此建議加強這些部位的裝甲。但統計學家 Abraham Wald 指出:你們看錯了!那些彈孔出現在引擎或駕駛艙的飛機,根本沒機會飛回來讓你們統計。你們只看到了「倖存者」。
在台股回測中,這個邏輯完全適用。如果你使用的免費數據源(如 Yahoo Finance 或未經處理的爬蟲資料)只包含「現在還在上市」的股票,那麼你正在犯下一個毀滅性的錯誤。
恐怖的「低價股翻身」幻覺
讓我們看一個最常見的例子:「低價股均值回歸策略」。
假設你的策略邏輯是:買入股價跌破 10 元的雞蛋水餃股,賭它會反彈。 如果你用「今天的上市清單」去抓過去 10 年的歷史股價回測,你會發現績效驚人。為什麼? 因為你的清單裡包含了長榮航 (2618)(曾經跌到個位數後來翻倍)、包含了旺宏 (2337)(曾經減資再起)。
但你的清單裡「剛好」漏掉了:
- 復興航空 (6702):2016 年解散,股票變壁紙,跌幅 100%。
- 樂陞 (3662):2017 年下市,收購案騙局,跌幅 100%。
- 博達 (2398):著名的掏空案。
在真實的歷史中,你買入這籃子低價股時,你會買到長榮航,也會買到復興航空。但在你的「倖存者」回測中,復興航空被資料庫剔除(因為它現在不存在了),你的程式碼以為你當年完美避開了所有地雷,只買到了後來會翻身的股票。
這不是回測,這是作弊。
技術解法:如何構建 Point-in-Time 資料庫?
要避開這個陷阱,你不能只用 get_current_tickers()。你需要建立或購買具有 Point-in-Time (PIT) 性質的資料庫。
1. 資料源選擇
- 免費/低成本陷阱:大喊「免費台股 API」的工具通常不包含下市數據。使用
yfinance抓台股時要非常小心。 - 專業數據源:TEJ (台灣經濟新報)、CMoney 等付費資料庫通常有「下市櫃」分類,你必須顯式地將這些數據納入回測。
- 券商 API (Shioaji/Fugle):雖然好用,但通常只提供即時或一定區間的歷史數據。若要回測 10 年,你通常需要自己維護一個 SQL 資料庫,並「手動」保留那些消失的代碼。
2. 程式邏輯修正 (Pseudo-code)
錯誤寫法 (Look-ahead + Bias):
# 這是自殺式的寫法
# 此函數通常只返回「今天」還活著的股票
universe = api.get_all_stocks()
for stock_id in universe:
history = api.get_price(stock_id, start="2015-01-01")
run_strategy(history)
正確寫法 (模擬真實歷史環境):
# 必須模擬每一天當下能看到的清單
dates = pd.date_range(start="2015-01-01", end="2025-01-01")
for today in dates:
# 這裡的 universe 必須包含當天上市,但後來可能下市的股票
daily_universe = database.get_universe_at_date(today)
# 針對當天清單做篩選
target_stocks = select_stocks(daily_universe)
# 下單...
開源工具的支援
如果你使用開源回測框架,要確認它們如何處理資料包 (Data Bundle):
- Zipline / Zipline-Reloaded:它的架構支援
ingest過程,你可以寫自定義的bundle來匯入包含已下市股票的 CSV 檔。這是最嚴謹的做法。 - Backtrader:非常靈活,它不在乎你的數據源是什麼。你需要自己準備一份包含下市股的 CSV,並在回測時間軸走到該股票下市日時,模擬「以最後價格強制平倉」或「歸零」的邏輯。
結語
量化交易不是在比誰的演算法數學更難,而是在比誰的數據更乾淨、更接近真實。 在台股這個淺碟市場,下市、減資、暫停交易頻繁發生。如果你想用 Python 打造你的交易機器人,請先花 80% 的時間清洗數據。
記住:垃圾進,垃圾出 (Garbage In, Garbage Out)。不要讓倖存者偏差騙走了你的積蓄。
🛠️ CULTIVATE Recommended Tools | 精選工具推薦
- Codecademy: Learn Python and Data Science interactively from scratch.
- Interactive Brokers: Low cost professional trading platform for global markets.
- Poe: Access all top AI models (GPT-4, Claude 3, Gemini) in one place.
Disclosure: CULTIVATE may earn a commission if you purchase through these links.