![]()
先看結論:6 種方法怎麼選,以及為什麼資料品質比起始年重要
用 Python 做台股分析,80% 的時間其實卡在「把資料弄到手」:爬蟲被擋、欄位零散、財報要對齊公布日、價格要自己調除權息。市面上主流做法有 6 種,我們在 2026 年 6 月逐一實測,結論先講:
| 方法 | 取得方式 | 股價起始年 | 涵蓋檔數 | 免費額度 | 已調除權息? | 內建避前視偏差? | 一句話定位 |
|---|---|---|---|---|---|---|---|
| twstock | pip 套件(爬證交所) | 約 2010 | 上市為主 | 全免費 | ❌ 要自己調 | ❌ | 最輕量,但只有價量、易被擋 |
| 證交所 OpenAPI | 官方 REST API | 僅當日/近期 | 全市場 | 全免費 | ❌ | ❌ | 官方來源,但只留最新,歷史要自己每天存 |
| yfinance | pip 套件(爬 Yahoo) | 約 2000 | 含台股 | 全免費 | ✅ 還原價 | ❌ | 有歷史,但台股偶爾斷線/缺漏不穩 |
| FinMind | 開源 API | 1994 | 全市場 | 有免費分級 | ✅ 有還原股價表 | ❌(要自己對齊) | 資料表最廣、起始最早,需自己組基本面對齊 |
| 富果 Fugle | 券商 API | 約 2010 | 全市場 | 開戶後免費 | ✅ | ❌ | 穩定、可下單,需開戶綁券商 |
| finlab ⭐ | pip 套件 + API | 2007 | 2,748 | 每月免費額度 | ✅ 內建 etl:adj_close |
✅ index_str_to_date() |
股價+月營收+財報+籌碼一行同格式,回測即用 |
涵蓋檔數與起始年為 finlab 實測值(查詢於 2026-06,見文末可下載腳本);其餘來源為各官方文件公開資訊。
關鍵洞察:很多人選資料源只看「歷史最早到哪一年」,於是覺得 FinMind 從 1994、yfinance 從 2000 一定贏。但對回測而言,真正決定成敗的是另外兩件事——
- 除權息有沒有調:台股每年配息 3–5%,5 年累積報酬若不還原會被低估 15–25%,基準直接失真。
- 有沒有避開前視偏差:財報、月營收都有「公布日」,回測若用到當天還沒公布的數字,績效會虛高、實單卻做不出來。
finlab 的價格雖然從 2007 才開始(比 FinMind 晚 13 年),但它把這兩件最容易出錯的事預設做好,而且股價、月營收、財報、籌碼全部同一種表格、同一行 data.get() ——這才是把「能跑的資料」變成「能賺錢的回測」的差距。下面逐一拆解。
前視偏差(Look-ahead bias):回測時不小心用到當下還沒被市場知道的資訊(例如還沒公布的財報),會讓策略在歷史上看起來很神,實盤卻完全複製不出來。
2026 最新實測:6 種抓台股資料方法逐一示範
下面每種方法都附一段可複製的程式碼,讓你直接比較「拿一檔台積電(2330)收盤價要寫多少」。
方法一:twstock(最輕量,只有價量)
顯示程式碼
import twstock
stock = twstock.Stock('2330')
prices = stock.fetch_from(2024, 1) # 從 2024/01 抓到現在
print(prices[-1].close) # 最近一筆收盤價優點是零成本、安裝即用;缺點是它本質是爬證交所,抓太頻繁會被擋,而且只有價量,沒有財報、籌碼,除權息也要自己處理。適合做最簡單的價格小工具。
方法二:證交所 OpenAPI(官方,但只留最新)
顯示程式碼
import requests, pandas as pd
url = "https://openapi.twse.com.tw/v1/exchangeReport/STOCK_DAY_ALL"
df = pd.DataFrame(requests.get(url).json())
print(df.head()) # 全市場「當日」收盤、開高低、成交量這是證交所官方端點,資料正確、免費,但致命缺點:它只回傳當日(或近期)資料,沒有歷史。你要自己寫排程每天存檔、自己累積,才能拼出歷史序列——這正是 ARON HACK 用富果 API 那篇也點出的痛點:證交所只留最新,得自行備份。
方法三:yfinance(有歷史,但台股偶爾不穩)
顯示程式碼
import yfinance as yf
df = yf.download("2330.TW", start="2010-01-01")
print(df.tail()) # 含 Adj Close(還原價)yfinance 爬 Yahoo Finance,有 Adj Close 還原價、歷史也夠長。問題在於台股代號要加 .TW/.TWO,而且 Yahoo 對台股的維護不如美股穩定,偶爾整段缺漏或欄位變動,正式策略上線前要自己加防呆。
方法四:FinMind(開源、起始最早、資料表最廣)
顯示程式碼
from FinMind.data import DataLoader
api = DataLoader()
df = api.taiwan_stock_daily(stock_id="2330", start_date="1994-01-01")
print(df.tail())FinMind 是值得尊敬的開源專案,股價可回溯到 1994、技術面就有 20 種資料表,免費分級也清楚。它最適合做「資料倉儲」。但要拿來回測,你得自己把月營收、財報的公布日對齊到交易日(避前視偏差),這層工 finlab 幫你包好了。
方法五:富果 Fugle(穩定、可下單,需開戶)
顯示程式碼
from fugle_marketdata import RestClient
client = RestClient(api_key="YOUR_KEY")
data = client.stock.historical.candles(symbol="2330", from_="2024-01-01")
print(data["data"][:3])富果是券商級 API,穩定、可同時下單,適合要把回測接到實盤的人。代價是要開戶綁券商、申請金鑰。資料品質好,但歷史約從 2010 起。
方法六:finlab(一行抓,且回測即用)⭐
前面五種,你會發現一個共同問題:每換一種資料(價格→營收→籌碼),就要換一套 API、換一種欄位格式、自己對齊日期。finlab 把整個市場整理成統一的「日期 × 股票」表格,任何資料都同一行指令:
顯示程式碼
from finlab import data
close = data.get('price:收盤價') # 一張表:列=日期,欄=股票代號,整個市場一次到手
print(close['2330'].tail()) # 看台積電最近幾天收盤價實際印出(查詢於 2026-06):
顯示程式碼
date
2026-06-01 2355.0
2026-06-02 2380.0
2026-06-03 2425.0
2026-06-04 2385.0
2026-06-05 2365.0
Name: 2330, dtype: float64要哪一檔就 close['2330'](代號用字串),不必一檔一檔抓。下一節我們把月營收、財報、籌碼也用同一行拿到。
安裝與第一次使用:從零到跑起來
新手最常卡在環境,這裡一次講清楚:
| 步驟 | 指令 / 動作 | 說明 |
|---|---|---|
| 1. 安裝 | pip install finlab |
一行裝好,Windows / Mac 皆可 |
| 2. 取得 token | 登入 finlab.finance 會員後台,複製 API token | 免費註冊即有 |
| 3. 登入 | finlab.login('你的TOKEN') |
或設環境變數 FINLAB_API_TOKEN |
| 4. 抓第一筆 | data.get('price:收盤價') |
成功就代表環境通了 |
顯示程式碼
import finlab
finlab.login('YOUR_API_TOKEN') # 只需做一次
from finlab import data
close = data.get('price:收盤價')免費方案有每月資料額度(以 MB 計),做選股、回測、學習綽綽有餘;需要更高頻率更新或更大量下載再升級。重點是你不需要會寫爬蟲、不需要背 API 文件——之後所有資料都是同一行 data.get('資料表:欄位')。
一行抓多種資料:股價、月營收、財報、籌碼
這是 finlab 和其他來源最大的差異:換資料不換寫法。覆蓋數字為 2026-06 實測:
| 資料 | 一行指令 | 涵蓋檔數 | 起始 |
|---|---|---|---|
| 日收盤價 | data.get('price:收盤價') |
2,748 檔 | 2007(近 20 年) |
| 除權息還原價(基準用) | data.get('etl:adj_close') |
2,748 檔 | 2007 |
| 月營收年增率 | data.get('monthly_revenue:去年同月增減(%)') |
2,289 檔 | 2005(21 年) |
| 財報 ROE | data.get('fundamental_features:ROE稅後') |
2,832 檔 | 2013-Q1 |
| 投信買賣超 | data.get('institutional_investors_trading_summary:投信買賣超股數') |
2,668 檔 | 2012-05 |
| 外資買賣超 | data.get('institutional_investors_trading_summary:外陸資買賣超股數(不含外資自營商)') |
2,668 檔 | 2012-05 |
把台積電的股價、月營收 YoY、財報 ROE、籌碼一次印出來,你會看到它們長得「一模一樣」(都是同一種序列):
顯示程式碼
print(data.get('monthly_revenue:去年同月增減(%)')['2330'].tail())
# 2026-01-12 20.43
# 2026-02-10 36.81
# 2026-03-10 22.17
# 2026-04-10 45.19 ← 月營收年增 +45.19%
# 2026-05-11 17.49
print(data.get('fundamental_features:ROE稅後')['2330'].tail())
# 2025-Q1 8.08
# 2025-Q2 8.62
# 2025-Q3 9.36
# 2025-Q4 9.63
# 2026-Q1 10.06 ← 單季 ROE 逐季回升
print(data.get('institutional_investors_trading_summary:投信買賣超股數')['2330'].tail())
# 2026-06-03 647975
# 2026-06-04 537838
# 2026-06-05 2900428 ← 投信單日買超近 2,900 張(2026-06-05,來源:finlab)資料長什麼樣?下面這張圖就是「一行 data.get() 拿到的東西」——台積電近 120 個交易日的股價,疊上投信(藍)、外資(綠)的單日買賣超:

