ZVT 项目研究站 · 财务数据

ZVT 财务数据:四个对象、两套时间字段,怎么取怎么读

ZVT 的财务面由四个 schema 承载:财务指标 FinanceFactor、资产负债表 BalanceSheet、利润表 IncomeStatement、现金流量表 CashFlowStatement。它们的取数方式与行情完全一样(record_data / query_data),真正的难点在时间字段:同一张表里同时有 report_periodreport_date,用错哪一个,回测就会出现未来函数。

对象:4 个 schema关键指标:important_cols 共 9 列依据源码 finance.py(2026-09-18)

四个财务对象与两套时间字段

FinanceFactorROE / 增速 / 毛利率…
BalanceSheet资产负债表
IncomeStatement利润表
CashFlowStatement现金流量表
四个类名逐字取自 src/zvt/domain/fundamental/finance.py(非官方架构图);report_period 为 String 列、report_date 为 DateTime 列。
Four objects

ZVT 的四个财务对象:各自装什么、怎么用

下表按 ZVT 源码里的类定义整理。四个类的用法完全一致,差别只在字段覆盖面。

对象内容典型用法适用场景注意点
FinanceFactor财务指标:每股收益、营业总收入、净利润、营收/净利同比增速、ROE、ROTA、毛利率、净利率等FinanceFactor.record_data(code='000338')query_data(columns=FinanceFactor.important_cols())做基本面筛选与财务因子表名 finance_factorimportant_cols() 返回 9 列,日常分析先取这 9 列
BalanceSheet资产负债表与指标表同样的 record_data / query_data看资产负债结构、杠杆字段多、口径细,建议按 important_cols() 收窄再分析
IncomeStatement利润表同上看收入与利润构成与指标表的数值可能来自不同 provider,注意混用
CashFlowStatement现金流量表同上看经营/投资/筹资现金流季度与年度记录的可得时间不同
写法提醒:财务数据的取数与行情共用同一套接口——Schema.record_data(provider=..., code(s)=...) 写库、Schema.query_data(filters=..., order=..., limit=..., columns=..., index=...) 查询。也就是说你在「取数与查询」页学到的参数在这里原样适用。
Fields

ZVT 财务字段怎么选:先 important_cols(),再去看全字段

ZVT 的财务表字段很多,官方为每个财务 schema 都提供了 important_cols(),这是最省事的入口。

  1. 先取关键列

    FinanceFactor.record_data(code='000338')
    df = FinanceFactor.query_data(code='000338',
                                  columns=FinanceFactor.important_cols(),
                                  index='timestamp')

    说明:README 的市场级选股示例就是这么写的。预期输出:以时间为索引、9 列指标的表格。

  2. important_cols() 到底是哪 9 列

    按源码 FinanceFactor.important_cols() 的定义,依次是:basic_eps(每股收益)、total_op_income(营业总收入)、net_profit(净利润)、op_income_growth_yoy(营收同比)、net_profit_growth_yoy(净利同比)、roerotagross_profit_margin(毛利率)、net_margin(净利率)。

  3. 要看全字段就 help()

    在交互式环境里对 schema 调 FinanceFactor.help() 可以列出全部列;也可以直接读源码 src/zvt/domain/fundamental/finance.py(约 991 行,四个类都在这个文件里)。

  4. 横截面选股怎么写

    df = FinanceFactor.query_data(
        filters=[FinanceFactor.roe > 0.08,
                 FinanceFactor.report_period == 'year',
                 FinanceFactor.op_income_growth_yoy > 0.08],
        start_timestamp='2019-01-01',
        order=FinanceFactor.roe.desc(), limit=20,
        columns=['code'] + FinanceFactor.important_cols(), index='code')

    说明:这段是 README 的「市场级选股」示例——ROE>8% 且营收增速>8% 的年度报告,按 ROE 倒序取前 20。预期输出:20 行候选。注意示例结果里出现了 ROE 数值明显异常的行,做排序前建议先做极值检查。

Two time fields

report_period 与 report_date:两套时间字段别混用

这是财务数据最容易出错的地方。源码里这两个字段是并存的,含义不同。

字段源码里的类型怎么理解用它做什么用错的后果
report_periodColumn(String(32))报告期类别,README 示例里按 'year' 过滤筛选「只要年报」「只要季报」它不是日期。拿它当时间轴排序会得到毫无意义的顺序
report_dateColumn(DateTime)该条记录对应的报告日期字段按时间对齐财务数据与行情若实际是「报告期末」而非「公告日」,会提前使用尚未公布的数据
timestampZVT 通用时间列查询输出里作为索引出现的时间与其它表做时间对齐时用与 report_date 的关系未在官方文档说明,必须自己核验
provider / codeColumn(String(32))数据来源与标的代码区分同一张表里来自不同源、不同标的的记录多源混写时不拆开,会出现同一天多条冲突记录
官方没有回答的问题(而这正是关键):财务表的 report_date / timestamp 究竟等于「报告期末」还是「公告日」,README 全文没有说明,不同 provider 也可能不同。正确做法是自己做一次对照:挑一家你熟悉的公司,把它的年报公告日与库里的 report_date 并排打印出来——对得上就能当公告日用,对不上就必须按公告日重排。这一步做完,才谈得上「没有未来函数」。
Boundary

