halo 的技术博客

返回

Fama-French 五因子里有一个 RMW,叫「稳健盈利能力」(Robust Minus Weak)。它的定义用的是营业盈利能力(Operating Profitability, OP)= (营业收入 − 营业成本 − SG&A − 利息) / 账面权益。也就是说,它先扣掉销售管理费用、扣掉利息,再看还剩多少。

Novy-Marx(2013) 在 “The Other Side of Value” 里挑了个刺:你扣太多的那部分,恰恰是噪声。SG&A 是管理层怎么花钱的选择,利息是资本结构的选择——它们和「这家公司到底有多能赚钱」关系很弱,反而把信号搅浑了。他主张用更朴素的 毛利率(Gross Profitability):

GP = (营业收入 − 营业收入成本) / 总资产
   = 毛利 / 总资产
plaintext

毛利是利润表里最「现金化」的一块:它只扣掉直接生产/采购成本,还没被管理层和财务结构污染。Novy-Marx 的实证结论是——毛利率比 RMW 的运营盈利能力预测力更强、更稳定,而且它和账面市值比(HML)几乎是「一枚硬币的两面」,合起来能解释大部分价值溢价。

本文不重复他的论文结论,而是用一份自包含合成面板把这件事「复现」一遍,并回答一个更尖锐的问题:为什么毛利率更持久、更稳? 顺带把六类真实陷阱讲清楚。

一、直觉:毛利率是利润表里「最像现金」的那块#

一张利润表从上往下:

营业收入
− 营业成本(COGS)
= 毛利 ─────────────── ← 毛利率看这里
− 销售管理费用(SG&A)
− 研发费用、利息、其它
= 营业利润 ─────────── ← RMW/OP 看这里
− 税
= 净利润
plaintext

毛利只扣「直接成本」——对制造业是原材料+产线,对零售是进货成本。这部分在会计准则下最贴近现金:卖一件货,货款减进货价,几乎就是现金流。而 SG&A 里藏着「今年我们多打了广告」「给高管多发了奖金」这类管理层自由裁量,利息则纯粹是「借了多少钱」的财务选择——两者都和「这门生意本身赚不赚钱」弱相关,却会剧烈抖动营业利润。

Novy-Marx 原话的核心意思:利润率的持久部分在毛利里,营业利润里的波动大多是不可持续的会计噪声。要捕捉「质量」,就该抓持久的那块。

二、合成面板:让 GP 持久、OP 不持久,但都来自同一个质量 q#

为了干净地对比,我们造一个面板:每只股票 ii 有一个潜在的、持久的质量因子 qi,tq_{i,t},用 AR(1) 演化(持续性 0.95,所以高度自相关)。然后:

  • 毛利率 GP = q+小噪声q + 小噪声 —— 持久,因为噪声小,基本就是 qq 本身;
  • 营业盈利 OP = 0.6q+大噪声0.6q + 大噪声 —— 同样的信息源 qq,但叠加大量 SG&A/利息式噪声,所以不持久

下月收益由 qq 驱动(通过 GP 暴露),再叠加市场、轻微价值和个股噪声:

注意信号系数被刻意压得很小(GP 是 0.008),不是那种「给个 0.5 直接涨 50%」的作弊设定——我们要的是真实截面里那种微弱但稳定的 alpha。

三、十分位分层:毛利率的单调性能有多干净#

经典质量因子检验:用 t 月的 GP 排序,分成十档(D1 最低 → D10 最高),看每档 t+1 月的平均收益。

