第三章:宏观状态识别——用PMI、CPI、利率判断市场状态
说实话,做因子投资最怕什么?
不是因子失效,而是你根本不知道它为什么失效。
我见过太多人,拿着回测漂亮的因子冲进市场,结果三个月就被打得鼻青脸肿。为什么?因为市场状态变了,而你的因子还停留在牛市思维里。
这一章,我们就聊聊怎么用宏观经济指标来判断市场状态。说白了,就是给因子择时找个宏观背景板。
3.1 为什么宏观状态对因子择时这么重要?
先讲个我自己的经历。
2018年,我管理的一个多因子策略突然连续回撤。回测里明明很稳健的估值因子,怎么就不灵了?我翻来覆去查代码,查数据,最后发现——那年是典型的“紧信用+去杠杆”环境,市场对高估值股票极度厌恶,但我的估值因子用的是静态PE,根本没考虑宏观环境。
嗯,从那以后,我再也不敢忽略宏观状态了。
宏观状态对因子的影响,其实可以归纳为三点:
- 因子收益的周期性:比如动量因子在牛市中表现好,在熊市中容易崩盘
- 因子风险的聚集性:经济衰退时,低质量因子的风险会集中爆发
- 因子之间的相关性:不同宏观状态下,因子间的相关性会剧烈变化
核心观点:因子择时不是预测未来,而是识别当前状态,然后选择最适配的因子。
3.2 三个核心宏观指标:PMI、CPI、利率
宏观指标那么多,为什么我偏偏选这三个?
你想想看,一个经济体无非就三个维度:增长、通胀、货币环境。PMI代表增长,CPI代表通胀,利率代表货币环境。三个指标基本能勾勒出宏观全貌。
3.2.1 PMI(采购经理人指数)
PMI是经济的“体温计”。高于50说明经济在扩张,低于50说明在收缩。
我个人习惯用PMI的三个月移动平均来平滑噪音。为什么?因为单月PMI波动太大,经常被季节性因素干扰。平滑后,趋势更清晰。
| PMI状态 | 经济含义 | 因子偏好 |
|---|---|---|
| > 52 | 强劲扩张 | 动量、成长因子 |
| 48 - 52 | 温和增长 | 价值、质量因子 |
| < 48 | 收缩/衰退 | 低波、防御因子 |
3.2.2 CPI(消费者物价指数)
CPI反映通胀压力。通胀高的时候,市场会预期加息,这对很多因子都是利空。
我在项目中遇到过一个问题:CPI同比数据波动太大,直接用来做信号会频繁切换。后来我改用CPI的环比折年率,加上三个月平滑,效果好了很多。
小技巧:CPI数据发布有滞后性,建议用市场预期的CPI(比如彭博调查值)代替实际值。预期数据更能反映市场定价。
3.2.3 利率(政策利率或10年期国债收益率)
利率是资金的“价格”。低利率环境有利于成长股,高利率环境有利于价值股。
这里要注意:利率的变化方向比利率的绝对水平更重要。我曾经犯过这个错——只看利率绝对值,结果在利率下降周期里配置了价值因子,亏得挺惨。
3.3 宏观状态分类:一个简单的四象限框架
把PMI和利率结合起来,我们可以构建一个四象限框架。这是我个人最常用的方法。
这个框架虽然简单,但非常实用。我每次做因子配置前,都会先看看当前落在哪个象限。
3.4 实战:用Python实现宏观状态识别
光说不练假把式。下面是我实际项目中用的一段代码,用来识别宏观状态。
import pandas as pd
import numpy as np
def identify_macro_state(pmi, cpi, rate):
"""
识别宏观状态
pmi: 最新PMI值
cpi: 最新CPI同比
rate: 最新政策利率
"""
# 定义阈值(可根据历史分位数调整)
pmi_threshold = 50
cpi_threshold = 3.0 # 3%通胀警戒线
rate_threshold = 2.5 # 中性利率估计
# 判断增长状态
growth = '扩张' if pmi > pmi_threshold else '收缩'
# 判断通胀状态
inflation = '高通胀' if cpi > cpi_threshold else '低通胀'
# 判断货币环境
monetary = '紧缩' if rate > rate_threshold else '宽松'
# 综合判断
if growth == '扩张' and monetary == '宽松':
state = '复苏'
elif growth == '扩张' and monetary == '紧缩':
state = '过热'
elif growth == '收缩' and monetary == '宽松':
state = '衰退'
else:
state = '滞胀'
return {
'state': state,
'growth': growth,
'inflation': inflation,
'monetary': monetary
}
# 示例:2023年Q4数据
result = identify_macro_state(pmi=49.5, cpi=2.8, rate=3.0)
print(f"当前宏观状态:{result['state']}")
# 输出:当前宏观状态:滞胀
注意:阈值不是固定的。我建议每季度重新计算一次阈值,用过去5年的历史分位数来动态调整。固定阈值在结构性变化的市场里会失效。
3.5 宏观状态与因子择时的联动
识别出宏观状态后,怎么用它来指导因子配置?
我的做法是:建立一个状态-因子映射表,每个状态对应一组偏好因子。
| 宏观状态 | 偏好因子 | 规避因子 | 配置权重调整 |
|---|---|---|---|
| 复苏 | 动量、成长、小盘 | 低波、防御 | 动量+20%,低波-10% |
| 过热 | 价值、商品、通胀对冲 | 成长、长久期 | 价值+15%,成长-15% |
| 衰退 | 低波、质量、国债 | 动量、小盘 | 低波+25%,动量-20% |
| 滞胀 | 防御、现金、商品 | 几乎所有权益因子 | 现金+30%,权益-30% |
这里有个坑:状态切换有滞后性。我曾经在2020年3月,PMI刚跌破50就切换到衰退配置,结果错过了随后的大反弹。后来我加了两个规则:
- 状态确认需要连续两个月的数据支持
- 切换时采用渐进式调整,而不是一步到位
3.6 进阶:用宏观因子做状态概率估计
如果你觉得硬分类太粗糙,可以试试概率化方法。
我个人喜欢用逻辑回归或朴素贝叶斯来估计每个状态的概率。这样配置因子时,可以按概率加权,而不是非黑即白。
from sklearn.linear_model import LogisticRegression
# 假设我们有历史数据
X = historical_macro_data # PMI, CPI, 利率等
y = historical_states # 0=复苏, 1=过热, 2=衰退, 3=滞胀
model = LogisticRegression(multi_class='multinomial')
model.fit(X, y)
# 预测当前状态概率
current_data = [[49.5, 2.8, 3.0]]
probs = model.predict_proba(current_data)[0]
state_names = ['复苏', '过热', '衰退', '滞胀']
for name, prob in zip(state_names, probs):
print(f"{name}: {prob:.2%}")
# 输出示例:
# 复苏: 12.3%
# 过热: 8.7%
# 衰退: 35.6%
# 滞胀: 43.4%
有了概率,因子配置就变成了一个优化问题:目标权重 = sum(状态概率 * 该状态下的因子权重)。这样切换更平滑,回撤也更小。
3.7 避坑指南
最后,分享几个我踩过的坑:
- 不要过度拟合:宏观指标就那么几个,别想着用20个变量做回归。我见过有人用30个宏观指标做因子择时,结果样本外一塌糊涂。
- 注意数据频率:PMI是月度数据,CPI也是月度,利率可以日度。做状态识别时,统一用月度频率,别混用。
- 宏观状态不是万能的:它只能提供背景,不能替代因子本身的质量。烂因子在什么宏观状态下都是烂因子。
我的习惯:每周末花10分钟,看看最新的PMI、CPI和利率数据,判断当前状态。然后检查因子组合是否需要微调。这个习惯坚持了5年,帮我躲过了好几次大回撤。
宏观状态识别,说白了就是给因子择时找个“天气预报”。有了它,你至少知道今天是晴天还是雨天,该带伞还是该涂防晒霜。至于具体怎么走,那是下一章的事了。
公众号:蓝海资料掘金营,微信deep3321