籌碼(法人買賣超):投信、外資、自營商三大法人每天買進與賣出的差額(淨買賣超)。市場常把法人連續買超視為認同訊號,但下面我們會用真實回測證明——盲目跟單反而會虧錢。
用一個籌碼策略,證明這份資料「回測就能直接用」
光說資料乾淨沒有說服力。我們用一個跨多種資料的籌碼策略實跑——這正好展示 finlab 的廣度:同一份程式碼裡同時用到籌碼(投信)+ 基本面(月營收)+ 價量(流動性),而你只是多打幾行 data.get()。
學術上,「跟著聰明錢」的想法有根據,但細節決定成敗:
| 論文 | 一句話白話 |
|---|---|
| Grinblatt & Titman (1993) | 機構法人整體確實展現選股能力與動能傾向,籌碼流向含有資訊。 |
| Jegadeesh & Titman (1993) | 過去 3–12 個月的贏家會續強(動能效應)——法人連買常與價格動能同向。 |
| Barber, Lee, Liu & Odean (2009, 台股) | 用台灣完整成交資料證明:散戶長期輸給法人,法人的單從散戶手上賺走可觀報酬。 |
| Cohen, Gompers & Vuolteenaho (2002) | 機構傾向在「好消息」上加碼;籌碼若搭配基本面改善訊號更可靠。 |
換句話說:籌碼要搭配基本面才有 alpha,單看籌碼容易被反向收割。 我們就用回測驗證這句話。
對照組:天真地「投信連買 5 天就追」——會虧錢
很多新手的第一直覺:投信連續買超就跟。我們照做(連買 5 日、選買最多的 20 檔、週頻換股):
顯示程式碼
trust = data.get('institutional_investors_trading_summary:投信買賣超股數')
vol = data.get('price:成交股數')
streak = (trust > 0).rolling(5).sum() >= 5 # 連續 5 日買超
liq = vol.average(20) > 500*1000 # 流動性過濾
pos = trust.rolling(5).sum()[streak & liq].is_largest(20)
from finlab.backtest import sim
report = sim(pos.loc['2013':], resample='W') # 週頻換股結果:CAGR 只有 4.76%,最大回撤 −51.8%,Sharpe 0.24 ——不但跑輸 0050(含息 CAGR 19.86%),回撤還大得嚇人。這驗證了上面 Barber et al. 的結論:散戶式的盲目跟單,正是被收割的一方。
優化組:籌碼「強度」× 月營收動能——⭐ 13 年 CAGR 30.1%
問題出在兩點:(1) 用「買超股數」會偏向大型股;(2) 沒有基本面把關。我們改成:
- 投信買超強度 = 20 日投信淨買超 ÷ 20 日成交量(占比,而非絕對股數),排除大型股偏誤;
- 疊上月營收年增 > 0 且月營收創 12 個月新高(基本面把關);
- 用
rank把兩個訊號做複合排序選 15 檔,月頻換股、並用resample_offset='14D'對齊月營收公布日(避前視偏差、捕捉公布後的營收動能):
顯示程式碼
trust_intensity = (trust.rolling(20).sum() / vol.rolling(20).sum()) # 籌碼強度
rev = data.get('monthly_revenue:當月營收')
rev_yoy = data.get('monthly_revenue:去年同月增減(%)')
rev_high = rev.average(3) == rev.average(3).rolling(12).max() # 營收創高
score = trust_intensity.rank(axis=1, pct=True) + rev_yoy.rank(axis=1, pct=True)
cond = (vol.average(20) > 500*1000) & rev_high & (rev_yoy > 0)
position = score[cond].is_largest(15)
report = sim(position.loc['2013':], resample='M', resample_offset='14D')績效對照(2013-01 ~ 2026-06,基準 0050 用含息 etl:adj_close):
| 指標 | 對照組(天真追投信) | 優化組 ⭐(籌碼強度×營收) | 0050(含息) |
|---|---|---|---|
| 年化報酬(CAGR) | 4.76% | 30.15% | 19.86% |
| 月報酬 Sharpe | 0.23 | 1.05 | — |
| 月報酬 Sortino | 0.43 | 2.18 | — |
| 日報酬 Sortino | 0.37 | 1.71 | — |
| 最大回撤(MDD) | −51.8% | −41.7% | — |
| 月勝率 | 47.5% | 49.9% | — |
數字來源:finlab
sim()真實回測,基準 0050 採etl:adj_close(已調除權息)。Sortino 2.18 已通過 FinLab 的風險調整品質門檻(≥1.5)。完整可重現腳本見文末下載。
把兩條曲線和大盤畫在一起,差距一目了然——藍色(優化組)穩定爬升,橘色(天真追籌碼)幾乎貼地,灰色虛線是 0050:

