mcpField
F
finlab

finlab

github.com/koreal6803数据与数据库4201.9k 次安装2 天前更新
代码仓库

关于 finlab

finlab 是用于量化策略研究的 Python 包和 Agent 技能,面向处理市场数据与回测的用户。它指导从数据获取、因子构建到模拟和生成 HTML 报告的流程,并提供各市场的专门参考资料。

主要功能

  1. 01获取多个受支持市场的数据
  2. 02构建因子和投资组合仓位
  3. 03使用 sim 回测策略
  4. 04生成 FinLab HTML 报告
  5. 05因子分析与机器学习工作流
  6. 06可选订单执行

适用场景

  1. 01查找策略所需的市场数据集
  2. 02构建并测试量化信号
  3. 03为回测生成 HTML 报告
  4. 04将回测结果转换为订单

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/koreal6803/finlab-ai --skill finlab

安装后在 Claude Code 中输入/finlab确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

backtesting-reference.md
best-practices.md
dataframe-reference.md
factor-analysis-reference.md
factor-examples.md
machine-learning-reference.md
trading-reference.md
us-market.md

详细介绍

FinLab 量化交易包

前提条件

运行任何 FinLab 代码前,请按顺序检查以下内容:

  1. 已安装 uv(Python 包管理器):

    uv --version
    

    如果尚未安装 uv,请告知用户安装。

    安装后,确保 uv 已添加到 PATH:

    source $HOME/.local/bin/env 2>/dev/null  # Add uv to current shell
    
  2. 已通过 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.py
    

    uv run --with 会自动创建包含依赖项的临时环境,无需管理 venv。

    想要免安装? 直接在 FinLab Studio 中运行笔记本。这是一个托管的 Jupyter 环境,已预装 finlab,并且你的账户已登录。

  3. 已登录 FinLab(finlab >= 2.0;无需旧版 API 令牌):

    桌面环境(有浏览器): 登录一次,凭据会缓存在本地:

    python -m finlab login
    
    import 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 列不是发布日期
  • 美国市场上的 Report API 名称(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
VIP5000 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.mdsim() 参数、止损、再平衡
trading-reference.md券商设置、OrderExecutor、Position
factor-examples.md60+ 个策略示例
dataframe-reference.mdFinLabDataFrame 方法
factor-analysis-reference.mdIC、Shapley、因子分析
best-practices.md常见错误、前视偏差
machine-learning-reference.mdML 特征工程
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.md
  • df.sector.map(mapping):将组级标量值(例如板块权重)广播到完整的 DataFrame 形状,以便组合因子,详见 dataframe-reference.md
  • df.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.md
  • report.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-update Cloud 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.md
  • data.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 时绝不上传

评论

支持 Markdown