文件
開啟 Studio

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()
查目前帳號是不是 VIPdata.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.DataFrame

Download historical data.

See https://ai.finlab.tw/database for the full data catalogue.

參數

dataset str

The name of dataset. tw_tick:SYMBOL and tw_minute:SYMBOL return after-market long-form pandas frames and require both dates (at most 31 calendar days). See the intraday data guide.

save_to_storage bool 預設 True

Whether to cache intraday data or retained versions (as_of/version). False raises ValueError for ordinary reads; use data.set_storage(data.CacheStorage()) instead.

force_download bool 預設 False

Whether to force download the dataset from cloud.

lazy bool 預設 False

Return a lazy computation wrapper after fetching the dataset.

progress ProgressMode 預設 'silent'

'display', 'event', or 'silent'.

progress_callback Callable[[ProgressEvent], None] | None

Receives structured events in event mode.

start DateBound

Optional inclusive lower bound on the date column. Accepts any date-like value (string or Timestamp). Pushed down to the Arrow read so only in-range rows are materialised. Requires the dataset to have a date column/index, otherwise raises ValueError.

end DateBound

Optional inclusive upper bound on the date column. Same rules as start; a string covers the whole period it names, as df.loc[:end] does ('2024-03' includes March 31). When both start and end are None the result is byte-identical to a plain read.

as_of DateBound

Return 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_statement keeps permanent vintages instead (financial_statement_versions).

version str | int | None

Return exactly this generation from data.versions(dataset). Mutually exclusive with as_of.

回傳

pd.DataFrame

financial data as a DataFrame. With pandas 2 (for example on Colab or

pd.DataFrame

Python 3.10) it shares its values with the cache: editing it in place,

pd.DataFrame

such as df.loc[...] = 0 or df.fillna(0, inplace=True), also

pd.DataFrame

changes later data.get results in the same session, including the

pd.DataFrame

prices sim() backtests with. Edit a copy instead

pd.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:openprice:開盤價
price:highprice:最高價
price:lowprice:最低價
price:closeprice:收盤價
price:volumeprice:成交股數
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.DataFrame

Search 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.

參數

keyword str | None
market str | None
details bool 預設 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.

參數

dataset str
market str | 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_codestr必填市場代碼,例如 '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.

參數

exchange str | 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().

sector str | list[str] 預設 'ALL'

Sector name(s) with regex matching. Uses the current classification for every date, including categories created later.

exclude_sector str | list[str] | None

Sector(s) to exclude (TW only).

industry str | list[str] 預設 'ALL'

Industry filter (international markets).

asset_type str | None

TW 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_type str | list[str] 預設 'ALL'

Security type filter (international markets), e.g. 'common_stock'.

index str | None

Market 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_universe backtest example.

whitelist str | Iterable[str] | None

Explicit 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.

market str | None

Legacy alias for TW exchange+asset_type.

category str | list[str] | None

Legacy alias for sector.

exclude_category str | list[str] | None

Legacy 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.

參數

sector str | list[str] 預設 'ALL'

Sector name(s) to include. Supports regex-like substring matching.

industry str | list[str] 預設 'ALL'

Industry name(s) to include. Supports regex-like substring matching.

exchange str | list[str] 預設 'ALL'

Exchange name(s) to include. Common values: 'NASDAQ', 'NYSE', 'AMEX'.

security_type str | list[str] 預設 'ALL'

Security type(s) to include. Use 'common_stock' for clean US equities.

index str | None

Market 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)
參數型別預設說明
marketstr'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官方文件,就可以掌握製作技術指標的方法了。

參數

indname str

指標名稱, 以 TA-Lib 舉例,例如 SMA, STOCH, RSI 等,可以參考 talib 文件。

以 Pandas-ta 舉例,例如 supertrend, ssf 等,可以參考 Pandas-ta 文件。

adjust_price bool 預設 False

是否使用還原股價計算。

resample str 預設 'D'

技術指標價格週期,ex: D 代表日線, W 代表週線, ME 代表月線。 MS 這類標在期初的週期,K 棒改標在該期最後一個交易日,避免提早看到期末價格。

market str

市場選擇,ex: TW_STOCK 代表台股, US_STOCK 代表美股。

strict bool 預設 False

預設 False。True 時只接受 TA-Lib 的數值參數名稱, 拒絕輸入價格 selector;pandas_ta 尚不支援,會拋出 NotImplementedError。 例如 data.indicator('RSI', strict=True, timeperiod=14)。 只檢查名稱,不保證參數在每種設定下都影響結果;參數值由 TA-Lib 檢查。 無股票或全 NaN 時不執行指標計算。

**kwargs dict 預設 {}

技術指標的參數設定,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 來獲得更詳細的資訊, 包括資料存放的資料夾與讀取方式。

參數

storage data.Storage

