第 2 章 · 01 EMA 与卡尔曼滤波平滑对比(对应 QS004)


文档摘要

第 2 章 · 01 EMA 与卡尔曼滤波平滑对比(对应 QS004) 速查摘要:技术分析里几乎所有指标都绕不开"平滑"——把噪声大的价格序列变成趋势清晰的曲线。本节手造 10 天股价数据,对比三种平滑器:简单移动平均(SMA,等权)、指数移动平均(EMA,近期权重高)、一维卡尔曼滤波(预测-更新递归估计)。三者平滑哲学完全不同:SMA 是"无脑平均"、EMA 是"重近轻远"、卡尔曼是"带模型的最优估计"。理解这三种,就理解了平滑的核心光谱。 涉及脚本:原项目 QS004-avoid-algo-trading-mistakes/01exponentialmovingaverage.

第 2 章 · 01 EMA 与卡尔曼滤波平滑对比(对应 QS004)

速查摘要:技术分析里几乎所有指标都绕不开"平滑"——把噪声大的价格序列变成趋势清晰的曲线。本节手造 10 天股价数据,对比三种平滑器:简单移动平均(SMA,等权)指数移动平均(EMA,近期权重高)一维卡尔曼滤波(预测-更新递归估计)。三者平滑哲学完全不同:SMA 是"无脑平均"、EMA 是"重近轻远"、卡尔曼是"带模型的最优估计"。理解这三种,就理解了平滑的核心光谱。

涉及脚本:原项目 QS004-avoid-algo-trading-mistakes/01_exponential_moving_average.py(约 93 行 Python)

⚠️ 注意:本脚本完全独立可跑——数据是手造的 10 个数,不依赖 OpenBB 或任何外部数据源,只要装了 pandas/numpy/matplotlib 就能跑,是第 2 章里环境要求最低的脚本。关键参数 ewm(span=window, adjust=False) 里的 adjust=False 必须显式写,否则 pandas 默认 adjust=True 会在序列开头用不同的(非递归)公式,导致结果与教科书 EMA 不一致——这是新手常踩的坑。

工具与原理

三种平滑器的数学本质

平滑的目的是从含噪信号里估计真实趋势。三种方法假设不同:

1. 简单移动平均(SMA)——窗口内等权平均。

SMAₜ = (Pₜ + Pₜ₋₁ + ... + Pₜ₋ₙ₊₁) / n

窗口为 n 的 SMA 把最近 n 个观测值等权求平均。优点是简单稳定;缺点是对窗口内每个数据同等对待——昨天和 n 天前权重一样,所以对近期变化反应慢。pandas 实现:series.rolling(window=n).mean()

2. 指数移动平均(EMA)——指数衰减加权,近期权重高。

EMAₜ = α·Pₜ + (1-α)·EMAₜ₋₁, 其中 α = 2/(span+1)

α 是平滑系数,span 越大 α 越小(平滑越强、反应越慢)。关键性质是无限记忆但指数衰减——理论上每个历史数据点都还影响当前 EMA,但权重随时间指数衰减到 0。所以 EMA 比 SMA 对近期更敏感、对转折反应更快,是 MACD、RSI 等指标的基础。pandas 实现:series.ewm(span=n, adjust=False).mean()

3. 一维卡尔曼滤波——带过程模型的递归最优估计。

卡尔曼滤波假设系统有"真实状态"但观测含噪,通过"预测 + 测量更新"两步递归估计真实状态。一维(常数模型)版本的核心循环:

预测: prediction = state_estimate (假设状态不变) prediction_error = estimation_error + process_variance 更新: kalman_gain = prediction_error / (prediction_error + measurement_variance) state_estimate = prediction + kalman_gain·(measurement - prediction) estimation_error = (1 - kalman_gain)·prediction_error

