finlab.data: data.get Data Download API
finlab.data is the core module for downloading FinLab datasets. The usual workflow is to find dataset keys with data.search(), download them with data.get(), then control market scope with data.universe() or data.set_market().
| Task | API | Common usage |
|---|---|---|
| Download prices, fundamentals, revenue, and trading data | data.get() |
data.get('price:收盤價') |
| Find table and field names | data.search() |
data.search('ROE') |
| Restrict listed, OTC, sector, or US universes | data.universe() / data.us_universe() |
with data.universe(market='TSE'): |
| Control download size and memory usage | truncate_start, cache settings |
data.truncate_start = '2020-01-01' |
First-time users should read Data Download. To turn downloaded data into stock-selection conditions, continue with finlab.dataframe.
Use Cases
- Download historical data such as stock prices, financial statements, and institutional trading
- Filter data by market or industry sector
- Search for available data tables and fields
- Configure data caching strategies
- Limit data download range to save memory
Quick Examples
Basic Usage: Download Data
from finlab import data
# Download closing prices
close = data.get('price:收盤價')
# Download P/E ratio
pe_ratio = data.get('price_earning_ratio:本益比')
# Download monthly revenue
revenue = data.get('monthly_revenue:當月營收')
English aliases for Taiwan OHLCV
Under the default Taiwan market or data.set_market("tw"), these English keys return the same data and share the cache with the existing Chinese keys. The aliases also work with data.gets(), lazy=True, and start/end date filters. volume means shares traded.
| English key | Existing Taiwan key |
|---|---|
price:open |
price:開盤價 |
price:high |
price:最高價 |
price:low |
price:最低價 |
price:close |
price:收盤價 |
price:volume |
price:成交股數 |
data.set_market("tw")
tw_close = data.get("price:close")
data.set_market("us")
us_close = data.get("price:close")
After switching to the US market, price:close still returns US closing prices. Use the existing keys for fields outside these five aliases.
Search Available Fields
# Search for fields containing "收盤" (close)
data.search('收盤')
# Output: ['price:收盤價', 'etl:不含除權息收盤價', ...]
# Search US stock data
data.search('close', market='us')
# Search US ETF/fund data
data.search('close', market='us_fund')
Restrict Market Scope
# Only fetch listed (TSE) company data
with data.universe(market='TSE'):
close = data.get('price:收盤價')
# Only fetch specific industry sectors
with data.universe(category=['水泥工業', '食品工業']):
close = data.get('price:收盤價')
# Switch to US ETF/fund data
data.set_market('us_fund')
fund_close = data.get('price:adj_close')
Remove a universe filter
Use data.reset_universe() to disable the filter. data.set_universe(),
data.universe(), and data.us_universe() without any filter do the same and
drop no identifiers:
data.set_universe(sector='半導體業')
filtered = data.get('price:收盤價')
data.reset_universe()
unfiltered = data.get('price:收盤價')
The reset applies to subsequent data.get() and data.gets() calls, including
cached reads. It preserves cached datasets, the active market, date limits, and
already returned DataFrames. Inside data.universe() or data.us_universe(), a
reset lasts until another selection or context exit; exiting still restores the
selection from before that context. Repeated resets are safe.
Detailed Guide
See Data Download Details for: - Complete data download tutorial - Data table structure explanation - Advanced filtering techniques - Error handling methods
Global Configuration
Force Cloud/Local Data
from finlab import data
# Force cloud download (re-download every time)
data.force_cloud_download = True
# Force local cache only (offline environment)
data.use_local_data_only = True
Limit Data Time Range
# Only download data from 2020-2023 (saves memory)
data.truncate_start = '2020-01-01'
data.truncate_end = '2023-12-31'
# All subsequent data.get() calls will use this range
close = data.get('price:收盤價')
Recommended Usage
- Development phase: Use
truncate_startto limit data range for faster testing - Production backtesting: Remove truncate limits, use full historical data
- Low memory: Set
truncate_startor useuse_local_data_only
API Reference
data.get()
finlab.data.get
Shared fetch pipeline plus data.get() single-dataset wrapper.
DownloadedFrame
module-attribute
(df, raw_feather_bytes) — bytes is None when payload was inlined.
get
get(
dataset,
save_to_storage=True,
force_download=False,
lazy=False,
progress='silent',
progress_callback=None,
*,
start=None,
end=None,
as_of=None,
version=None,
)
Download historical data.
See https://ai.finlab.tw/database for the full data catalogue.
| PARAMETER | DESCRIPTION |
|---|---|
dataset
|
The name of dataset.
TYPE:
|
save_to_storage
|
Whether to cache intraday data or retained versions
(
TYPE:
|
force_download
|
Whether to force download the dataset from cloud.
TYPE:
|
lazy
|
Return a lazy computation wrapper after fetching the dataset.
TYPE:
|
progress
|
TYPE:
|
progress_callback
|
Receives structured events in event mode.
TYPE:
|
start
|
Optional inclusive lower bound on the
TYPE:
|
end
|
Optional inclusive upper bound on the
TYPE:
|
as_of
|
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
TYPE:
|
version
|
Return exactly this generation from
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
DataFrame
|
financial data as a DataFrame. |
is_tradable
Whether loaded data completed its final scheduled refresh before next open.
Daily TW data is judged by publication evidence, not expiry; use data.readiness() for the reason. Markets without publication evidence and runs without a trading calendar fall back to the published expiry.
next_future_expiry
Next future expiry time among cached datasets (UTC).
Returns only expiry times in the future, skipping already expired data.
| RETURNS | DESCRIPTION |
|---|---|
datetime | None
|
datetime in UTC representing the next future expiry, or None if |
datetime | None
|
no future expiries exist or no data is available. |
Common Data Tables
Price Data:
- price:收盤價 - Daily closing price
- price:開盤價 - Daily opening price
- price:最高價 / price:最低價 - Daily high/low
- price:成交股數 - Trading volume
Fundamental Data:
- price_earning_ratio:本益比 - P/E ratio
- price_earning_ratio:股價淨值比 - P/B ratio
- fundamental_features:股東權益報酬率 - ROE
- financial_statement:每股盈餘 - EPS
Institutional Trading Data:
- institutional_investors_trading_summary:投信買賣超股數
- margin_transactions:融資使用率
- etl:外資持股比例
Monthly Revenue:
- monthly_revenue:當月營收
- monthly_revenue:去年同月增減(%)
See the full list at the Database Catalog.
Common Errors
- KeyError: Data table name is wrong or API token is not set
- Empty DataFrame: Query conditions too strict or data does not exist
- Out of memory: Too much data downloaded, use
truncate_startto limit range
data.search()
finlab.data.search
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) and free_until (inclusive cutoff, or None).
Missing catalog permissions remain unknown; search does not grant access.
Examples:
# Search for fields containing "股東" (shareholder)
data.search('股東')
# ['fundamental_features:股東權益報酬率', 'internal_equity_pledge:百分之十以上大股東持有股數', ...]
# Search with everyday terms: dataset names, descriptions, aliases
# and table columns are matched as well as keys
data.search('市值') # market value -> ['etl:market_value', ...]
data.search('集保') # TDCC holdings -> ['inventory', 'etl:inventory:零股股數', ...]
# Matching ignores full/half-width forms, 占/佔, (%) and 今日/當日
data.search('融資餘額') # ['margin_transactions:融資今日餘額']
# Search for US stock PE ratio
data.search('pe', market='us')
# List all Taiwan stock fields
all_fields = data.search()
print(f"Total {len(all_fields)} fields")
Hints for mistyped keys
When data.get() cannot find a dataset it raises finlab.exceptions.DatasetNotFoundError (a RuntimeError subclass) listing the closest valid keys. If the key is a registered equivalent legacy name, it emits a UserWarning and fetches the correct key instead.
Download failures
When data.get() fails to download data it raises finlab.exceptions.SignedDownloadError (a DataError subclass). The message names the dataset, the HTTP status or kind of connection problem, and what to do; it never contains the download URL. To branch on the cause, read e.kind ("http", "timeout", "connection", "ssl", "redirects", "browser", "invalid_reply", "other") and e.status (the HTTP status, None when no response arrived) instead of matching the message. For compatibility it also keeps the requests type raised before (such as requests.HTTPError or requests.Timeout) and is a requests.RequestException and OSError; new code should use except DataError.
data.describe()
finlab.data.describe
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.
data.describe('price:收盤價')
data.describe('monthly_revenue') # Category columns and description
data.describe('monthly_revenue:key_date')
data.describe('us_price:close', market='us')
This query shares the search catalog cache and downloads no dataset. layout describes the published dataset; source_layout is the upstream storage format only when explicitly documented. Missing metadata returns None. The update schedule does not establish observation frequency. index_end is the last index label and may be a future period date; source_created_time is the artifact creation time. Neither establishes row availability or latest_data_date.
columns lists fields published in the catalog. An unlisted key_date returns catalogued=False, key_date_available=None, and category_description. This does not establish whether it can be downloaded or whether its values are announcement dates. Other unknown names raise KeyError; an unavailable or empty catalog raises RuntimeError.
data.universe()
finlab.data.universe
universe
universe(
exchange='ALL',
sector='ALL',
exclude_sector=None,
industry='ALL',
asset_type=None,
security_type='ALL',
index=None,
*,
whitelist=None,
market=None,
category=None,
exclude_category=None,
)
Context manager to set a global stock universe filter for data retrieval.
Auto-dispatches TW vs international logic based on the active data context.
Parameters
exchange : str | list[str], default 'ALL'
TW: 'TWSE'/'TPEx' (or legacy 'TSE'/'OTC').
International: 'NASDAQ'/'NYSE'/'AMEX'/'HKEX'/'TSE'/etc.
sector : str | list[str], default 'ALL'
Sector name(s) with regex matching.
exclude_sector : str | list[str] | None, default None
Sector(s) to exclude (TW only).
industry : str | list[str], default 'ALL'
Industry filter (international markets).
asset_type : str | None, default None
TW only: 'ETF' or 'STOCK_FUTURE'.
security_type : str | list[str], default 'ALL'
Security type filter (international markets), e.g. 'common_stock'.
index : str | None, default 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, default 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.
Examples
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:收盤價')
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')
us_universe
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.
Parameters
sector : str | list[str], default 'ALL' Sector name(s) to include. Supports regex-like substring matching. industry : str | list[str], default 'ALL' Industry name(s) to include. Supports regex-like substring matching. exchange : str | list[str], default 'ALL' Exchange name(s) to include. Common values: 'NASDAQ', 'NYSE', 'AMEX'. security_type : str | list[str], default 'ALL' Security type(s) to include. Use 'common_stock' for clean US equities. index : str | None, default 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.
Notes
index uses the latest row of the constituent table to select columns
for the entire price history. Backtesting these columns introduces
survivorship and look-ahead bias; later index changes can also change
results for earlier dates.
For historical selection, read unfiltered prices and apply the dated constituent records to scores before ranking, as shown below. Dates before the first record and price symbols absent from the table are False. The example matches symbols exactly: spelling differences, renamed stocks and missing price history can exclude constituents. Source delays or later corrections remain in the records; this is not an immutable snapshot of what was known at the time. Use each date's mask after that day's close.
Examples
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.
membership
Return daily TW listing eligibility for explicit pre-ranking masking.
Supports TSE, OTC, and TSE_OTC. Dates/columns follow the unfiltered Taiwan close-price table (subject to the active data date window). Listing dates are inclusive and termination dates exclusive. Suspensions and zero-volume days do not terminate membership. Unknown periods are False and reported by warning/attrs. This is effective-date eligibility reconstructed from current records, not a historical data vintage or an as-known-at-the-time guarantee. Source corrections may change historical eligibility.
Existing universe context/filter state is neither applied nor changed. Obtain scores without a snapshot universe that already removed securities. Apply the mask before each cross-sectional ranking. No version argument or automatic changes to ranking methods are introduced.
Examples
from finlab import data from finlab.data import universe close = data.get('price:收盤價') eligible = universe.membership('TSE_OTC') position = close.pct_change(20)[eligible].is_largest(20)
reset_universe
Disable the global stock universe filter for subsequent data reads.
Securities absent from the market catalog are included again. set_universe()
without filters does the same. Cached data, the active market and date limits
are preserved. Existing DataFrames are not modified.
Inside universe or us_universe, this disables filtering until the
next selection or context exit. Exiting restores the selection that was
active before entering that context.
set_universe
set_universe(
exchange='ALL',
sector='ALL',
exclude_sector=None,
industry='ALL',
asset_type=None,
security_type='ALL',
index=None,
*,
whitelist=None,
market=None,
category=None,
exclude_category=None,
)
Set global stock universe filter. Auto-dispatches based on current market.
When data.set_market('tw') (or no market set), uses TW logic
(security_categories). For any other market (us, hk, jp, kr, uk),
loads {market}_company_profile and filters by available columns.
Calling without any filter is the same as :func:reset_universe: the
filter is removed and no security is dropped.
Parameters
exchange : str | list[str], default 'ALL'
TW: 'TWSE', 'TPEx' (or legacy 'TSE', 'OTC').
International: 'NASDAQ', 'NYSE', 'AMEX', 'HKEX', 'TSE', etc.
sector : str | list[str], default 'ALL'
Sector name(s) with regex matching.
exclude_sector : str | list[str] | None, default None
Sector(s) to exclude (TW only).
industry : str | list[str], default 'ALL'
Industry filter (international markets).
asset_type : str | None, default None
TW only: 'ETF' or 'STOCK_FUTURE'.
security_type : str | list[str], default 'ALL'
Security type filter (international markets), e.g. 'common_stock'.
index : str | None, default 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, default 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 (e.g. 'TSE_OTC', 'ETF').
category : str | list[str] | None
Legacy alias for sector.
exclude_category : str | list[str] | None
Legacy alias for exclude_sector.
set_us_universe
Set global US stock universe filter.
Thin wrapper around _set_intl_universe_impl for backward compatibility.
Parameters
sector : str | list[str], default 'ALL'
Sector filter with regex-like substring matching.
industry : str | list[str], default 'ALL'
Industry filter with regex-like substring matching.
exchange : str | list[str], default 'ALL'
Exchange filter (e.g., 'NASDAQ', 'NYSE', 'AMEX').
security_type : str | list[str], default 'ALL'
Security type filter. Use 'common_stock' for clean US equities.
index : str | None, default None
Market index to filter by. Supported values:
'SP500'/'SPX' (S&P 500), 'NASDAQ100'/'NDX' (NASDAQ 100).
Uses the latest constituent list for every historical date. For
historical index selection, see the us_universe backtest example.
Examples:
# Example 1: Only listed companies
with data.universe(market='TSE'):
close = data.get('price:收盤價')
print(f"Number of listed companies: {len(close.columns)}")
# Example 2: Specific industry sectors
with data.universe(category=['半導體業']):
close = data.get('price:收盤價')
# Example 3: Top 100 by market cap
with data.universe(size=100):
close = data.get('price:收盤價')
# Example 4: Combined conditions
with data.universe(market='TSE_OTC', category=['電子工業'], size=50):
close = data.get('price:收盤價')
Available market parameter values:
- 'TSE' - Listed (Taiwan Stock Exchange)
- 'OTC' - OTC (Taipei Exchange)
- 'TSE_OTC' - Listed + OTC
- 'ALL' - All (including Emerging Stock Board)
data.us_universe()
finlab.data.us_universe
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.
Parameters
sector : str | list[str], default 'ALL' Sector name(s) to include. Supports regex-like substring matching. industry : str | list[str], default 'ALL' Industry name(s) to include. Supports regex-like substring matching. exchange : str | list[str], default 'ALL' Exchange name(s) to include. Common values: 'NASDAQ', 'NYSE', 'AMEX'. security_type : str | list[str], default 'ALL' Security type(s) to include. Use 'common_stock' for clean US equities. index : str | None, default 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.
Notes
index uses the latest row of the constituent table to select columns
for the entire price history. Backtesting these columns introduces
survivorship and look-ahead bias; later index changes can also change
results for earlier dates.
For historical selection, read unfiltered prices and apply the dated constituent records to scores before ranking, as shown below. Dates before the first record and price symbols absent from the table are False. The example matches symbols exactly: spelling differences, renamed stocks and missing price history can exclude constituents. Source delays or later corrections remain in the records; this is not an immutable snapshot of what was known at the time. Use each date's mask after that day's close.
Examples
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.
US Market Filtering:
data.set_market('us')
# Get the full price history of the latest S&P 500 constituents
with data.us_universe(index='SP500'):
close = data.get('price:close')
# Get Technology stocks among the latest NASDAQ 100 constituents
with data.us_universe(index='NDX', sector='Technology'):
close = data.get('price:close')
# Get a clean US common-stock universe
with data.us_universe(security_type='common_stock'):
close = data.get('price:close')
# Can also use data.universe() with set_market
with data.universe(index='SP500', exchange='NASDAQ'):
close = data.get('price:close')
Supported index parameter values:
| Index | Accepted aliases |
|---|---|
| S&P 500 | 'SP500', 'SPX', 'S&P500', 'S&P 500' |
| NASDAQ 100 | 'NASDAQ100', 'NDX', 'NASDAQ 100' |
index can be combined with sector, industry, exchange, and security_type — the result is the intersection of all filters.
Historical index backtests
index='SP500' or 'NDX' selects columns for the entire history using the last row of the constituent table. Backtesting these columns introduces survivorship and look-ahead bias: later additions appear before they joined, while removed stocks disappear from the entire history. Index changes can therefore change earlier results when the same strategy is rerun. The index parameter of data.universe(), data.set_universe() and data.set_us_universe() works the same way.
For historical selection, read unfiltered US prices, apply the constituent record dated on or before each price date to scores, then rank stocks:
from finlab import data
with data.us_universe(): # Temporarily clear the existing universe; restore it on exit.
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, use us_index_constituents:nasdaq100. Dates before the first record and price symbols absent from the table are False; use each date's mask after that day's close. This example matches symbols exactly, so spelling differences, renamed stocks or missing price history can still exclude constituents. The mask is rebuilt from the records currently stored: source delays, gaps and later corrections still affect results. It is not a complete snapshot of what was known at the time.
data.indicator()
finlab.data.indicator
Technical indicator computation: data.indicator().
get_strategies
取得已上傳量化平台的策略回傳資料。
可取得自己策略儀表板上的數據,例如每個策略的報酬率曲線、報酬率統計、夏普率、近期部位、近期換股日..., 這些數據可以用來進行多策略彙整的應用喔!
| PARAMETER | DESCRIPTION |
|---|---|
api_token
|
若未帶入finlab模組的api_token,會自動跳出GUI頁面, 複製網頁內的api_token貼至輸入欄位即可。
TYPE:
|
Returns: (dict): strategies data Response detail:
``` py
{
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:{...},
...}
```
indicator
支援 Talib 和 pandas_ta 上百種技術指標,計算 2000 檔股票、10年的所有資訊。
在使用這個函式前,需要安裝計算技術指標的 Packages
| PARAMETER | DESCRIPTION |
|---|---|
indname
|
指標名稱, 以 TA-Lib 舉例,例如 SMA, STOCH, RSI 等,可以參考 talib 文件。 以 Pandas-ta 舉例,例如 supertrend, ssf 等,可以參考 Pandas-ta 文件。
TYPE:
|
adjust_price
|
是否使用還原股價計算。
TYPE:
|
resample
|
技術指標價格週期,ex:
TYPE:
|
market
|
市場選擇,ex:
TYPE:
|
strict
|
預設 False。True 時只接受 TA-Lib 的數值參數名稱,
拒絕輸入價格 selector;pandas_ta 尚不支援,會拋出 NotImplementedError。
例如
TYPE:
|
**kwargs
|
技術指標的參數設定,TA-Lib 中的 RSI 為例,調整項為計算週期
TYPE:
|
建議使用者可以先參考以下範例,並且搭配 talib官方文件,就可以掌握製作技術指標的方法了。
Technical Indicator Examples:
from finlab import data
# Get MACD indicator
macd = data.indicator('macd', data.get('price:收盤價'))
# Get RSI indicator
rsi = data.indicator('rsi', data.get('price:收盤價'), period=14)
Cache Management
finlab.data.set_storage
設定本地端儲存歷史資料的方式
假設使用 data.get 獲取歷史資料則,在預設情況下,程式會自動在本地複製一份,以避免重複下載大量數據。
storage 就是用來儲存歷史資料的接口。我們提供兩種 storage 接口,分別是 finlab.data.CacheStorage (預設) 以及
finlab.data.FileStorage。前者是直接存在記憶體中,後者是存在檔案中。詳情請參考 CacheStorage 和 FileStorage 來獲得更詳細的資訊。
在預設情況下,程式會自動使用 finlab.data.FileStorage 並將重複索取之歷史資料存在作業系統預設「暫時資料夾」。
| PARAMETER | DESCRIPTION |
|---|---|
storage
|
The interface of storage
TYPE:
|
Examples:
欲切換成以檔案方式儲存,可以用以下之方式:
可以在本地端的 ./finlab_db/price#收盤價.pickle 中,看到下載的資料,
可以使用 pickle 調閱歷史資料:
finlab.data.CacheStorage
將歷史資料儲存於快取中
Examples:
欲切換成以檔案方式儲存,可以用以下之方式:
可以直接調閱快取資料:
cache_version
Identifies the cached frame; changes on every write, even at the same revision.
get_time_expired
Return the published expiry known for the cached version read, if any.
read_dataframe_date_range
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
:class:FileStorage.
release_memory
Release cached data in RAM; with no disk copy, this clears everything.
finlab.data.FileStorage
將歷史資料儲存於檔案中
| PARAMETER | DESCRIPTION |
|---|---|
path
|
資料儲存的路徑
TYPE:
|
use_cache
|
是否額外使用快取,將資料複製一份到記憶體中。
TYPE:
|
Examples:
欲切換成以檔案方式儲存,可以用以下之方式:
可以在本地端的 ./finlab_db/price#收盤價.feather 中,看到下載的資料,
可以使用 pandas.read_feather 調閱歷史資料:
cache_version
Identifies the bytes this storage last read or wrote, even across replacements dated the same revision; else the file on disk.
diagnose
get_time_created
The cache's revision: its file mtime, stamped by the last download.
get_time_expired
Return the published expiry known for the cached version read, if any.
has_feather_cache
Return whether name has a Feather (non-legacy) cache on disk.
merge_recent_delta
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).
merge_table_delta
Apply a full table's delta to the cached Feather via a streaming merge.
Like :meth:merge_recent_delta: False leaves the cache untouched.
read_dataframe_date_range
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.
release_memory
Release the in-memory DataFrame cache, keeping files and their revisions.
set_dataframe_bytes
Persist a feather payload verbatim, skipping pandas re-encoding.
Custom Cache Strategy:
from finlab.data import set_storage, FileStorage
# Use a custom directory
storage = FileStorage('/path/to/custom/cache')
set_storage(storage)
# All subsequent data will be cached to the specified location
close = data.get('price:收盤價')
User Role
Example:
from finlab import data
# Query user role (requires at least one data.get() call first)
close = data.get('price:收盤價')
role = data.get_role() # 'free', 'vip', ...
print(f"Current role: {role}")
if data.is_vip():
print("VIP member — full data access enabled")
Other Utilities
finlab.data.get_strategies
取得已上傳量化平台的策略回傳資料。
可取得自己策略儀表板上的數據,例如每個策略的報酬率曲線、報酬率統計、夏普率、近期部位、近期換股日..., 這些數據可以用來進行多策略彙整的應用喔!
| PARAMETER | DESCRIPTION |
|---|---|
api_token
|
若未帶入finlab模組的api_token,會自動跳出GUI頁面, 複製網頁內的api_token貼至輸入欄位即可。
TYPE:
|
Returns: (dict): strategies data Response detail:
``` py
{
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:{...},
...}
```
FAQ
Q: How do I find out what data is available for download?
Method 1: Use search()
Method 2: Check the online database Visit the FinLab Database Catalog to browse the full list.
Q: Data download is slow, what can I do?
# Method 1: Limit time range
data.truncate_start = '2020-01-01'
# Method 2: Use cache (second call will be fast)
close = data.get('price:收盤價') # First call is slow
close = data.get('price:收盤價') # Second call is fast (uses cache)
# Method 3: Use universe to limit stock count
with data.universe(size=100):
close = data.get('price:收盤價') # Only downloads 100 stocks
Q: KeyError: 'price:收盤價' - what should I do?
Possible causes:
1. Not logged in - Run finlab.login() and complete login
2. Incorrect field name - Use data.search('收盤') to verify the correct name
3. Insufficient data permission - Check whether the account can access this dataset
import finlab
# Check if logged in
try:
token, token_type = finlab.get_token()
print(f"Logged in ({token_type})")
except:
print("Not logged in, please run finlab.login()")
Q: How do I download US stock data?
from finlab import data
# US stock closing prices
us_close = data.get('price:close', market='us')
# Search US stock fields
us_fields = data.search(market='us')
Q: What about missing values in the data?
close = data.get('price:收盤價')
# Check missing values
print(f"Missing value ratio: {close.isna().sum().sum() / close.size:.2%}")
# Fill missing values
close_filled = close.fillna(method='ffill') # Forward fill
# Or drop stocks with too many missing values
close_clean = close.dropna(
axis=1, thresh=len(close) * 0.8
) # Keep stocks with 80%+ data
Q: How can I save memory?
# Method 1: Limit time range
data.truncate_start = '2020-01-01'
# Method 2: Process in batches
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]
# Process 100 stocks at a time...
# Method 3: Only download the fields you need
# Avoid calling data.get() for too many tables at once
Resources
- Data Download Detailed Tutorial - Complete usage guide
- FinLab Database Catalog - All available data tables
- Quick Start Guide - Getting started
- FAQ - More troubleshooting
Historical Taiwan listing eligibility
universe.membership() returns a boolean FinlabDataFrame on the Taiwan close-price dates and columns. It supports TSE, OTC, and TSE_OTC without changing existing universe contexts or ranking methods.
from finlab import data
from finlab.data import universe
# Fetch scores without an existing snapshot universe removing securities.
close = data.get("price:收盤價")
score = close.pct_change(20)
eligible = universe.membership("TSE_OTC")
position = score[eligible].is_largest(20)
Apply eligibility before every cross-sectional ranking. The mask cannot restore securities previously removed from score data. Membership reads bypass the snapshot universe without changing it, respect the active date window, and accept force_download=True.
Intervals use current company records, historical delisted-company records, and exchange termination lists. Listing dates are inclusive; termination dates are exclusive. Multiple listing periods and exchange transfers are supported. Suspensions and missing trades do not terminate listing eligibility; apply trading conditions separately. Indicator warm-up data is not erased.
Unverified historical periods remain False with a warning. Inspect eligible.attrs["membership_missing_history"] for incomplete company histories. Securities without company listing records, such as ETFs, are not included merely because they have price columns; this is not a complete ETF universe.
This reconstructs effective-date eligibility from currently available records. It does not provide universe versions or as-known-at-the-time snapshots. Historical corrections can still change results, so it cannot guarantee reproduction of old backtests.
Taiwan trading calendar, rebalance windows, and data readiness