台股 0050/0051 多因子策略實測:結合波動度體制與 Rolling Sharpe 打造動態避風港

本文目錄
  1. 先搞懂主角:0050 與 0051 到底差在哪?
  2. 策略核心:從「固定閾值」到「體制感知」
  3. 三大體制怎麼運作?進出場條件全公開
  4. 程式碼示意:Rolling Sharpe 與體制判斷怎麼寫
  5. 避雷防坑指南:量化開發常見的三個坑
  6. 回測數據對比:D2_Regime 的示範結果
  7. 實務執行架構:從訊號到帳本
  8. 常見問題 FAQ
  9. 結論:策略再好,執行力才是關鍵

如果你也曾在台股市場裡,看著手上的電子股在大盤反轉時被腰斬,卻不知道該不該停損,那你大概能理解「用固定規則打天下」為什麼行不通。這篇文章談的台股 0050/0051 多因子策略,核心不是預測明天漲跌,而是讓系統依照市場「體制」自動調整持股水位。我會拆解波動度體制模型、Rolling Sharpe 動態權重的設計邏輯,並附上可照抄驗證的 Python 示意程式碼。

資料誠信聲明:本文所有績效數字均為策略研究與教學示範用途,來自可重現的回測腳本,非實盤交易紀錄。回測期間短、樣本筆數少,且同期大盤為大多頭,歷史績效不代表未來。讀者需自行驗證後謹慎使用。策略自 2026/07/12 起才進入模擬交易階段,實際表現請參考網站的實盤追蹤頁。

先搞懂主角:0050 與 0051 到底差在哪?

很多人把 0050、0051 當成「兩檔很像的 ETF」,但它們的產業曝險與波動特性差很多,而這正是多因子策略要分開對待兩者的原因。

項目 元大台灣50(0050) 元大台灣中型100(0051)
追蹤指數 臺灣50指數 臺灣中型100指數
成分股定位 台股市值前 50 大權值股 市值第 51~150 名的中型股
產業結構 半導體權重極高,台積電一檔就佔相當大比重 電子、傳產、金融相對分散,中小型電子與 AI 供應鏈比重較高
波動特性 相對穩、與大盤連動高 波動較大、超額報酬與超額風險同時放大
費用率 經理費+保管費合計約 0.4% 上下(實際以投信公告為準) 同類型費用結構,實際以投信公告為準
常見用途 大盤 beta、現金停泊、長期持有 中小型股 Alpha 來源、選股池

為什麼這個差異對策略很重要? 0050 的成分股是「大家都知道的好公司」,法人研究覆蓋率高、價格效率高,要從中榨出超額報酬很難;0051 的中型股研究覆蓋率低、籌碼與營收變化的資訊落差大,才是多因子策略比較有機會的地方。所以本文策略的設計是:用 0050 當現金停泊與大盤體制判斷的錨,用 0051 成分股當選股池。

提醒:兩檔 ETF 的規模、費用率、成分股會隨時間調整,實際數字請以投信官網與公開資訊觀測站最新公告為準。

策略核心:從「固定閾值」到「體制感知」

最直覺的版本邏輯很單純:只要決策分數 score >= 0.60,就滿倉硬上。這樣做在多頭裡效果驚人,但問題是——市場不會永遠是多頭。固定閾值在熊市一樣讓你滿倉,等於沒有風控。

二期優化的核心,就是加入市場體制模型(Volatility Regime)。系統根據大盤 200 日均線位置與波動度百分位數,自動判斷目前是牛市、盤整、還是熊市,再動態調整三件事:

  • 進場門檻(分數要多高才能買)
  • 部位上限(最多能壓幾成資金)
  • 選股檔數上限

這套邏輯稱為 D2_Regime。搭配 Rolling Sharpe 機制,系統會滾動重算籌碼、營收、ROE、動能這四大因子在「當下體制」裡的最優權重比例,而不是死板地套用同一組權重打天下。

三大體制怎麼運作?進出場條件全公開

這是整套策略的靈魂,用表格攤開來看最清楚:

體制 判斷條件 進場部位分配 決策分數門檻 選股上限
牛市 Bull 大盤高於年線且低波 100% 0.45 分 5 檔
盤整 Sideways 大盤高於年線但高波 50% 0.55 分 2 檔
熊市 Bear 大盤低於年線 上限 10%(強制清空主動持股) 0.65 分 0 檔

熊市「清空持股」和「門檻 0.65 分」怎麼共存?

這是最常被問到的邏輯銜接問題,這裡一次講清楚:

  • 強制清空持股是「既有部位」的處理規則:一旦體制切換為熊市,系統在次一交易日開盤把主動選股部位全部平倉,資金轉為現金(或停泊在 0050)。
  • 0.65 分門檻與 0 檔選股上限是「新倉」的規則:清空後系統並非完全停擺,而是進入「只觀察、不建倉」狀態。0 檔上限代表當天不允許開任何新主動倉;0.65 分門檻則是萬一體制在盤中被重新判定回非熊市時,新倉必須跨過的高標準門檻。

