CPI · 消费者物价指数
CPI 大概是财经新闻里出现频率最高的一个缩写。但绝大多数人只记住了「通胀数据」这四个字,至于它具体在算什么、怎么算的、数字为什么会跳,其实并不清楚。
对写 EA 的人来说,搞清楚这些的意义不在于预测行情 —— 而在于你知道哪些分钟的报价是不可信的。
一、它在衡量什么
CPI 衡量的是一篮子消费品与服务的价格变化。关键点有三个:
- 一篮子:不是所有商品,是选定的一组,代表典型家庭的消费结构
- 权重固定周期更新:食品、住房、交通、医疗……各类占比不同,且会定期调整
- 有两个版本:名义 CPI(全部项目)与核心 CPI(剔除食品和能源)
因为这两类价格受天气、地缘等短期冲击影响大,月度波动剧烈,会盖住价格水平的中期趋势。剔除之后看到的是更平滑的「潜在通胀」。
但也正因为剔除了,核心 CPI 和你的实际生活成本感受会不一致 —— 油价涨的时候,名义 CPI 会先反映出来。
二、它是怎么算出来的
本质是一个加权的价格指数,形式上是把「当期这一篮子要花多少钱」除以「基期要花多少钱」:
注意数量 Q 用的是基期的消费量,不是当期的。这叫拉斯佩尔型指数 —— 它固定了消费结构,只让价格变。
平时新闻里说的「通胀率」,是从指数再算出来的变化率:
环比 = ( CPIt − CPIt−1 ) / CPIt−1 × 100%
固定篮子的副作用
因为消费量固定,CPI 无法反映「某样东西变贵了,大家改买便宜的替代品」这种行为。这在经济学上叫替代偏误,它让 CPI 倾向于略微高估生活成本的上升。这不是错误,是口径选择的必然结果 —— 但看数据的人应该知道这一点。
三、谁发布,什么时候
| 项目 | 内容 |
|---|---|
| 发布机构 | 美国劳工统计局(BLS) |
| 频率 | 每月一次,通常在当月 10–15 日之间 |
| 发布时间 | 美东时间上午 8:30(对应北京时间 20:30 或 21:30,取决于夏令时) |
| 覆盖月份 | 发布的是上一个月的数据,不是当月 |
TimeCurrent() 返回的是经纪商服务器时间,它既不是北京时间,也不一定等于美东时间。服务器还可能按季度切换夏令时。
对接经济日历时,务必先用一次真实事件做对照验证,确认你读到的时间戳与服务器时间在同一基准上 —— 差一个小时,你的「避开窗口」就整个错位了。
四、市场为什么关注它
传导链大致是这样:
- CPI 是通胀最直观的度量之一
- 通胀水平影响央行对利率路径的判断
- 利率预期影响债券收益率与折现率
- 折现率变化影响各类资产的定价,也影响不同货币的相对吸引力
所以外汇与贵金属市场对 CPI 的反应通常比股票市场更直接 —— 它直接作用在利率与汇率这两个变量上。
五、EA 里怎么处理这类时段
这是本站讲宏观的落脚点:不是让你预测数据,而是让程序知道这段时间该歇着。
MT5 内置了经济日历接口,可以直接读未来的事件,不用你去维护一张时间表:
//--- 判断是否处于高重要性事件的敏感窗口内
bool IsNewsWindow(const int minBefore = 30, const int minAfter = 15)
{
MqlCalendarValue values[];
datetime now = TimeCurrent();
datetime from = now - minAfter * 60;
datetime to = now + minBefore * 60;
if(!CalendarValueHistory(values, from, to, "US", NULL))
return false; // 读不到日历就按"无事件"处理,不要误封交易
for(int i = 0; i < ArraySize(values); i++)
{
MqlCalendarEvent ev;
if(!CalendarEventById(values[i].event_id, ev))
continue;
if(ev.importance == CALENDAR_IMPORTANCE_HIGH)
return true;
}
return false;
}
然后叠一层点差过滤。数据发布时最典型的现象就是点差瞬间拉大,这一层的成本是真实发生的,回测里却看不到:
bool SpreadTooWide()
{
long spread = 0;
if(!SymbolInfoInteger(_Symbol, SYMBOL_SPREAD, spread))
return false;
return (spread > MaxSpreadPoints); // 按品种单独设阈值
}
再稳一点的做法是加波动率突变熔断 —— 用快 ATR 与慢 ATR 的比值判断「最近这几十根 K 线的波动明显超出常态」:
double af[1], as[1];
CopyBuffer(hATRfast, 0, 0, 1, af); // 例如 n=7
CopyBuffer(hATRslow, 0, 0, 1, as); // 例如 n=30
if(as[0] > 0 && af[0] / as[0] > SpikeRatio) // 如 2.0
{
// 波动率突然放大:不开新仓,已有持仓照常管理
return;
}
① 时间窗口(事前,靠日历)→ ② 点差检查(事中,靠报价)→ ③ 波动率熔断(事后,靠 K 线)。
三层都不要求你判断数据好坏,只回答一个问题:现在的报价环境是否还适合执行策略。这就是工程思维和预测思维的区别。
六、五个常见误读
1. 把名义 CPI 和核心 CPI 混着看
两个数字的波动来源不同。一个月里油价大涨,名义 CPI 会跳,核心 CPI 可能纹丝不动。看错口径,你会得出完全相反的结论。
2. 只盯同比,忽略基数效应
同比是和去年同月比。如果去年同期正好有个异常高(或低)的值,今年的同比就会被机械地压低(或抬高),跟这个月实际发生了什么无关。看同比的同时要看环比,或者看几个月的变化趋势。
3. 认为「数据好 = 价格一定往某个方向走」
市场交易的是预期差,不是绝对值。数据已经完全被预期到的情况下,发布瞬间的反应可能很小;反之,一个看似平淡的数字如果偏离预期很远,反应也可能很大。而且经常出现「数据出来后价格先走一个方向、再反向走回去」的情况。这部分属于市场行为。
4. 用单月数据下结论
单个数据点的噪音很大,统计局自己也会做季节调整与后续修正。看趋势,不看单点 —— 这一点和判断策略是否有效是同一个道理。
5. 以为 EA 只要「避开」就够了
避开只解决新开仓的问题。已经持有的仓位在数据发布时同样面临跳空与滑点,止损单在跳空下不会按你设定的价格成交。这属于风控设计范畴(L4),不是日历过滤能解决的。
小结
CPI 是一个有明确口径、明确发布节奏、也明确局限性的统计量。它的价值不在于告诉你行情往哪走,而在于它标出了一年中有十二个报价环境会突然恶化的时间点。对写 EA 的人来说,后者才是可以直接变现的信息。