精髓在 kalman_gain(卡尔曼增益):它是一个 0 到 1 之间的"信任权重"。增益大(接近 1)说明测量可信,新观测吸收得多;增益小(接近 0)说明测量噪声大,更依赖模型预测。增益由"预测误差 / (预测误差 + 测量方差)"自动算出,是自适应的——预测越准、测量噪声越大,越相信模型;反之越相信测量。

三者的对比光谱

平滑器 权重分配 对近期反应 复杂度 适用场景
SMA 窗口内等权 最低 简单去噪、长期趋势
EMA 指数衰减 通用、多数技术指标
卡尔曼 自适应(按信噪比) 最快且可调 含噪估计、追踪系统

直觉:EMA 比 SMA 更贴近期价、转折更快;卡尔曼在测量噪声大时能智能"忽略"异常观测,平滑效果可由 process_variance/measurement_variance 调节。

脚本精读

第一步:造 10 天股价数据(13-19 行)

data = { 'date': pd.date_range('2020-01-01', periods=10, freq='B'), 'price': [100, 103, 107, 105, 108, 107, 115, 110, 108, 112] } df = pd.DataFrame(data) df['date'] = pd.to_datetime(df['date']) df.set_index('date', inplace=True)

要点:

  • pd.date_range('2020-01-01', periods=10, freq='B') 生成 10 个工作日(freq='B' = Business day,自动跳过周末),作为日期索引。
  • 价格手造,故意有起伏(有涨有跌),让三种平滑器的差异看得出来。
  • set_index('date', inplace=True) 把日期列设为索引,变成标准时序 DataFrame。

第二步:算 SMA 和 EMA(26-32 行)

window_size = 3 df['sma'] = df['price'].rolling(window=window_size, min_periods=1).mean() df['ema'] = df['price'].ewm(span=window_size, adjust=False).mean()

两个关键参数:

  • rolling(window=3, min_periods=1):min_periods=1 表示窗口不满 3 个时也算(用 1 个、2 个观测也能算),所以序列开头不会有 NaN;默认 min_periods=window 会让前 n-1 行是 NaN。生产代码里要不要补全取决于场景,这里为了对比方便开了。
  • ewm(span=3, adjust=False):span 是衰减期数(等价于 SMA 的窗口概念),adjust=False 是关键——它用纯递归公式 EMAₜ = α·Pₜ + (1-α)·EMAₜ₋₁,与教科书一致;默认 adjust=True 会在序列开头用补偿公式纠正"早期样本少"的偏差,但结果就不再是教科书 EMA。做技术指标务必 adjust=False

第三步:手写一维卡尔曼滤波(36-60 行)

initial_state = df['price'][0] state_estimate = initial_state estimation_error = 0.5 # 初始估计误差 process_variance = 0.1 # 过程方差 measurement_variance = 0.1 # 测量方差 kf = [] for price in df['price']: # Prediction prediction = state_estimate prediction_error = estimation_error + process_variance # Update kalman_gain = prediction_error / (prediction_error + measurement_variance) state_estimate = prediction + kalman_gain * (price - prediction) estimation_error = (1 - kalman_gain) * prediction_error kf.append(state_estimate) df['kf'] = kf

逐段解读卡尔曼循环的两个阶段:

预测阶段(Prediction):一维常数模型"假设状态不变",所以预测值 = 上一轮状态估计(prediction = state_estimate)。但预测引入不确定性,所以预测误差 = 上轮估计误差 + 过程方差(prediction_error = estimation_error + process_variance)。process_variance 表达"状态本身随机漂移多少"。

更新阶段(Update):拿到新观测 price,计算卡尔曼增益 kalman_gain = prediction_error / (prediction_error + measurement_variance)。测量方差小(准)增益接近 1、大幅吸收新观测;测量方差大(噪)增益接近 0、更信模型。然后 state_estimate = prediction + kalman_gain·(price - prediction) 修正,estimation_error = (1 - kalman_gain)·prediction_error 更新(吸收新观测后不确定性下降)。

