4. 数据频率对齐:日频、周频、月频、季频数据的对齐与重采样技术
做宏观择时模型,最头疼的事情是什么?
我个人觉得,不是策略逻辑设计,也不是参数调优。而是——数据频率对不齐。
你想想看,GDP数据一个季度才出一回,CPI每个月公布一次,而股市行情是每天在跳。把这些数据揉到一起,就像把大象、马、兔子关进同一个笼子,你得先让它们步调一致。
我在搭建第一个宏观择时模型时,就栽过这个跟头。当时直接把日频的股指数据和季频的GDP数据丢进回归模型,结果跑出来一堆伪回归。嗯,后来才明白,频率不对齐,模型就是空中楼阁。
4.1 为什么必须做频率对齐?
说白了,不同频率的数据,背后是不同节奏的经济活动。
- 日频数据:市场情绪、资金流动、短期波动。噪音多,信号弱。
- 周频数据:开工率、库存变化、短期信贷。比日频稳定一些。
- 月频数据:CPI、PMI、社融、工业增加值。宏观择时的核心信号源。
- 季频数据:GDP、上市公司财报、资本形成总额。最慢,但最扎实。
如果你不做对齐,模型会「看到」日频数据每天更新,而季频数据三个月才动一次。结果就是,模型过度拟合了日频的噪音,忽略了季频的趋势。
核心原则:低频数据决定方向,高频数据决定节奏。对齐的目的是让低频数据「指导」高频数据,而不是让高频数据「淹没」低频数据。
4.2 对齐策略:降频 vs 升频
对齐有两种思路。我习惯先问自己一个问题:我的模型最终要预测什么?
如果预测的是季度GDP增速,那就把所有数据都降频到季频。如果预测的是明天股市涨跌,那就得把低频数据升频到日频。
4.2.1 降频(Downsampling)
把高频数据聚合到低频。常用的聚合方式:
| 原始频率 | 目标频率 | 常用聚合方法 | 适用场景 |
|---|---|---|---|
| 日频 | 月频 | 月末取值、月均值、月累计值 | 股指、利率、汇率 |
| 日频 | 季频 | 季末取值、季度均值 | 市场波动率、信用利差 |
| 月频 | 季频 | 季末取值、季度均值 | CPI、PMI、社融 |
我的经验:对于宏观择时,我更喜欢用「月末取值」或「季末取值」。因为宏观数据发布有滞后性,用月末值更贴近实际可用的信息集。用均值会引入未来信息,造成前视偏差。
4.2.2 升频(Upsampling)
把低频数据填充到高频。常用的方法:
- 向前填充(ffill):用上一个已知值填充缺失值。最常用,也最安全。
- 向后填充(bfill):用下一个已知值填充。容易引入未来信息,慎用。
- 线性插值:假设数据在两点之间线性变化。适合趋势明显的序列。
- 样条插值:更平滑,但容易过拟合。我一般不用。
我曾经踩过的坑:用线性插值把季度GDP升频到日频。结果模型在季度中间「看到」了GDP在平滑增长,但实际上GDP数据只在季度末才公布。模型提前知道了「未来」的信息,回测表现好得离谱,实盘一塌糊涂。
记住:升频时只能用过去已知的信息。向前填充是最保守、最诚实的方法。
4.3 重采样技术实战
下面是我在项目中常用的重采样代码框架。以Python的pandas为例。
import pandas as pd
import numpy as np
# 假设我们有三个数据源
# 1. 日频的沪深300指数
# 2. 月频的CPI数据
# 3. 季频的GDP数据
# 读取数据(假设已加载)
# hs300_daily: 日期索引, 收盘价
# cpi_monthly: 日期索引, CPI同比
# gdp_quarterly: 日期索引, GDP同比
# 第一步:统一索引为日期格式
hs300_daily.index = pd.to_datetime(hs300_daily.index)
cpi_monthly.index = pd.to_datetime(cpi_monthly.index)
gdp_quarterly.index = pd.to_datetime(gdp_quarterly.index)
# 第二步:降频——把日频指数转为月频
# 方法:月末最后一个交易日收盘价
hs300_monthly = hs300_daily.resample('M').last()
# 方法:月内平均收盘价(更平滑,但会引入未来信息)
hs300_monthly_avg = hs300_daily.resample('M').mean()
# 第三步:升频——把季频GDP填充到月频
# 方法:向前填充
gdp_monthly = gdp_quarterly.resample('M').ffill()
# 第四步:对齐所有数据到同一个频率(月频)
aligned_data = pd.DataFrame({
'hs300': hs300_monthly['close'],
'cpi': cpi_monthly['cpi_yoy'],
'gdp': gdp_monthly['gdp_yoy']
})
# 删除缺失值
aligned_data = aligned_data.dropna()
print(aligned_data.head())
关键点:对齐后的数据,每一行代表同一个时间点的信息。这个时间点,应该是所有数据都「已知」的时间点。比如GDP在季度末之后一个月才公布,那你的对齐时间点应该再往后推一个月。
4.4 频率对齐的避坑指南
我总结了几个实战中容易出问题的地方:
- 发布时滞:宏观数据不是实时公布的。GDP滞后1-2个月,CPI滞后1个月。对齐时,数据的时间戳应该是「可获取时间」,而不是「数据所属时间」。
- 交易日历:A股有交易日,宏观数据按自然月。对齐时要注意跳过非交易日。用pandas的
resample配合bfill或ffill可以处理。 - 数据修订:宏观数据经常修订。比如GDP初值、修正值、终值。对齐时要用「当时可获取的版本」,而不是修订后的版本。否则又是前视偏差。
- 频率不一致的统计量:日频的波动率和月频的波动率不是一个量级。对齐后,要检查统计特征是否合理。
一个小技巧:我习惯在数据对齐后,画一张时间序列图。把不同频率的数据叠在一起看。如果某个数据在图中出现「阶梯状」跳跃,说明升频方式可能有问题。如果某个数据出现「锯齿状」波动,说明降频时可能混入了噪音。
4.5 知识体系总览
下面这张图,是我自己整理的数据频率对齐核心逻辑。你可以把它当作一个检查清单。
这张图把整个流程串起来了。从左到右,先识别数据频率,再选择对齐策略,最后输出统一频率的数据集。每次做数据对齐前,我都会过一遍这个流程,确保没有遗漏。
最后说一句:数据频率对齐看起来是个技术活,其实是个「认知活」。你选择什么样的对齐方式,本质上是在表达你对经济数据发布机制的理解。对齐做得越细致,模型就越贴近真实世界的决策环境。