換句話說:熊市 = 先清空、再凍結新倉,門檻是「解凍後的第一道防線」,兩者不衝突,而是先後順序關係。

四大因子細節

  • 籌碼面:投信近 3 日累計淨買超 > 0(熊市體制下此因子權重會拉高,因為熊市裡籌碼訊號相對不易失真)
  • 營收面:TTM 營收年增率 >= 10%(熊市體制下此因子權重自動調降,避免踩到財報美化的雷)
  • ROE 面:TTM ROE >= 10%(牛市體制下權重相對最高)
  • 動能面:20 日高點趨勢向上,且收盤價高於月線、月線 > 季線

出場是紀律問題:個股收盤跌破 60 日均線(MA60)就在次日開盤平倉,或觸發 2 倍 ATR 動態停損點。單一持股上限鎖在 20%,單筆最大風險控制在 1.5%,這是用「2 倍 ATR 波動度」計算建倉比例後的結果,避免單押某檔股票爆倉。

程式碼示意:Rolling Sharpe 與體制判斷怎麼寫

以下為示意程式碼,非可直接執行之完整系統,目的是讓讀者理解邏輯,資料來源、欄位名稱與參數請依自身環境調整。

1. 用 pandas 計算滾動 Sharpe 與因子權重

PYTHON
import numpy as np
import pandas as pd
def rolling_sharpe_weights(factor_returns: pd.DataFrame,
window: int = 60,
min_periods: int = 30) -> pd.DataFrame:
"""
factor_returns: 各因子的日報酬(index=日期, columns=因子名稱)
回傳:每個時間點各因子的滾動 Sharpe 佔比(權重和為 1)
"""
roll_mean = factor_returns.rolling(window, min_periods=min_periods).mean()
roll_std = factor_returns.rolling(window, min_periods=min_periods).std()
roll_sharpe = roll_mean / roll_std.replace(0, np.nan)
# 只取正 Sharpe 的因子,負值歸零避免反向加權
positive = roll_sharpe.clip(lower=0)
weights = positive.div(positive.sum(axis=1), axis=0)
return weights

2. 用 200 日均線與波動度百分位判斷體制

PYTHON
import numpy as np
import pandas as pd
def classify_regime(price: pd.Series,
vol_window: int = 20,
ma_window: int = 200,
vol_lookback: int = 252,
high_vol_pct: float = 0.7) -> pd.Series:
"""
price: 大盤(例如 0050)收盤價序列
回傳:'bull' / 'sideways' / 'bear' 三種體制標籤
"""
ma = price.rolling(ma_window).mean()
daily_ret = price.pct_change()
vol = daily_ret.rolling(vol_window).std()
# 波動度在過去一年的百分位
vol_pct = vol.rolling(vol_lookback).rank(pct=True)
above_ma = price > ma
is_high_vol = vol_pct >= high_vol_pct
regime = pd.Series(index=price.index, dtype="object")
regime[above_ma & ~is_high_vol] = "bull"
regime[above_ma & is_high_vol] = "sideways"
regime[~above_ma] = "bear"
return regime

3. 依體制決定部位上限與選股檔數

PYTHON
REGIME_RULES = {
"bull":     {"score_threshold": 0.45, "max_positions": 5, "exposure": 1.00},
"sideways": {"score_threshold": 0.55, "max_positions": 2, "exposure": 0.50},
"bear":     {"score_threshold": 0.65, "max_positions": 0, "exposure": 0.00},
}
def get_rule(regime: str) -> dict:
return REGIME_RULES.get(regime, REGIME_RULES["bear"])

這三段加起來,就是「體制判斷 → 動態權重 → 部位規則」的主幹。實際系統還要接上資料清洗、因子計算、下單與風控,這只是骨架。

避雷防坑指南:量化開發常見的三個坑

地雷一:忽略資料污染,回測數字漂亮到不真實

常見的錯誤是在歷史資料補全時混入未來函數(look-ahead bias),例如用「當年度已公布財報」回推「當時還不知道的營收」,回測就會虛高到不真實。這種數字在樣本內好看,一出樣本外就崩掉。

防範建議:務必用 OOS(樣本外)隔離測試期驗證策略,並確認每個因子在 t 時間點只使用 t 之前可得的資料。

地雷二:固定閾值滿倉硬上,回撤失控

固定 0.60 分閾值在熊市一樣讓你滿倉,等於沒有風控。防範建議:搭配體制判斷做動態部位限額,不要用單一套邏輯打天下。

地雷三:排程可靠性沒設計好,訊號漏推

這是「非策略性」但很致命的問題。通用原則是:

1. 排程任務要能回報執行結果(成功/失敗都要有訊號),不能默默失敗。

2. 執行環境若可能進入睡眠,需在排程前後加上防睡眠機制(例如 macOS 的 caffeinate)。

3. 關鍵任務建議設定「補跑」機制與逾時告警,而不是只依賴單一時間點觸發。

