关于 finlab
finlab 是用于量化策略研究的 Python 包和 Agent 技能,面向处理市场数据与回测的用户。它指导从数据获取、因子构建到模拟和生成 HTML 报告的流程,并提供各市场的专门参考资料。
主要功能
- 01获取多个受支持市场的数据
- 02构建因子和投资组合仓位
- 03使用 sim 回测策略
- 04生成 FinLab HTML 报告
- 05因子分析与机器学习工作流
- 06可选订单执行
适用场景
- 01查找策略所需的市场数据集
- 02构建并测试量化信号
- 03为回测生成 HTML 报告
- 04将回测结果转换为订单
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ koreal6803/ finlab-ai --skill finlab安装后在 Claude Code 中输入/finlab确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
backtesting-reference.mdbest-practices.mddataframe-reference.mdfactor-analysis-reference.mdfactor-examples.mdmachine-learning-reference.mdtrading-reference.mdus-market.md详细介绍
FinLab 量化交易包
前提条件
运行任何 FinLab 代码前,请按顺序检查以下内容:
-
已安装 uv(Python 包管理器):
uv --version如果尚未安装 uv,请告知用户安装。
安装后,确保
uv已添加到 PATH:source $HOME/.local/bin/env 2>/dev/null # Add uv to current shell -
已通过 uv 安装 FinLab(要求版本 >= 2.2.15):
uv python install 3.12 # Ensure Python is available (skip if already installed) uv pip install --system "finlab>=2.2.15" 2>/dev/null || uv pip install "finlab>=2.2.15"或者使用
uv run免配置执行(建议用于一次性脚本):uv run --with "finlab" python3 script.pyuv run --with会自动创建包含依赖项的临时环境,无需管理 venv。想要免安装? 直接在 FinLab Studio 中运行笔记本。这是一个托管的 Jupyter 环境,已预装
finlab,并且你的账户已登录。 -
已登录 FinLab(finlab >= 2.0;无需旧版 API 令牌):
桌面环境(有浏览器): 登录一次,凭据会缓存在本地:
python -m finlab loginimport finlab finlab.login() # reuses cached credentials, or starts browser login if none无头环境 / cron / Docker: 在有浏览器的计算机上登录并运行:
python -m finlab token --env在无头环境中设置导出的三个变量:
FINLAB_REFRESH_TOKEN、FINLAB_SESSION_ID和FINLAB_API_KEY。FinLab 会自动使用它们。请将输出视为凭据:使用平台的机密存储,不要将其粘贴到聊天中或提交到代码库。Google Colab: 在单元格中运行
finlab.login(),并按照登录链接操作。从旧版令牌迁移:
FINLAB_API_TOKEN和finlab.login('<api_token>')已弃用。运行python -m finlab migrate,设置浏览器登录或上述三个环境变量,然后从配置中移除旧令牌。旧版令牌状态: 官方身份验证指南尚未公开确认移除版本或日期;客户端警告文本中的
2026/08/01并非移除公告。移除客户端回退机制与在服务端拒绝旧版令牌是两项独立变更,而缓存的data.get()调用无法测试服务端身份验证——请使用上述受支持的登录流程。
语言
请使用用户所用的语言作答。 如果用户用中文书写,请用中文作答;如果用英文书写,请用英文作答。
市场支持
FinLab 支持 tw(默认)、us、kr、jp、hk、uk、us_fund(美国 ETF/基金)、rotc(台湾兴柜)和 tw_cb(台湾可转换债券)。每个会话中调用一次 data.set_market(<code>) 来选择市场;未加前缀的数据集名称会解析为当前市场对应的数据表(在 us 下,price:close → us_price:close)。如果当前市场没有某个名称,系统会静默回退到 TW 数据表:中文键(price:收盤價、monthly_revenue:當月營收)仅适用于 TW 和 rotc,因此在 us 下,data.get('price:收盤價') 会返回台湾股价。在 TW 以外的市场,请使用英文键(price:close)或带前缀的名称(us_price:adj_close)。data.set_market('rotc') (v2.0.9) 可启用興櫃(台湾兴柜)——需要上市前的价格走势或主 TSE/OTC 目录中没有的营收因子时,请使用此选项。tw_cb 不是 set_market 的有效代码(会引发 ValueError):请读取 cb_price:*,并传入 sim(position, market=TWCBMarket())(from finlab.markets.tw_cb import TWCBMarket)。
本文件其余部分以及 dataframe-reference.md、backtesting-reference.md、best-practices.md、factor-analysis-reference.md 和 machine-learning-reference.md 均与市场无关——各市场使用的 API 行为相同。
对于美国市场相关工作——无论是个股(data.set_market('us'))还是 ETF/基金(data.set_market('us_fund'))——都应**先阅读 [us-market.md](us-market.md)**。以下查询应触发阅读该文档:美国股票、S&P 500、NASDAQ 100、美股、SPY / QQQ、行业 SPDR、杠杆 / 反向 ETF、ETF 轮动、us_price:、us_fund_price:、data.us_universe(...),或 us_income_statement:/us_cash_flow:/us_balance_sheet:*`。文档说明了:
- 哪些美国数据表适合回测,哪些仅提供当前快照(分析师共识、比率、DCF 仅限实时使用——不要将其用于历史数据)
- 按
key_date对齐的季度基本面数据——无需使用.shift()变通;原始filing_date列不是发布日期 - 美国市场上的
ReportAPI 名称(creturn/daily_creturn/get_stats();没有get_equity()) - 两种市场的美国回测默认值:
USMarket(fee_ratio=0、tax_ratio=0、trade_at_price='close')以及用于 ETF/基金回测的USFundMarket - 如何通过
data.set_market(...)切换会话范围内的市场(data.get()不支持market=关键字参数) - 按美元成交额取前 N 名来构建股票池、通过
us_index_constituents:*获取时点准确的 S&P 500 / NASDAQ 100 成分股(data.us_universe(index=...)不具备时点准确性)、质量筛选条件,以及排除行业的原因 - 针对美国数据的前视偏差检查清单(滚动窗口股票池筛选、避免幸存者偏差)
- 使用
USFundMarket和us_fund_price:*进行 ETF / 行业轮动回测
其他市场相关查询可跳过该文档。
账户等级与用量
等级
| 等级 | 每日限额 |
|---|---|
| 免费 | 500 MB |
| VIP | 5000 MB |
运行 python -m finlab status 查看当前套餐和配额。
用量重置
- 每天 UTC+8 上午 8:00 重置
- 超出限额后,用户必须等待重置,或前往 finlab.finance 升级为 VIP
快速入门示例
from finlab import data
from finlab.backtest import sim
# 1. Fetch data
close = data.get("price:收盤價")
vol = data.get("price:成交股數")
pb = data.get("price_earning_ratio:股價淨值比")
# 2. Create conditions
cond1 = close.rise(10) # Rising last 10 days
cond2 = vol.average(20) > 1000*1000 # High liquidity
cond3 = pb.rank(axis=1, pct=True) < 0.3 # Low P/B ratio
# 3. Combine conditions and select stocks
position = cond1 & cond2 & cond3
position = pb[position].is_smallest(10) # Top 10 lowest P/B
# 4. Backtest
report = sim(position, resample="M", upload=False)
# 5. Print metrics - Two equivalent ways:
# Option A: Using metrics object
print(report.metrics.annual_return())
print(report.metrics.sharpe_ratio())
print(report.metrics.max_drawdown())
# Option B: Using get_stats() dictionary (different key names!)
stats = report.get_stats()
print(f"CAGR: {stats['cagr']:.2%}")
print(f"Sharpe: {stats['daily_sharpe']:.2f}")
print(f"MDD: {stats['max_drawdown']:.2%}")
# Benchmark stats (finlab >= 2.0.17): same keys via report.get_benchmark_stats()
# 6. Write the FinLab-generated HTML report (REQUIRED — do not hand-roll your own HTML)
report.to_html("report.html")
print("Open report.html to inspect equity curve, monthly returns, drawdown, and trade list.")
核心工作流:策略开发 5 步
第 1 步:获取数据
使用 data.get("<TABLE>:<COLUMN>") 获取数据:
from finlab import data
# Price data
close = data.get("price:收盤價") # TWD
volume = data.get("price:成交股數") # shares
# Financial statements
roe = data.get("fundamental_features:ROE稅後") # %
revenue = data.get("monthly_revenue:當月營收") # thousand TWD, dated when disclosed: the 2026-10-12 row is September
eps = data.get("financial_statement:每股盈餘") # TWD, that quarter alone
# Valuation
pe = data.get("price_earning_ratio:本益比")
pb = data.get("price_earning_ratio:股價淨值比")
# Institutional trading
foreign_buy = data.get("institutional_investors_trading_summary:外陸資買賣超股數(不含外資自營商)") # shares
# Market benchmark
taiex = data.get("taiex_total_index:收盤指數") # TAIEX close
# Technical indicators
rsi = data.indicator("RSI", timeperiod=14)
macd, macd_signal, macd_hist = data.indicator("MACD", fastperiod=12, slowperiod=26, signalperiod=9)
台湾地区的表格沿用交易所的单位。monthly_revenue:* 和 financial_statement:* 中的金额单位为新台币千元(千元):月营收 214,752,761 即 2,147.5 亿新台币。股价和每股数据的单位为新台币;成交量和机构投资者净买入量的单位为股。financial_statement:* 中的损益表字段(包括 EPS)仅涵盖该季度,不是年初至今的累计数据。月营收按披露日期标注,披露日期为次月 10 日前:标注为 2026-10-12 的这一行是 9 月的营收,因此应写明其涵盖的月份,而不是标注日期所在的月份。data.describe("<TABLE>:<COLUMN>") 会返回字段的目录说明。
使用 data.universe() 按市场/类别筛选:
# Limit to specific industry
with data.universe(market='TSE_OTC', category=['水泥工業']):
price = data.get('price:收盤價')
# Set globally
data.set_universe(market='TSE_OTC', category='半導體')
使用 data.search('keyword', market='<code>') 查找可用数据集;market 可以是 市场支持 中任意 set_market 代码,也可以是 'all',用于搜索所有市场。请使用数据集原生语言的关键词(例如,data.search('營收', market='tw')、data.search('revenue', market='us'))。
第 2 步:创建因子和条件
使用 FinLabDataFrame 方法创建布尔条件:
# Trend
rising = close.rise(10) # Rising vs 10 days ago
sustained_rise = rising.sustain(3) # Rising for 3 consecutive days
# Moving averages
sma60 = close.average(60)
above_sma = close > sma60
# Ranking
top_market_value = data.get('etl:market_value').is_largest(50)
low_pe = pe.rank(axis=1, pct=True) < 0.2 # Bottom 20% by P/E
# Industry ranking
industry_top = roe.industry_rank() > 0.8 # Top 20% within industry
所有 FinLabDataFrame 方法请参阅 dataframe-reference.md。
第 3 步:构建持仓 DataFrame
使用 &(AND)、|(OR)、~(NOT)组合条件:
# Simple position: hold stocks meeting all conditions
position = cond1 & cond2 & cond3
# Limit number of stocks
position = factor[condition].is_smallest(10) # Hold top 10
# Entry/exit signals with hold_until
entries = close > close.average(20)
exits = close < close.average(60)
position = entries.hold_until(exits, nstocks_limit=10, rank=-pb)
重要: 持仓 DataFrame 应包含:
- 索引:DatetimeIndex(日期)
- 列:股票代码(例如,'2330'、'1101')
- 值:布尔值(True = 持有)或数值(持仓规模)
第 4 步:回测
from finlab.backtest import sim
# Basic backtest
report = sim(position, resample="M")
# With risk management
report = sim(
position,
resample="M",
stop_loss=0.08,
take_profit=0.15,
trail_stop=0.05,
position_limit=1/3,
fee_ratio=1.425/1000/3,
tax_ratio=3/1000,
trade_at_price='open',
upload=False
)
# Extract metrics - Two ways:
# Option A: Using metrics object
print(f"Annual Return: {report.metrics.annual_return():.2%}")
print(f"Sharpe Ratio: {report.metrics.sharpe_ratio():.2f}")
print(f"Max Drawdown: {report.metrics.max_drawdown():.2%}")
# Option B: Using get_stats() dictionary (note: different key names!)
stats = report.get_stats()
print(f"CAGR: {stats['cagr']:.2%}") # 'cagr' not 'annual_return'
print(f"Sharpe: {stats['daily_sharpe']:.2f}") # 'daily_sharpe' = metrics.sharpe_ratio(), not 'monthly_sharpe'
print(f"MDD: {stats['max_drawdown']:.2%}") # same name
# Benchmark comparison (finlab >= 2.0.17): same ffn keys, computed on the
# market benchmark over the backtest period — no need to recompute from
# market.get_benchmark()
bench = report.get_benchmark_stats()
print(f"Benchmark CAGR: {bench['cagr']:.2%} | MDD: {bench['max_drawdown']:.2%}")
完整的 sim() API 请参阅 backtesting-reference.md。
第 4.5 步:交付 FinLab HTML 报告(必需)
每次回测后,都应附上一份供用户查看的 HTML 文件,即 FinLab 生成的文件:
report = sim(position, resample="M", upload=False)
report.to_html("report.html") # the FinLab-generated file is the deliverable
标准交付内容是由 report.to_html() 生成的文件——除非用户明确要求,否则不要自行制作单独的报告(自定义 HTML 页面、Plotly 摘要、仪表板、Markdown 文件)。如需总结结果,请在终端输出简短摘要,并提供 FinLab 报告。例外情况:在批量运行中(参数扫描、筛选多个变体),可跳过每次运行的 HTML 报告,仅为用户将要查看的最终策略生成报告。
如果在同一会话中运行多个策略,请选择描述性文件名(例如,momentum_top10.html、value_lowpb.html),以便用户比较结果而不会覆盖文件。写入文件后,请告知用户文件路径,以便打开。report.to_terminal() 仅可作为非图形界面终端中的补充;不能替代 HTML 报告。
有关该文件内容的详情,请参阅 backtesting-reference.md 中的“report.to_html() — 标准交付内容”章节。
第 5 步:执行订单(可选)
将回测结果转换为实盘交易:
from finlab.online.order_executor import Position, OrderExecutor
from finlab.online.sinopac_account import SinopacAccount
# 1. Convert report to position
position = Position.from_report(report, fund=1000000)
# 2. Connect broker account
acc = SinopacAccount()
# 3. Create executor and preview orders
executor = OrderExecutor(position, account=acc)
executor.create_orders(view_only=True) # Preview first
# 4. Execute orders (when ready)
executor.create_orders()
完整的经纪商设置和 OrderExecutor API 请参阅 trading-reference.md。
参考文件
| 文件 | 内容 |
|---|---|
| backtesting-reference.md | sim() 参数、止损、再平衡 |
| trading-reference.md | 券商设置、OrderExecutor、Position |
| factor-examples.md | 60+ 个策略示例 |
| dataframe-reference.md | FinLabDataFrame 方法 |
| factor-analysis-reference.md | IC、Shapley、因子分析 |
| best-practices.md | 常见错误、前视偏差 |
| machine-learning-reference.md | ML 特征工程 |
| us-market.md | 美国市场特性:数据映射、季度对齐、默认设置、股票池构建 |
新增内容(自 v1.5.8 起)
近期版本新增功能的简要说明。每个参考文件都会用 (vX.Y.Z) 标注确切的 API 版本。
v2.0.15(2026-07-18)
df.sector(by=...):sector 访问器现在接受自定义分类——dict /pd.Series(stock_id → group)或随时间变化的pd.DataFrame;未列出的股票会被排除。适用于所有sector.*方法,详见 dataframe-reference.mddf.sector.map(mapping):将组级标量值(例如板块权重)广播到完整的 DataFrame 形状,以便组合因子,详见 dataframe-reference.mddf.weight.by_group(weights, by, default):在板块/组之间分配资金——规范化持仓,使每组的总额等于其份额;未分配的部分会留在现金中,详见 dataframe-reference.md
v2.0.12(2026-06-01)
sim()/hold_until():trail_stop_activation——要求达到最低未实现收益后,才启用trail_stop。详见 backtesting-reference.md 和 dataframe-reference.mdreport.to_html(path, title=...):独立 HTML 现在会设置浏览器标签页标题和 FinLab 网站图标;传入title可区分多策略报告文件夹,详见 backtesting-reference.md- 仪表板设置模态框:将语言、浅色/深色主题和蜡烛图配色方案(默认、东红、西绿)整合到同一个面板中
v2.0.9(2026-05-27)
data.set_market("rotc"):興櫃现已成为一等市场代码;price:收盤價/monthly_revenue:*/ 等会解析到rotc_目录,且sim()使用ROTCMarket默认值data.search(market="rotc"):仅限兴柜市场目录
v2.0.1(2026-04-26)
python -m finlab cloud(CLI):将策略部署到finlab-auto-updateCloud Functions 运行时,并按 Asia/Taipei 时区每日调度——支持deploy、get、list、run、logs、schedule set/delete、delete、status。详见 trading-reference.md- 在全市场月度策略中,
sim()的峰值 RSS 降低约 800 MB(从约 2.0–2.2 GiB 降至约 1.29 GiB);因此可以使用此前会因内存不足而终止的 S 级云端工作进程
v2.0.0(2026-04-22)——重大版本
finlab.exceptions:结构化错误层级(FinlabError、DataError、BacktestError等),详见 backtesting-reference.mddata.get(lazy=True)/data.gets(..., lazy=True):批量获取并延迟计算;DataContext.override上下文管理器用于限定状态作用域df.cs/df.sector/df.weight访问器;rolling().std/var/skew/kurt/median,详见 dataframe-reference.md- 用于实时持仓流的
PositionStreamMixin,详见 trading-reference.md - 顶层导出
from finlab import FinlabDataFrame backtest.sim()重构为 5 个可测试阶段;从optimize.combinations中移除eval()
v1.5.13(2026-03-22)
universe(index=...)/us_universe(index=...):按 S&P 500 / NASDAQ 100 筛选美国股票- 新增市场代码
TW_CB(台湾可转换债券)
v1.5.11(2026-03-11)
data.get_role()/data.is_vip():查询用户配额等级- 报告迁移至规范的 Firestore 流程(对用户透明)
v1.5.9
finlab.schemas:类型化的PositionEntry、OrderEntry、PortfolioData契约OrderExecutor.generate_orders(as_entries, quantity_type)和generate_order_entries()PortfolioSyncManager.get_data_typed()/set_data_typed()data.get()在配额使用率达到 80% 时发出警告sim()使用针对不同市场的默认fee_ratio/tax_ratio(不再硬编码台湾市场的值)
v1.5.8(基准版本)
verify_strategy():自动化前视偏差检测器report.to_terminal():为非 Jupyter 运行提供 ASCII 报告- 策略整体执行速度提升 3.4 倍
金融数据对齐
绝不要使用 reindex() 或 reindex_like(),包括对最终持仓使用这些方法。FinLabDataFrame 会在算术、比较和布尔运算期间自动调整日期和股票列:sales_to_price = eps_sales / close。不要手动对齐,也不要使用 pandas/NumPy 绕过此行为。先计算季度偏移和滚动窗口,再与日频数据合并;使用 sim(position, resample=...) 设置再平衡计划。仅使用 index_str_to_date() 检查日期。遇到错误时,检查类型并查阅 dataframe-reference.md。
避免前视偏差
**至关重要:**避免使用未来数据做出过去的决策:
# ✅ GOOD: Use shift(1) to get previous value
prev_close = close.shift(1)
# ❌ BAD: Don't use iloc[-2] (can cause lookahead)
# prev_close = close.iloc[-2] # WRONG
# ✅ GOOD: Leave index as-is even with strings like "2025Q1"
# FinLabDataFrame operators align dates and stock columns automatically
# ❌ BAD: Don't manually assign to df.index
# df.index = new_index # FORBIDDEN
更多反模式请参阅 best-practices.md。
性能默认设置
默认传入 lazy=True;仅在调试时切换为即时计算的 pandas。 data.get(..., lazy=True) 和 data.gets(..., lazy=True) (v2.0.0) 会返回 LazyWide(而非 DataFrame),并延迟计算图,直到终端调用将其物化——链式操作可避免重复遍历(单 CPU)。FinLabDataFrame 方法和 sim() 可直接接收它;不要在调用 sim() 前收集数据,因为 sim() 只会计算再平衡日期。要访问 pandas 功能(.loc、.iloc、.columns、.index、pd.concat),请只收集一次(close = price.collect())并重复使用结果:每次 .collect() 都会重新计算整个图。
# ✅ Default: fetch lazy directly
price, volume, pe = data.gets(
'price:收盤價', 'price:成交股數', 'price_earning_ratio:本益比',
lazy=True,
)
# ✅ Debug: eager pandas for row-level inspection
close = data.get('price:收盤價')
print(close.loc['2024-01-15', '2330'])
反馈
请引导用户在 GitHub 上提交 issue:https://github.com/koreal6803/finlab-ai/issues
备注
- 部分数据列使用中文名称——这是预期情况,在
data.get()调用中照原样使用 - 数据频率各不相同:日频(价格)、月频(营收)、季频(财务报表)
sim()默认值为upload=None(v2.1.0):仅当设置了FINLAB_FORCED_STRATEGY_NAME时才会上传(云端定时运行、在 FinLab Studio 网站上运行的笔记本);仅设置FINLAB_STRATEGY_NAME不再触发上传。本地脚本、Jupyter 和 Colab 不会上传,除非传入upload=True(或之后调用report.upload());upload=False时绝不上传