欢迎加入专注于财经数据与量化投研的【数据科学实战】知识星球!在这里,您将获取持续更新的《财经数据宝典》和《量化投研宝典》,这两部宝典相辅相成,为您在量化投研道路上提供明确指引。 我们提供了精选的国内外量化投研的 250+ 篇高质量文章,并每日更新最新研究成果,涵盖策略开发、因子分析、风险管理等核心领域。 无论您是量化投资新手还是经验丰富的研究者,星球社区都能帮您少走弯路,事半功倍,共同探索数据驱动的投资世界!
引言
金融市场天生充满噪声。每一笔交易、对冲、强制清算、套利和算法再平衡,最终都会压缩成一个叫做"价格"的数字。当我们把这个数字绘制在图表上时,它看起来很精确,但精确并不等于清晰。
如何从嘈杂的价格数据中提取有价值的信号?这正是平滑技术存在的意义。本文将介绍三种主流的自适应平滑方法:McGinley Dynamic(麦金利动态指标)、KAMA(考夫曼自适应移动平均线)和 Kalman Filter(卡尔曼滤波器),并通过 Python 代码带你逐一实现。
核心目标:降噪但不破坏结构
所有平滑技术的存在都是因为原始价格往往难以直接使用。它对所有信息都会做出反应,无论这些信息是否有意义。
"过滤"可以有不同的含义:
McGinley Dynamic 专注于响应速度,KAMA 专注于市场状态感知,Kalman 滤波专注于概率估计。
三种方法详解
McGinley Dynamic:修复滞后问题
McGinley Dynamic 的创建是为了解决传统移动平均线(特别是 EMA)的一个具体问题:固定的平滑参数会导致当价格加速时均线严重滞后,而当价格停滞时又会过度反应。
McGinley 的解决方案简单而实用:不以固定速率平滑价格,而是根据价格相对于均线本身的偏离程度来调整速度。
KAMA:响应需要被"赚取"
KAMA(Kaufman Adaptive Moving Average,考夫曼自适应移动平均线)采用了更具选择性的方法。
KAMA 不是对价格与均线之间的距离做出反应,而是衡量价格移动的效率。它比较一段回溯期内的净方向性移动与总移动量。这个比率决定了均线适应的速度。
- 当价格持续朝一个方向移动且波动较小时,效率高,KAMA 变得更敏感
- 当价格来回震荡但没有明确方向时,效率下降,KAMA 大幅减慢
Kalman Filter:估计你无法直接观察的东西
Kalman 滤波与 McGinley 和 KAMA 有本质区别。它不是平滑价格,而是估计一个潜在状态。
核心假设是:观察到的价格是某个更深层次事物的嘈杂测量值。滤波器将对该状态的先验信念与新观察结合起来,根据不确定性对各自进行加权。
这引入了两个大多数指标忽略的概念:
Python 实现
环境准备
import numpy as np
import pandas as pd
import yfinance as yf
import matplotlib.pyplot as plt
McGinley Dynamic 实现
def mcginley_dynamic(price, period=14):
"""
计算 McGinley Dynamic 指标
参数:
price: 价格序列(pandas Series)
period: 周期参数,默认为 14
返回:
McGinley Dynamic 指标序列
"""
md = np.zeros(len(price))
md[0] = price.iloc[0] # 初始值设为第一个价格
for i in range(1, len(price)):
# 根据价格偏离程度动态调整平滑速度
md[i] = md[i-1] + (price.iloc[i] - md[i-1]) / (
period * (price.iloc[i] / md[i-1])**4
)
return
pd.Series(md, index=price.index)
KAMA 实现
def kama(price, er_period=10, fast=2, slow=30):
"""
计算 KAMA(考夫曼自适应移动平均线)
参数:
price: 价格序列(pandas Series)
er_period: 效率比率计算周期,默认为 10
fast: 快速平滑常数周期,默认为 2
slow: 慢速平滑常数周期,默认为 30
返回:
KAMA 指标序列
"""
# 计算净价格变化(方向性移动)
change = price.diff(er_period).abs()
# 计算总波动(所有价格变化之和)
volatility = price.diff().abs().rolling(er_period).sum()
# 效率比率 = 净变化 / 总波动
er = change / volatility
er = er.fillna(0.0)
# 计算平滑常数
fast_sc = 2 / (fast + 1) # 快速平滑常数
slow_sc = 2 / (slow + 1) # 慢速平滑常数
# 根据效率比率在快慢平滑常数之间插值
sc = (er * (fast_sc - slow_sc) + slow_sc) ** 2
# 计算 KAMA
kama_values = np.zeros(len(price))
kama_values[0] = price.iloc[0]
for i in range(1, len(price)):
kama_values[i] = kama_values[i-1] + sc.iloc[i] * (price.iloc[i] - kama_values[i-1])
return pd.Series(kama_values, index=price.index)
Kalman Filter 实现
def kalman_filter(price, q=1e-5, r=1e-2):
"""
一维卡尔曼滤波器实现
参数:
price: 价格序列(pandas Series)
q: 过程噪声方差,控制状态演变的不确定性
r: 测量噪声方差,控制观察值的不确定性
返回:
滤波后的价格估计序列
"""
x_hat = np.zeros(len(price)) # 状态估计
p = np.zeros(len(price)) # 估计误差协方差
# 初始化
x_hat[0] = price.iloc[0]
p[0] = 1.0
for k in range(1, len(price)):
# 预测步骤
x_pred = x_hat[k-1] # 状态预测
p_pred = p[k-1] + q
# 协方差预测
# 更新步骤
k_gain = p_pred / (p_pred + r) # 卡尔曼增益
x_hat[k] = x_pred + k_gain * (price.iloc[k] - x_pred) # 状态更新
p[k] = (1 - k_gain) * p_pred # 协方差更新
return pd.Series(x_hat, index=price.index)
传统均线对比
def sma(price, period=50):
"""简单移动平均线"""
return price.rolling(period).mean()
def ema(price, period=20):
"""指数移动平均线"""
return price.ewm(span=period, adjust=False).mean()
绑定绘图
# 下载苹果公司 2025 年的股票数据
data = yf.download("AAPL", start="2025-01-01", end="2025-12-31", progress=False)
price = data["Close"]
# 计算各种指标
md = mcginley_dynamic(price)
kama_line = kama(price)
kalman_line = kalman_filter(price)
sma_50 = sma(price, 50)
ema_20 = ema(price, 20)
# 绑制对比图
plt.figure(figsize=(15, 8))
plt.plot(price, label="价格", alpha=0.5)
plt.plot(sma_50, label="SMA 50", linestyle="--")
plt.plot(ema_20, label="EMA 20", linestyle=":")
plt.plot(md, label="McGinley Dynamic", linewidth=2)
plt.plot(kama_line, label="KAMA", linewidth=2)
plt.plot(kalman_line, label="Kalman Filter", linewidth=2)
plt.title("自适应滤波器 vs 传统移动平均线(AAPL 2025)")
plt.legend()
plt.show()
不同市场状态下的表现
强趋势市场
在清晰的趋势中,McGinley 通过减少滞后优于传统移动平均线。KAMA 在这种条件下表现通常更好,高效率使其快速响应同时仍能过滤小幅回撤。Kalman 滤波器调参得当时,能产生平滑的趋势估计且滞后最小。
震荡市场
这是差异变得明显的地方。McGinley 会反复对偏差做出反应,产生频繁的小幅调整。KAMA 在这里表现出色,低效率迫使平滑常数下降,使线条变平,传达了一个重要信息:市场没有提供有意义的方向。
突然的趋势转换
在急剧反转或突破期间,McGinley 会滞后直到价格移动足够远才触发加速。KAMA 只在效率提高后才响应,这意味着它避免了虚假反转但牺牲了早期入场。Kalman 滤波器如果过程噪声设置允许,可以平滑适应。
交易者常忽略的关键洞察
自适应不等于智能:McGinley 和 KAMA 会适应,但它们不会推理。将这些工具当作会思考的实体会导致误用。
平坦的指标也是信息:平坦的 KAMA 或稳定的 Kalman 估计告诉你价格行为缺乏值得行动的结构。忽略这个信息是交易者最常犯的错误之一。
噪声不可避免,误解是可选的:
如何选择
- 如果你进行主观交易并想要更清晰的趋势而不需要复杂性,McGinley 是一个实用的升级
- 如果你想要市场状态感知和更少的虚假信号,KAMA 值得关注
- 如果你构建系统、研究信号或动态管理风险,Kalman 滤波打开了不同级别的控制
总结
从固定移动平均线到自适应平均线再到概率滤波器的演进,反映了市场分析的更广泛转变。首先我们减少了滞后,然后我们尊重市场状态,现在我们承认不确定性。
未来的工具可能会建立在不确定性感知框架之上,无论是通过 Kalman 滤波器、贝叶斯模型,还是在信号旁边估计置信度的混合系统。优势将来自更好的估计。
不要寻找单一的最佳工具,把这些方法看作是不同的透镜,每一个都能帮助你从不同角度理解市场。
参考文章
加入专注于财经数据与量化投研的知识星球【数据科学实战】,获取本文完整研究解析、代码实现细节。财经数据与量化投研知识社区
核心权益如下:
- 赠送《财经数据宝典》完整文档,汇集多年财经数据维护经验
- 赠送《量化投研宝典》完整文档,汇集多年量化投研领域经验
- 赠送《PyBroker-入门及实战》视频课程,手把手学习量化策略开发
- 每日分享高质量量化投研文章(已更新 180+篇)、代码和相关资料
星球已有丰富内容积累,包括量化投研论文、财经高频数据、 PyBroker 视频教程、定期直播、数据分享和答疑解难。适合对量化投研和财经数据分析有兴趣的学习者及从业者。欢迎加入我们!