跳至主要內容
台股研究 約 8 分鐘閱讀

Python 取得台股資料完整教學:6 種方法比較+免爬蟲一行抓股價/月營收/財報/籌碼(2026)

用 Python 抓台股資料,80% 時間卡在「把資料弄到手」:爬蟲被擋、欄位零散、除權息要自己調、財報要對齊公布日。本文先實測比較 6 種主流做法(twstock、證交所 OpenAPI、yfinance、FinMind、富果 Fugle、finlab)的資料起始年、涵蓋檔數與前視偏差陷阱,再示範用 finlab 一行 data.get() 拿到 2748 檔近 20 年股價、2289 檔月營收、財報與三大法人籌碼,並用一個籌碼策略實測(13 年 CAGR 30.1%)證明這份資料回測就能直接用。每段都附可複製程式碼與輸出。

一行抓台股籌碼 CAGR 30.1% Sharpe 2.18

Python 一行抓台股籌碼資料:投信買超 × 月營收動能 13 年實測 CAGR 30.1%

先看結論: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 一定贏。但對回測而言,真正決定成敗的是另外兩件事——

  1. 除權息有沒有調:台股每年配息 3–5%,5 年累積報酬若不還原會被低估 15–25%,基準直接失真。
  2. 有沒有避開前視偏差:財報、月營收都有「公布日」,回測若用到當天還沒公布的數字,績效會虛高、實單卻做不出來。

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 個交易日的股價,疊上投信(藍)、外資(綠)的單日買賣超:

一行 data.get() 拿到的資料長這樣:台積電股價疊三大法人籌碼

籌碼(法人買賣超):投信、外資、自營商三大法人每天買進與賣出的差額(淨買賣超)。市場常把法人連續買超視為認同訊號,但下面我們會用真實回測證明——盲目跟單反而會虧錢


用一個籌碼策略,證明這份資料「回測就能直接用」

光說資料乾淨沒有說服力。我們用一個跨多種資料的籌碼策略實跑——這正好展示 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:

籌碼策略 13 年權益曲線:優化組 vs 天真追籌碼 vs 0050

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

逐年報酬:籌碼策略 vs 0050

下面是完整互動式回測報告——月報酬熱力圖、權益曲線、年度績效、持股明細全在裡面,可直接在文章中操作:

重點不是這支策略本身,而是: 你之所以能在十幾行內把「籌碼 + 月營收 + 流動性」組成策略並嚴謹回測,是因為這些資料一行就拿到、格式統一、除權息與公布日都對齊好了。換成爬蟲方案,光是把這三種資料對齊到同一張交易日表格,就要寫上百行清洗碼。想看更多因子組合,可參考 四因子選股實戰:複合因子贏過 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 / 工具取得資料」的入門站。延伸學習路徑:


常見問題(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 則彈性更大。
這些資料能直接拿去實單嗎? 回測通過不代表實單一定賺。要考慮滑價、手續費、流動性與資金控管,且過去績效不代表未來,務必小額驗證。
為什麼不直接用免費爬蟲就好? 爬蟲適合小工具與學習;但要做嚴謹回測,自己對齊除權息與財報公布日、維護反爬蟲,長期成本很高。把時間花在策略,通常比花在資料工程更划算。

📎 可下載資源


作者:FinLab 量化研究團隊——專注台股因子研究與回測工程,所有數字皆由 finlab 套件實跑、可追溯、可重現。最後更新:2026-06。資料覆蓋數字查詢於 2026-06。投資有風險,過去績效不代表未來表現,本內容僅供教學參考,不構成投資建議,請依個人風險承受度審慎評估。

FinLab AI

想建立自己的策略?

用自然語言描述你的選股想法,AI 自動驗證、回測、給你答案

免費開始

更多技術指標研究

查看全部