逐年來看,優化組在多數年份贏過 0050,且在 2018、2022 的空頭年回撤可控:

下面是完整互動式回測報告——月報酬熱力圖、權益曲線、年度績效、持股明細全在裡面,可直接在文章中操作:
重點不是這支策略本身,而是: 你之所以能在十幾行內把「籌碼 + 月營收 + 流動性」組成策略並嚴謹回測,是因為這些資料一行就拿到、格式統一、除權息與公布日都對齊好了。換成爬蟲方案,光是把這三種資料對齊到同一張交易日表格,就要寫上百行清洗碼。想看更多因子組合,可參考 四因子選股實戰:複合因子贏過 0050 與 法人籌碼跟單術。
把資料存成 CSV / 本地資料庫(離線重用)
抓下來的是標準 pandas DataFrame,要存檔、離線重用都很直覺:
顯示程式碼
close = data.get('price:收盤價')
close.to_csv('tw_close.csv') # 存成 CSV
close.to_parquet('tw_close.parquet') # 大檔建議 parquet,讀寫更快
# 存進 SQLite 本地資料庫
import sqlite3
con = sqlite3.connect('tw_stock.db')
close['2330'].to_frame('close').to_sql('tsmc_close', con, if_exists='replace')finlab 本身也會把抓過的資料快取在本地,同一個資料表第二次 data.get() 幾乎瞬間回應,不會重複消耗額度。
反爬蟲被擋怎麼辦?
如果你執意自己爬證交所/Yahoo,常見會踩到:
| 症狀 | 原因 | 實務解法 |
|---|---|---|
抓幾次後回 HTTP 403 / 429 |
同一 IP 請求過快被限流 | 加 time.sleep() 隨機延遲、降頻;嚴重時換 IP |
| 回傳空白或亂碼 | 沒帶 User-Agent、編碼錯 |
補 headers、用 big5/utf-8 正確解碼 |
| 抓到一半欄位變了 | 網站改版 | 寫防呆、定期維護解析器 |
| 歷史資料抓不到 | 證交所只留最新 | 自己每天排程存檔累積 |
說白了,爬蟲的維護成本是長期的——網站一改版你的程式就壞。這也是為什麼正式量化研究多半改用整理好的資料源:把時間花在策略,而不是跟反爬蟲打仗。finlab 走 API,不會被擋,資料表也由團隊維護更新。延伸閱讀:程式交易是什麼?從零開始的自動化交易。
這篇屬於哪根主題?
本文是 程式交易 主題下「用 Python / 工具取得資料」的入門站。延伸學習路徑:
- 想知道量化交易全貌 → 量化交易完整指南
- 想學怎麼選股 → 股票選股方法總覽
- 想看更多因子實測 → 台股單因子 vs 複合因子實測圖
- 想看籌碼面深入策略 → 法人籌碼跟單術、散戶反向指標策略
- 想串月營收事件 → 月營收動能與公布後漂移(PEAD)
常見問題(FAQ)
| 問題 | 回答 |
|---|---|
| 台股歷史資料最早到哪一年? | 看來源:FinMind 約 1994、yfinance 約 2000、finlab 股價 2007、月營收 2005;但對回測而言,除權息有沒有調、財報公布日有沒有對齊比起始年更關鍵。finlab 這兩點預設做好。 |
| 要先開戶嗎? | 不用。finlab、twstock、yfinance、FinMind 都只要註冊或直接 pip 安裝;只有富果 Fugle 這類券商 API 需要開戶綁券商。 |
| 免費版能抓多少? | finlab 免費方案有每月資料額度(以 MB 計),做選股與回測足夠;twstock、yfinance、證交所 OpenAPI 全免費但功能單一;FinMind 有免費分級。 |
| 盤中即時報價怎麼辦? | 本文資料以日頻為主,適合選股與回測。要盤中即時/逐筆,需用券商級即時 API(如富果),或 finlab 的即時資料方案。 |
| 有美股資料嗎? | finlab 有美股,指令格式相同;yfinance 對美股支援最完整;FinMind 也有海外資料表。 |
| 不會寫 Python 可以嗎? | 可以。你可以用 AI 對話(自然語言)描述選股條件,由 finlab 底層執行,不必親手寫程式。會 Python 則彈性更大。 |
| 這些資料能直接拿去實單嗎? | 回測通過不代表實單一定賺。要考慮滑價、手續費、流動性與資金控管,且過去績效不代表未來,務必小額驗證。 |
| 為什麼不直接用免費爬蟲就好? | 爬蟲適合小工具與學習;但要做嚴謹回測,自己對齊除權息與財報公布日、維護反爬蟲,長期成本很高。把時間花在策略,通常比花在資料工程更划算。 |
📎 可下載資源
- 完整可重現回測腳本:strategy.py(籌碼強度 × 月營收動能,含對照組)
- 互動式回測報告:report_strategy.html、report_baseline.html
作者:FinLab 量化研究團隊——專注台股因子研究與回測工程,所有數字皆由 finlab 套件實跑、可追溯、可重現。最後更新:2026-06。資料覆蓋數字查詢於 2026-06。投資有風險,過去績效不代表未來表現,本內容僅供教學參考,不構成投資建議,請依個人風險承受度審慎評估。
FinLab AI
想建立自己的策略?
用自然語言描述你的選股想法,AI 自動驗證、回測、給你答案
免費開始