Piotroski F-Score 9 分选股法:如何用 FMP 接口一键排查美股财务健康度?
在美股基本面量化与价值选股(Value Investing)中,芝加哥大学会计学教授 Joseph Piotroski 于 2000 年提出的 Piotroski F-Score(皮奥特罗斯基 9 分法) 是过滤“价值陷阱”最常用的财务健康度标尺。该模型从盈利能力、资本结构与运营效率三个维度提取 9 个二元财务信号(满足记 1 分、不满足记 0 分),用于识别基本面正在发生边际改善的标的。
但在工程实盘中直接调用 FMP 官方的 Financial Scores(财务健康评分接口,/stable/financial-scores)与 Financial Scores Bulk(财务评分批量接口,/stable/scores-bulk)时,开发者往往会遇到三个具体问题:第一,为什么按教科书年度公式手算出来的分数,常与接口返回的 piotroskiScore 相差 1~2 分?第二,为什么英伟达(NVDA)与波音(BA)在最新截面上同为 6 分,底层失分结构却完全不同?第三,在全市场 18,046 条美元财报评分记录中,为何有 33.27% 的 8~9 分高分记录同时处于 altmanZScore < 1.81 区间?
本文基于 quote-fmp.com 网关拉取的 10 家美股代表性公司最近 8 个已结账季度三大报表(共 80 个公司季度切片)及全市场 62,886 条批量评分截面摘要(数据快照截至 2026-11-04,留存于同目录脱敏核对摘要 JSON),逐项拆解 FMP 的 8 季度滚动复算规则、批量初筛的噪音边界,并给出可复现的单股 9 项复算与对账 Python 代码。
一、 FMP 的 Piotroski 9 分是怎么算出来的?8 季度滚动口径与规则边界
许多量化研究者的第一个困惑是:拉取两期 10-K 年报(period=annual)按 Piotroski (2000) 原论文公式复算,结果在非四季报期间与 /stable/financial-scores 返回的 piotroskiScore 频繁出入。
需要首先厘清的是,Piotroski (2000) 原论文是以年度财报为基础定义的:其总资产收益率(ROA)与经营现金流均按期初总资产缩放,杠杆率考核长期债务占平均总资产比例的年度变动,且第 7 项股权融资信号(EQ_OFFER)考核“过去一年是否未发行普通股”(未增发且股数持平时在原论文中得 1 分)。而对照本站 财务指标计算公式全集、FMP 官方文档的九项文字定义以及本文对 10 家公司 80 个季度 Income Statement(利润表接口)、Balance Sheet Statement(资产负债表接口) 和 Cash Flow Statement(现金流量表接口) 的实盘复算,FMP 接口采用的是最近 8 个季度(Q0..Q7,其中 Q0 为最新结账季、Q4 为去年同季)滚动窗口,且在 F2 与 F6 两项上采用了不同于 ΔROA 与负债率的判定规则:
| 维度与分值 | 题号与考核指标 | 本文验证的 FMP 8 季滚动复算口径 (Q0..Q7) | 规则特征及与仅替换 F2/F6 对照口径的差异 |
|---|---|---|---|
| 盈利能力 (4 分) | F1 总资产收益率 · F2 盈利水平 | F1:sum(NI[0:4]) / totalAssets[0] > 0;F2:sum(NI[0:4]) > 0 | FMP 官方定义将 F2 设为净利大于 0(NI_TTM > 0),使 F1 与 F2 同向绑定;若在同滚动窗口下将 F2 替换为 ΔROA_TTM > 0,ROA 高位微降的公司会少 1 分 |
| 盈利能力 (续) | F3 经营现金流 · F4 应计盈余质量 | F3:sum(OCF[0:4]) > 0;F4:sum(OCF[0:4]) > sum(NI[0:4]) | 要求滚动 4 季经营现金流为正且高于滚动 4 季净利润,过滤应计项目偏高、现金含量不足的账面盈利 |
| 资本结构 (3 分) | F5 流动比率 · F6 长期债务 · F7 股本变动 | F5:CR[0] > CR[4];F6:longTermDebt[0] < longTermDebt[4];F7:weightedAverageShsOut[0] < weightedAverageShsOut[4] | F6 直接比较长期债务绝对金额(若替换为长期债务占总资产比 LTD / TA 同比下降,扩表期公司得分会不同);注意 F7 用严格小于判断,未增发但股数持平或零债务 0 < 0 均会判 0 分 |
| 运营效率 (2 分) | F8 毛利率同比 · F9 总资产周转率 | F8:GM[0] > GM[4](单季同比);F9:(sum(Rev[0:4]) / TA[0]) > (sum(Rev[4:8]) / TA[4]) | F8 比较最新单季与去年同季毛利率;F9 比较当前 TTM 与去年同期 TTM 的总资产周转率(以各自期末总资产作分母) |
把这套规则转化为工程直觉,有两条核心纪律需要在写选股器前明确:
- F1 与 F2 的“同进同退”效应:在
totalAssets[0] > 0的常规前提下,ROA_TTM = netIncome_TTM / totalAssets[0]的正负号完全取决于netIncome_TTM。在 FMP 口径下,只要公司过去四季累计盈利(无论 ROA 同比是升是降),F1 与 F2 会同时得 2 分;反之若过去四季累计亏损(如英特尔 INTC 的netIncome_TTM为 -120.32 亿美元),则会同时丢掉 F1 与 F2 两分。 - F6 绝对债务额对扩表期公司更严苛:若用长期债务占总资产比例
longTermDebt / totalAssets衡量杠杆,总资产扩张快于债务增长的公司可以得分;而 FMP 直接比较最新季末longTermDebt[0]与去年同季longTermDebt[4]的绝对美元金额。为了单独量化 F2 与 F6 这两处规则选择带来的分差,下文表二设置了一列“仅替换 F2/F6 的滚动对照分”(即保持 8 季度滚动窗口与其余 7 项计算方式不变,仅将 F2 改为ROA_TTM[0:4] > ROA_TTM[4:8]、将 F6 改为(longTermDebt[0] / totalAssets[0]) < (longTermDebt[4] / totalAssets[4]))。
二、 10 家美股单期截面实盘对账:为什么苹果拿满 9 分,而英伟达和波音同为 6 分?
我们先调用 Statements(财务报表接口) 分类下的 Financial Scores(财务健康评分接口,/stable/financial-scores),观察苹果(AAPL)与波音(BA)的原生返回结构(数据快照截至 2026-11-04):
// GET /stable/financial-scores?symbol=AAPL 及 symbol=BA (取数时间 2026-11-04)
[
{ "symbol": "AAPL", "reportedCurrency": "USD", "altmanZScore": 12.479213455651779, "piotroskiScore": 9, "workingCapital": 3942000000,
"totalAssets": 404548000000, "retainedEarnings": 13700000000, "ebit": 159237000000, "marketCap": 4843808342000, "totalLiabilities": 292455000000, "revenue": 478834000000 },
{ "symbol": "BA", "reportedCurrency": "USD", "altmanZScore": 1.499309458800008, "piotroskiScore": 6, "workingCapital": 15311000000,
"totalAssets": 170739000000, "retainedEarnings": 16429000000, "ebit": 10305000000, "marketCap": 137339499101, "totalLiabilities": 164177000000, "revenue": 94913000000 }
]
为检验表一的 8 季度滚动复算口径,我们拉取苹果(AAPL)、美光(MU)、AMD、英伟达(NVDA)、微软(MSFT)、特斯拉(TSLA)、波音(BA)、英特尔(INTC)、谷歌(GOOGL)与超微电脑(SMCI)共 10 家公司最近 8 个季度的三大报表,逐项计算 F1..F9 并与接口最新截面原值比对(数据快照截至 2026-11-04):
标的 (最新财季 / 披露日 filingDate) | F-Score (FMP 接口分 vs 仅替换 F2/F6 的滚动对照分) | 盈利 4 项 (F1..F4 得分与 OCF-NI 差额) | 资本结构 3 项 (F5..F7 得分与核心变动) | 效率 2 项 (F8..F9) 与 altmanZScore |
|---|---|---|---|---|
| AAPL (FY26 Q4 / 2026-11-03) | 9 分 vs 9 分 | 1,1,1,1(4 分 · 现金流超净利 +129.22 亿美元) | 1,1,1(3 分 · 流动比 +0.13x,股本缩减 -1.65%) | 1,1(2 分 · 毛利率 +0.71pp) · Z = 12.48 |
| MU (FY26 Q4 / 2026-10-09) | 8 分 vs 8 分 | 1,1,1,1(4 分 · 现金流超净利 +47.06 亿美元) | 1,1,0(2 分 · 长期债降 -112.25 亿美元,股本 +1.25%) | 1,1(2 分 · 毛利率 +42.09pp) · Z = 13.78 |
| AMD (FY26 Q3 / 2026-11-04) | 7 分 vs 7 分 | 1,1,1,1(4 分 · 现金流超净利 +15.04 亿美元) | 1,0,0(1 分 · 长期债增 +47.32 亿美元,股本 +0.62%) | 1,1(2 分 · 毛利率 +2.20pp) · Z = 19.12 |
| NVDA (FY27 Q2 / 2026-08-26) | 6 分 vs 5 分 | 1,1,1,0(3 分 · 净利超现金流 -585.19 亿美元) | 1,0,1(2 分 · 长期债增 +239.00 亿美元,股本 -0.72%) | 1,0(1 分 · 周转率降 -0.2279x) · Z = 37.59 |
| MSFT (FY27 Q1 / 2026-10-28) | 6 分 vs 6 分 | 1,1,1,1(4 分 · 现金流超净利 +532.47 亿美元) | 0,1,1(2 分 · 流动比降 -0.18x,股本 -0.09%) | 0,0(0 分 · 毛利率 -1.25pp) · Z = 9.42 |
| TSLA (FY26 Q3 / 2026-10-22) | 6 分 vs 5 分 | 1,1,1,1(4 分 · 现金流超净利 +154.92 亿美元) | 0,1,0(1 分 · 流动比降 -0.33x,股本 +0.40%) | 1,0(1 分 · 毛利率 +1.60pp) · Z = 15.31 |
| BA (FY26 Q3 / 2026-10-27) | 6 分 vs 6 分 | 1,1,1,0(3 分 · 净利超现金流 -36.44 亿美元) | 0,1,0(1 分 · 长期债降 -32.60 亿美元,股本 +3.21%) | 1,1(2 分 · 毛利率转正 +19.17pp) · Z = 1.50 |
| INTC (FY26 Q3 / 2026-10-30) | 5 分 vs 6 分 | 0,0,1,1(2 分 · TTM 净亏损 -120.32 亿美元) | 1,0,0(1 分 · 长期债额增但占总资产比降 -1.28pp) | 1,1(2 分 · 毛利率 +4.75pp) · Z = 2.58 |
| GOOGL (FY26 Q3 / 2026-10-29) | 5 分 vs 5 分 | 1,1,1,0(3 分 · 净利超现金流 -561.43 亿美元) | 1,0,0(1 分 · 长期债增 +1,034.95 亿美元) | 1,0(1 分 · 周转率降 -0.2490x) · Z = 9.72 |
| SMCI (FY27 Q1 / 2026-11-03) | 4 分 vs 5 分 | 1,1,0,0(2 分 · TTM 经营现金流 -63.26 亿美元) | 0,0,0(0 分 · 长期债额增但占总资产比降 -13.79pp) | 1,1(2 分 · 毛利率 +3.43pp) · Z = 3.62 |
在本次核验的 10 家公司最新时点截面上,按表一公式复算的 9 项总分与 /stable/financial-scores 返回的 piotroskiScore 10 家全部吻合(需要说明的是,10 家样本总分一致验证了该 8 季滚动公式在常规美股报表上的复现能力,但不能反证 FMP 内部所有未公开边界分支)。拆解具体子项,可以看到三个核心实战特征:
1. 扩表期的周转率/应计项失分 vs 经营现金流转负的失分(以 NVDA 与 SMCI 为例)
表面上看,英伟达(NVDA)的 F-Score 为 6 分,仅比超微电脑(SMCI,4 分)高 2 分。但穿透到底层报表数字,两者的失分结构截然不同:
- NVDA 丢掉的 3 分(F4、F6、F9)来自资产负债表快速扩表与营运资本占用:截至 FY27 Q2(2026-07-26),NVDA 滚动四季净利润
NI_TTM为 1,928.79 亿美元,经营现金流OCF_TTM为 1,343.60 亿美元(F1、F2、F3 均得 1 分);失分项分别为 F4(OCF_TTM < NI_TTM,差额 -585.19 亿美元)、F6(长期债务longTermDebt从去年同季 84.63 亿美元增至 323.63 亿美元)以及 F9(期末存货inventory达 315.75 亿美元、总资产totalAssets从 1,407.40 亿美元同比扩张 127.56% 至 3,202.72 亿美元,分母翻倍使总资产周转率从 1.1739x 降至 0.9460x;关于存货周转天数的行业背景可参考 AI 算力硬件周期监控实战)。此外,由于总资产增速快于净利润增速,NVDA 的ROA_TTM从去年同期的 61.53% 微降至 60.22%——若按仅替换 F2 的对照口径考核ΔROA_TTM > 0会少得 1 分(5 分),而 FMP 的NI_TTM > 0规则计入 1 分。 - SMCI 丢掉的 5 分(F3、F4、F5、F6、F7)则包含经营现金流全年转负:截至 FY27 Q1(2026-09-30),SMCI 虽然账面
NI_TTM录得 36.56 亿美元,但滚动四季经营现金流OCF_TTM为 -63.26 亿美元(F3、F4 双双得 0 分),同时流动比率从 5.39x 降至 3.02x(F5 得 0 分)、加权平均股本weightedAverageShsOut从 6.57 亿股升至 6.58 亿股(F7 得 0 分)。唯一出现口径分差的是 F6:SMCI 长期债务绝对额从 46.75 亿美元增至 66.83 亿美元(FMP 判 0 分),但由于总资产从 143.86 亿美元扩张至 357.16 亿美元,其长期债务占总资产比例实则从 32.50% 降至 18.71%(仅替换 F2/F6 的滚动对照分判 1 分)。
2. 为什么波音(BA)也能拿 6 分?用同接口的 altmanZScore 补齐存量负债观察视角
对比表中同为 6 分的英伟达(NVDA)、微软(MSFT)、特斯拉(TSLA)与波音(BA),体现出单用 Piotroski F-Score 选股的局限:F-Score 大部分指标衡量的是“同比边际变化方向(Delta)”,而非“资产负债表存量负债水平(Level)”。
波音(BA)在 2026Q3 的单季毛利率从去年同期的 -10.21% 修复至 +8.96%(F8 得 1 分),长期债务从 446.11 亿美元缩减至 413.51 亿美元(F6 得 1 分),总资产周转率从 0.5383x 微升至 0.5559x(F9 得 1 分),加上 TTM 扭亏使得 F1、F2、F3 各得 1 分,合计拿到 6 分。此时配合 /stable/financial-scores 同屏返回的 altmanZScore,即可直观对比存量偿债缓冲:
- Altman Z-Score 五因子加权公式与经验阈值边界:
altmanZScore = 1.2A + 1.4B + 3.3C + 0.6D + 1.0E,其中A = workingCapital / totalAssets、B = retainedEarnings / totalAssets、C = ebit / totalAssets、D = marketCap / totalLiabilities、E = revenue / totalAssets。需注意,Altman 经典的Z > 2.99(稳健区)、1.81~2.99(灰色观察区)、Z < 1.81(高危预警区) 原始阈值是基于上市制造业企业样本标定的;在跨行业量化初筛中,该阈值仅作为衡量资产负债表存量缓冲的经验过滤线,对金融、地产租赁等高杠杆行业天然不适用,也不能直接解释为非制造业公司的破产发生概率。 - AAPL(
Z = 12.48)与 BA(Z = 1.50)实盘算例对比:以 AAPL 为例,代入接口返回的 7 个底层字段可得1.2 × (39.42 ÷ 4,045.48) + 1.4 × (137.00 ÷ 4,045.48) + 3.3 × (1,592.37 ÷ 4,045.48) + 0.6 × (48,438.08 ÷ 2,924.55) + 1.0 × (4,788.34 ÷ 4,045.48) = 0.0117 + 0.0474 + 1.2989 + 9.9375 + 1.1836 = 12.4792(与接口返回值最大绝对误差仅约7.1e-15);而波音(BA)的总负债高达 1,641.77 亿美元(占总资产 1,707.39 亿美元的 96.16%),五项加权之和为 1.50,低于 1.81 经验阈值。 - 复算
altmanZScore的ebit字段口径注意点:FMP 计算C = ebit / totalAssets时,读取的是利润表中的ebit字段(即incomeBeforeTax + interestExpense,包含利息收入与非经营性损益),而非营业利润operatingIncome。例如 NVDA 最近四季累计ebit为 2,302.07 亿美元,高于累计operatingIncome(1,975.79 亿美元);GOOGL 累计ebit为 2,907.13 亿美元,高于累计operatingIncome(1,569.76 亿美元);INTC 累计operatingIncome虽为正(+19.17 亿美元),但受非经营项目拖累累计ebit为 -92.57 亿美元,拉低其 Z-Score 至 2.58。自行验算时切勿拿operatingIncome代入。
三、 全市场 /stable/scores-bulk 快照统计:62,886 条记录的分层分布与四类干扰源
如果要对全市场评分截面做批量统计,调用 Bulk(批量数据接口) 分类下的 Financial Scores Bulk(财务评分批量接口,/stable/scores-bulk)可在单次 HTTP 请求中拉回全库 62,886 条评分记录。
我们对 2026-11-04 拉取的 62,886 条原始 CSV 记录按报表币种、F-Score 分档与 Altman Z-Score 阈值做分层汇总(统计摘要见同目录脱敏核对 JSON),可以看到仅靠评分数值排序会混入多类非目标记录:
| 快照统计层级 (2026-11-04 截面) | 记录总数 | 8~9 分高分记录数 (占比) | 0~2 分低分记录数 (占比) | 8~9 分记录的 Z-Score 阈值切分与分布特征 |
|---|---|---|---|---|
全库原始 CSV 流 (/stable/scores-bulk) | 62,886 条 | 2,880 条 (4.58%,其中 9 分 404 条占 0.64%) | 12,491 条 (19.86%,含 0 分 617 条) | 31.53%(908 / 2,880)满足 Z < 1.81;混有非美元财报及全球多市场跨币种原币金额 |
第一层:限定美元财报 (reportedCurrency == "USD") | 18,046 条 | 1,013 条 (5.61%,其中 9 分 177 条、8 分 836 条) | 4,594 条 (25.46%,含 0 分 237 条) | 33.27%(337 / 1,013)满足 Z < 1.81,18.76%(190 条)位于 1.81~2.99 区间 |
第二层:美元 8~9 分且叠加 Z > 2.99 阈值 | 486 条 (待进一步清洗的候选记录) | 486 条 (占美元 8~9 分记录的 47.98%) | 已按阈值过滤 | 全部满足 F >= 8 且 Z > 2.99;尚未按上市交易所、证券类型与行业联表剔除 |
在基于 /stable/scores-bulk 构建实盘选股漏斗时,必须注意上表揭示的四项数据边界(尤其注意表三的 486 条仅是满足美元财报、F >= 8、Z > 2.99 的候选记录数,并非已完成美股普通股清洗后的最终股票数):
- 格式边界:Bulk 接口返回 CSV 文本流而非 JSON 数组:与常规
/stable/*接口返回 JSON 不同,/stable/scores-bulk与 Company Profile Bulk(公司概况批量接口,/stable/profile-bulk)均直接返回带表头的 CSV 文本流(详见 FMP 数据 API 全面测评),在 Python 中须用csv.DictReader(io.StringIO(text))流式解析,直接调用.json()会报错。 - 币种与上市地边界:
reportedCurrency仅代表财报记账币种,不等于美股交易所挂牌:以台积电美股 ADR(TSM)为例,其piotroskiScore为 8 分、altmanZScore为 16.52,但其reportedCurrency为新台币TWD(marketCap亦按同币种折算为 68.97 万亿新台币);反之,部分非美交易所挂牌公司或 OTC 凭证也会采用USD披露财报。若不先校验reportedCurrency就直接按float(row["marketCap"]) > 10e9过滤市值,会把大批以日元(JPY)、新台币(TWD)计价的中小盘记录误判为百亿美元大盘股。 - 为什么美元 8~9 分记录中有 33.27%(337 / 1,013)落入
altmanZScore < 1.81? 这里的 33.27% 仅表示低于 1.81 阈值的记录占比,绝不能解释为破产风险发生率。核查存档中的这 337 条记录,可见四类典型成因:
- 银行、保险、租赁与房地产信托(REITs):如美国银行(BAC,
F = 8, Z = 0.27)、第一资本金融(COF,F = 9, Z = -0.12)、飞机租赁公司 AerCap(AER,F = 9, Z = 0.98)及住宅 REITs(AMH,F = 9, Z = 1.51)。金融与地产机构负债结构特殊,制造业 Z-Score 阈值对其无效。 - 优先股与衍生/场外代码:如存档中的 COF-PK、COF-PJ、AAM-PA 等优先股记录,以及 AAVVF、ABTZY 等场外代码。工程上不能仅凭代码是否含连字符或字母长度做硬规则判定,而应与
/stable/profile-bulk证券主表按symbol联表,通过exchange、sector、isEtf、isFund、isActivelyTrading字段做精确剔除。 - 零负债导致分母无定义的退化特例(
totalLiabilities == 0):例如存档中的 BC-PA(piotroskiScore = 8,totalAssets = 34.4 亿美元,但totalLiabilities = 0),此时 Z-Score 公式第四项D = marketCap / totalLiabilities出现零分母无定义,接口直接返回altmanZScore == 0,从而落入Z < 1.81区间。 - 高负债非金融公司:如安防服务商 ADT(
F = 8,总资产 159.5 亿美元、总负债 123.1 亿美元、营运资本 -11.1 亿美元,对应Z = 0.61)。在美元 8~9 分且满足Z > 2.99的 486 条候选记录中,大市值 9 分样本包括苹果(AAPL)、埃克森美孚(XOM)、康菲石油(COP)、美敦力(MDT)、派克汉尼汾(PH)、史赛克(SYK)等,实盘入池前仍需完成上述证券主表联表过滤。
四、 Python 实战代码:10 家美股 9 项得分逐位复算与双向勾稽断言
下面给出仅依赖 Python 标准库的单股 9 项复算与对账脚本(54 行)。脚本从 https://quote-fmp.com/stable 拉取单股财务评分与最近 8 个季度的三大报表,在校验三表 8 季财期严格对齐与分母非零后,逐位算出 F1..F9 九个二元得分项及 altmanZScore,并通过 assert 断言与接口返回值比对。
考虑到试用档密钥配额为 20 RPM(每分钟 20 次请求),而遍历 10 家公司需发起 40 次请求,脚本内置了请求间隔与 HTTP 429 分钟级窗口退避。运行前请设置环境变量 export FMP_KEY="你的密钥"(Windows PowerShell 使用 $env:FMP_KEY="你的密钥"):
import json, os, time, urllib.error, urllib.request
BASE_URL, API_KEY = "https://quote-fmp.com/stable", os.environ["FMP_KEY"]
def fmp_get(path: str, **params) -> list[dict]:
params["apikey"] = API_KEY
url = f"{BASE_URL}/{path}?" + "&".join(f"{k}={v}" for k, v in params.items())
for attempt in range(3):
try:
req = urllib.request.Request(url, headers={"User-Agent": "fmpquote-fscore/1.0"})
with urllib.request.urlopen(req, timeout=20) as resp:
return json.loads(resp.read().decode("utf-8"))
except urllib.error.HTTPError as e:
if e.code == 429 and attempt < 2:
wait_s = max(1.0, float(e.headers.get("Retry-After", "60")))
time.sleep(wait_s)
continue
raise
def audit_piotroski_9(sym: str, pace_sec: float = 0.0) -> dict:
sc = fmp_get("financial-scores", symbol=sym)[0]
inc = fmp_get("income-statement", symbol=sym, period="quarter", limit=8)
bal = fmp_get("balance-sheet-statement", symbol=sym, period="quarter", limit=8)
cf = fmp_get("cash-flow-statement", symbol=sym, period="quarter", limit=8)
if pace_sec > 0: time.sleep(pace_sec)
dates = [x["date"] for x in inc]
assert len(dates) == 8 and dates == [x["date"] for x in bal] == [x["date"] for x in cf], f"财期未对齐: {sym}"
ta0, ta4, tl0 = bal[0]["totalAssets"], bal[4]["totalAssets"], sc["totalLiabilities"]
assert ta0 > 0 and ta4 > 0 and tl0 > 0 and inc[0]["revenue"] > 0 and inc[4]["revenue"] > 0, f"分母异常: {sym}"
ni_ttm, ocf_ttm = sum(x["netIncome"] for x in inc[:4]), sum(x["operatingCashFlow"] for x in cf[:4])
rev_ttm, rev_prev = sum(x["revenue"] for x in inc[:4]), sum(x["revenue"] for x in inc[4:8])
cr0, cr4 = bal[0]["totalCurrentAssets"] / bal[0]["totalCurrentLiabilities"], bal[4]["totalCurrentAssets"] / bal[4]["totalCurrentLiabilities"]
gm0, gm4 = inc[0]["grossProfit"] / inc[0]["revenue"], inc[4]["grossProfit"] / inc[4]["revenue"]
flags = [
int((ni_ttm / ta0) > 0), int(ni_ttm > 0), int(ocf_ttm > 0), int(ocf_ttm > ni_ttm),
int(cr0 > cr4), int(bal[0]["longTermDebt"] < bal[4]["longTermDebt"]),
int(inc[0]["weightedAverageShsOut"] < inc[4]["weightedAverageShsOut"]),
int(gm0 > gm4), int((rev_ttm / ta0) > (rev_prev / ta4)),
]
z_calc = (1.2 * sc["workingCapital"] + 1.4 * sc["retainedEarnings"] + 3.3 * sc["ebit"] + 1.0 * sc["revenue"]) / ta0 + 0.6 * sc["marketCap"] / tl0
assert sum(flags) == sc["piotroskiScore"] and abs(z_calc - sc["altmanZScore"]) < 1e-6, f"口径不一致: {sym}"
return {"symbol": sym, "date": dates[0], "f_score": sum(flags), "flags": flags, "z_score": round(z_calc, 2)}
for ticker in ["AAPL", "MU", "AMD", "NVDA", "MSFT", "TSLA", "BA", "INTC", "GOOGL", "SMCI"]:
print(audit_piotroski_9(ticker, pace_sec=1.2))
根据上述函数返回结果整理如下,10 家公司均通过三表财季对齐检查与 assert 双向断言(例如 AAPL 输出 {'symbol': 'AAPL', 'date': '2026-09-26', 'f_score': 9, 'flags': [1, 1, 1, 1, 1, 1, 1, 1, 1], 'z_score': 12.48},NVDA 输出 {'symbol': 'NVDA', 'date': '2026-07-26', 'f_score': 6, 'flags': [1, 1, 1, 0, 1, 0, 1, 1, 0], 'z_score': 37.59};完整 80 个季度的三表输入与复算值均已归档于同目录实测证据 JSON)。
五、 常见问答(FAQ)
1. /stable/financial-scores 只返回当前最新一期的评分快照,做历史回测时能否直接把 limit=8 改大来生成历史序列?
不能仅靠修改 limit 参数实现。首先,第四节的 audit_piotroski_9 固定读取最新截面切片 [:4] 与 [4:8];若拉取 limit=40(10 年季报),需要编写滑动窗口循环,在确认三表历史财期逐季对齐后,按偏移量 i 依次截取 [i:i+4] 与 [i+4:i+8],且 40 个连续季度最多只能生成 33 个完整 8 季滚动 F-Score 窗口。其次,历史各期的 Altman Z-Score 第四项 D = marketCap / totalLiabilities 必须关联对应评估日的历史市值,不能复用最新评分接口里的 sc["marketCap"]。最后,在回测严谨性上,须区分“基于现有报表重建历史滚动序列”与“严格 Point-in-Time(PIT)回测”:按每期财报的 acceptedDate(SEC 接收时间戳)截断仅能避免在财报披露前提前使用该期数据,但无法消除上市公司事后会计重述(Restatement)对历史报表数值的覆盖(回测防前视与退市样本处理可参考 消除美股回测幸存者偏差实战)。若需观察 FMP 预计算的 DCF、ROE、ROA、D/E、P/E、P/B 六维字母评级(S+ 至 D-)历史序列,可配合调用 Analyst(分析师数据接口) 分类下的 Ratings Snapshot(评级快照接口,/stable/ratings-snapshot)与 Historical Ratings(历史财务评分接口,/stable/ratings-historical)。
2. 为什么部分长期大额回购的消费或医药股 Altman Z-Score 偏低,筛选时该如何结合现金流指标交叉核验?
成熟期现金牛公司在长期执行大额股票回购与现金分红时,会通过两条路径影响 Altman Z-Score:一是当期分红或注销式回购冲减留存收益(retainedEarnings),直接压低第二项 B = retainedEarnings / totalAssets(例如表一中 AAPL 2025 财年末至 2026 财年一季末的 retainedEarnings 曾一度为负值);二是若公司通过发行债券筹资回购股票,会推高分母总负债(totalLiabilities),从而压低第四项 D = marketCap / totalLiabilities(注意 D 项分子是总市值而非账面股东权益)。实盘初筛非金融股时,对 piotroskiScore >= 8 且 OCF_TTM > NI_TTM > 0 的公司,可联动 Key Metrics TTM(TTM 关键指标接口,/stable/key-metrics-ttm)核验自由现金流收益率(freeCashFlowYieldTTM)与净债务/EBITDA(netDebtToEBITDATTM),将“高现金流支撑的回购型公司”与“经营失血的高负债公司”区分开来。如需在本地复现上述 10 家美股 9 项得分复算代码,可前往 快速接入指南 免费申领试用 Key(20 RPM / 0.3 GiB,滚动 30 天额度,支持国内直连与微信扫码开通),5 分钟内即可跑通单股财务健康度核验流程。