问题描述
还有
cashflow和STK_CASHFLOW_STATEMENT
income和STK_INCOME_STATEMENT
似乎income,blance,cashflow都可以用get_fundamentals来获取
但是STK_BALANCE.SHEET等都需要用run_query来获取
为什么是这样子?
感谢大神解答,谢谢!
解决方案
这是一个非常专业且切中要害的问题!在 JoinQuant(聚宽)平台中,balance/income/cashflow 与 STK_BALANCE_SHEET/STK_INCOME_STATEMENT/STK_CASHFLOW_STATEMENT 确实都代表了上市公司的三大财务报表,但它们在数据深度、设计初衷以及调用方式上有着本质的区别。
简单来说:前者是为量化回测高度定制的标准化数据,后者是原汁原味的深度财务数据库。
以下是详细的区别解析:
1. 数据深度与字段丰富度不同
-
balance/income/cashflow(基础财务表):- 这是聚宽早期推出并一直维护的标准化财务数据。
- 它提取了三大报表中最核心、量化策略中最常用的字段(如总资产、净利润、营业收入等)。
- 特点:字段相对精简,经过了标准化处理,非常适合快速计算常见的财务因子(如 PE、PB、ROE 等)。
-
finance.STK_BALANCE_SHEET等(高级财务表):- 这是聚宽后来推出的
finance(金融数据库)模块的一部分。 - 它包含了上市公司披露的最原始、最详尽的财务报表科目。不仅包含基础字段,还包含非常细分的会计科目(如“发放贷款及垫款”、“衍生金融负债”等特定行业的细分科目)。
- 特点:数据极度丰富,甚至包含了“调整前”和“调整后”(追溯调整)的数据,适合做深度的基本面排雷和复杂的财务建模。
- 这是聚宽后来推出的
2. 为什么调用的 API 不同?
这与两个数据库在底层设计时如何处理**“未来函数(Look-ahead Bias)”**有关。
-
为什么用
get_fundamentals获取基础表?get_fundamentals是专门为量化回测设计的 API。当你传入date参数(例如date='2015-10-15')时,引擎在底层会自动帮你寻找在该日期之前(含当日)上市公司最新发布的那一份财报。- 核心优势:它自动处理了财报的“发布日(pub_date)”逻辑,完美规避了未来函数。你不需要关心这天公司发的是一季报还是年报,API 直接给你当时市场能看到的最新数据。
-
为什么用
finance.run_query获取高级表?finance模块是一个通用的关系型数据库查询接口。finance.run_query只是执行一条 SQL 查询。- 在这个库中,一条财务记录会明确区分“报告期(report_date,如 12月31日)”和“实际公告日(pub_date,如次年 4月15日)”。
- 核心区别:使用
finance.run_query时,系统不会自动帮你规避未来函数。你需要自己在query().filter()中严格限制pub_date <= context.current_dt,否则很容易取到当时尚未发布的财报数据,导致回测结果虚高。
3. 总结与使用建议
| 特性 | 基础表 (balance等) + get_fundamentals |
高级表 (STK_BALANCE_SHEET等) + finance.run_query |
|---|---|---|
| 数据丰富度 | 常用核心字段,高度标准化 | 极度详尽,包含所有细分会计科目及追溯调整数据 |
| 防未来函数 | 自动防范(通过 date 参数) |
需手动防范(需过滤 pub_date) |
| 查询速度 | 极快,适合大规模回测 | 相对较慢,适合特定深度研究 |
| 适用场景 | 90% 的常规量化策略、多因子选股 | 深度基本面分析、特定行业(如银行/保险)的特殊财务指标提取 |
建议:
如果你只是需要用到净利润、营业收入、总资产、现金流净额等常规指标来构建多因子策略,强烈建议使用 get_fundamentals + balance/income/cashflow,因为代码更简洁,且绝对安全(无未来函数)。
只有当你发现基础表中找不到你需要的某个冷门财务科目时,再去使用 finance.run_query 查询 STK_... 系列表,并务必记得在 filter 中加上对 pub_date 的时间限制!