4、滤波器设计:移动平均线(SMA/EMA/WMA)、卡尔曼滤波简介、小波去噪、巴特沃斯滤波器
说到量化交易里的信号处理,滤波器绝对是个绕不开的话题。
我刚开始做策略研究那会儿,总想着怎么把价格数据里的噪音去掉。说白了,K线图上那些毛刺,看着就让人心烦。你想想看,如果连原始数据都处理不干净,后面那些复杂的模型怎么可能跑得稳?
这一章,咱们就聊聊几种最实用的滤波器。从最简单的移动平均线,到稍微高级点的卡尔曼滤波,再到小波去噪和巴特沃斯滤波器。嗯,都是我在实战中反复用过的家伙。
4.1 移动平均线:最朴素的信号平滑器
移动平均线这东西,估计每个做交易的人都见过。但你真的用对了吗?
我个人习惯把移动平均线分成三类:简单移动平均(SMA)、指数移动平均(EMA)和加权移动平均(WMA)。它们的目标都一样——把价格序列里的高频噪音滤掉,留下趋势。
4.1.1 简单移动平均(SMA)
SMA 是最老实巴交的滤波器。它把过去 N 个周期的价格加起来,再除以 N。公平对待每一个数据点,谁也不偏心。
def sma(price, window):
"""简单移动平均"""
return price.rolling(window=window).mean()
但这里有个坑。我曾经在回测一个趋势策略时,发现 SMA 的滞后性特别严重。为什么?因为它对最近的价格和 10 天前的价格一视同仁。市场都转向了,它还在原地踏步。
4.1.2 指数移动平均(EMA)
EMA 就聪明多了。它给最近的价格更高的权重,越老的数据权重越小。说白了,EMA 更「记仇」——它更在意刚刚发生的事情。
def ema(price, span):
"""指数移动平均"""
return price.ewm(span=span, adjust=False).mean()
我记得有一次做高频策略,SMA 死活跟不上节奏,换成 EMA 之后,信号延迟直接降了 30%。
4.1.3 加权移动平均(WMA)
WMA 是 SMA 和 EMA 的折中方案。你可以自己定义权重,想怎么偏就怎么偏。
def wma(price, weights):
"""加权移动平均,weights 为自定义权重列表"""
return price.rolling(window=len(weights)).apply(
lambda x: np.dot(x, weights) / sum(weights)
)
我一般用线性递减权重,比如 [5,4,3,2,1]。这样既照顾了近期数据,又没完全抛弃历史信息。
4.2 卡尔曼滤波:动态系统的状态估计器
卡尔曼滤波,听起来很高大上对吧?其实没那么玄乎。
它本质上是一个递归算法。每一时刻,它先根据上一时刻的状态做个预测,然后用当前观测值去修正这个预测。预测和修正,反复迭代。
我在做期货跨期套利时用过卡尔曼滤波。当时要估计两个合约的价差均值,传统移动平均根本搞不定,因为价差均值本身就在漂移。卡尔曼滤波却能实时跟踪这个漂移。
import numpy as np
class KalmanFilter:
def __init__(self, process_variance, measurement_variance):
self.process_variance = process_variance # 过程噪声
self.measurement_variance = measurement_variance # 测量噪声
self.estimate = 0.0
self.error_estimate = 1.0
def update(self, measurement):
# 预测
self.error_estimate += self.process_variance
# 卡尔曼增益
kalman_gain = self.error_estimate / (self.error_estimate + self.measurement_variance)
# 修正
self.estimate += kalman_gain * (measurement - self.estimate)
self.error_estimate = (1 - kalman_gain) * self.error_estimate
return self.estimate
4.3 小波去噪:多尺度的信号分解
小波去噪,说白了就是把信号拆成不同频率的成分,然后把噪音所在的成分砍掉,再拼回去。
为什么用小波?因为傅里叶变换只能告诉你信号里有哪些频率,但不知道这些频率出现在什么时候。小波变换能同时告诉你「什么频率」和「什么时候」。
我曾经在股指期货的 tick 数据上试过小波去噪。效果确实好,但计算量也大。实盘时要注意性能问题。
import pywt
def wavelet_denoise(signal, wavelet='db4', level=1):
"""小波去噪"""
coeffs = pywt.wavedec(signal, wavelet, level=level)
# 软阈值处理
sigma = np.median(np.abs(coeffs[-1])) / 0.6745
threshold = sigma * np.sqrt(2 * np.log(len(signal)))
coeffs_thresh = [pywt.threshold(c, threshold, mode='soft') for c in coeffs]
# 重构
return pywt.waverec(coeffs_thresh, wavelet)
4.4 巴特沃斯滤波器:最平坦的通带响应
巴特沃斯滤波器,是数字信号处理里的经典。它的特点是通带内最平坦,没有纹波。
在量化交易里,我主要用它来做低频趋势提取。比如你想保留 20 周期以上的趋势,滤掉 5 周期以下的噪音,巴特沃斯低通滤波器就很好用。
from scipy.signal import butter, filtfilt
def butter_lowpass(data, cutoff, fs, order=4):
"""巴特沃斯低通滤波器"""
nyquist = 0.5 * fs
normal_cutoff = cutoff / nyquist
b, a = butter(order, normal_cutoff, btype='low', analog=False)
# 使用 filtfilt 实现零相位延迟
return filtfilt(b, a, data)
4.5 实战对比:选哪个?
| 滤波器 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| SMA | 简单、直观 | 滞后严重 | 长周期趋势判断 |
| EMA | 响应快、滞后小 | 对噪音敏感 | 短线交易、信号触发 |
| WMA | 灵活、可定制 | 需要手动调权重 | 特殊需求场景 |
| 卡尔曼滤波 | 自适应、实时跟踪 | 参数调优复杂 | 动态均值回归、套利 |
| 小波去噪 | 多尺度、效果好 | 计算量大 | 离线分析、tick 数据 |
| 巴特沃斯 | 通带平坦、零相位 | 边界效应 | 趋势提取、低频滤波 |
说实话,没有哪个滤波器是万能的。我自己的经验是:先用 EMA 快速验证想法,如果效果不理想,再上卡尔曼或小波。别一上来就整复杂的,容易把自己绕进去。
嗯,这一章就到这儿。下一章咱们聊聊特征工程,那才是真正拉开策略差距的地方。