15、高频滤波技术:卡尔曼滤波、小波去噪、低通滤波
做高频交易的朋友都知道,原始行情数据里全是噪声。你想想看,每秒几千笔的逐笔成交,里面有多少是散户的冲动单、做市商的刷单、程序化套利的对倒?
我刚开始做高频策略那会儿,直接把原始tick数据喂进模型,结果回测曲线漂亮得像假的一样——实盘一跑,直接亏到怀疑人生。后来才明白,信号提取的第一步,不是找信号,而是去噪声。
今天咱们就聊聊三种最实用的高频滤波技术:卡尔曼滤波、小波去噪、低通滤波。这三种方法各有各的脾气,用对了地方就是神器,用错了就是灾难。
核心观点:没有万能的滤波器,只有适合场景的滤波器。高频数据里,延迟和保真度永远是死对头。
15.1 低通滤波:最朴素但最有效
低通滤波的原理很简单——让低频信号通过,衰减高频噪声。说白了,就是给价格序列做个平滑。
我个人习惯用指数加权移动平均(EWMA)作为低通滤波器。为什么不用简单移动平均?因为SMA的延迟太大了,高频交易里每多1毫秒延迟,可能就是几万块的盈亏。
import numpy as np
import pandas as pd
def ewma_filter(prices, alpha=0.1):
"""
指数加权移动平均低通滤波
alpha: 平滑系数,越小越平滑,延迟越大
"""
filtered = np.zeros_like(prices)
filtered[0] = prices[0]
for i in range(1, len(prices)):
filtered[i] = alpha * prices[i] + (1 - alpha) * filtered[i-1]
return filtered
# 示例:对1秒快照数据做滤波
prices = pd.Series([100.0, 100.1, 100.05, 100.2, 100.15, 100.3])
smoothed = ewma_filter(prices.values, alpha=0.3)
print(f"原始价格: {prices.values}")
print(f"滤波后: {smoothed}")
实战技巧:alpha值怎么选?我一般用交叉验证。拿过去一周的数据,让滤波后的序列和未来1秒的真实价格做相关性分析,选相关性最高的alpha。别凭感觉拍脑袋。
低通滤波最大的坑是什么?相位延迟。你想想看,滤波后的价格总是比真实价格慢半拍。做趋势跟踪还好,做均值回归策略的话,这个延迟会让你买在最高点、卖在最低点。
避坑指南:我曾经在一个做市策略里用了低通滤波,结果发现每次报价都比对手慢。后来一查,是滤波延迟导致信号滞后了3个tick。从那以后,我做高频策略时,低通滤波只用在特征工程里,绝不直接用在交易信号上。
15.2 卡尔曼滤波:状态估计的王者
卡尔曼滤波,说白了就是用数学模型来猜真实价格。它不像低通滤波那样傻傻地平滑,而是根据你对市场运动的假设,动态调整滤波参数。
我刚开始学卡尔曼滤波时,被那一堆矩阵运算搞得头大。后来发现,其实核心就两个步骤:预测 + 更新。
import numpy as np
class KalmanFilter:
def __init__(self, process_variance=1e-5, measurement_variance=1e-3):
# 状态:价格和速度
self.x = np.array([0.0, 0.0]) # [价格, 速度]
self.P = np.eye(2) * 1000 # 协方差矩阵
self.F = np.array([[1, 1], # 状态转移矩阵
[0, 1]])
self.H = np.array([[1, 0]]) # 观测矩阵
self.Q = np.eye(2) * process_variance # 过程噪声
self.R = measurement_variance # 观测噪声
def update(self, measurement):
# 预测
self.x = self.F @ self.x
self.P = self.F @ self.P @ self.F.T + self.Q
# 更新
y = measurement - self.H @ self.x
S = self.H @ self.P @ self.H.T + self.R
K = self.P @ self.H.T / S
self.x = self.x + K * y
self.P = (np.eye(2) - K @ self.H) @ self.P
return self.x[0] # 返回滤波后的价格
# 使用示例
kf = KalmanFilter(process_variance=1e-5, measurement_variance=1e-3)
prices = [100.0, 100.1, 100.05, 100.2, 100.15, 100.3]
filtered = [kf.update(p) for p in prices]
print(f"滤波后价格: {filtered}")
关键参数:
- process_variance(过程噪声):你对价格运动模型的信任度。值越小,越相信模型;值越大,越相信观测数据。
- measurement_variance(观测噪声):你对行情数据的信任度。高频数据里这个值通常设得比较大,因为噪声多。
卡尔曼滤波最牛的地方是自适应。市场波动大的时候,它自动增加对观测数据的权重;市场平稳的时候,它更依赖模型预测。这一点,低通滤波做不到。
个人经验:我在做股指期货高频策略时,用卡尔曼滤波来估计隐含波动率。效果比直接用历史波动率好很多,因为卡尔曼能实时捕捉波动率的突变。嗯,这里要注意:参数初始化很重要,我一般用过去100个tick的数据做预热。
15.3 小波去噪:多分辨率的利器
小波去噪,说白了就是把价格信号拆成不同频率的成分,然后扔掉那些高频噪声成分,再把剩下的拼回去。
为什么用小波?因为价格信号不是平稳的——趋势、波动、噪声混在一起。小波能同时看到时间和频率两个维度的信息,这是傅里叶变换做不到的。
import pywt
import numpy as np
def wavelet_denoise(prices, wavelet='db4', level=3):
"""
小波去噪
wavelet: 小波基函数,db4是Daubechies小波
level: 分解层数
"""
# 小波分解
coeffs = pywt.wavedec(prices, wavelet, level=level)
# 阈值处理(软阈值)
sigma = np.median(np.abs(coeffs[-1])) / 0.6745
threshold = sigma * np.sqrt(2 * np.log(len(prices)))
# 对细节系数做阈值处理
coeffs_thresh = list(coeffs)
for i in range(1, len(coeffs_thresh)):
coeffs_thresh[i] = pywt.threshold(coeffs_thresh[i], threshold, mode='soft')
# 重构信号
denoised = pywt.waverec(coeffs_thresh, wavelet)
return denoised[:len(prices)]
# 示例
prices = np.random.randn(1000) * 0.1 + np.sin(np.linspace(0, 10, 1000))
denoised = wavelet_denoise(prices, wavelet='db4', level=3)
print(f"原始信号标准差: {np.std(prices):.4f}")
print(f"去噪后标准差: {np.std(denoised):.4f}")
避坑指南:我曾经在逐笔数据上用db4小波做去噪,结果发现重构后的价格序列出现了边界效应——开头和结尾的数据明显失真。后来我改用mode='periodization'模式,才解决了这个问题。做高频数据时,边界处理一定要小心,因为你的交易信号可能就在边界附近。
小波去噪有三个关键选择:
- 小波基函数:db系列(Daubechies)最常用,高频数据推荐db4或db6
- 分解层数:层数越多,去噪越彻底,但信号失真也越大。我一般设3-5层
- 阈值策略:软阈值比硬阈值更平滑,但会损失一些幅度信息
15.4 三种滤波器的对比与选择
说了这么多,到底该用哪个?我整理了一个对比表,方便你快速决策:
| 滤波器 | 延迟 | 计算速度 | 自适应能力 | 适用场景 |
|---|---|---|---|---|
| 低通滤波(EWMA) | 中等 | 极快 | 无 | 特征工程、趋势跟踪 |
| 卡尔曼滤波 | 低 | 快 | 强 | 实时交易信号、波动率估计 |
| 小波去噪 | 高(需要窗口数据) | 中等 | 中等 | 离线分析、回测数据清洗 |
我的建议:
- 做实时交易,首选卡尔曼滤波。延迟低、自适应强,就是参数调起来有点麻烦
- 做特征工程,用低通滤波就够了。简单、快、不容易出bug
- 做回测数据清洗,用小波去噪。效果好,但别用在实盘信号上
最后说一句:滤波器不是万能的。我见过太多人把滤波后的曲线当圣杯,结果实盘一塌糊涂。记住,滤波只是工具,不是策略。真正赚钱的,是你对市场微观结构的理解,而不是你用了多复杂的滤波器。
最后的小建议:别一上来就搞卡尔曼滤波。先试试低通滤波,看看效果。如果不行,再上卡尔曼。小波去噪留着做离线分析。记住,简单的东西往往最可靠。