ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

1991-2024.06上市公司现金流数据集:口径统一与自由现金流因子实战

2026/9/17 18:23:52 拓冰建站 浏览量
1991-2024.06上市公司现金流数据集:口径统一与自由现金流因子实战 简介这份资源聚焦上市公司现金流与财务指标分析面向金融研究、会计实证、量化投研及经管专业师生用于解决长周期现金流指标获取难、跨软件口径不统一的问题。数据覆盖1991年至2024年6月的季度面板囊括沪深北A股主板、中小企业板、创业板、科创板公司字段含净利润现金净含量、营业收入现金含量、营业利润现金净含量、折旧摊销、公司现金流、股权现金流、公司自由现金流、股权自由现金流以及现金适合比率、现金再投资比率、现金满足投资比率、营运指数、全部现金回收率、资本支出与折旧摊销比等衍生指标均提供当期与TTM两种口径并附带股票代码、简称、统计截止日期、报表类型、行业代码与名称、公告来源等标识信息便于合并与截面比较。资源为单个docx文件压缩包约51KB内含网盘链接指向excel与dta两类数据文件及配套字段说明可分别适配Excel、Stata等工具开展回归、因子构建与现金流质量检验。目前已有144人学习下载。1. 从 1991 到 2024.06上市公司现金流数据集的边界在哪手上有过一份横跨三十多年的财务数据集的人大概都经历过同一个瞬间先看最新一期报表字段齐全、口径清楚觉得很干净再翻到最早那几百行发现科目名对不上、单位对不上、甚至同一家公司前后两年的经营活动现金流净额根本不在一个会计准则体系里。现金流分析这件事难的不是算比率而是先让 1991 年和 2024 年 6 月这两个端点能用同一套逻辑对话。这份数据集覆盖的时间跨度正好压在几次会计口径调整上谁直接拿它跑因子、做回测、算自由现金流折现第一步就得面对口径统一的问题。后面几章按字段口径怎么对齐、数据怎么拼成宽表、指标怎么算、结论怎么验证的顺序推下去适合做量化研究、财务分析、数据清洗的从业者按需取用。2. 现金流量表口径拆解与数据源选型2.1 三张表里现金流指标到底从哪儿来很多人做现金流分析只抓一张现金流量表就开始算比率结果算出来的现金含量没法解释。原因在于现金流量表里的流量科目必须和利润表、资产负债表的存量科目勾稽起来才有意义。经营活动现金流净额要和净利润对比资本开支要和固定资产、在建工程的增量对比货币资金的余额变化要和现金及现金等价物净增加额对比。这三条勾稽线断了任何一条指标就只能当参考值看不能进模型。按国内会计准则的常见科目做现金流分析至少要拿到下面这些字段。列名在不同数据源里叫法不一样落地时要先做一次字段映射。报表归属常见字段用来算什么口径注意点现金流量表经营活动产生的现金流量净额现金含量、OCF/营收早期科目名可能带净额后缀差异现金流量表购建固定资产、无形资产和其他长期资产支付的现金资本开支、自由现金流部分年份缺此项需用投资活动净额近似现金流量表投资活动产生的现金流量净额四象限分类含理财赎回波动大现金流量表筹资活动产生的现金流量净额四象限分类、融资依赖度含分红与借款方向解释要谨慎利润表净利润现金含量分母注意归母与合并口径之别资产负债表货币资金、固定资产、总资产、总负债周转、资本开支强度存量科目只取期末值一个常见误用是把经营活动现金流净额为正直接等同于公司健康。实际上一家公司可以通过压供应商账期、延迟付款把 OCF 短期做正这时必须回到应付账款周转和 OCF/净利润的偏离度上做交叉验证。指标本身没有立场口径和时序才是判断依据。2.2 数据源对比接口、频率与字段完整性获取这段长周期数据常见路径有三类各有取舍。来源类型覆盖起点频率优点主要短板交易所与指定披露平台原始公告上市当年起按报告期最权威含更正公告非结构化解析成本高开源财经数据接口多数覆盖到 1990 年代中后期年/季免登录、字段规整早期字段缺失、偶发断档商业金融数据库覆盖较完整年/季口径做过统一需授权字段定义随版本变对个人和小团队最省事的路线是先用开源接口把主体数据拉下来再把早期缺口用公告原文补齐。常见做法是用 akshare 一类的接口按股票逐只取三张表本地落 Parquet。下面是最小可跑的抓取骨架接口名与返回字段以你本机实际安装版本为准。import akshare as ak import pandas as pd import time # 单只股票取现金流量表stock 需带交易所前缀 cf ak.stock_financial_report_sina(stocksh600519, symbol现金流量表) print(cf.shape) print(cf.columns.tolist()) # 批量抓取加 sleep 降低被限流的概率失败记入队列稍后重试 codes [sh600519, sz000651, sh601318] frames, failed [], [] for code in codes: try: tmp ak.stock_financial_report_sina(stockcode, symbol现金流量表) tmp[股票代码] code frames.append(tmp) except Exception as e: failed.append((code, str(e))) time.sleep(0.8) # 控制请求节奏批量场景建议 0.5~1.5 秒 cf_all pd.concat(frames, ignore_indexTrue) cf_all.to_parquet(cashflow_raw.parquet, indexFalse) print(失败清单:, failed)stock参数是带sh/sz/bj前缀的证券代码不带前缀会直接报错symbol决定取哪张表三张表要分别调用三次再按代码和报告期合并。time.sleep的值不是随便写的接口侧通常有频率限制0.5 秒以下批量跑几百只就会大面积失败。failed列表必须落盘长任务中断后要能续跑否则重跑一次的成本比修 bug 还高。2.3 1991—2024.06 区间内的口径变更与断层这段区间里有几个明显的分水岭。一是 1990 年代中后期会计准则体系的建立早期报表的科目颗粒度远粗于现在二是 2007 年前后与国际趋同的新准则实施部分科目被重新定义或拆分三是季报披露制度的逐步铺开2002 年之前绝大多数公司一年只有一份年报中期数据基本空白。这意味着直接把 1995 年和 2020 年的季度序列拼在一起做同比得到的曲线会有一段人造的跳变。处理方式不是删数据而是加标记位。通常我会在宽表里保留三个辅助列report_type年报/中报/季报、accounting_std按报告期区间打的标准标签、is_restated是否被后续更正公告覆盖过。做时间序列分析时按accounting_std分段建模做横截面分析时用最近一期数据即可不必强行拉平历史。另外要注意退市和借壳公司的历史数据依然留在库里做回测时如果不剔除会引入明显的幸存者偏差这一点在第 5 章会具体展开。3. 用 pandas 把 33 年财报拼成现金流指标宽表3.1 报告期对齐、去重与单位统一原始数据落到本地之后第一件事不是算指标而是把主键定死。财务数据的天然主键是「证券代码 报告期」但真实数据里同一组合经常出现多行有的是更正后的重述版本有的是合并口径与母公司口径混在一起还有的是接口重复返回。处理顺序是先去重、再对齐、最后统一单位。import pandas as pd df pd.read_parquet(cashflow_raw.parquet) # 1) 统一报告期格式去掉中文和分隔符 df[报告期] pd.to_datetime(df[报告期].astype(str) .str.replace(年, -) .str.replace(月, -) .str.replace(日, ), errorscoerce) # 2) 主键去重保留披露日期最新的一条视为重述后版本 df df.sort_values(披露日期).drop_duplicates( subset[股票代码, 报告期], keeplast ) # 3) 单位统一把金额列全部换算成元 amount_cols [c for c in df.columns if 现金流 in c or 现金 in c] for c in amount_cols: df[c] pd.to_numeric(df[c], errorscoerce) # 若源头单位为万元此处乘以 10000务必先抽样核对量级 df[c] df[c] * 10000 print(df.groupby(df[报告期].dt.year)[股票代码].nunique().tail(10))去重时用披露日期排序保留最后一条是因为更正公告通常晚于原始披露取最新等于取重述后口径。单位换算是这段代码里最容易翻车的地方不同接口返回的金额可能是元、万元甚至千元直接乘系数前必须抽一家公司拿它的营业收入和公开年报数字比对一次量级对不上就说明系数错了。最后那行按年份统计股票数量是用来快速看覆盖率的如果某一年突然掉到个位数多半是接口在该区间断档需要单独补数据。3.2 现金流量表的 TTM 滚动与年报对齐做横截面比较时用单季数据会受季节性影响用年报数据又太滞后。通行做法是算 TTM滚动十二个月。现金流量表和利润表里的科目都是流量项TTM 等于最近四个报告期之和资产负债表里的科目是存量项直接取最新一期期末值绝对不能做 TTM 求和否则会得到毫无意义的放大数字。flow_cols [经营活动产生的现金流量净额, 购建固定资产、无形资产和其他长期资产支付的现金, 净利润, 营业总收入] stock_cols [货币资金, 资产总计, 负债合计] df df.sort_values([股票代码, 报告期]) # 流量项按股票分组滚动四期求和 for c in flow_cols: df[c _TTM] (df.groupby(股票代码)[c] .transform(lambda s: s.rolling(4, min_periods4).sum())) # 存量项直接取当期值不做滚动 for c in stock_cols: df[c _LATEST] df[c] # 年报口径只保留 12-31 的报告期 df_annual df[df[报告期].dt.month 12].copy()min_periods4保证只有连续四个季度齐全时才出值早期只有年报的年份会自然变成空值这比用不足四期的数据硬算更安全。groupby之后再transform是关键直接对整表rolling会跨股票串行。实际使用时横截面因子建议用 TTM 列趋势分析用年报列两套口径分开存表避免混用。3.3 现金流指标的批量计算口径统一之后指标计算本身反而是最轻的一步。下面这几个指标是现金流分析里复用率最高的覆盖偿债、盈利质量和再投资能力三个维度。# 现金含量经营现金流对净利润的覆盖倍数长期低于 0.6 需警惕 df[现金含量] df[经营活动产生的现金流量净额_TTM] / df[净利润_TTM] # 资本开支强度反映再投资压力 df[资本开支强度] (df[购建固定资产、无形资产和其他长期资产支付的现金_TTM] / df[营业总收入_TTM]) # 简化自由现金流经营现金流减资本开支 df[自由现金流_TTM] (df[经营活动产生的现金流量净额_TTM] - df[购建固定资产、无形资产和其他长期资产支付的现金_TTM]) # 自由现金流收益率需要总市值按报告期对齐后合并 df[FCF收益率] df[自由现金流_TTM] / df[总市值] # 经营现金流对营收的比率衡量收入变现效率 df[OCF营收比] df[经营活动产生的现金流量净额_TTM] / df[营业总收入_TTM]现金含量的分母用 TTM 净利润而不是单季是为了平滑季节性分母为负时该指标失去意义用之前要先过滤掉亏损样本否则会得到一堆负数比率污染排序。自由现金流_TTM这里用的是最简口径没有加回利息和折旧摊销做估值模型时要换成 FCFF 口径否则会低估企业价值。FCF收益率依赖市值数据市值必须按同一报告期的期末日期对齐用错日期会让整个因子失效。3.4 数据质量校验清单指标算完不算完还得过一遍校验。下面这份清单是踩过坑之后沉淀下来的建议固化成函数每次更新数据都跑。校验项判断方法异常后的动作主键唯一duplicated([股票代码,报告期]).sum()应为 0回到 3.1 重跑去重报告期连续相邻两期间隔应小于 200 天标记缺口避免直接做同比现金含量极值绝对值大于 10 的占比应低于 5%检查净利润是否接近 0单位一致性货币资金量级变化不应超过 10 倍核对原始接口单位勾稽关系现金净增加额 ≈ 期末减期初现金余额偏差大说明口径混用4. 现金流分析的落地诊断、估值与排序4.1 现金流四象限的构造与解读把经营活动、投资活动、筹资活动三个净额的正负组合起来一共有八种形态实务里通常归成四类来读。这个分类在筛选异常公司时特别高效尤其是排查利润漂亮但现金流难看的标的。经营投资筹资常见解读典型阶段-经营造血、持续扩产、外部融资高速扩张期--依靠自身现金流投资并还债分红成熟稳健期-收缩投资、回笼资金偿还债务战略收缩期--经营失血、变卖资产、依赖融资高风险期import numpy as np def quadrant(row): o np.sign(row[经营活动产生的现金流量净额]) i np.sign(row[投资活动产生的现金流量净额]) f np.sign(row[筹资活动产生的现金流量净额]) return f{int(o)},{int(i)},{int(f)} df[现金流形态] df.apply(quadrant, axis1) dist df[df[报告期].dt.month 12][现金流形态].value_counts(normalizeTrue) print(dist.head(8))np.sign把金额压缩成 -1/0/1零值单独成类因为净额恰好为零往往意味着存在抵消项值得单独看。按年报统计形态分布是快速判断当前市场整体处于扩张还是收缩期的一个粗指标。需要注意投资活动净额受理财赎回影响极大很多制造业公司的投资净额常年为正并不代表它在收缩判断时要先剥离交易性金融资产相关的流入流出。4.2 自由现金流折现的简化实现有了 FCF 序列做一个两阶段折现模型并不复杂。核心变量只有三个基期自由现金流、前段增速及年限、永续增速再加上折现率和股本。def two_stage_dcf(fcf0, g1, n, g2, wacc, net_debt, shares): 两阶段自由现金流折现返回每股内在价值 pv 0.0 fcf fcf0 for t in range(1, n 1): fcf fcf * (1 g1) # 前段按 g1 增长 pv fcf / (1 wacc) ** t # 逐年折现 tv fcf * (1 g2) / (wacc - g2) # 永续期终值 pv tv / (1 wacc) ** n equity pv - net_debt # 扣除净负债得到股权价值 return equity / shareswacc必须大于g2否则终值公式发散程序不会报错但结果会大得离谱建议在函数入口加断言。net_debt用有息负债减货币资金不要用总负债否则会把经营性负债也算进去。这个模型对参数极度敏感g1差一个百分点估值能差三成所以实务里不单点取值而是跑一组参数做敏感性矩阵看估值区间而不是估值点。4.3 现金流因子的横截面排序与行业中性化拿自由现金流收益率做选股因子时直接全市场排序会有问题银行、地产天然是负自由现金流公用事业天然高现金流排出来全是行业暴露。标准做法是先做行业内排序再等权合成。# 行业内分位排序pctTrue 返回 0~1 的分位数 df[FCF分位] (df.groupby([报告期, 行业分类])[FCF收益率] .rank(pctTrue, na_optionkeep)) # 剔除极端值避免小市值公司的比率失真 df df[(df[FCF收益率].abs() 1)] # 合成为组合分数现金流质量与估值兼顾 df[综合分] 0.6 * df[FCF分位] 0.4 * df[现金含量].groupby( df[报告期]).rank(pctTrue)na_optionkeep保证缺失值不参与排序也不会被默认为最小值。abs() 1这个过滤是为了剔掉分母接近零导致的极端值阈值可以根据分布直方图调整但不能省。合成权重 0.6/0.4 是经验值实际调参时建议做分层回测看不同权重下的分组单调性而不是凭直觉拍。5. 长周期现金流数据的验证技巧5.1 用退市样本反过来验证幸存者偏差覆盖到 2024 年 6 月的数据集最大的隐性风险不是缺失而是活下来的公司。做任何基于历史财务数据的回测如果样本只包含当前仍在上市的公司收益率会被系统性高估。验证方法很直接把已退市、已暂停上市的公司历史行单独捞出来看它们在退市前三年的现金流形态分布。# 以是否仍在上市作为分组比较末期现金流质量 delisted df[df[退市标记] 1] live df[df[退市标记] 0] compare pd.DataFrame({ 退市组: delisted.groupby(报告期)[现金含量].median(), 存续组: live.groupby(报告期)[现金含量].median() }) print(compare.tail(12))如果退市组在临近退市时现金含量中位数明显低于存续组说明这个指标确实有预警能力同时也说明你的回测必须把它们放进去。这一步做不做决定了你的策略在真实市场里能不能扛住。另一个容易被忽略的点是补数据的方向补早期数据时优先补大市值公司会让 1990 年代的样本严重偏斜覆盖率曲线要按市值分层看而不是只看总数。5.2 把现金流质量做成时间序列告警单个报告期的指标只能做横截面对比真正有价值的是连续变化。一个实操技巧是把现金含量和OCF营收比做成双指标的滚动 Z 分数超过阈值就触发告警用于跟踪持仓池里的公司。g df.groupby(股票代码) # 用过去 12 个季度做滚动基准最少需要 8 期 df[现金含量_z] g[现金含量].transform( lambda s: (s - s.rolling(12, min_periods8).mean()) / s.rolling(12, min_periods8).std() ) df[OCF营收比_z] g[OCF营收比].transform( lambda s: (s - s.rolling(12, min_periods8).mean()) / s.rolling(12, min_periods8).std() ) # 双指标同时跌破 -2 倍标准差标记为观察对象 df[告警] ((df[现金含量_z] -2) (df[OCF营收比_z] -2)).astype(int) print(df[df[告警] 1][[股票代码, 报告期, 现金含量, OCF营收比]].tail(20))min_periods8是为了让基准稳定期数太少 Z 分数会剧烈跳变。用公司自身的滚动基准而不是全市场均值目的是剔除行业和规模差异让告警反映的是这家公司的相对恶化而非整个行业的周期下行。两条线同时跌破才触发能显著降低误报率——单指标偶尔受一次性事件影响双指标同向的概率要低得多。落地时把结果按週或按季输出成 CSV接入到日常跟踪流程里比事后再翻财报高效得多。本文还有配套的精品资源点击获取