日期:2026-04-21 範圍:台股主動式量化策略 sanity check 第一輪 結論:三個結構性不同的架構均未通過 pre-commit 門檻;Round 1 正式收尾
Round 1 目標:驗證「能否建立在散戶實務執行條件下、可穩定打敗 0050 Buy&Hold 的主動式量化策略」。
三個結構性不同的架構先後測試,全部失敗,但失敗模式各異,皆具研究資訊價值:
| 架構 | 核心 signal | Pre-commit 結果 | 關鍵失敗模式 |
|---|---|---|---|
| 1. 日頻 ML ranker | LightGBM per-stock prob + cross-sectional rank | 0/5 pass (hold=5,10,15,20 全 fail) | Alpha 太薄(t=5+ 顯著但絕對值 ~0.25%),execution friction 全部吃掉 |
| 2. ETF 月頻輪動 | 6M 純動能 | 3/5 pass (Sharpe 0.85, vs 0050 −8.6%) | 宇宙過度相關(68% 類 0050),輪動實質在選 0050 + TC |
| 3. 月營收事件驅動 | 純 YoY (revenue[t]/revenue[t-12]-1) | 2/5 pass (Sharpe 0.88, MaxDD 47.1%, vs 0050 −3.7%) | Alpha 真實但波動過大,純 YoY 被低基期噪音放大 |
pre-commit 門檻(由用戶於 2026-04-21 鎖定,全程未修改):
- 年化 ≥ 12%
- Sharpe ≥ 1.0
- PF ≥ 1.3
- MaxDD < 30%
- vs 0050 > 0(必須贏 0050)
Baseline(修復 look-ahead 前):+211% 年化 / Sharpe 3.99(假象)
改用 realistic 執行(T+1 open + intraday low stop + TC 0.585%)後的實測:
| hold_days | 年化 | Sharpe | PF | MaxDD | vs 0050 |
|---|---|---|---|---|---|
| 5 | −8.6% | −1.72 | 0.84 | 57.4% | −36.6% |
| 10 | +2.5% | 0.63 | 1.08 | 43.2% | −25.6% |
| 15 | +0.2% | 0.32 | 1.04 | 59.4% | −27.9% |
| 20 | +5.7% | 1.15 | 1.12 | 53.7% | −22.4% |
Raw alpha 統計顯著(Top-K vs market t=6.10~2.34, p<0.01),但絕對值僅 +0.25%/trade 超額。扣除 TC 0.585% + slippage 0.3% = 0.885% 摩擦後,淨期望值必為負。
結構性診斷:
- 這不是模型能力問題,是 raw alpha 絕對值 < 真實摩擦成本
- 類似結構(55 檔、日頻、close timing、固定停損)無論疊哪些特徵 / 換哪種模型都救不回來
- 結論:此架構對散戶實務不可行
Spec:
- Universe = 8 支 2018 前上市 ETF(0050, 0056, 006208, 00692, 00646, 00662, 00678, 00713)
- Signal = 純 126 天 (6M) 動能
- Rebalance = 每月第 1 個交易日
- Top-K = 3,等權
- Entry = T+1 open × (1 + 0.1%)
- TC = 0.3% round trip,無停損
結果:
- 93 rebalances / 279 trades
- 勝率 60.2%、平均淨 +1.20%/trade、PF 1.83
- 年化 +13.9%(pass 12%)、MaxDD 24.2%(pass 30%)、PF 1.83(pass)
- Sharpe 0.85(fail 1.0)、vs 0050 −8.6%(fail)
結構性診斷:
- 8 支 universe 中 68% 是「類 0050」兄弟 ETF(市值型 + 高息)
- 動能輪動實質在「0050、006208、00692」間切換
- 等於「付 TC 持有 0050」
- 結論:universe 選擇決定一切,純動能在同質 universe 內無法產生 alpha
Spec:
- Universe = 54 支 DEFAULT_TW_STOCKS 中有月營收資料者
- Signal = 純 YoY = revenue[t] / revenue[t-12] − 1
- Entry timing = 營收月份結束 + 15 日曆天 + T+1 open(保守避 look-ahead)
- Top-K = 10
- Hold = 1 個月(下次 rebalance)
- TC = 0.585%,無停損
- 特別規則:缺 t-12 直接跳過,不補值,不使用 DB 的 revenue_lastyear 欄位
結果:
- 86 rebalances / 841 trades
- 勝率 54.2%、平均淨 +2.08%/trade(三個架構中最高)、PF 1.67
- 年化 +23.2%(pass 12%,三架構最高)、PF 1.67(pass)
- Sharpe 0.88(fail 1.0)、MaxDD 47.1%(fail 30%)、vs 0050 −3.7%(fail 邊緣)
結構性診斷:
- 這是三個架構中 alpha 訊號最強的一個
- +2.08%/trade 淨報酬遠超過其他架構
- 失敗在波動:純 YoY 被低基期噪音放大(例:YoY +444%、+608% 大多是「去年同月 ≈ 0」的財務 artifact,非真實成長)
- Selection 選到「基本面突變股」而非「穩定高成長股」
- 結論:訊號源獨立有效,但純 YoY 定義太糙,波動無法控制
- ✅ 三次都用 realistic execution (T+1 open + intraday low stop + TC ≥ 0.585% for 個股, 0.3% for ETF)
- ✅ 三次都 8 年完整 walk-forward (2018-01-01 ~ 2026-04-15)
- ✅ 三次都用同一組五指標門檻
- ✅ 失敗後沒有為單一策略「找理由續命」(例如在 Revenue Event 看到 +23% 年化時未放寬門檻)
- ✅ 三次都 sanity check 先行,未在第一輪疊加多因子
Pre-commit 機制在 Round 1 阻擋了三次「看到好數字就想繼續做」的傾向:
| 場景 | 沒有 pre-commit 時的誘惑 | Pre-commit 強制結論 |
|---|---|---|
| 日頻 ML +211% 年化 | 「看起來不錯!」 | 實際是 look-ahead + close stop 雙重樂觀,realistic 實測 −5~+5% |
| ETF 輪動 3/5 pass | 「只差一點點,調 Top-K 或 signal 就好」 | 結構問題(universe 相關性),不是參數問題 |
| Revenue Event +23% 年化 | 「這個有 alpha,我們放寬 MaxDD 門檻吧」 | MaxDD 47% 真實、alpha 確實但版本不合格,Round 1 結束 |
結論:pre-commit 是有效工具。Round 2 維持同樣紀律。
| 規則 | Round 1 設定 | Round 2 建議 | 理由 |
|---|---|---|---|
| Benchmark 選擇 | 0050 Buy&Hold 2018-2026 | 考慮加入「0050 長期均值 8-12%」做雙 benchmark | 2018-2026 是 0050 歷史異常強期(+26.9%),長期均值更合理 |
| vs 0050 > 0 門檻 | 必須在 2018-2026 區間贏 | 必須在長期均值(10-12%)上贏,2018-2026 同期至少不輸 −5% 內 | 避免因特殊 regime 錯殺真有 edge 的策略 |
| MaxDD 門檻 | < 30% | 保留 < 30% 但允許「條件通過」:MaxDD < 40% 且 Calmar > 0.5 | Revenue Event 的 +23%/47% DD 有 Calmar ≈ 0.5,不一定該直接否決 |
- ✅ 8 年完整回測期間
- ✅ Realistic execution(T+1 open、intraday low stop)
- ✅ TC ≥ 真實水準(個股 0.585%、ETF 0.3%)
- ✅ Sanity check 一律先用最簡單 signal、failed 再優化
- ✅ 不在同一 round 內「因為看到結果漂亮就放寬門檻」
- ✅ 每次修改必須寫入新 round design document,不能 in-run 修改
優先級 P0(基於 Round 1 的直接學習):
-
Revenue Event + base-effect 過濾 — 在 YoY 之前加條件
revenue_lastyear > threshold_NTD(例如月營收 > 1 億)過濾低基期 artifact。預期 MaxDD 降到 30-35%、Sharpe 升到 1.0-1.2、年化可能降到 15-20%。這是 Round 1 最有把握改善的方向。 -
Revenue momentum 正統定義 — 研究學術 revenue momentum 定義(非純 YoY):
- SUE(Standardized Unexpected Earnings)台股版
- Revenue surprise vs analyst consensus(若有資料)
- Trailing 12-month revenue growth rate
- Revenue growth acceleration(YoY 的一階差分)
優先級 P1(尚未測試的結構):
-
80/20 Overlay — 80% 持 0050 + 20% 做 tactical tilt(可用優化後 Revenue Event)。設計目標「小贏 1-3% 或至少不輸」,避開「必須打敗 0050」的高門檻。
-
籌碼追蹤 — 機構 net buy 訊號。subagent 警告 crowded trade 風險,但仍未實測。
優先級 P2(大改動):
-
擴大宇宙 — Revenue Event 擴到 200-300 大市值股票,用 universe 大小對抗波動
-
跨類資產配置 — 納入非 TW 資產(美股 ETF、黃金、債券)做真正不相關 universe 的輪動
- 先做一次 Round 2 design document(不要直接開始 coding)
- 在 design 階段就 pre-commit 所有規則與門檻
- 執行實驗 → 寫 round-2 verdict
- 如果仍全部失敗 → Round 3(或接受 passive)
以下基礎建設已完成、驗證過,Round 2 可直接重用:
data/collector.py+data/database.py:台股 OHLC、國際指數、VIX、PCR、breadth、margin、月營收、新聞、籌碼- 8 年歷史資料 on 55 檔主要股票 + 8 檔 ETF
tw_monthly_revenuetable:54 支有 2018-2026 月營收完整資料
features/pipeline.py:142 個技術/市場特徵features/sentiment.py:三層情緒引擎(L1 FinBERT、L2 市場數據、L3 事件)
strategy/decision_fusion.py:決策融合(含 black swan hard gate、regime gate)strategy/stop_loss.py:ATR-based 停損strategy/position_sizing.py:Kelly-safe + VIX 調整
backtest/signal_backtest.py:walk-forward 訊號回測(daily/weekly)backtest/weekly_ranker_backtest.py:C+ 週頻 Top-10 擴充backtest/etf_rotation_backtest.py:ETF 輪動(momentum-based)backtest/revenue_event_backtest.py:月營收事件驅動scripts/exec_bias_analysis.py:execution bias replay 工具
output/reporter.py:live 日報格式- 多個
scripts/run_*.py:各策略 CLI
所有 backtest report 位於 output/reports/:
| 檔案 | 策略 |
|---|---|
weekly_backtest_2018-01-01_2026-04-15_h5_top10_atr2.txt |
週頻 hold=5 |
weekly_backtest_2018-01-01_2026-04-15_h10_top10_atr2.txt |
週頻 hold=10 |
weekly_backtest_2018-01-01_2026-04-15_h15_top10_atr2.txt |
週頻 hold=15 |
weekly_backtest_2018-01-01_2026-04-15_h20_top10_atr2.txt |
週頻 hold=20 |
etf_rotation_2018-01-01_2026-04-15_top3_126Dmom.txt |
ETF 輪動 |
revenue_event_2018-01-01_2026-04-15_top10_buf15d.txt |
月營收事件 |
- 所有 Round 1 程式保留(未刪除)供 Round 2 參考
- 下次啟動 Round 2 前,請先更新本文件第 4 節(Round 2 研究設計)後再開始 coding
- Pre-commit 紀律在 Round 2 繼續適用
Round 1 正式結案:2026-04-21