n_dec = 10
dec_ret = np.zeros((n_dec, T))
for t in range(T):
    order = np.argsort(GP[:, t])
    ranks = np.empty(N); ranks[order] = np.arange(N)
    d = np.clip(ranks // (N // n_dec), 0, n_dec-1)
    for k in range(n_dec):
        sel = (d == k)
        dec_ret[k, t] = ret[sel, t+1].mean()
ls_monthly = dec_ret[-1, :] - dec_ret[0, :]      # D10 − D1
ann_ret = 12.0 * ls_monthly.mean()
ann_vol = ls_monthly.std() * np.sqrt(12)
sharpe  = ann_ret / ann_vol
python

按毛利率十分位分层(t 月毛利率 → t+1 月收益):从 D1 到 D10 单调爬升

实测(合成面板,系数刻意压低):D1=−0.43%,逐档爬到 D10=+0.61%,严格单调;多空组合月均约 1.04%、年化 ≈ 12.5%、波动率 6.4%、Sharpe 1.96。单调分层是质量因子「有效」最直观的证据——不是一两档在撑,而是整条楼梯往上走。

四、CAPM alpha 与防御性:多空组合的 β≈0#

把多空组合对月度市场收益做回归,看它的 alpha 和 beta:

Xm = np.vstack([np.ones(T), mkt]).T
coef, *_ = np.linalg.lstsq(Xm, ls_monthly, rcond=None)
beta, alpha_m = coef[1], coef[0]
capm_alpha_ann = 12.0 * alpha_m
python

实测:β≈−0.01(基本为 0),年化 CAPM α≈12.4%。这点和 Novy-Marx 的实盘结论一致——毛利率因子本质是防御性的:它买的不是「高风险才有高收益」的 beta,而是「好公司本身就值钱」的纯粹质量溢价。当市场崩的时候,优质股往往跌得少,所以多空组合(买高抛低)的市场暴露被自然对冲掉了。

毛利率多空组合累计净值:年化 12.5%、Sharpe 1.96,且基本不靠市场方向

五、毛利率 vs 营业盈利:同样的 q,谁预测力更强#

这是本文的关键实验。GP 和 OP 都源自同一个 qq,所以「信息量」相同;差别只在噪声。我们用逐月 rank-IC(因子值对下月收益的秩相关)来比:

from scipy.stats import rankdata
def rank_ic(sig, t):
    y = ret[:, t+1]
    return np.corrcoef(rankdata(sig[:, t]), rankdata(y))[0, 1]
ic_gp = np.array([rank_ic(GP, t) for t in range(T)])
ic_op = np.array([rank_ic(OP, t) for t in range(T)])
ic_gp_mean, ic_op_mean = ic_gp.mean(), ic_op.mean()
t_gp = ic_gp_mean / (ic_gp.std() / np.sqrt(T))
python

逐月 rank-IC:毛利率(蓝)整体碾压营业盈利(橙),均值 0.042 对 0.015

实测:GP 的平均 rank-IC = 0.042,OP 只有 0.015——毛利率的预测力是营业盈利的近 3 倍;GP 的 IC t 统计量 = 6.71(远超 2 的显著性门槛)。这正是 Novy-Marx 的核心论点被量化后最干净的表达:同样的信息源 qq,你少扣一点(只扣直接成本),信号就更清楚

六、为什么毛利率更稳:面板自相关#

「预测力强」还不够,质量因子要能「拿得住」——也就是信号要持久。我们对 GP 和 OP 各自算面板自相关(lag 1 到 12 月):

def acf_panel(X, maxlag):
    out = np.zeros(maxlag)
    for L in range(1, maxlag+1):
        a, b = X[:, :-L], X[:, L:]
        ma, mb = a.mean(1, keepdims=True), b.mean(1, keepdims=True)
        num = ((a-ma)*(b-mb)).sum(1)
        den = np.sqrt(((a-ma)**2).sum(1)*((b-mb)**2).sum(1))
        out[L-1] = np.nanmean(num/den)
    return out
acf_gp = acf_panel(GP, 12)
acf_op = acf_panel(OP, 12)
python

面板自相关:毛利率 lag1=0.92、lag12=0.41,而营业盈利 lag1 仅 0.05——持久性天差地别

实测:

指标毛利率 GP营业盈利 OP
lag-1 自相关0.9150.047
lag-12 自相关0.4130.029

毛利率的自相关高到 0.92——这月的高毛利,明年这时候大概率还高;而营业盈利 lag-1 就只剩 0.05,几乎白噪声。这就是「现金含量」的物理含义:直接成本结构比管理层的开销选择稳定得多,所以毛利率才是那个能跨期持有的质量信号。OP 不是没信息,是它的信息被 SG&A/利息的噪声稀释掉了,半衰期短得做不出换手友好的策略。

七、真实陷阱(别直接照抄)#

  1. 合成数据是「照着结论造」的,存在幸存者之外的设定偏误。我让 GP 噪声 0.05、OP 噪声 0.80,天然就在帮 GP;实盘里 GP 与 OP 的差距没这么戏剧化。真实回测要用真实财报(Compustat/Wind),并确认用的是 adj. 口径(剔除金融股,因金融的「营业成本」定义混乱)。

  2. 分母是总资产还是账面权益,结论会变。Novy-Marx 原版用总资产(asset-based),RMW 用账面权益(equity-based)。小市值/高杠杆股在两个口径下排序会翻,必须固定并在论文里说清。本文用总资产口径。

  3. 毛利率在「毛利率结构突变」行业会失效。比如技术迭代让某行业 COGS 骤降(或芯片缺货让 COGS 骤升),单季毛利率跳跃不反映持久质量——要加行业中性化或用毛利率的滚动变化率辅助,别裸用水平值。

  4. 质量因子和动量、价值高度共线。本文 CAPM β≈0 是因为多空本身对冲了市场;但若和投资组合里已有的价值/盈利暴露叠加,会双重计数。实盘要把毛利率因子对市值、行业、账面市值比中性化后再入组合。

  5. 低频 + 换手:财报季才更新,信号本身低频,但 D1/D10 两极的「差公司」可能突然 ST/退市——需要剔除低流动性、ST、上市不足一年的标的,否则多空里「空的那头」会踩流动性与退市雷。

  6. 毛利率高 ≠ 护城河牢。高毛利可能只是暂时垄断或周期顶点,下一季被颠覆。它捕捉的是「当前质量」,不是「未来护城河」;要做持久质量,应叠加毛利率稳定性(如滚动 std 的倒数),而非单看水平。

八、小结#

Novy-Marx 的洞见其实一句话:利润表里越靠上的、越贴近现金的那块,越能代表一家公司的「真质量」。本文用一份合成面板实跑验证:

  • 毛利率十分位严格单调,多空年化 12.5%、Sharpe 1.96;
  • CAPM β≈0、α≈12.4%——是防御性的纯粹质量溢价,不是 beta 伪装;
  • 同样的信息源下,毛利率 rank-IC 0.042 碾压营业盈利 0.015(t=6.71);
  • 根因在持久性:毛利率面板自相关 0.92 vs 0.05——「现金含量」比「会计利润」稳一个量级。

把毛利的「干净」和质量的「持久」合起来看,你就明白为什么 Fama-French 的 RMW 被反复质疑、而毛利率类因子在实盘多因子里长期占一席。从「应计异象(现金流 vs 纸面盈利)」到「净权益发行(管理层的脚在投票)」,再到本文的毛利率——一条主线贯穿:利润表里的现金成分,才是硬 alpha 的藏身处

毛利率因子:Novy-Marx 之后,利润表的现金含量才是硬 alpha
https://blog.halo26812.eu.org/blog/gross-profitability-factor
Author halo
Published at 2026年7月17日
版权声明 CC BY-NC-SA 4.0
Comment seems to stuck. Try to refresh?✨