複合動能優化版(動能+ROE 品質+營收確認)
在傳統 12−1 動能上加入 ROE>10 的品質過濾與營收年增率確認,季度換股、平均持有約 9 檔。2013 年 9 月至 2026 年 6 月台股回測年化報酬 36.4%、日夏普 1.18、最大回撤 -40.1%;同視窗(2013 年 9 月起)0050 含息年化 20.9%、最大回撤 -34.0%。
投資警語:本文僅供教學參考,不構成投資建議。過去績效不代表未來表現,投資有風險。
回測績效
- 年化報酬率
- 36.4%
- 日夏普
- 1.18
- 最大回撤
- -40.1%
- 總報酬率
- 5086%
- 平均持股
- 8.7 檔
回測含手續費 0.1425% 與賣出證交稅 0.3%(finlab 套件 sim() 預設成本),日夏普未扣無風險利率。策略淨值自資料可得日(2013-09-30)起算。
淨值曲線(對數座標)
複合動能優化版(動能+ROE 品質+營收確認)0050 買進持有(含息)
與 0050 含息買進持有對照
| 對象 | 年化報酬率 | 日夏普 | 最大回撤 | 統計視窗 |
|---|---|---|---|---|
| 複合動能優化版(動能+ROE 品質+營收確認) | 36.4% | 1.18 | -40.1% | 2013-09-30 〜 2026-06-18 |
| 0050 買進持有(含息) | 20.9% | 1.14 | -34.0% | 2013-09-30 〜 2026-06-18 |
註:0050 含息若從更早的 2008-01-01 起算(含 2008 年金融海嘯),至 2026-06-20 為年化 14.8%、日夏普 0.74、最大回撤 -52.4%;上表對照採與策略淨值相同的統計視窗。
完整策略程式碼
安裝 finlab 套件後即可直接執行重現(finlab.login() 會自動引導登入,不需手動填 token)。想用 AI 輔助安裝與跑第一次回測,可以走 安裝教學。
展開程式碼(strategy.py)
"""動能投資策略 — 與 /blog/momentum-strategy 同口徑的完整可重現程式。
回測資料自 2008-01-01 取得;本頁策略(複合動能優化版)用到的 ROE 與營收資料較晚才齊備,淨值曲線實際自 2013-09-30 起算、統計至 2026-06-18。執行前安裝 finlab 並登入(finlab 會自動引導):
pip install finlab
python strategy.py
包含:原始 12-1 動能(前 30、月換股,實測輸 0050)與複合動能優化版
(複合動能 + ROE>10 + 營收 YoY>0、季換股、前 10),數字與文章一致。
"""
import finlab
from finlab import data
from finlab.backtest import sim
finlab.login() # finlab 會自動引導登入
adj = data.get("etl:adj_close")
roe = data.get("fundamental_features:ROE稅後")
yoy = data.get("monthly_revenue:去年同月增減(%)")
# ---- 原始 12-1 動能:過去 12 個月報酬扣掉最近 1 個月,選前 30 檔,月換股 ----
mom_12_1 = adj.pct_change(252) - adj.pct_change(21)
position_simple = mom_12_1.is_largest(30)
report_simple = sim(position_simple, resample="M", fee_ratio=0.001425, tax_ratio=0.003, upload=False)
report_simple.display()
print(report_simple.get_stats())
# ---- 複合動能優化版:3 月與 6 月動能都為正 + ROE>10 + 營收 YoY>0,季換股,前 10 ----
mom_3m = adj.pct_change(60)
mom_6m = adj.pct_change(120)
pool = (mom_3m > 0) & (mom_6m > 0) & (roe > 10) & (yoy > 0)
position_composite = mom_6m[pool].is_largest(10)
report_composite = sim(position_composite, resample="Q", fee_ratio=0.001425, tax_ratio=0.003, upload=False)
report_composite.display()
print(report_composite.get_stats())
在 Studio 裡用同一套真實資料調整條件、重跑回測。