API 參考
finlab.data
本頁內容11
finlab.data 負責下載 FinLab 的所有資料:股價、財報、月營收、籌碼都在這裡。每份資料都是一張表,每一列是一個日期、每一欄是一檔股票。最常用的流程是先用 data.search() 找到資料表欄位,再用 data.get() 下載,需要時用 data.set_market() 或 data.universe() 控制市場與股票範圍。
選哪個函式
| 你想做的事 | 用這個 |
|---|---|
| 下載股價、財報、月營收、籌碼資料 | data.get('price:收盤價') |
| 找資料表與欄位名稱 | data.search('ROE') |
| 不下載,先看一個資料集的格式與說明 | data.describe('price:收盤價') |
| 切換台股、美股、美股 ETF/基金 | data.set_market('us') |
| 只取上市、上櫃、特定產業或股票清單 | with data.universe(market='TSE'): |
| 只取美股指數成分股、產業或交易所 | with data.us_universe(index='SP500'): |
| 取消股票範圍篩選 | data.reset_universe() |
| 依歷史日期判斷上市櫃資格 | universe.membership('TSE_OTC') |
| 計算所有股票的技術指標 | data.indicator('RSI', timeperiod=14) |
| 限制下載的日期範圍、加快測試 | data.truncate_start = '2020-01-01' |
| 改變資料在本機的存放方式 | data.set_storage() |
| 下載前預估用量、記錄實際用量 | data.plan_download()、data.download_usage() |
| 查目前帳號是不是 VIP | data.get_role()、data.is_vip() |
| 取得已上傳策略的儀表板數據 | data.get_strategies() |
第一次使用請先讀下載資料;要把資料寫成選股條件,接著看 FinlabDataFrame。
下載資料
data.get() 用「資料表:欄位」的名稱下載資料:
from finlab import data
# 下載收盤價
close = data.get('price:收盤價')
# 下載本益比
pe_ratio = data.get('price_earning_ratio:本益比')
# 下載月營收
revenue = data.get('monthly_revenue:當月營收')每一列的日期是那份資料公布、你拿得到的日期,所以月營收標在次月 10 日(申報期限)。免費帳號的台股資料到 2023 年底,VIP 每天更新到最新。
finlab.data.get
get(dataset, save_to_storage, force_download, lazy, progress, progress_callback, start, end, as_of, version) -> pd.DataFrameDownload historical data.
See https://ai.finlab.tw/database for the full data catalogue.
參數
datasetstrThe name of dataset.
tw_tick:SYMBOLandtw_minute:SYMBOLreturn after-market long-form pandas frames and require both dates (at most 31 calendar days). See the intraday data guide.save_to_storagebool預設TrueWhether to cache intraday data or retained versions (
as_of/version).FalseraisesValueErrorfor ordinary reads; usedata.set_storage(data.CacheStorage())instead.force_downloadbool預設FalseWhether to force download the dataset from cloud.
lazybool預設FalseReturn a lazy computation wrapper after fetching the dataset.
progressProgressMode預設'silent''display','event', or'silent'.progress_callbackCallable[[ProgressEvent], None] | NoneReceives structured events in event mode.
startDateBoundOptional inclusive lower bound on the
datecolumn. Accepts any date-like value (string orTimestamp). Pushed down to the Arrow read so only in-range rows are materialised. Requires the dataset to have adatecolumn/index, otherwise raisesValueError.endDateBoundOptional inclusive upper bound on the
datecolumn. Same rules asstart; a string covers the whole period it names, asdf.loc[:end]does ('2024-03'includes March 31). When bothstartandendareNonethe result is byte-identical to a plain read.as_ofDateBoundReturn the dataset exactly as it was published at this time (naive values are Asia/Taipei, for every market; a bare date means 00:00 that day, before that day's publications). Only versions the server still retains are available; list them with
data.versions(dataset). Requires a paid data plan and counts toward the download quota; a version already downloaded is read from local storage.financial_statementkeeps permanent vintages instead (financial_statement_versions).versionstr | int | NoneReturn exactly this generation from
data.versions(dataset). Mutually exclusive withas_of.
回傳
pd.DataFramefinancial data as a DataFrame. With pandas 2 (for example on Colab or
pd.DataFramePython 3.10) it shares its values with the cache: editing it in place,
pd.DataFramesuch as
df.loc[...] = 0ordf.fillna(0, inplace=True), alsopd.DataFramechanges later
data.getresults in the same session, including thepd.DataFrameprices
sim()backtests with. Edit a copy insteadpd.DataFrame(
df = data.get(...).copy()). pandas 3 returns an independent frame.
常用資料表
| 類別 | key | 內容 |
|---|---|---|
| 股價 | price:收盤價 | 每日收盤價 |
| 股價 | price:開盤價 | 每日開盤價 |
| 股價 | price:最高價 / price:最低價 | 日內極值 |
| 股價 | price:成交股數 | 成交量 |
| 財報 | price_earning_ratio:本益比 | P/E ratio |
| 財報 | price_earning_ratio:股價淨值比 | P/B ratio |
| 財報 | fundamental_features:ROE稅後 | ROE |
| 財報 | financial_statement:每股盈餘 | EPS |
| 籌碼 | institutional_investors_trading_summary:投信買賣超股數 | 投信買賣超 |
| 籌碼 | margin_transactions:融資使用率 | 融資使用率 |
| 籌碼 | etl:外資持股比例 | 外資持股比例 |
| 月營收 | monthly_revenue:當月營收 | 當月營收 |
| 月營收 | monthly_revenue:去年同月增減(%) | 營收年增率 |
完整列表請到資料庫目錄查詢。
用英文 key 取台股價格
預設台股市場或 data.set_market("tw") 下,以下英文 key 與既有中文 key 取得相同資料,並共用快取。data.gets()、lazy=True 與 start/end 日期篩選也支援這些別名。volume 是成交股數。
| 英文 key | 既有台股 key |
|---|---|
price:open | price:開盤價 |
price:high | price:最高價 |
price:low | price:最低價 |
price:close | price:收盤價 |
price:volume | price:成交股數 |
from finlab import data
data.set_market("tw")
tw_close = data.get("price:close")
data.set_market("us")
us_close = data.get("price:close")切換到美股後,price:close 仍取得美股收盤價。上述五個別名之外的欄位請使用原本的 key。
找資料表與欄位
用關鍵字搜尋
data.search() 只查目錄、不下載資料:
from finlab import data
# 搜尋 ROE 相關資料
data.search('ROE')
# ['fundamental_features:ROE稅後', 'fundamental_features:ROE綜合損益']
# 搜尋包含「收盤」的欄位
data.search('收盤')
# ['price:收盤價', 'etl:不含除權息收盤價', ...]
# 用常見說法搜尋:也會比對資料名稱、說明、別名與整表欄位
data.search('市值') # ['etl:market_value', ...]
data.search('集保') # ['inventory', 'etl:inventory:零股股數', ...]
# 比對時忽略全半形、占/佔、(%)、今日/當日
data.search('融資餘額') # ['margin_transactions:融資今日餘額']
# 搜尋美股資料
data.search('close', market='us')
data.search('pe', market='us')
# 搜尋美股 ETF / 基金資料
data.search('close', market='us_fund')
# 列出所有台股欄位
all_fields = data.search()
print(f"共 {len(all_fields)} 個欄位")finlab.data.search
search(keyword, market, details) -> pd.Series | pd.DataFrameSearch available data fields in the finlab database.
The keyword matches dataset keys and, when the catalog provides them, each
dataset's name, description, aliases and table columns. Matching ignores
case, full/half-width differences, 占/佔, (%) and 今日/當日.
Returns a pandas Series of dataset names (object dtype, name "dataset").
With details=True, returns a DataFrame with dataset, auth
(free or vip), free_until (inclusive cutoff, or None), and
requires_date_range (bool). When True, get() requires both start/end;
these intraday keys represent dataset families, not a full symbol list.
This flag is independent of frequency: the tw_price_60min wide tables
do not require dates. Missing permissions stay unknown; no access is granted.
參數
keywordstr | Nonemarketstr | Nonedetailsbool預設False
看一個資料集的格式
data.describe() 回傳一個資料集或整張表的格式與說明,同樣不下載資料:
from finlab import data
data.describe('price:收盤價')
data.describe('monthly_revenue') # 整張表的欄位與說明
data.describe('monthly_revenue:key_date')
data.describe('us_price:close', market='us')查詢共用搜尋的目錄快取,不下載資料。layout 是發布資料的格式,source_layout 是目錄明列的上游儲存格式;沒有提供的資訊回傳 None。schedule 是更新排程,不能當成觀測頻率 frequency。index_end 是最後一個索引標籤,可能包含未來的期間日期;source_created_time 是資料檔建立時間,兩者都不能當成逐筆資料的可用時間或 latest_data_date。
columns 列出目錄可查到的欄位。未列出的 key_date 會回傳 catalogued=False、key_date_available=None,並保留 category_description;這不代表無法下載,也不能據此判定它是公告日。其他查無的名稱會拋出 KeyError,目錄無法取得或為空時拋出 RuntimeError。
finlab.data.describe
describe(dataset, market) -> dict[str, Any]Inspect an exact dataset key or category using the cached search catalog.
No dataset is downloaded. layout describes the published dataset
(pivot/table/long), whereas source_layout is only populated if the
catalog explicitly describes upstream storage. frequency is never
inferred from the crawler's cron schedule.
index_end is the catalog's last index label, which can be a future
period label. It is not the latest available observation date.
source_created_time is the published artifact's creation time, not a
row's availability time. latest_data_date is None unless explicitly
published under that name. Missing metadata stays None.
An unlisted category:key_date returns category context with
catalogued=False and unknown layout/availability. Absence from the
catalog does not prove that get() cannot download it, nor that its values
represent announcement dates. Check the category description for semantics.
Other unknown keys raise KeyError; an unavailable/empty catalog raises
RuntimeError. Markets follow search(), except that "all" is not supported.
參數
datasetstrmarketstr | None
切換市場
data.set_market()
設定之後的 data.get() 與回測要用哪個市場。預設是台股。
from finlab import data
data.set_market('us') # 美股
us_close = data.get('price:close')
data.set_market('us_fund') # 美股 ETF / 基金
fund_close = data.get('price:adj_close')
data.set_market('tw') # 切回台股| 參數 | 型別 | 預設 | 說明 |
|---|---|---|---|
market_code | str | 必填 | 市場代碼,例如 'tw'、'us'、'us_fund'。 |
限定股票範圍
data.universe() 與 data.us_universe() 是 with 區塊:區塊內的 data.get() 只回傳符合條件的股票,離開區塊後還原進入前的篩選。
台股:上市櫃、產業、股票清單
from finlab import data
# 範例 1:只取上市公司
with data.universe(market='TSE'):
close = data.get('price:收盤價')
print(f"上市公司數量: {len(close.columns)}")
# 範例 2:特定類股
with data.universe(category=['水泥工業', '食品工業']):
close = data.get('price:收盤價')
# 範例 3:指定股票清單
with data.universe(whitelist=['2330', '2317', '2454']):
close = data.get('price:收盤價')
# 範例 4:組合條件
with data.universe(market='TSE_OTC', category=['電子工業']):
close = data.get('price:收盤價')可用的 market 參數:
| 值 | 範圍 |
|---|---|
'TSE' | 上市 |
'OTC' | 上櫃 |
'TSE_OTC' | 上市+上櫃 |
'ALL' | 全部(含興櫃) |
market 與 category 都用今天的上市櫃別與產業分類篩選整段歷史:後來從上櫃轉上市的股票,轉板前也算在 'TSE'、不在 'OTC';後來才新增的產業類別(例如 2023 年 7 月新增的綠能環保),也會套用到更早的日期。回測要依日期判斷上市櫃資格,改用下方的 universe.membership()。
finlab.data.universe
universe(exchange, sector, exclude_sector, industry, asset_type, security_type, index, whitelist, market, category, exclude_category)Context manager to set a global stock universe filter for data retrieval.
Auto-dispatches TW vs international logic based on the active data context.
參數
exchangestr | list[str]預設'ALL'TW: 'TWSE'/'TPEx' (or legacy 'TSE'/'OTC'). International: 'NASDAQ'/'NYSE'/'AMEX'/'HKEX'/'TSE'/etc. TW uses each stock's current exchange for every date: a stock that moved from TPEx to TWSE counts as TWSE before its move. For date-by-date listing eligibility, use
universe.membership().sectorstr | list[str]預設'ALL'Sector name(s) with regex matching. Uses the current classification for every date, including categories created later.
exclude_sectorstr | list[str] | NoneSector(s) to exclude (TW only).
industrystr | list[str]預設'ALL'Industry filter (international markets).
asset_typestr | NoneTW only: 'ETF' or 'STOCK_FUTURE'. 'STOCK_FUTURE' uses the latest underlying list for every historical date: stocks appear before their futures listed, and former underlyings disappear. For historical selection, see the stock-futures backtest example below.
security_typestr | list[str]預設'ALL'Security type filter (international markets), e.g. 'common_stock'.
indexstr | NoneMarket index to filter by (international markets only). For US market: 'SP500'/'SPX', 'NASDAQ100'/'NDX'. Uses the latest constituent list for every historical date. For historical index selection, see the
us_universebacktest example.whiteliststr | Iterable[str] | NoneExplicit security IDs; a string is one ID. Alone, bypasses the current market catalog, so delisted IDs can be retained. With other filters, takes their intersection. Empty or zero-overlap selections return empty security data. IDs must already exclude unwanted security types; this static set does not encode listing eligibility by date.
marketstr | NoneLegacy alias for TW exchange+asset_type.
categorystr | list[str] | NoneLegacy alias for
sector.exclude_categorystr | list[str] | NoneLegacy alias for
exclude_sector.
範例
TW market (default):
from finlab import data
with data.universe(exchange=['TWSE', 'TPEx'], sector=['鋼鐵工業', '航運業']):
close = data.get('price:收盤價')Legacy TW usage (still works):
with data.universe(market='TSE_OTC', sector='水泥', exclude_sector='ETF'):
close = data.get('price:收盤價')Stock-futures backtest, from each stock's first futures trade (standard or mini contract). Underlyings no longer listed today are not included:
with data.universe(): # Temporarily clear any existing universe filter.
close = data.get('price:收盤價')
underlying = data.get('single_stock_futures_and_equity_options_underlying')
volume = data.get('futures_price:成交量')
underlying = underlying[underlying['是否為股票期貨標的'] == 'Y']
contracts = underlying['股票期貨、選擇權商品代碼'].astype(str) + 'F一般'
traded = volume.reindex(columns=contracts).gt(0)
traded.columns = underlying['symbol'].astype(str)
listed = traded.T.groupby(level=0).any().T.cummax()
has_futures = listed.reindex(close.index, method='ffill', fill_value=False)
score = close.pct_change(20)
position = score.where(has_futures).is_largest(10)US market (S&P 500):
data.set_market('us')
with data.universe(index='SP500'):
close = data.get('price:close')US market (NASDAQ 100 Technology stocks):
data.set_market('us')
with data.universe(index='NDX', sector='Technology'):
close = data.get('price:close')JP market:
data.set_market('jp')
with data.universe(sector='Technology'):
close = data.get('price:close')美股:指數成分股、產業、交易所
from finlab import data
data.set_market('us')
# 取得最新 S&P 500 成分股的整段價格歷史
with data.us_universe(index='SP500'):
close = data.get('price:close')
# 取得最新 NASDAQ 100 成分股中的科技股
with data.us_universe(index='NDX', sector='Technology'):
close = data.get('price:close')
# 取得乾淨的美股普通股 universe
with data.us_universe(security_type='common_stock'):
close = data.get('price:close')
# 也可以用 data.universe() 搭配 set_market
with data.universe(index='SP500', exchange='NASDAQ'):
close = data.get('price:close')支援的 index 參數值:
| 指數 | 可用別名 |
|---|---|
| S&P 500 | 'SP500', 'SPX', 'S&P500', 'S&P 500' |
| NASDAQ 100 | 'NASDAQ100', 'NDX', 'NASDAQ 100' |
index 可與 sector、industry、exchange、security_type 組合使用,篩選結果為交集。美股的 sector 名稱:Technology、Healthcare、Financial Services、Consumer Cyclical、Industrials、Communication Services、Consumer Defensive、Energy、Basic Materials、Real Estate、Utilities。
finlab.data.us_universe
us_universe(sector, industry, exchange, security_type, index)Context manager to set a global stock universe filter for US market data retrieval.
This context manager limits the set of US stocks returned by data functions to a specific sector, industry, exchange, and/or index selection. The filter is applied globally within the context and is restored after the context exits.
參數
sectorstr | list[str]預設'ALL'Sector name(s) to include. Supports regex-like substring matching.
industrystr | list[str]預設'ALL'Industry name(s) to include. Supports regex-like substring matching.
exchangestr | list[str]預設'ALL'Exchange name(s) to include. Common values: 'NASDAQ', 'NYSE', 'AMEX'.
security_typestr | list[str]預設'ALL'Security type(s) to include. Use 'common_stock' for clean US equities.
indexstr | NoneMarket index to filter by. Supported values: 'SP500'/'SPX' (S&P 500), 'NASDAQ100'/'NDX' (NASDAQ 100). Can be combined with sector/industry/exchange for further filtering.
範例
from finlab import data
with data.us_universe(sector='Technology', exchange='NASDAQ'):
close = data.get('us_price:close')Filter to common stocks only:
with data.us_universe(security_type='common_stock'):
close = data.get('us_price:close')Filter to the latest S&P 500 constituents (all historical dates):
with data.us_universe(index='SP500'):
close = data.get('us_price:close')Filter to the latest NASDAQ 100 Technology stocks (all historical dates):
with data.us_universe(index='NDX', sector='Technology'):
close = data.get('us_price:close')Historical index backtest:
with data.us_universe(): # Temporarily clear any existing universe filter.
close = data.get('us_price:close')
constituents = data.get('us_index_constituents:sp500')
in_index = constituents.reindex(close.index, method='ffill').eq(True)
score = close.pct_change(20)
position = score.where(in_index).is_largest(3)For NASDAQ 100, replace us_index_constituents:sp500 with
us_index_constituents:nasdaq100.
用歷史成分股回測美股指數
index='SP500' 或 'NDX' 取成分股表的最後一列,再用這份最新名單篩選整段歷史的欄位。直接拿來回測會有存活者偏誤與前視:後來才加入的股票會出現在加入前的日期,已剔除的股票則會從整段歷史消失。指數調整後,同一策略重跑也可能改變過去的結果。data.universe()、data.set_universe() 與 data.set_us_universe() 的 index 參數也採這個方式。
要依歷史紀錄篩選,先讀取未篩選的美股價格,再將當日或之前最近一筆成分股紀錄套在分數上,最後才排名選股:
from finlab import data
with data.us_universe(): # 暫時清除既有 universe 篩選,離開後會還原
close = data.get('us_price:close')
constituents = data.get('us_index_constituents:sp500')
in_index = constituents.reindex(close.index, method='ffill').eq(True)
score = close.pct_change(20)
position = score.where(in_index).is_largest(3)NASDAQ 100 改讀 us_index_constituents:nasdaq100。成分股紀錄開始前的日期與表中沒有的價格代號都設為 False;請在當日收盤後使用當日遮罩。這份範例以代號完全相同為準,代號寫法不同、更名或缺少價格歷史時,仍可能漏掉成分股。遮罩依目前保存的紀錄重建,來源延遲、缺漏與事後更正仍會影響結果,不能視為當時已知資料的完整快照。
universe.membership()
依歷史日期取得台股上市櫃資格:回傳布林 FinlabDataFrame,日期與股票欄位依台股收盤價資料排列。支援 TSE、OTC、TSE_OTC;不改變現有 with data.universe(...) 或排名方法。
from finlab import data
from finlab.data import universe
# 在沒有舊 universe 過濾的情況下取得完整原始資料。
close = data.get("price:收盤價")
score = close.pct_change(20)
eligible = universe.membership("TSE_OTC")
position = score[eligible].is_largest(20)| 參數 | 型別 | 預設 | 說明 |
|---|---|---|---|
market | str | 'TSE_OTC' | 'TSE'、'OTC' 或 'TSE_OTC'。 |
每次橫斷面排名前都要套用遮罩。若原始資料已被舊 universe 刪掉股票,新遮罩無法補回那些資料。membership() 本身不受舊股票集合限制,也不改動該集合;日期範圍仍遵循資料截取設定。
資格以現有公司基本資料、下市櫃公司資料及兩市場終止名單中的有效日期建立:上市櫃日包含在內,終止日起排除;支援多段上市期間及轉板。停牌、沒有成交不等於終止上市,應另外加入交易條件。遮罩不清空指標計算所需的前期資料。
缺少上市日期的歷史期間維持 False,並發出警告;可從 eligible.attrs["membership_missing_history"] 查看需要補齊歷史的股票。沒有公司上市資格紀錄的證券(例如 ETF)也不會因價格欄位存在就被納入。這份資料不能當作完整的 ETF 母體。
此功能依目前可得紀錄重建歷史有效資格,沒有保存母體版本,也不是「當時已知資訊」快照。補正歷史事件仍可能改變結果;無法保證重現舊回測。
data.reset_universe()
取消股票範圍篩選。不帶任何篩選條件的 data.set_universe()、data.universe() 與 data.us_universe() 效果相同,不會排除任何代號。
from finlab import data
data.set_universe(sector='半導體業')
filtered = data.get('price:收盤價')
data.reset_universe()
unfiltered = data.get('price:收盤價')重設會套用到後續的 data.get()、data.gets(),包含快取讀取;不會刪除快取、切換市場、改變日期限制,或修改已回傳的 DataFrame。在 data.universe() 或 data.us_universe() 區塊內重設後,篩選會停用直到下一次設定或離開區塊;離開區塊仍會還原進入前的篩選。可以重複呼叫重設。
計算技術指標
data.indicator() 一次算出每檔股票的技術指標,使用前要先安裝 TA-Lib 或 pandas-ta:
from finlab import data
# 每檔股票的 14 日 RSI
rsi = data.indicator('RSI', timeperiod=14)
# MACD 有三個輸出
macd, macd_signal, macd_hist = data.indicator('MACD')finlab.data.indicator
indicator(indname, adjust_price, resample, strict, **kwargs) -> pd.DataFrame | tuple[pd.DataFrame, ...]支援 Talib 和 pandas_ta 上百種技術指標,計算 2000 檔股票、10年的所有資訊。
在使用這個函式前,需要安裝計算技術指標的 Packages
建議使用者可以先參考以下範例,並且搭配 talib官方文件,就可以掌握製作技術指標的方法了。
參數
indnamestr指標名稱, 以 TA-Lib 舉例,例如 SMA, STOCH, RSI 等,可以參考 talib 文件。
以 Pandas-ta 舉例,例如 supertrend, ssf 等,可以參考 Pandas-ta 文件。
adjust_pricebool預設False是否使用還原股價計算。
resamplestr預設'D'技術指標價格週期,ex:
D代表日線,W代表週線,ME代表月線。MS這類標在期初的週期,K 棒改標在該期最後一個交易日,避免提早看到期末價格。marketstr市場選擇,ex:
TW_STOCK代表台股,US_STOCK代表美股。strictbool預設False預設 False。True 時只接受 TA-Lib 的數值參數名稱, 拒絕輸入價格 selector;pandas_ta 尚不支援,會拋出 NotImplementedError。 例如
data.indicator('RSI', strict=True, timeperiod=14)。 只檢查名稱,不保證參數在每種設定下都影響結果;參數值由 TA-Lib 檢查。 無股票或全 NaN 時不執行指標計算。**kwargsdict預設{}技術指標的參數設定,TA-Lib 中的 RSI 為例,調整項為計算週期
timeperiod=14。
控制下載範圍與快取
限制資料時間範圍
from finlab import data
# 只下載 2020-2023 年的資料(節省記憶體)
data.truncate_start = '2020-01-01'
data.truncate_end = '2023-12-31'
# 之後所有 data.get() 都會套用此範圍
close = data.get('price:收盤價')強制使用雲端或本地資料
from finlab import data
# 強制使用雲端資料(每次都重新下載)
data.force_cloud_download = True
# 或只用本地快取(無網路環境);兩者不要同時開啟
# data.use_local_data_only = True自訂快取存放位置
下載過的資料預設會在本機存一份,下次 data.get() 不用重新下載。用 set_storage() 改存到指定資料夾,或改成只放在記憶體:
from finlab import data
from finlab.data import set_storage, FileStorage
# 使用自訂資料夾
storage = FileStorage('/path/to/custom/cache')
set_storage(storage)
# 之後所有資料會快取到指定位置
close = data.get('price:收盤價')finlab.data.set_storage
set_storage(storage) -> None設定本地端儲存歷史資料的方式
假設使用 data.get 獲取歷史資料則,在預設情況下,程式會自動在本地複製一份,以避免重複下載大量數據。
storage 就是用來儲存歷史資料的接口。我們提供兩種 storage 接口,分別是 finlab.data.CacheStorage 以及
finlab.data.FileStorage (預設)。前者是直接存在記憶體中,後者是存在檔案中。詳情請參考 CacheStorage 和 FileStorage 來獲得更詳細的資訊,
包括資料存放的資料夾與讀取方式。
參數
storagedata.StorageThe interface of storage
範例
欲切換成以檔案方式儲存,可以用以下之方式:
from finlab import data
data.set_storage(data.FileStorage())
close = data.get('price:收盤價')finlab.data.CacheStorage
CacheStorage()將歷史資料儲存於快取中
範例
欲切換成以檔案方式儲存,可以用以下之方式:
from finlab import data
data.set_storage(data.CacheStorage())
close = data.get('price:收盤價')可以直接調閱快取資料:
close = data._storage._cache['price:收盤價']方法與屬性
set_revision
set_revision
set_revision(name, revision) -> NoneDate the cached frame at revision.
參數
namestrrevisiondatetime.datetime
get_time_expired
get_time_expired
get_time_expired(name) -> datetime.datetime | NoneReturn the published expiry known for the cached version read, if any.
參數
namestr
cache_version
cache_version
cache_version(name) -> int | NoneIdentifies the cached frame; changes on every write, even at the same revision.
參數
namestr
published_hash
published_hash
published_hash(name) -> str | NoneThe verified content hash the cached frame was written with, if any.
參數
namestr
read_dataframe_date_range
read_dataframe_date_range
read_dataframe_date_range(name, start, end) -> pd.DataFrame | NoneReturn in-cache rows with date in [start, end] (both inclusive).
The whole frame already lives in memory here, so there is no memory win
over a full read; the filter is applied for API parity with
FileStorage.
參數
namestrstartpd.Timestamp | Noneendpd.Timestamp | None
clear
clear
clear() -> NoneRemove all in-memory data and timestamp metadata.
release_memory
release_memory
release_memory() -> NoneRelease cached data in RAM; with no disk copy, this clears everything.
finlab.data.FileStorage
FileStorage(path, use_cache)將歷史資料儲存於檔案中
參數
pathstr資料儲存的路徑。不指定時用固定的資料夾(本機為
~/finlab_db),不隨工作目錄改變。 自行指定時請用絕對路徑;'./finlab_db'這類相對路徑會隨每次執行的工作目錄不同而找不到快取,整包重新下載。use_cachebool預設True是否額外使用快取,將資料複製一份到記憶體中。
範例
欲切換成以檔案方式儲存,可以用以下之方式:
from finlab import data
data.set_storage(data.FileStorage())
close = data.get('price:收盤價')可以在本地端的 ~/finlab_db/price#收盤價.feather 中,看到下載的資料,
可以使用 pandas.read_feather 調閱歷史資料:
import pandas as pd
close = pd.read_feather('~/finlab_db/price#收盤價.feather')方法與屬性
get_dataframe_row_count
get_dataframe_row_count
get_dataframe_row_count(name) -> int | NoneReturn the local dataframe row count.
參數
namestr
get_dataframe_index
get_dataframe_index
get_dataframe_index(name) -> pd.Index | NoneReturn the local dataframe index.
參數
namestr
set_dataframe
set_dataframe
set_dataframe(name, df, revision, content_hash) -> NoneWrite df; a verified content_hash is embedded for published_hash.
參數
namestrdfpd.DataFramerevisiondatetime.datetime | Nonecontent_hashstr | None
has_feather_cache
has_feather_cache
has_feather_cache(name) -> boolReturn whether name has a Feather (non-legacy) cache on disk.
參數
namestr
merge_recent_delta
merge_recent_delta
merge_recent_delta(name, short_df, expected_hash, revision) -> boolApply a .recent delta to the cached Feather via a streaming merge.
The stored table is walked one Arrow record batch at a time, so peak
memory is ~= one batch + the delta instead of the three full-table
copies the in-memory merge materialises. Returns False (leaving the
existing cache untouched) when the streamed hash does not match
expected_hash, so the caller can fall back to a full download. The
replacement is atomic (os.replace).
參數
namestrshort_dfpd.DataFrameexpected_hashstrrevisiondatetime.datetime | None
merge_table_delta
merge_table_delta
merge_table_delta(name, delta, expected_hash, revision) -> boolApply a full table's delta to the cached Feather via a streaming merge.
Like merge_recent_delta: False leaves the cache untouched.
參數
namestrdeltaTableDeltaexpected_hashstrrevisiondatetime.datetime | None
set_dataframe_bytes
set_dataframe_bytes
set_dataframe_bytes(name, payload, revision) -> NonePersist a feather payload verbatim, skipping pandas re-encoding.
參數
namestrpayloadbytesrevisiondatetime.datetime | None
get_time_created
get_time_created
get_time_created(name) -> datetime.datetime | NoneThe cache's revision: its file mtime, stamped by the last download.
參數
namestr
get_time_expired
get_time_expired
get_time_expired(name) -> datetime.datetime | NoneReturn the published expiry known for the cached version read, if any.
參數
namestr
cache_version
cache_version
cache_version(name) -> tuple[int, int, int] | NoneIdentifies the bytes this storage last read or wrote, even across replacements dated the same revision; else the file on disk.
參數
namestr
published_hash
published_hash
published_hash(name) -> str | NoneThe content hash embedded in the cached Feather of cache_version.
Published files carry it, and so do the caches merged here. None for a cache without one, or when the file is no longer the version read. Reads only the file footer.
參數
namestr
set_revision
set_revision
set_revision(name, revision) -> NoneRe-date the cache file at a revision whose bytes it already holds.
A file another process replaced since this one was loaded keeps its date. Read-only caches keep their existing date; these bytes remain usable.
參數
namestrrevisiondatetime.datetime
read_dataframe_date_range
read_dataframe_date_range
read_dataframe_date_range(name, start, end) -> pd.DataFrame | NoneRead on-disk rows with date in [start, end] (both inclusive).
The date bounds are pushed down to the Arrow layer for Feather V2 caches,
so only in-range rows are decoded and the full table is never
materialised. Legacy pickle caches have no columnar pushdown, so they are
read fully and then filtered. Bypasses the in-memory _cache on purpose
so a slice read never pins the whole table in memory.
參數
namestrstartpd.Timestamp | Noneendpd.Timestamp | None
release_memory
release_memory
release_memory() -> NoneRelease the in-memory DataFrame cache, keeping files and their revisions.
diagnose
diagnose
diagnose(dataset) -> None診斷本地儲存狀態
參數
datasetstr指定要檢查的資料集名稱,例如 'price:收盤價'。如果不指定,則列出所有本地資料。
範例
from finlab import data
data._storage.diagnose() # 列出所有本地資料
data._storage.diagnose('price:收盤價') # 檢查特定資料集預估與記錄下載用量
付費資料方案可用 data.plan_download(key) 免扣下載額度檢查一般整表讀取。每個候選檔案(full、recent、delta)各一列,包含 route(cache/recent/delta/full)、needs_update(未知時留空)、size_bytes 與 planned_bytes。data.download_usage() 是 with 區塊,收集區塊內每次下載的用量紀錄。清單可用迴圈處理:
import pandas as pd
from finlab import data
keys = ['price:收盤價', 'us_price:close']
plan = pd.concat([data.plan_download(key) for key in keys], ignore_index=True)
plan.to_csv('download-plan.csv', index=False)
with data.download_usage() as rows:
for key in keys:
data.get(key)
receipts = pd.DataFrame(rows)
receipts.to_csv('download-usage.csv', index=False)
receipts.to_json('download-usage.json', orient='records', force_ascii=False)預檢不簽下載網址;舊伺服器不支援時會直接報錯,不會改用會扣額度的下載測試。預檢是快照,hash/合併失敗仍可能再下載 full,發布中的資料也可能改變;未知的費用保留空值,不能視為零或保證上限。本介面限一般整表讀取,不涵蓋盤中資料、as_of/version 與 start/end 最佳化。
用量的 event='provider'、billed_bytes 由伺服器逐項回報。簽網址即計量,傳輸或合併失敗也保留紀錄;quota 是帳號共用當日累計 MiB,不能當作逐項帳單。event='fallback' 的 reason 說明退回原因,event='cache' 表示讀取本機。收到回應前會先留下未知紀錄;舊伺服器未提供 bytes,或簽發回應遺失/重試時,bytes 會留空。provider 費用仍為空值時,不能加總成完整帳單。scope 拋出例外後,仍可在 finally 中匯出 pd.DataFrame(rows)。收集不增加網路請求,包含 scope 內一般 get/gets 的平行工作,不包含其他程式的下載。
處理下載錯誤
| 例外 | 什麼時候發生 |
|---|---|
finlab.exceptions.DatasetNotFoundError | 找不到資料集,通常是 key 打錯 |
finlab.exceptions.SignedDownloadError | 下載資料失敗,例如連線逾時或 HTTP 錯誤 |
finlab.exceptions.QuotaExceededError | 今天的下載額度用完 |
key 打錯:data.get() 找不到資料集時會拋出 DatasetNotFoundError(RuntimeError 的子類別),並列出拼法接近的正確 key。若輸入的是已登記的等價舊名稱,會發出 UserWarning 並自動改抓正確的 key。
下載失敗:拋出 SignedDownloadError(DataError 的子類別)。訊息寫出資料集、HTTP 狀態碼或連線問題的類別與建議做法,不含下載網址。程式要判斷原因時讀 e.kind("http"、"timeout"、"connection"、"ssl"、"redirects"、"browser"、"invalid_reply"、"other")與 e.status(HTTP 狀態碼,沒有收到回應時是 None),不要比對訊息字串。為了相容,它也保留原本的 requests 例外型別(例如 requests.HTTPError、requests.Timeout),並且是 requests.RequestException 與 OSError;新寫的程式建議用 except DataError。
每日下載額度:免費與 VIP 帳號在下載回應的當日用量達 80% 時,都會顯示一次預警。額度用完時,data.get()/data.gets() 會拋出 QuotaExceededError(同時是 DataError 與 RuntimeError 的子類別),訊息包含額度與每日台灣時間 08:00 重置的說明。批次回測請先捕捉這個例外,再處理一般回測錯誤,避免將額度用完誤認成策略失敗。
查詢帳號與策略
查帳號角色
from finlab import data
# 查詢使用者角色(需先執行至少一次 data.get())
close = data.get('price:收盤價')
role = data.get_role() # 'free', 'vip', ...
print(f"目前角色: {role}")
if data.is_vip():
print("VIP 會員,享有完整資料存取權限")finlab.data.get_role
get_role() -> str | NoneReturn the current user role (e.g. 'free' or 'vip').
finlab.data.is_vip
is_vip() -> boolReturn True if the current user is a VIP member.
取得已上傳的策略
data.get_strategies() 回傳你上傳到 FinLab 的策略在儀表板上的數據,可以用來彙整多個策略:
from finlab import data
strategies = data.get_strategies()
for name, info in strategies.items():
print(name, info['stats']['daily_sharpe'])finlab.data.get_strategies
get_strategies(api_token) -> dict[str, Any] | str取得已上傳量化平台的策略回傳資料。
可取得自己策略儀表板上的數據,例如每個策略的報酬率曲線、報酬率統計、夏普率、近期部位、近期換股日..., 這些數據可以用來進行多策略彙整的應用喔!
參數
api_tokenstr若未帶入finlab模組的api_token,會自動跳出GUI頁面, 複製網頁內的api_token貼至輸入欄位即可。
回傳
dictstrategies data
dict[str, Any] | strResponse detail:
dict[str, Any] | strdict[str, Any] | str{ strategy1:{ 'asset_type': '', 'drawdown_details': { '2015-06-04': { 'End': '2015-11-03', 'Length': 152, 'drawdown': -0.19879090089478024 }, ... }, 'fee_ratio': 0.000475, 'last_trading_date': '2022-06-10', 'last_updated': 'Sun, 03 Jul 2022 12:02:27 GMT', 'ndays_return': { '1': -0.01132480035770611, '10': -0.0014737286933147464, '20': -0.06658015749110646, '5': -0.002292995729485159, '60': -0.010108700314771735 }, 'next_trading_date': '2022-06-10', 'positions': { '1413 宏洲': { 'entry_date': '2022-05-10', 'entry_price': 10.05, 'exit_date': '', 'next_weight': 0.1, 'return': -0.010945273631840613, 'status': '買進', 'weight': 0.1479332345384493 }, 'last_updated': 'Sun, 03 Jul 2022 12:02:27 GMT', 'next_trading_date': '2022-06-10', 'trade_at': 'open', 'update_date': '2022-06-10' }, 'return_table': { '2014': { 'Apr': 0.0, 'Aug': 0.06315180932606546, 'Dec': 0.0537589857541485, 'Feb': 0.0, 'Jan': 0.0, 'Jul': 0.02937490104459939, 'Jun': 0.01367930162104769, 'Mar': 0.0, 'May': 0.0, 'Nov': -0.0014734320286596825, 'Oct': -0.045082529665408266, 'Sep': 0.04630906972509852, 'YTD': 0.16626214846456966 }, ... }, 'returns': { 'time': [ '2014-06-10', '2014-06-11', '2014-06-12', ... ], 'value': [ 100, 99.9, 100.2, ... ] }, 'stats': { 'avg_down_month': -0.03304015302646822, 'avg_drawdown': -0.0238021414698247, 'avg_drawdown_days': 19.77952755905512, 'avg_up_month': 0.05293384465715908, 'cagr': 0.33236021285588846, 'calmar': 1.65261094975066, 'daily_kurt': 4.008888367138843, 'daily_mean': 0.3090784769257415, 'daily_sharpe': 1.747909002374217, 'daily_skew': -0.6966018726321078, 'daily_sortino': 2.8300677082214034, ... }, 'tax_ratio': 0.003, 'trade_at': 'open', 'update_date': '2022-06-10' }, strategy2:{...}, ...}
dict[str, Any] | str
常見問題
如何知道有哪些資料可以下載?
方法 1:使用 search()
from finlab import data
# 列出所有欄位
all_fields = data.search()
for field in all_fields[:10]:
print(field)方法 2:查看線上資料庫:前往 FinLab 資料庫目錄 瀏覽完整列表。
下載資料很慢怎麼辦?
from finlab import data
# 方法 1:限制時間範圍
data.truncate_start = '2020-01-01'
# 方法 2:使用快取(第二次會很快)
close = data.get('price:收盤價') # 第一次慢
close = data.get('price:收盤價') # 第二次快(使用快取)
# 方法 3:使用 universe 限制股票範圍
with data.universe(market='TSE', category=['半導體業']):
close = data.get('price:收盤價') # 只保留上市半導體股的欄位出現 KeyError: 'price:收盤價' 怎麼辦?
可能原因:
- 未登入:執行
finlab.login()完成登入 - 欄位名稱錯誤:使用
data.search('收盤')確認正確名稱 - 資料權限不足:確認帳戶是否能存取該資料
import finlab
# 檢查是否已登入
try:
token, token_type = finlab.get_token()
print(f"✅ 已登入({token_type})")
except:
print("❌ 未登入,請執行 finlab.login()")如何下載美股資料?
from finlab import data
# 切換到美股市場後取得美股收盤價
data.set_market('us')
us_close = data.get('price:close')
# 搜尋美股欄位
us_fields = data.search(market='us')資料有缺失值怎麼辦?
from finlab import data
close = data.get('price:收盤價')
# 檢查缺失值
print(f"缺失值比例: {close.isna().sum().sum() / close.size:.2%}")
# 填補缺失值
close_filled = close.ffill() # 向前填補
# 或刪除有缺失值的股票
close_clean = close.dropna(axis=1, thresh=len(close) * 0.8) # 保留 80% 以上資料的股票如何節省記憶體?
from finlab import data
# 方法 1:限制時間範圍
data.truncate_start = '2020-01-01'
# 方法 2:分批處理
close = data.get('price:收盤價')
all_stocks = close.columns
for batch in [all_stocks[i : i + 100] for i in range(0, len(all_stocks), 100)]:
batch_close = close[batch]
# 處理 100 檔...
# 方法 3:只下載需要的欄位
# 不要一次 data.get() 太多資料表下一步
- 下載資料 完整下載教學、資料表結構、進階篩選與錯誤處理。
- FinlabDataFrame 把下載的資料寫成選股條件:排名、均線、產業內比較。
- 台股換股期間與資料就緒 交易日曆、資料更新期間與何時可以換股。
- 常見問題 登入、下載與回測的更多疑難排解。
這一頁有幫到你嗎?