
用一個跑在自己電腦上、連本地模型都能接的 AI agent,把 finlab 台股回測整套搬到本機,會發生什麼事?我們用 Pi(開源 agent CLI)做了完整實驗:策略想法與台股資料全程不出本機,靠它反覆替換因子重跑。主軸只做一件事,把品質因子從常見的 ROE 換成「營業利益率」,比較哪個品質定義在台股更管用。最終的三因子版本(營業利益率+動能+低波)在 2018-01 到 2026-06 這段期間年化(CAGR)19.3%、日夏普比率 1.33、最大回撤 -25.9%;只看營業利益率單因子的版本只有 13.8%。
| 指標 | 三因子(營業利益率+動能+低波) | 只看營業利益率(單因子基準) | 0050 含息 |
|---|---|---|---|
| 年化報酬(CAGR) | 19.3% | 13.8% | 25.0% |
| 最大回撤(MDD) | -25.9% | -32.5% | -34.0% |
| 日夏普比率 | 1.33 | 0.80 | 1.22 |
| 月索提諾比率 | 1.73 | 1.01 | 1.92 |
| 總報酬 | +338% | +194% | +559% |
| 平均持股數 | 20 檔 | 20 檔 | 1 檔 ETF |
口徑:2018-01 到 2026-06(資料快照 2026-06-09),策略含 finlab 預設交易成本,0050 為還原價含息買進持有純指數算術、不扣成本(詳見文末回測方法)。先把話講清楚:三因子的年化 19.3% 仍輸給含息 0050 的 25.0%,所以這不是一個「報酬贏大盤」的策略。它贏的地方是風險調整後的數字,在本文設定下、2018 到 2026 這段期間,日夏普 1.33 高於 0050 的 1.22,最大回撤 -25.9% 也比 0050 的 -34.0% 淺約 8 個百分點。用較淺的回撤換取接近但偏低的報酬,是它真正的定位。
這篇真正要示範的是一種研究方式:當回測引擎跑在你自己的電腦上、不限次數、沒有 API 費用時,你會願意把同一個策略換十種因子各跑一遍,直到看清楚哪個因子真的有貢獻。下面公開招牌提示詞、Pi 與 finlab 的核心程式碼、三組持股數敏感度,以及可下載的完整重現腳本。
Pi 是什麼?為什麼適合在本地端反覆做回測實驗
Pi(pi.dev、原始碼在 earendil-works/pi)是一個開源的 AI agent 命令列工具。它和多數雲端 AI 助手最大的差別有四個,而這四個差別剛好都打中量化研究的痛點:
| 特性 | Pi 的做法 | 對量化研究的意義 |
|---|---|---|
| 開源 | 程式碼公開,可自行檢視與修改 | 你能確認它對你的策略碼與資料做了什麼 |
| 可接本地模型 | 支援 Ollama/Gemma 等在本機跑的模型 | 策略想法與台股資料不必送到任何雲端 |
| 本地免費不限次 | 用本地模型跑沒有 API 計費 | 同一策略換十種因子各跑一遍也不心疼 |
| 可擴充(skills/extensions) | 能把常用流程包成自己的擴充 | 把慣用的 finlab 回測口徑固定下來,一句話重現 |
對量化研究的人來說,最後兩列特別關鍵。研究的本質是反覆試錯:換因子、換權重、換持股數,看結論穩不穩。如果每跑一次都要付一筆 API 費用、或要把財報資料與選股邏輯上傳到雲端,你會不自覺地少做實驗、早早收手。Pi 接本地模型後,回測這件事的邊際成本趨近於零,資料也留在自己機器上,你才有本錢做到「窮舉因子」這種紮實但耗次數的工作。想先補齊 AI agent 與量化研究的整體脈絡,可以先讀AI 量化交易實戰指南再回來看本文的本地實驗。
要強調的是,Pi 取代的是「寫程式」與「反覆操作」這一步,數字本身仍然來自 finlab 套件實際執行的回測。AI 負責把你的中文想法翻成 Python、自動重跑、整理對照表;真正的台股資料、交易成本與回測引擎都是 finlab 在做。判斷一篇 AI 量化內容可不可信,第一個檢查點就是看數字是 AI「用語言講出來的」還是「真的跑出來的」,本文全部績效都來自 finlab 回測引擎輸出。
招牌用法:本地免費不限次,所以拿來窮舉因子
把 finlab 裝進 Pi 之後,最發揮它特長的用法是「在本機批次比較因子」。雲端付費的工具你會精打細算每一次呼叫,本地免費就沒有這個顧慮。下面三段提示詞是本文實際用過的,直接複製貼給 Pi 即可:
顯示程式碼
用本地的 Ollama 模型,把這支策略的品質因子從 ROE 換成營業利益率,
重跑回測比較兩個版本在台股的夏普與最大回撤,全程不要連外網。顯示程式碼
在本機批次掃 8 個常見因子(動能、低波、ROE、營業利益率、殖利率、
營收年增、本益比、市值)的前瞻報酬與資訊係數,不要上傳任何資料到雲端。顯示程式碼
把這份 finlab skill 包成我自己的 Pi extension,
之後一句話就能跑我慣用的回測口徑。第一段就是本文的主軸。實際對話像這樣:
💬 你對 Pi 說:
用本地的 Ollama 模型,把這支策略的品質因子從 ROE 換成營業利益率,重跑回測比較兩個版本在台股的夏普與最大回撤,全程不要連外網。我要看哪個品質定義在台股更有效。
🤖 Pi 回覆:
已用本地模型完成兩個版本的回測,資料與運算都在本機,沒有對外連線。回測區間 2018-01 到 2026-06,含 finlab 預設手續費與證交稅:
- 把品質因子換成營業利益率後,三因子版本年化 19.3%、日夏普 1.33、最大回撤 -25.9%
- 只看營業利益率單因子的版本年化 13.8%、日夏普 0.80、最大回撤 -32.5%
- 單因子明顯較弱,加上動能與低波之後夏普才拉到 1.33、回撤收斂到 -25.9%
結論:營業利益率作為品質因子在台股可用,但要靠動能與低波補位才有穩定的風險調整後表現。要不要我接著把 ROE 版本也跑出來並排比較?
這段對話的價值在於它是免費且可重複的。你可以一直追問「再換成毛利率」「再把動能改成 240 日」,Pi 會用本地模型一次次重跑,你不必擔心帳單。這正是本地 agent 對量化研究最實際的好處:把實驗次數從「捨不得多跑」變成「想跑就跑」。
把 FinLab 裝進 Pi:一份 skill 到處能用
要讓 Pi(或任何支援 Agent Skills 的工具)能讀台股資料、跑回測,只要裝一次 finlab skill。它是一份 SKILL.md,同一份能裝進 Pi、Claude Code、Codex CLI、Cursor 等工具,裝一次到處能用。安裝指令(所有工具通用):
npx skills add https://github.com/koreal6803/finlab-ai --skill finlab
裝好之後,把下面這句話交給 Pi,它會依流程完成設定,並用本地模型重現本文的本地回測:
用 AI 開始 FinLab
把這句話交給你的AI,它會帶你完成設定並做出第一個策略。
告訴你的AI:
幫我設定 FinLab,在本地端跑獲利品質動能低波策略,請讀:https://finlab.finance/setup?relatedUrl=/blog/pi-agent-finlab-local-backtest
完全不想裝任何東西也有零安裝路徑:用瀏覽器開 FinLab Studio,輸入選股條件就能產生回測。想用 AI 對話迭代策略,桌面路徑可選 Codex app 或 Claude cowork;想要資料完全不出本機、免費不限次的隱私路徑,就把 Pi 接上本地的 Ollama 模型。資料與回測引擎在同一套流程裡,首次取資料時套件會自動引導登入。各 AI 工具的安裝細節整理在 AI skill 安裝頁。
naive 做法:只看營業利益率,年化 13.8%
先從最直覺的做法開始。如果你相信「本業賺錢能力強的公司報酬較好」,最簡單的實作是把營業利益率拿來排名,每月選最高的前 20 檔。這就是我們的單因子基準。
把這段邏輯交給 Pi,它產生的 finlab 程式碼如下,每一行都對應一個動作:
顯示程式碼
from finlab import data
from finlab.backtest import sim
# 載入資料(首次執行會自動引導登入)
close = data.get("price:收盤價")
volume = data.get("price:成交股數")
operating_margin = data.get("fundamental_features:營業利益率").index_str_to_date()
# 季財報依公布時點對齊到日頻,避免用到未來資料
operating_margin = operating_margin.reindex(close.index, method="ffill")
# 流動性過濾:近 20 日平均成交金額 > 1,000 萬
amount = (close * volume).rolling(20).mean()
liquid = (amount > 10_000_000) & close.notna()
# 單因子:營業利益率排名,每月選前 20 檔
score = operating_margin.where(liquid).rank(axis=1, pct=True)
position = score.is_largest(20)
report = sim(position, resample="M", name="只看營業利益率")
report.display()結果是年化 13.8%、日夏普 0.80、最大回撤 -32.5%、總報酬 +194%。這個成績把問題講得很清楚:單獨一個品質因子,即使是「本業獲利能力」這種直覺上很強的指標,在這段期間既輸給含息 0050 的 25.0%,回撤也接近大盤的 -34.0%。換句話說,光看公司會不會賺錢,不足以選出風險報酬都好的組合。
這個結論本身就是本地反覆實驗的產物。如果回測要錢、要連雲端,你可能跑完單因子覺得「還行」就停了;在本機免費跑,你才會願意往下追問「那加上動能與低波會怎樣」。
改良做法:營業利益率+動能+低波,年化 19.3%、回撤更淺
下一步是把品質、動能、低波三個低相關的訊號合起來。做法是各因子在全市場做百分位排名,三者相加成綜合分數,取前 20 檔,再用分數平方加權(分數高的多配一點,集中在排名最前面的標的)、每月再平衡。
這是 Pi 產生的核心程式碼,分成「載入資料、算三個因子、排名選股、加權、回測」幾個段落,方便逐步跟上:
顯示程式碼
from finlab import data
from finlab.backtest import sim
# 1) 載入資料
close = data.get("price:收盤價")
volume = data.get("price:成交股數")
operating_margin = data.get("fundamental_features:營業利益率").index_str_to_date()
operating_margin = operating_margin.reindex(close.index, method="ffill")
# 2) 流動性過濾
amount = (close * volume).rolling(20).mean()
liquid = (amount > 10_000_000) & close.notna()
# 3) 三個因子:獲利品質、動能、低波
rank_margin = operating_margin.where(liquid).rank(axis=1, pct=True)
rank_momentum = close.pct_change(120).where(liquid).rank(axis=1, pct=True)
volatility = close.pct_change().rolling(60).std()
rank_low_vol = volatility.where(liquid).rank(axis=1, pct=True, ascending=False)
score = rank_margin + rank_momentum + rank_low_vol
# 4) 取前 20 名,分數平方加權,每月再平衡
top20 = score.rank(axis=1, ascending=False) <= 20
weight = (score[top20].fillna(0)) ** 2
weight = weight.div(weight.sum(axis=1), axis=0)
report = sim(weight, resample="M", name="獲利品質動能低波")
report.display()完整互動式回測報告(月報酬熱力圖、權益曲線、年度績效都在裡面),可以直接在這裡操作:
三因子版本年化 19.3%、日夏普 1.33、月索提諾 1.73、最大回撤 -25.9%、總報酬 +338%。和單因子基準擺在一起看,差別很明顯:報酬從 13.8% 拉到 19.3%、日夏普從 0.80 跳到 1.33、回撤從 -32.5% 收斂到 -25.9%。動能負責抓住上漲段的選股勝率,低波負責壓低整體波動,品質負責濾掉本業不賺錢的公司,三者互補。
把三個組合的年化報酬、日夏普與月索提諾做成並排長條圖,每個指標誰高誰低一目了然:

