本文以反面教材為主。 走完這套選股條件 SOP 之後,ROE 這個因子在台股 2015 到 2026 年的四種門檻沒有一個贏過含息 0050,疊上第二個因子也只是把年化推到 17.1%、回撤反而變深。這個結果本身就是這套流程的價值所在:用最少的力氣證明一個因子不值得用。

執行這個策略
複製提示詞,讓 AI 依照上方證據的資料、條件與風險檢查重跑一次。
告訴你的AI:
幫我用 finlab 把 ROE 分成五等分回測,看看報酬是不是隨 ROE 遞增,請讀:https://finlab.finance/setup?relatedUrl=/blog/stock-screening-5-steps
圖 1:ROE 由寬到嚴四種門檻 vs 0050 含息(2015-03~2026-07,對數座標)。四條線幾乎黏在一起,2023 到 2024 一度領先大盤,終點仍落後。
關鍵數字:門檻抓多嚴,其實沒差多少
| 選股條件 | 年化報酬 | 總報酬 | 日夏普 | 最大回撤 | 平均持股 |
|---|---|---|---|---|---|
| ROE 前 80% | 14.2% | 350% | 0.77 | -34.7% | 863 檔 |
| ROE 前 60% | 14.7% | 373% | 0.79 | -34.6% | 657 檔 |
| ROE 前 40% | 14.5% | 364% | 0.76 | -34.8% | 445 檔 |
| ROE 前 20% | 14.0% | 341% | 0.71 | -35.4% | 222 檔 |
| 低負債比前 20% | 9.7% | 184% | 0.52 | -37.1% | 175 檔 |
| ROE 前 40% + 動能收斂 30 檔 | 17.1% | 499% | 0.65 | -46.0% | 30 檔 |
| 0050 含息買進持有 | 20.7% | 740% | 1.04 | -34.0% | 1 檔 |
回測區間 2015-03-31 至 2026-07-24,季換股,策略端的手續費與證交稅照實內扣;0050 那一列是還原權值買進持有,不含交易成本。
四種門檻的年化落在 14.0% 到 14.7% 之間,差距 0.7 個百分點;把條件從前 80% 收到前 20%,持股數從 863 檔砍到 222 檔,報酬幾乎沒有變化,回撤還略微變深。多數人以為「條件抓嚴一點會比較賺」,這批資料上看不到這件事。
為什麼需要一套流程
設計選股策略對剛開始接觸的人並不簡單。常見的失敗長這樣:一口氣寫下上百行程式碼、疊了十幾個條件,回測結果卻不如大盤。真正的原因通常出在驗證:沒有逐一確認每個條件到底有沒有貢獻。
下面五個步驟的目的,是讓每個因子都要先自己過一關,才有資格進到策略裡。量化交易的完整概念可以另外看,這裡只談選股條件本身怎麼設。
步驟 1:尋找因子
因子不是什麼特別的東西,就是日常會看的指標,股東權益報酬率、負債比率、RSI 都算。只要能量化成數值,就能拿來當因子。
台股能取得的欄位可以到 FinLab 資料庫查,基本面、籌碼面、技術面的原始欄位都在那裡,每個欄位頁面附有更新頻率與涵蓋範圍。
本文接下來一路用「股東權益報酬率(ROE)」當範例,因為它是最多人第一個想到的基本面因子,而且它在學術上有明確的候選資格:Novy-Marx(2013) 發現獲利能力對橫斷面報酬的解釋力與帳面市值比相當,Fama & French(2015) 也把獲利能力正式納入五因子模型(RMW 用的是營業利益除以帳面權益)。要補一句的是,Novy-Marx 測的是毛利除以總資產,他同時指出稅後盈餘類的指標預測力弱得多,ROE 只是這個家族裡的一個候選,本文的結果也正好落在他預期的那一側。
步驟 2:判定效果
找到想用的資料後,先確認這個因子單獨有沒有選股效果。做法是把因子橫向排名,再設計由寬到嚴的條件:
顯示程式碼
from finlab import data
from finlab.backtest import sim
roe = data.get('fundamental_features:ROE稅後')
volume = data.get('price:成交股數')
# 橫向百分位排名:0 代表全市場最低,1 代表最高
roe_rank = roe.rank(axis=1, pct=True)
# 流動性過濾:20 日平均成交量 200 張以上,濾掉買不到的冷門股
liquid = volume.average(20) > 200 * 1000
stocks1 = (roe_rank > 0.2) & liquid # 寬鬆,前 80%
stocks2 = (roe_rank > 0.4) & liquid # 前 60%
stocks3 = (roe_rank > 0.6) & liquid # 前 40%
stocks4 = (roe_rank > 0.8) & liquid # 嚴格,前 20%
report = sim(stocks4, resample='Q')
report.display()換股頻率設成季(Q),因為 ROE 每季才公布一次,用更高頻率換股只會多付手續費、拿不到新資訊。如果你的因子是價格類,才適合用週(W)或月(M)。
這裡有一個容易踩的坑:sim() 有 fee_ratio 與 tax_ratio 兩個參數,把它們設成 0 可以讓回測曲線立刻變漂亮,但那條曲線在真實帳戶裡不存在。測因子的階段就要把成本開著,否則你會在後面才發現整個優勢都被手續費吃掉。本文所有數字都用 sim() 的預設成本,也就是手續費 0.1425% 與賣出證交稅 0.3%。
另外,判斷因子有沒有用,不能只看「累積報酬比大盤高」。極端的反例是:某策略第一天比大盤多賺 3%,之後每天報酬與大盤完全相同。它的累積報酬永遠贏大盤,但實際上第二天之後毫無貢獻。要看的是夏普比率、alpha 與 beta,以及與大盤的差距是否持續拉開。
步驟 3:沒效果就直接棄用
如果因子單獨測起來就輸大盤,先把它拿掉,不要急著疊其他條件補救。
低負債比就是一個具體例子。用同樣的方法測「負債比率最低的 20%」,2015 到 2026 年化只有 9.7%、日夏普 0.52、最大回撤 -37.1%,比含息 0050 的 20.7% 差了一大截。
圖 2:低負債比前 20%(紅線)全期落後;ROE 前 40% 疊上價格動能後(紫線)在 2024 年底前多數時間走在 0050 之上,2025 年起被拉開。
值得補一句的是,一個因子在論文裡顯著,不代表它在你的市場與區間裡還站得住。Harvey、Liu 與 Zhu(2016) 統計過文獻上被提出的數百個因子,指出在這麼多次嘗試之下,傳統的顯著性門檻遠遠不夠嚴格,多數因子撐不過更高的檢驗標準。所以每個因子都要在你自己的資料上重測一次。
這種因子留在策略裡的代價很具體:全市場約 2,000 檔股票裡真正會漲的只有一小部分,用一個沒有鑑別度的條件先篩掉八成,後面再好的濾網也只能在剩下的名單裡挑。地基不穩,後面疊得再高都會垮。
步驟 4:設定門檻
確認因子有效之後,才輪到決定門檻要多寬。把步驟 2 的四個回測攤開對照:
圖 3:條件越嚴,持股從 863 檔降到 222 檔,年化卻在 14.0% 到 14.7% 之間震盪,沒有單調上升。
四個門檻的年化最高點出現在中間的前 60%(14.7%),最嚴格的前 20% 只有 14.0%。回撤方面,最嚴格的那組反而最深(-35.4%)。
判準應該是兩件事:總報酬要夠高,以及風險要分散得掉。在報酬相近時,持股較多的那一組更有利,一來分散程度較好,二來樣本數大比較不會過擬合,三來留下足夠的股票,後面才有空間再疊第二個因子。所以這個案例會選前 60% 或前 40%,把條件收到最緊反而沒有好處。
一個常見的直覺是「門檻收緊,報酬會跟著大幅提升」,例如從前 80% 收到前 40% 就能讓總報酬翻倍。上面這四組實跑數字看不到這種效果:總報酬全部落在 341% 到 373% 之間。
進階:因子與報酬不是等比例的
上面的做法假設 ROE 越高越好。把全市場按 ROE 分成五等分各自回測,可以直接檢驗這個假設:
圖 4:ROE 五分位年化報酬。最低分位 3.5%、回撤 -53.6%,Q3 到 Q5 集中在 13.7% 到 14.0%。
| 分位 | 年化報酬 | 日夏普 | 最大回撤 |
|---|---|---|---|
| Q1(ROE 最低 20%) | 3.5% | 0.23 | -53.6% |
| Q2 | 11.1% | 0.61 | -37.2% |
| Q3 | 13.7% | 0.75 | -34.9% |
| Q4 | 13.9% | 0.75 | -34.2% |
| Q5(ROE 最高 20%) | 14.0% | 0.71 | -35.4% |
排序是成立的,年化從 3.5% 一路升到 14.0%。但升幅集中在前段:Q1 到 Q3 差了 10.2 個百分點,Q3 到 Q5 只差 0.3 個百分點。
站上另一篇 EPS 與 ROE 的分位實測得到更強的版本:那裡的 ROE 最高分位年化 8.27%,反而輸給次高分位的 11.38%,正比關係直接斷在最後一組。兩篇的差別在口徑,那篇用近四季合計(TTM)、依財報公告日換股、股票池要求股價大於 10 元、回測從 2013 年起;本文用單季 ROE、固定季底換股、只做均量過濾、從 2015 年起。TTM 平滑掉單季的暴衝,公告日換股也避開了財報空窗,所以那組數字對高分位的品質判斷更嚴格。兩組結果指向同一件事:ROE 的高分位沒有想像中值錢。
換句話說,ROE 的訊號幾乎全部來自「避開最爛的那 20%」,而不是「挑出最強的那 20%」。這解釋了為什麼步驟 4 裡收緊門檻沒有效果:前 40% 和前 20% 都已經在飽和區裡。實務上的意義是,這個因子適合當排除條件,不適合當排序條件。
步驟 5:疊加下一個因子
留下足夠的股票之後,就可以加入第二個因子,把名單收斂到可以實際買齊的檔數。寫法是把前一步的布林矩陣乘上新因子,再取前 N 名:
顯示程式碼
close = data.get('price:收盤價')
# 第二個因子:60 日價格動能
momentum = close / close.shift(60) - 1
base = (roe_rank > 0.6) & liquid # 沿用步驟 4 選定的前 40%,同樣要過流動性
position = (base * (momentum + 1)).is_largest(30)
report = sim(position, resample='Q')新因子如果同時有正負值,要先加一個常數讓它整段為正,否則負值相乘會把排序翻過來。上面的 momentum + 1 就是為了這件事。
實測結果:年化從單因子的 14.5% 升到 17.1%,總報酬 499%。但代價寫在另外兩欄,日夏普從 0.76 降到 0.65,最大回撤從 -34.8% 加深到 -46.0%。持股從 445 檔收斂到 30 檔,波動自然變大。
含息 0050 同期是年化 20.7%、日夏普 1.04、回撤 -34.0%。全期四項頭條指標,疊加版全部落後。
但落後集中在最後 19 個月
把同一條淨值切成兩段,結果和「全期落後」給人的印象差很多:
| 期間 | 疊加版年化/日夏普 | 0050 含息年化/日夏普 |
|---|---|---|
| 2015-03 ~ 2024-12 | 15.7%/0.63 | 14.9%/0.83 |
| 2025-01 ~ 2026-07 | 28.9%/0.85 | 65.2%/2.03 |
在 2024 年底之前的九年多,疊加版的累積報酬走在大盤前面,逐日比對也顯示它在全期 2,761 個交易日中有 2,238 天(81%)的淨值高於 0050。但同一段的日夏普是 0.63,仍低於 0050 的 0.83,也就是那九年多的領先是用更大的波動換來的。到了 2025 年起的權值股行情,0050 年化 65.2%、日夏普 2.03,一支 30 檔的中小型組合連風險調整後都追不上。
所以全期結論不變,只是講得更精確:兩段期間的風險調整後報酬都輸給 0050,最後 19 個月則連累積報酬也被拉開。要不要接受這種波動,取決於你的策略是否需要在權值股領漲時跟上大盤。
這套流程真正的用途
走完五步之後,這個案例沒有生出一個能打敗大盤的策略。流程本身運作正常:它在三個回測之內就告訴你 ROE 單獨用不夠、低負債比該丟掉、收緊門檻沒有用。
同一批資料如果用「先寫一百行、再看總報酬」的方式做,你會花好幾天,最後拿到一條看起來不錯的曲線,卻不知道貢獻來自哪個條件。
至於什麼樣的組合真的能贏,站上的股票選股完整指南有六個經典因子的單獨實測與複合後的對照,而台股選股器則把八個常見選股條件的 11 年回測與最新名單攤開,複合版本在風險調整後勝出,單因子則全數落後。這兩頁的結論與本文一致:贏的關鍵在組合方式,單一條件調得更嚴幫不上忙。
回測方法與限制
| 項目 | 本文設定 |
|---|---|
| 交易成本 | sim() 預設已內扣手續費 0.1425%(未打折)與賣出證交稅 0.3% |
| 滑價 | 未額外假設,成交價採換股日收盤價 |
| 股票池 | 全上市櫃,未排除金融股、KY 股與 ETF |
| 流動性過濾 | 20 日平均成交量 > 200 張 |
| 生存者偏誤 | finlab 資料庫保留已下市股票,回測期間內下市者仍計入 |
| 前視偏差 | ROE 取自 fundamental_features,依財報公布日對齊;季換股 |
| 權重 | 等權重,未設單檔上限 |
| 周轉率 | 未估算;季頻換股的換手率低於月頻策略 |
| 樣本內外 | 全段樣本內(in-sample),未做樣本外或滾動測試 |
| 基準 | 0050 使用 etl:adj_close 還原價買進持有,含息,切到與策略相同的起始日 |
夏普與索提諾皆由淨值序列計算,無風險利率取 1%。持股數達數百檔的組合在實務上難以完整複製,本文用它們檢驗「門檻寬嚴」這個變數,不是把它們當成可直接執行的策略。
常見問題
Q1:選股條件設多少檔股票才合理? 本文的疊加範例收斂到 30 檔。檔數太少會讓單一個股主導績效,太多則難以買齊。站上的分散投資實測量化過這個取捨。
Q2:ROE 前 20% 為什麼贏不了前 60%? 因為 ROE 的鑑別力集中在低分位。五分位實測顯示 Q3 到 Q5 的年化只差 0.3 個百分點,收緊門檻等於在飽和區裡挑,卻同時犧牲了分散度。
Q3:回測時可以把手續費設成 0 嗎? 測試階段也不建議。季換股的成本相對低,但月頻或週頻策略的成本會顯著吃掉優勢,關掉成本會讓你在錯誤的前提下選因子。
Q4:因子要用排名還是絕對數值?
排名(rank(axis=1, pct=True))比較穩定,因為絕對門檻會隨產業結構與景氣而失準,同一個 ROE 15% 在不同年份代表的相對位置差很多。
Q5:怎麼知道兩個因子疊起來有沒有加成? 把單因子與疊加後的版本用同一段區間、同一組成本設定各跑一次,比較年化、夏普與回撤三欄。本文的例子年化上升但夏普與回撤都變差,屬於報酬與風險同時放大,不算真正的加成。
Q6:這套流程可以用在技術面因子嗎? 可以,換股頻率要跟著資料頻率調整。技術指標類的實測可以看技術面選股因子的回測整理。
互動式回測報告
下面是疊加版本(ROE 前 40% + 動能收斂 30 檔)的完整回測報表:
下載資源
| 檔案 | 用途 |
|---|---|
| strategy.py | 五個步驟的完整可重現腳本,含流動性過濾與分段檢查 |
| data.csv | 六個變體與 0050 含息的逐日淨值 |
| metrics.json | 四種門檻、五分位、疊加版與基準的完整指標 |
重跑方式:安裝 finlab 套件後直接執行 strategy.py(第一次執行會自動引導登入),或把檔案內容貼給你的 AI 助手,換成你自己想測的因子。
延伸閱讀
投資警語:本文僅供教學與研究參考,不構成投資建議。過去績效不代表未來表現,投資一定有風險,請審慎評估自身風險承受能力。
最後更新:2026-07|回測區間:2015-03-31~2026-07-24|作者:FinLab 量化研究團隊(經量化研究員審閱)
FinLab AI
想建立自己的策略?
用自然語言描述你的選股想法,AI 自動驗證、回測、給你答案
免費開始