The 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) -> None

Date the cached frame at revision.

參數

name str
revision datetime.datetime
get_time_expired
函式

get_time_expired

get_time_expired(name) -> datetime.datetime | None

Return the published expiry known for the cached version read, if any.

參數

name str
cache_version
函式

cache_version

cache_version(name) -> int | None

Identifies the cached frame; changes on every write, even at the same revision.

參數

name str
published_hash
函式

published_hash

published_hash(name) -> str | None

The verified content hash the cached frame was written with, if any.

參數

name str
read_dataframe_date_range
函式

read_dataframe_date_range

read_dataframe_date_range(name, start, end) -> pd.DataFrame | None

Return 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.

參數

name str
start pd.Timestamp | None
end pd.Timestamp | None
clear
函式

clear

clear() -> None

Remove all in-memory data and timestamp metadata.

release_memory
函式

release_memory

release_memory() -> None

Release cached data in RAM; with no disk copy, this clears everything.

類別

finlab.data.FileStorage

FileStorage(path, use_cache)

將歷史資料儲存於檔案中

參數

path str

資料儲存的路徑。不指定時用固定的資料夾(本機為 ~/finlab_db),不隨工作目錄改變。 自行指定時請用絕對路徑;'./finlab_db' 這類相對路徑會隨每次執行的工作目錄不同而找不到快取,整包重新下載。

use_cache bool 預設 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 | None

Return the local dataframe row count.

參數

name str
get_dataframe_index
函式

get_dataframe_index

get_dataframe_index(name) -> pd.Index | None

Return the local dataframe index.

參數

name str
set_dataframe
函式

set_dataframe

set_dataframe(name, df, revision, content_hash) -> None

Write df; a verified content_hash is embedded for published_hash.

參數

name str
df pd.DataFrame
revision datetime.datetime | None
content_hash str | None
has_feather_cache
函式

has_feather_cache

has_feather_cache(name) -> bool

Return whether name has a Feather (non-legacy) cache on disk.

參數

name str
merge_recent_delta
函式

merge_recent_delta

merge_recent_delta(name, short_df, expected_hash, revision) -> bool

Apply 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).

參數

name str
short_df pd.DataFrame
expected_hash str
revision datetime.datetime | None
merge_table_delta
函式

merge_table_delta

merge_table_delta(name, delta, expected_hash, revision) -> bool

Apply a full table's delta to the cached Feather via a streaming merge.

Like merge_recent_delta: False leaves the cache untouched.

參數

name str
delta TableDelta
expected_hash str
revision datetime.datetime | None
set_dataframe_bytes
函式

set_dataframe_bytes

set_dataframe_bytes(name, payload, revision) -> None

Persist a feather payload verbatim, skipping pandas re-encoding.

參數

name str
payload bytes
revision datetime.datetime | None
get_time_created
函式

get_time_created

get_time_created(name) -> datetime.datetime | None

The cache's revision: its file mtime, stamped by the last download.

參數

name str
get_time_expired
函式

get_time_expired

get_time_expired(name) -> datetime.datetime | None

Return the published expiry known for the cached version read, if any.

參數

name str
cache_version
函式

cache_version

cache_version(name) -> tuple[int, int, int] | None

Identifies the bytes this storage last read or wrote, even across replacements dated the same revision; else the file on disk.

參數

name str
published_hash
函式

published_hash

published_hash(name) -> str | None

The 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.

參數

name str
set_revision
函式

set_revision

set_revision(name, revision) -> None

Re-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.

參數

name str
revision datetime.datetime
read_dataframe_date_range
函式

read_dataframe_date_range

read_dataframe_date_range(name, start, end) -> pd.DataFrame | None

Read 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.

參數

name str
start pd.Timestamp | None
end pd.Timestamp | None
release_memory
函式

release_memory

release_memory() -> None

Release the in-memory DataFrame cache, keeping files and their revisions.

diagnose
函式

diagnose

diagnose(dataset) -> None

診斷本地儲存狀態

參數

dataset str

指定要檢查的資料集名稱,例如 '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 | None

Return the current user role (e.g. 'free' or 'vip').

函式

finlab.data.is_vip

is_vip() -> bool

Return 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_token str

若未帶入finlab模組的api_token,會自動跳出GUI頁面, 複製網頁內的api_token貼至輸入欄位即可。

回傳

dict

strategies data

dict[str, Any] | str

Response detail:

dict[str, Any] | str
dict[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:收盤價' 怎麼辦?

可能原因:

  1. 未登入:執行 finlab.login() 完成登入
  2. 欄位名稱錯誤:使用 data.search('收盤') 確認正確名稱
  3. 資料權限不足:確認帳戶是否能存取該資料
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() 太多資料表

下一步

↑↓ 選擇 Enter 開啟 Esc 關閉