照數據把代價講明白:三因子的年化 19.3% 仍低於含息 0050 的 25.0%,總報酬 +338% 也少於 0050 的 +559%。它沒有在絕對報酬上贏大盤。它贏在風險調整後的兩個地方,日夏普 1.33 高於 0050 的 1.22,最大回撤 -25.9% 比 0050 的 -34.0% 淺。月索提諾 1.73 則仍略低於 0050 的 1.92,這格沒有贏。如果你的目標是「報酬最大化」,買 0050 更直接;如果你想要的是更平穩的報酬曲線、更淺的帳面虧損,這個三因子組合才是它的適用情境。
把回撤單獨拉出來看,三因子在歷次下跌段的帳面虧損都比 0050 收斂:

ROE 還是營業利益率?本地免費實驗才問得起的問題
本文標題的核心問題是:品質因子到底該用 ROE 還是營業利益率?這兩個指標都屬於「獲利能力」家族,但口徑不同。ROE(股東權益報酬率)混入了財務槓桿,一家公司可以靠舉債把 ROE 撐高;營業利益率衡量的是本業每一塊營收能留下多少營業利益,比較純粹地反映「本業會不會賺錢」,不受槓桿影響。
在台股,這個差別值得實測。用同一套三因子框架(只把品質那一格在 ROE 與營業利益率之間切換),在本機各跑一遍,就能看出哪個品質定義對這段期間的台股更有貢獻。本文示範的營業利益率版本年化 19.3%、日夏普 1.33;用 ROE 的對照版本在我們另一篇實作裡是另一組數字,兩者可以互相參照(同框架的 ROE 版本見AI 量化交易實戰指南,那篇用的是 ROE)。這裡的重點不在宣布誰一定贏,更在於你有沒有一個免費、不限次、資料不出本機的環境,把這種「換一個欄位重跑」的問題問到底。
這正是 Pi 接本地模型最實際的場景。雲端付費工具會讓你在「再多跑一個因子版本」前猶豫;本地免費讓你能把品質因子換成毛利率、淨利率、營業利益率逐一比較,直到結論收斂。想看更多台股選股因子的系統性比較,可參考台股選股方法總整理與多因子選股能不能贏 0050 的實測。
三個因子背後的學術依據
這套組合不是憑空拼湊,三個因子各自對應行之有年的實證研究:
- 獲利品質:Novy-Marx (2013) 證明獲利能力強的公司即使估值不便宜,長期報酬仍系統性較高。他用的是毛利對資產,本文用營業利益率,同屬獲利能力家族但口徑不同,效果不能直接劃等號;正因如此,才需要在台股實測哪個口徑更有效。
- 價格動能:Jegadeesh & Titman (1993) 發現過去 3 到 12 個月的贏家股票,後續數月平均持續跑贏輸家,動能因子從此成為實證金融最廣被複製的異常報酬之一。本文用 120 個交易日(約半年)報酬當動能指標。
- 低波動:Ang, Hodrick, Xing & Zhang (2006) 記錄了「低波動異常」,即過去波動較低的股票,風險調整後報酬反而較高,與傳統「高風險高報酬」的直覺相反。本文用近 60 日報酬標準差排名,偏好低波端,這也是回撤能收斂到 -25.9% 的主要來源。
把三個低相關的訊號用排名加權合成,單一因子失靈時其他因子補位,比押注任何單一條件都穩健。這也解釋了為什麼單看營業利益率只有 13.8%,加上動能與低波後才到 19.3%。
持股數敏感度:結論對檔數不敏感
19.3% 是用「前 20 檔」跑出來的,會不會剛好挑到漂亮的檔數?我們在本機把持股數換成前 25、前 30 各跑一遍(本地免費所以多跑幾組沒有成本),三組的風險報酬結構一致:

