3、基础统计特征:滚动均值、滚动标准差、布林带计算、Z-score标准化
各位同学,欢迎来到第三章。
上一章我们聊了数据清洗,把脏数据都处理干净了。那接下来呢?
说白了,原始价格序列本身是「非平稳」的——今天100块,明天可能102块,后天又跌回99块。你直接拿这个序列去预测,很容易被噪声带偏。
所以我们需要提取一些「基础统计特征」。这些特征就像给数据做了一次体检,把隐藏在价格波动背后的规律给揪出来。
我个人习惯把这四个指标称为「量化四件套」:滚动均值、滚动标准差、布林带、Z-score。它们之间是有递进关系的,咱们一个一个来。
3.1 滚动均值:平滑噪声,看清趋势
滚动均值,也叫移动平均。它的核心思想很简单:用过去N天的平均值,来代替今天的价格。
为什么要这么做?
你想想看,单日价格受太多随机因素影响了——某个大户砸了一笔单、一条突发新闻、甚至交易所的撮合延迟。这些噪声会掩盖真正的趋势。
滚动均值就像给数据加了一个低通滤波器,把高频噪声滤掉,留下低频趋势。
计算公式:
MA_t = (P_t + P_{t-1} + ... + P_{t-N+1}) / N
其中P_t是当天的收盘价,N是窗口大小。
窗口怎么选?
这里有个经验法则:
- 短期交易(日内/几天):用5日、10日均线
- 中期交易(几周/几个月):用20日、60日均线
- 长期交易(季度/年度):用120日、250日均线
我的经验: 我在做ETF择时系统时,最常用的是20日均线。为什么?因为A股市场一个月大约有20个交易日,20日均线能很好地反映一个月的平均持仓成本。这个参数我调试了不下50次,最终发现它在大多数宽基ETF上表现最稳定。
代码实现:
import pandas as pd
import numpy as np
# 假设df是包含收盘价的DataFrame
df['MA_20'] = df['close'].rolling(window=20).mean()
df['MA_60'] = df['close'].rolling(window=60).mean()
注意: 滚动均值有一个「滞后性」问题。窗口越大,滞后越严重。比如60日均线,当价格已经反转时,均线可能还在慢慢爬升。所以均线更适合判断趋势方向,不适合做精确的买卖点。
3.2 滚动标准差:衡量波动风险
均值告诉我们价格「平均在哪」,标准差告诉我们价格「波动有多大」。
在量化交易里,波动率就是风险。标准差越大,说明价格上蹿下跳越厉害,持仓风险越高。
计算公式:
σ_t = sqrt( Σ(P_i - MA_t)² / N )
注意这里用的是「样本标准差」,分母是N而不是N-1。因为我们是滚动计算,N通常比较大(20以上),差别微乎其微。
代码实现:
df['STD_20'] = df['close'].rolling(window=20).std()
嗯,这里要注意一点:pandas的std()默认是样本标准差(分母N-1)。如果你想要总体标准差,需要手动设置ddof=0。
避坑指南: 我曾经在回测中发现一个奇怪的现象——某些ETF的波动率突然飙升,但价格并没有大幅波动。后来排查发现,是因为数据里有连续几天的停牌数据(价格不变),导致标准差被低估。所以计算滚动标准差之前,一定要确保数据是连续的,或者对停牌日做特殊处理。
3.3 布林带:价格通道的上下边界
布林带是滚动均值和滚动标准差的「组合拳」。它由三条线组成:
- 中轨:滚动均值(通常是20日均线)
- 上轨:中轨 + K × 滚动标准差
- 下轨:中轨 - K × 滚动标准差
K值通常取2。为什么是2?因为正态分布下,大约95%的数据会落在均值±2个标准差范围内。也就是说,价格突破布林带上轨或下轨,属于小概率事件。
布林带的交易逻辑:
- 价格触及上轨:超买信号,可能回调
- 价格触及下轨:超卖信号,可能反弹
- 布林带收窄(带宽变小):即将变盘
- 布林带扩张(带宽变大):趋势加速
代码实现:
# 计算布林带
df['MID'] = df['close'].rolling(window=20).mean()
df['STD'] = df['close'].rolling(window=20).std()
df['UPPER'] = df['MID'] + 2 * df['STD']
df['LOWER'] = df['MID'] - 2 * df['STD']
# 计算带宽(用于判断波动状态)
df['BANDWIDTH'] = (df['UPPER'] - df['LOWER']) / df['MID']
我的习惯: 我不单独用布林带做买卖决策,而是把它作为「过滤器」。比如当价格突破上轨时,我不会立刻做空,而是等价格回落到中轨以下再确认趋势反转。这样可以避免在强趋势行情中被「假突破」打脸。
3.4 Z-score标准化:让不同ETF站在同一起跑线
Z-score标准化,也叫「零均值标准化」。它的作用是把不同量纲的数据统一到同一个尺度上。
举个例子:沪深300的价格是4000点,创业板指的价格是2000点。你不能直接比较它们的绝对值。但如果你把它们都转换成Z-score,就可以比较了。
计算公式:
Z_t = (P_t - MA_t) / σ_t
Z-score的含义是:当前价格距离均值有多少个标准差。
- Z=0:价格等于均值
- Z=1:价格高于均值1个标准差
- Z=-2:价格低于均值2个标准差
代码实现:
df['Z_SCORE'] = (df['close'] - df['MA_20']) / df['STD_20']
核心应用: Z-score在ETF择时中非常实用。比如你可以设置阈值:当Z-score小于-2时,认为ETF被「低估」,可以考虑买入;当Z-score大于2时,认为被「高估」,可以考虑卖出。这个逻辑本质上就是「均值回归」策略。
不过我要提醒你,Z-score假设数据是正态分布的。但金融数据往往有「尖峰厚尾」特征——极端值出现的概率比正态分布更高。所以阈值设成2可能还不够,我有时候会设成2.5甚至3。
3.5 知识体系总览
下面这张图展示了这四个指标之间的关系:
从图中你可以看到,这四个指标是层层递进的:先有均值,再有标准差,然后组合成布林带,最后归一化成Z-score。每一步都在前一步的基础上增加了新的信息维度。
3.6 实战中的组合用法
在实际的ETF择时系统中,我不会单独使用某一个指标。我通常会这样组合:
| 信号类型 | 使用指标 | 判断逻辑 |
|---|---|---|
| 趋势确认 | 滚动均值(MA_20 vs MA_60) | 短期均线上穿长期均线 → 多头趋势 |
| 波动预警 | 布林带带宽 | 带宽收缩到历史低位 → 即将变盘 |
| 极端信号 | Z-score | Z-score < -2.5 → 超卖,考虑买入 |
| 风险控制 | 滚动标准差 | STD突然放大 → 降低仓位 |
重要提醒: 这些指标都是「滞后指标」。它们基于历史数据计算,无法预测未来。所以千万不要以为Z-score到了-2就一定会反弹——在极端行情下,Z-score可以到-5甚至更低。一定要结合止损策略一起使用。
好了,这一章的内容就到这里。这四个指标是量化择时的基本功,建议你拿到真实数据后,亲手跑一遍代码,看看不同参数下指标的表现差异。只有亲手调过参数,才能真正理解它们的脾气。
公众号:蓝海资料掘金营,微信deep3321