💡 核心心法:卡尔曼增益本质是个 0-1 的"信任分配器"。它动态决定"这一轮该多信测量还是多信模型",由预测误差和测量方差的相对大小自动算出,不需要人调——这是它比固定窗口的 SMA/EMA 高明的地方。三个参数(初始误差、过程方差、测量方差)是先验设定,可通过历史数据标定。

第四步:画图对比(66-87 行)

plt.style.use('dark_background') plt.figure(figsize=(10,6)) plt.plot(df.index, df['price'], label='Original Price', marker='o', alpha=0.5, color='lime') plt.plot(df.index, df['sma'], label=f'{window_size}-Day SMA', linestyle='dashed', color='cyan') plt.plot(df.index, df['ema'], label=f'{window_size}-Day EMA', linestyle='dotted', color='magenta') plt.plot(df.index, df['kf'], label='Kalman Filter', linestyle='solid', color='yellow') plt.title('Price with SMA, EMA and Kalman Filter', color='white') plt.legend() plt.grid(True, color='gray', linestyle='--', linewidth=0.5) plt.tight_layout() plt.show()

dark_background 深色主题,四条线用不同颜色和线型区分:原价是散点+半透明线,SMA 虚线,EMA 点线,卡尔曼实线。配图如下。

图: SMA/EMA/卡尔曼滤波对比

从图里能直观看到:EMA 比 SMA 更贴近原价(转折快),卡尔曼滤波在噪声大时更平滑、对突发尖峰有一定抑制。

关键技巧

技巧一:adjust=False 是递归 EMA。做技术指标(MACD、RSI 等用 EMA 的)必须显式写 ewm(span=n, adjust=False),否则结果与教科书不符。pandas 默认 adjust=True 是为统计估计设计的,不是为金融指标。

技巧二:min_periods 控制窗口不满时的行为rolling(window=n, min_periods=1) 让序列开头也出值(用可得样本算);默认会让前 n-1 行是 NaN。研究早期数据要不要纳入,看场景决定。

技巧三:卡尔曼增益是 0-1 的信任权重。一维常数卡尔曼里,kalman_gain = prediction_error / (prediction_error + measurement_variance),直觉就是"测量越准(分母小)→增益越大→越信测量"。理解这一条,卡尔曼滤波的核心就掌握了。

技巧四:三种平滑器用 linestyle 区分。多曲线对比图用 dashed/dotted/solid 区分线型,比单靠颜色更清晰(尤其打印成黑白时)。

技巧五:plt.style.use('dark_background') 深色主题。一行切换整体风格,适合做演示;记得给 title、label 设白色字,否则黑底看不见。

💡 速查要点:SMA 用 rolling().mean() 等权平均;EMA 用 ewm(span=n, adjust=False).mean() 指数衰减(adjust=False 是金融指标必备);卡尔曼滤波用"预测-更新"递归,核心是 0-1 的卡尔曼增益——测量越准增益越大。三者平滑哲学:无脑平均 / 重近轻远 / 带模型自适应。

本节要点

  1. SMArolling(window=n).mean(),窗口内等权,反应慢,适合长期趋势去噪。
  2. EMAewm(span=n, adjust=False).mean(),指数衰减、近期权重高、转折快,是多数技术指标的基础。
  3. adjust=False 是金融指标的必备参数,对应教科书递归公式 EMAₜ = α·Pₜ + (1-α)·EMAₜ₋₁
  4. 一维卡尔曼滤波核心是"预测(状态不变)+ 更新(用卡尔曼增益融合预测和测量)"两步循环,增益是 0-1 的信任权重。
  5. 三者对比:SMA 反应最慢、EMA 居中、卡尔曼可调且对噪声智能抑制;选择取决于场景——简单去噪用 SMA、通用指标用 EMA、含噪追踪用卡尔曼。

作者与出处
原作者: 灏天文库
整理: 灏天文库整理
本站整理收录,版权归原作者/开源协议所有;欢迎通过原文链接访问源仓库。
发布者: 作者: 灏天文库 转发
评论区 (0)
U