财务数据能拿到什么、拿不到什么

把 ZVT 财务数据的边界写清楚,比多列几个字段更有用。

你想要ZVT 的现状依据替代做法注意点
三大报表 + 常用财务指标四个 schema 都在,且都提供 important_cols()domain/fundamental/finance.py(约 991 行)直接用字段口径以选定 provider 为准
报告中「本期/上期」等明细行未在 README 中体现README 只演示了指标与三张表的取数看源码字段或换 provider 试不要按财务软件的表样预期它的字段
公告原文、PDF不提供ZVT 面向结构化数据另找公告数据源——
实时/盘中财务数据不存在这种数据财报本身是定期披露——任何声称「实时财报」的说法都要警惕
自动处理财务数据的可获得性框架不做这件事没有看到自动按公告日重排的说明自己按 report_date / 公告日做 as-of 对齐这是回测能否可信的分水岭,见「点时数据」页
一句话结论:ZVT 把财务数据取下来这件事做得不错;至于「什么时候才能用这条数据」,需要你自己在查询层加上时间条件——ZVT 不会拦你。
Recorders

ZVT 的财务数据由谁抓:先看 provider 目录里有没有对应 recorder

财务数据能不能取到,取决于某个 provider 是否实现了对应 schema 的 recorder。用之前先看文件在不在。

财务对象东财侧的 recorder 文件这意味着什么注意点
FinanceFactorrecorders/eastmoney/finance/eastmoney_finance_factor_recorder.py东财侧实现了财务指标抓取财务指标字段多,先取 important_cols()
BalanceSheet.../eastmoney_balance_sheet_recorder.py资产负债表有独立 recorder与利润表字段口径可能不同源
IncomeStatement.../eastmoney_income_statement_recorder.py利润表有独立 recorder同一公司同日多条时按 provider 拆开
CashFlowStatement.../eastmoney_cash_flow_recorder.py现金流量表有独立 recorder季度与年度记录的可得时间不同
三张表共用的基类.../base_china_stock_finance_recorder.py说明四类财务抓取共享一套基类逻辑改口径时影响面较大
其它 provider聚宽一侧另有财务与估值相关 recorder(如 jq_stock_valuation_recorder换源可以拿到不同口径的财务/估值数据换源会换口径,研究里要固定一家
验证方法(30 秒):打印一次 provider 映射表就知道这家源支持哪些财务表,例如 FinanceFactor.provider_map_recorder。列表里没有的对象,就是这家源抓不了——不要靠猜。
FAQ

财务数据常见问题

字段与用法以源码与 README 为准;口径类问题会说明官方是否明确。

财务指标和三大报表要分别取吗?

是。它们是四个独立 schema,各自 record_data;想要哪个就先写哪个。日常筛选用 FinanceFactor 的 9 个关键列基本够,需要拆结构时再取三张表。

为什么 ROE 会出现大于 1 的数值?

README 的示例输出里确实出现了 ROE 明显异常的行(例如大于 1 甚至更大的值)。这类情况通常与公司净资产为负或数据口径有关,但官方未做说明。做横截面排序前建议先做极值检查与 Winsorize,并在研究记录里写明处理规则。

能按公告日期筛选吗?

可以按 report_date(DateTime)加条件,但它是否等于公告日需要你自己核验——官方文档没有给出定义。核验方法见上一节的对照实验。

季报和年报怎么区分?

report_period(String 类型)过滤,README 示例里用的是 report_period == 'year'。具体的取值枚举建议打印一次该列的全部唯一值来确认。

同一家公司同一天出现多条记录怎么办?

先按 provider 拆开看是哪家源写的,再确认 code 是否一致。多源混写是「重复记录」最常见的来源;研究里应固定一个源作为基准。

这些财务数据可以直接拿来选股吗?

可以,但要加上两个前提:①极值处理;②时间对齐——用「当时已经公布的」财报而不是「后来才知道的」财报。第二点没做好,选股结果会系统性偏乐观,见「点时数据与未来函数」页。

财务数据取到了,下一步要解决「什么时候才能用它」

点时数据是这套工具链里最容易被忽略、也最影响结论可信度的一环:报告期、公告日、可获得日三者错位,回测结果就会失真。