| 持股數設定 | 年化報酬 | 最大回撤 | 日夏普 | 月索提諾 |
|---|---|---|---|---|
| 前 20(本文採用) | 19.3% | -25.9% | 1.33 | 1.73 |
| 前 25 | 18.4% | -26.1% | 1.30 | 1.70 |
| 前 30 | 17.0% | -26.6% | 1.24 | 1.61 |
三組的年化都落在 17.0% 到 19.3%、日夏普都在 1.24 以上、回撤都在 -26.6% 以內。檔數放愈多、報酬與夏普略降(分數較低的標的被納入,稀釋了排名最前面的訊號),但結論方向一致,不是靠某一個漂亮的持股數才成立。敏感度表的正確用法是確認結論對參數不敏感,不是回頭挑出最高的那一格當主角,因為前 20 是我們設定時就先決定的口徑。回測過擬合的風險與防範方法,回測是什麼有完整說明。
回測方法與限制
這些數字是怎麼算出來的,逐項交代:
| 項目 | 本文設定 |
|---|---|
| 回測區間 | 2018-01 到 2026-06,共約 8.4 年(資料快照日 2026-06-09) |
| 交易成本 | finlab sim() 台股預設值:手續費 0.1425%(未打折)、賣出證交稅 0.3%,已內扣 |
| 滑價 | 未另行假設;實際衝擊取決於資金規模與個股成交量,本文未估算策略容量 |
| 股票池 | 全上市櫃,finlab 資料含已下市股票,無生存者偏誤;未刻意排除金融股、KY 股與 ETF(ETF 因無營業利益率資料自然不會入選) |
| 流動性過濾 | 近 20 日平均成交金額大於 1,000 萬 |
| 前視偏差 | 營業利益率用 index_str_to_date 對齊財報公布時點、再向後填值到日頻;動能與波動只用已實現的收盤價 |
| 權重 | 取前 20 檔後分數平方加權(基準為等權),每月再平衡 |
| 周轉率 | 每月再平衡會換股,高周轉的成本已內含在 sim() 結果中;本文未單獨估算容量 |
| 樣本內外 | 全段樣本內(in-sample),未做樣本外測試;持股數敏感度是穩健性參考,不是樣本外證據 |
| 0050 基準 | etl:adj_close 還原價含息買進持有,純指數算術、不含交易成本;基準不扣成本而策略扣,比較口徑對策略偏保守 |
適合誰、不適合誰
Pi 本地回測這套流程適合:
- 重視隱私的研究者:策略邏輯與台股資料全程不出本機,不必把選股想法送上任何雲端。
- 想大量做因子實驗的人:本地模型免費不限次,適合窮舉因子、換權重、換持股數,把結論測到穩。
- 想固定研究口徑的人:能把慣用的 finlab 回測包成自己的 Pi extension,一句話重現。
不適合或要留意的情況:
- 想要報酬最大化:本文三因子年化 19.3% 輸給含息 0050 的 25.0%,追求絕對報酬的人,直接買 0050 更省事。
- 本地模型較弱:在本機跑的小模型,產生複雜程式碼的能力不如大型雲端模型,遇到難題可能要自己補一手或換接雲端模型。
- 不想裝任何工具:那就用零安裝的 FinLab Studio 直接在瀏覽器跑。
和一般看盤、下單軟體相比,這套流程的差別在於它能完整處理資料、因子、回測與成本,而且全程用中文跟 AI 對話、不必自己從零寫程式。想了解程式交易與一般看盤軟體的分界,可參考程式交易是什麼;想用 Python 從零打底,Python 量化交易教學會帶你跑出第一個台股回測。另一個常被拿來和 finlab 一起用的開源研究框架是 Qlib,整合做法見 Qlib 結合 finlab 的 AI 選股。
常見問題
Pi 是什麼?和一般 AI 助手有什麼不同?
Pi 是一個開源的 AI agent 命令列工具(pi.dev、原始碼 earendil-works/pi)。和多數雲端 AI 助手相比,它的特點是開源、能接本地模型(如 Ollama/Gemma)、本地跑免費不限次,而且可以用 skills/extensions 擴充。對量化研究來說,最大的好處是策略想法與資料能留在本機、反覆做實驗不必付 API 費用。
在本地端跑 finlab 回測,資料真的不會外流嗎?
把 Pi 接上本地模型(例如用 Ollama 跑 Gemma)後,模型推理與你的策略碼都在本機完成,不會把選股邏輯送到雲端。需要留意的是 finlab 台股資料本身在首次取用時會由套件引導登入並下載,這一步會連到 finlab 服務取資料;取得資料後的回測運算與因子實驗則可以完全在本機進行。
為什麼示範用營業利益率,不用更常見的 ROE?
ROE 混入了財務槓桿,公司可以靠舉債撐高;營業利益率衡量本業每一塊營收留下多少營業利益,比較純粹地反映本業獲利能力。哪個品質定義對台股更有效是個實證問題,正好適合用本地免費的回測環境把同一框架的兩個版本各跑一遍比較。本文示範的營業利益率版本年化 19.3%、日夏普 1.33。
這個三因子策略有贏 0050 嗎?
要看哪個指標。在本文設定下、2018 到 2026 這段期間,年化報酬 19.3% 輸給含息 0050 的 25.0%,月索提諾 1.73 也略低於 0050 的 1.92。但日夏普 1.33 高於 0050 的 1.22,最大回撤 -25.9% 也比 0050 的 -34.0% 淺。整體定位是用較淺的回撤換取接近但偏低的報酬,不是報酬贏大盤的策略。
本地模型跑得動 finlab 回測嗎?會不會很慢?
回測的運算量主要在 finlab 的資料處理與 sim(),這部分與你用哪個模型無關,本機就能跑。本地模型負責的是「把中文想法翻成 Python」「整理對照表」這類文字工作,小模型也能勝任簡單策略;遇到複雜邏輯時較弱的本地模型可能需要你補一手,或在難題時臨時換接雲端模型。
不會寫 Python 也能用 Pi 跑這個策略嗎?
可以。本文的提示詞就是示範:策略邏輯全用中文描述,程式由 Pi 產生。不過看得懂基本程式對你有利,因為你能檢查 AI 有沒有用到未來資料、成本有沒有扣。想補底子可參考 Python 量化交易教學。
怎麼把慣用的回測口徑固定下來、之後一句話重現?
用 Pi 的 extension 機制。把這份 finlab skill 與你慣用的回測設定(流動性門檻、再平衡頻率、加權方式)包成自己的 Pi extension,之後只要一句話就能套用同一口徑,不必每次重講規格。第三段招牌提示詞就是在做這件事。
要花錢嗎?需要多少資金才能開始?
學習與回測完全免費,用本地模型跑也沒有 API 費用,不需要投入任何資金。實際下單才需要資金;本策略持有 20 檔、偏中小型股,資金規模大到單筆買賣會影響股價時(流動性門檻 1,000 萬日均成交金額下,約數千萬以上),回測與實單的差距會擴大。
下載與重現
- strategy.py:營業利益率三因子策略完整原始碼,可直接執行取得最新選股清單
- data.csv:三條淨值曲線的每日數據
- metrics.json:全部指標的機器可讀快照
- 互動式回測報告:營業利益率三因子
延伸閱讀:想補齊量化交易的整體入門脈絡,可從量化交易完整指南開始。
投資警語:本文僅供教學參考,不構成投資建議。文中全部回測數據(年化 19.3%、最大回撤 -25.9% 等)為 2018-01 至 2026-06 的歷史模擬,已含 finlab 預設交易成本,但未含滑價與容量限制;過去績效不代表未來表現。本策略最大回撤 -25.9%,代表 100 萬可能一度縮水至約 74 萬,請依個人風險承受度審慎評估,僅使用虧損不影響生活的閒置資金。
最後更新:2026-06|回測區間:2018-01 ~ 2026-06(資料快照 2026-06-09)|作者:FinLab 量化研究團隊(經量化研究員審閱)
FinLab AI
想建立自己的策略?
用自然語言描述你的選股想法,AI 自動驗證、回測、給你答案
免費開始
