Altman Z-Score 实战指南:4 个财务数字如何算出企业的隐含信用评级
【免费下载链接】python-trainingPython training for business analysts and traders项目地址: https://gitcode.com/gh_mirrors/py/python-training
Altman Z-Score 用资产负债表、利润表和市值上的 4 个数字,就能把一家公司的信用风险折算成一个可比的评级刻度。这篇指南带你走完"拉财报 → 算四个比率 → 加权得 Z 值 → 映射 AAA 到 D"的完整链路,跑完后你可以对任意一家上市公司复现同样的分析。
30 秒上手:这套分析到底产出什么
先把结论摆出来:一份约 12 行的 Python 脚本,输入一个 ticker,输出两样东西——
- 一个 Z 值,比如4.343,数值越低,离违约越近;
- 一个常规信用刻度上的隐含评级,比如AA,银行和交易台可以直接拿它对标风险敞口。
仓库 python-training 里有一份完整可运行的示例 notebooks/8_altman_z_double_prime.ipynb,用 pyEX 客户端从 IEX 接口拉取三张财务报表加关键行情,逐行演示了全部计算过程。本地跑起来:
git clone https://gitcode.com/gh_mirrors/py/python-training打开该 notebook 后,把示例里内置的 api_token 换成你自己的数据接口凭据(仓库中的 token 仅作演示,以官方数据源为准),依赖环境见 binder/requirements.txt。
先看清四个分量的含义,再动笔算 ⚖️
Z-Score 出自 Edward Altman 1968 年提出的多元判别分析:在"违约组"和"正常组"两批企业里,找出最能区分两者的财务变量组合,再赋予权重。它不猜股价、不靠感觉,只用报表上现成的数字。
四个分量各盯一个风险维度:
- x1 营运资本 / 总资产:家底扣掉短期欠账后还剩多少,衡量短期流动性,权重 6.56;
- x2 留存收益 / 总资产:历史上是攒钱还是烧钱,衡量抗风险的家底,权重 3.26;
- x3 EBIT / 总资产:每块资产一年能"生"多少税前经营利润,权重 6.72;
- x4 权益市值 / 总负债:市场给股东的定价相对总欠账的倍数,隐含对偿债能力的信心,权重 1.05。
为什么 x1、x3 权重最高?经营赚钱能力和短期流动性是破产最直接的两个前兆。x4 权重看似最低,但分母是总负债,杠杆越高波动越大,实际影响不小。
代入 7 个报表数字,手算一遍验证流程
用一组虚构数据过一遍计算路径(单位:元):
| 报表项目 | 金额 | 来自 |
|---|---|---|
| currentAssets 流动资产 | 8 亿 | 资产负债表 |
| totalCurrentLiabilities 流动负债 | 3.2 亿 | 资产负债表 |
| totalAssets 总资产 | 20 亿 | 资产负债表 |
| retainedEarnings 留存收益 | -1 亿 | 资产负债表 |
| totalLiabilities 总负债 | 6 亿 | 资产负债表 |
| ebit 息税前利润 | 0.6 亿 | 利润表 |
| marketcap 总市值 | 15.6 亿 | 行情数据 |
四个分量依次是:
- x1 = (8 - 3.2) / 20 =0.24
- x2 = -1 / 20 =-0.05(注意是负的,这家公司历史上累计亏损)
- x3 = 0.6 / 20 =0.03
- x4 = 15.6 / 6 =2.60
加权求和:
Z = 6.56×0.24 + 3.26×(-0.05) + 6.72×0.03 + 1.05×2.60 = 1.5744 - 0.163 + 0.2016 + 2.73 = 4.343单项难看,整体未必危险——x2 为负拉低了分数,但 x4 贡献了大头,把整体撑回健康区间;反过来也成立。记住 4.343 这个数,下一节把它翻译成品级。
核心代码:12 行算出 Z 值
import pyEX as p c = p.Client(api_token="你的token", version="v1") # 替换为自己的凭据 def z_dp(ticker): bal = c.balanceSheetDF(ticker) # 资产负债表,按报告期排列 inc = c.incomeStatementDF(ticker) # 利润表 mc = c.keyStats(ticker)["marketcap"] # 当前总市值(实时行情) ta = bal["totalAssets"][0] # [0] 取最新一期 x1 = (bal["currentAssets"][0] - bal["totalCurrentLiabilities"][0]) / ta x2 = bal["retainedEarnings"][0] / ta x3 = inc["ebit"][0] / ta # 分子在利润表、分母在资产负债表,跨表组合 x4 = mc / bal["totalLiabilities"][0] return 6.56*x1 + 3.26*x2 + 6.72*x3 + 1.05*x4两个容易忽略的细节:x3 是跨表组合,别指望一张表里找齐分子分母;x4 分子用市价而不是账面所有者权益,这正是 Z''(Double Prime,专为上市公司信用风险校准)与 1968 年原始版本的关键区别之一。
从 Z 值到 AAA-D 的评级刻度:加 3.25 再查表 📊
原始 Z 模型只有三个粗分界:大于 2.6 算健康、1.1~2.6 是灰色地带、小于 1.1 高危(不同资料口径略有出入)。现代用法更进一步,直接映射到常规信用刻度,分两步:
- Z 值整体+3.25平移——Z 的数值域偏小,评级刻度偏大,先对齐量程;
- 在阈值表里找严格小于调整后 Z 值的最大阈值,取其对应评级。
def implied_rating(z): adj = z + 3.25 # 量程平移 z_map = [8.15, 7.6, 7.3, 7.0, 6.85, 6.65, 6.4, 6.25, 5.85, 5.65, 5.25, 4.95, 4.75, 4.5, 4.15, 3.75, 3.2, 2.5, 1.75] grades = ["AAA","AA+","AA","AA-","A+","A","A-","BBB+","BBB","BBB-", "BB+","BB","BB-","B+","B","B-","CCC+","CCC","CCC-","D"] # searchsorted 找"最大阈值下标",等价于查表;低于最小阈值时兜底返回 D import numpy as np i = min(np.searchsorted(z_map, adj, side="right"), len(z_map) - 1) return grades[min(i, len(grades) - 1)]验证一下开头案例:4.343 + 3.25 = 7.593,落在 7.3 与 7.6 之间,查表得AA。主要档位速查:
| 调整后 Z(Z + 3.25) | 隐含评级 |
|---|---|
| ≥ 8.15 | AAA |
| 7.6 ~ 8.15 | AA+ |
| 7.3 ~ 7.6 | AA |
| 5.85 ~ 6.4 | BBB 档 |
| 4.5 ~ 5.25 | B 档 |
| 1.75 ~ 2.5 | CCC 档 |
| < 1.75 | D(违约区) |
上面用了searchsorted写法,天然规避了"取不到值就报错"的边界问题;notebooks/8_altman_z_double_prime.ipynb 里的版本则用np.array(z_map)[np.array(z_map) < adj].max()实现同样的查表逻辑,可以对照着看。
五个最容易翻车的坑 ⚠️
Z-Score 是一面"有特定角度的镜子",换个角度照就会歪:
| 坑 | 表现 | 应对 |
|---|---|---|
| 样本偏向制造业 | 模型用美国上市公司违约/正常两组数据训练,科技、金融、公用事业结构差异大,同一 Z 值含义不同 | 同行业内比较,别跨行业比绝对值 |
| 财务数据滞后 | 用的是最近一期财报,市场变化要等季报才反映 | 配合最新市值滚动重算 x4,观察多期趋势 |
| 极端值越界 | 调整后 Z 低于 1.75 时,max()类查表会取不到值报错;totalLiabilities 为 0 时 x4 直接除零 | 显式兜底返回 "D";分母为 0 的标的直接跳过 |
| 会计口径差异 | EBIT 有的数据源叫ebit,有的叫operatingIncome,口径不同 x3 差一截 | 固定一个数据源,全程别混用 |
| 单点判断 | 一次 Z 值说明不了趋势 | 拉近 5~8 个季度看方向,斜率比点位重要 |
另外务必分清版本:本文全程用的是Z''(Double Prime),系数 6.56 / 3.26 / 6.72 / 1.05 是上市公司校准版;1968 年原始 Z 模型的分母组合和系数与此不同,引用文献时别混用。
跑通之后:批量扫描、看趋势、设预警 🚀
单公司流程跑顺后,按这个顺序小步扩展:
- 批量扫描:把
z_dp套到一组同行业 ticker 上,输出 (ticker, x1~x4, Z, 隐含评级) 表格,先看横截面分布; - 加时间维度:取 4~8 个历史报告期重算 Z,画趋势线并叠加评级阈值参考线;
- 交叉验证:用历史违约事件回测分界点,别直接照搬 2.99 / 1.81 这类流行阈值,以自己样本上的表现为准;
- 扩到组合层面:对持仓定期刷新 Z 值,把"隐含评级下滑一档"设成预警条件。
Z-Score 的价值不在那个分数本身,而在于它强迫你系统地过一遍流动性、积累、盈利和杠杆四个维度。把这条最小链路跑顺之后,换权重、加变量,都只是在这个骨架上扩展的事。
【免费下载链接】python-trainingPython training for business analysts and traders项目地址: https://gitcode.com/gh_mirrors/py/python-training
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考