回測數據對比:D2_Regime 的示範結果

以下數據由 tools/d2_backtest_summary.py 以策略原始程式碼重跑,為策略研究與教學示範用途,非實盤結果。

回測設定

  • 回測期間:2024-03-26 ~ 2026-06-24(約 2.2 年;本機資料自 2024/03 起)
  • 股池:0050 與 0051 成分股中的電子科技類股,共 51 檔
  • 成本假設:手續費 0.1425%(6 折)、證交稅 0.3%、買賣各 0.1% 滑價
指標 D2_Regime 0050 買入持有
累積報酬 249.95% 179.44%
年化報酬 78.46% 60.83%
最大回撤 -21.7% -28.47%
夏普值 2.152 —
交易筆數 23 筆 —
勝率 34.78% —

樣本限制(必讀):交易樣本僅 23 筆、期間僅約 2.2 年,且同期大盤為大多頭。這樣的樣本數不足以推論策略在空頭市場的表現,歷史績效不代表未來。

注意:過去流傳的「5.5 年」「年化 43.12%」「回撤 -25.88%」「方案 C」等數字,經重跑後無法重現,本文一律不採用。

實務執行架構:從訊號到帳本

策略再漂亮,沒辦法穩定執行都是紙上談兵。一套可運作的流程通常包含:

1. 定時排程:每日固定時間觸發訊號計算與推送,並設計失敗告警與補跑機制。

2. 雙向記帳:可用通訊軟體 Bot 接收口語化指令(例如「買 2330 650 1.2張」),背景程式定期解析並更新本地帳本檔案(如 paper_portfolio.json),方便隨時檢視部位。

在開發與監控過程中,我也習慣搭配 TradingView 來做技術面的交叉驗證。對多因子策略來說,TradingView 的價值在於把抽象的體制判斷視覺化:你可以直接在圖上疊加 200 日均線、觀察波動度指標的位置,人工確認程式判定的「牛市/盤整/熊市」切換點是否合理。當程式輸出與圖表明顯不一致時,往往就是資料或邏輯出問題的第一個警訊——這對正在驗證 Rolling Sharpe 權重是否合理的開發者來說,是很實用的除錯輔助。

常見問題 FAQ

Q1:台股多因子策略適合新手直接套用嗎?

如果你完全沒有量化交易 Python 的基礎,建議先從理解「體制判斷」與「因子權重」的邏輯開始,而不是直接複製參數。這套策略高度依賴資料品質與程式邏輯的正確性,資料污染就是最常見的坑,新手貿然套用容易誤判實際勝率。

Q2:Rolling Sharpe 動態權重跟固定權重差在哪?

固定權重是「一組參數用到底」,但市場體制會變化——熊市裡籌碼因子相對有效,牛市裡 ROE 因子相對關鍵。Rolling Sharpe 會定期滾動重算歷史數據,找出當前體制下表現較好的因子組合,動態調整權重。

Q3:為什麼熊市體制要強制清空持股,不是逢低加碼比較好?

這套策略的核心哲學是「防守優先」。強制清空持股雖然會犧牲部分反彈的獲利機會,但換來的是心理層面能撐過整個週期、不會在最壞的時候被迫停損出場。逢低加碼需要極高的資金控管與心理素質,並非所有投資人都適合。

Q4:0050 和 0051 我該選哪一檔?

兩者定位不同:0050 是市值型、與大盤連動高,適合當核心持股或現金停泊;0051 涵蓋中型股、產業較分散,波動與超額報酬空間都較大,適合作為選股池或衛星配置。本文策略是兩者並用,而非二選一。

Q5:本文的績效數字可以直接當成未來預期嗎?

不行。 本文數據為策略研究與教學示範用途,非實盤交易紀錄,且樣本僅 23 筆、期間約 2.2 年、同期為大多頭。讀者需自行驗證後謹慎使用。

結論:策略再好,執行力才是關鍵

D2_Regime 用體制感知取代了固定閾值的僵化邏輯,在可重現的回測中取得累積 249.95%、年化 78.46%、最大回撤 -21.7% 的示範結果,同期 0050 買入持有為累積 179.44%、年化 60.83%、最大回撤 -28.47%。但請務必記得:樣本只有 23 筆、期間僅約 2.2 年、且是多頭環境,這樣的數字不能線性外推到未來。

真正能讓你走得更遠的,是資料誠信、可驗證的程式邏輯,以及嚴格的風控紀律。如果你想開始建立自己的台股多因子策略,建議先從用圖表確認體制切換點開始練習,善用 TradingView 這類工具做視覺化驗證,再逐步導入你自己的 Python 回測系統。量化交易不是聖杯,但紀律加上正確的風控邏輯,能讓你在台股市場走得更穩。

現在就開始:打開你的 Python 環境,把上面的 classify_regime() 貼進去,用 0050 的歷史日線跑一次體制分類,看看過去幾年的牛熊切換點是否符合你的直覺——這是你驗證任何多因子策略的第一步。