python:pykalman 卡尔曼滤波
用 pykalman 库进行股市的技术分析,核心是利用卡尔曼滤波这种算法对股价数据进行处理和分析,比如降噪、趋势提取等。
你想了解如何使用 Python 的 pykalman 库来进行股市的技术分析,核心是利用卡尔曼滤波这种算法对股价数据进行处理和分析,比如降噪、趋势提取等。
一、核心思路
卡尔曼滤波(Kalman Filter)是一种最优估计算法,特别适合处理带噪声的时序数据。在股市分析中,我们可以用它来:
- 对股价进行降噪处理,剔除短期波动,提取核心趋势;
- 预测股价的下一时刻估值,辅助判断趋势方向;
- 计算滤波后的股价与原始股价的偏差,作为交易信号参考。
二、完整实现代码
首先需要安装依赖库:
pip install pandas matplotlib yfinance
如果是 Python3.7 则 pip install pykalman==0.9.7
如果是 Python3.8+ 则 pip install pykalman
pip show pykalman
Name: pykalman
Version: 0.10.2
Summary: An implementation of the Kalman Filter, Kalman Smoother, and EM algorithm in Python
Home-page: https://github.com/pykalman/pykalman
Author: Daniel Duckworth
以下是完整的股市分析代码(以特斯拉(TSLA)股价为例):
import yfinance as yf
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from pykalman import KalmanFilter
# ---------------------- 1. 获取股市数据 ----------------------
# 下载特斯拉(TSLA)近1年的日线数据
ticker = "TSLA"
start_date = "2025-01-01"
end_date = "2026-02-10"
data = yf.download(ticker, start=start_date, end=end_date)
# 提取收盘价作为分析标的
close_price = data["Close"].values
dates = data.index # 日期索引
# ---------------------- 2. 构建卡尔曼滤波器 ----------------------
# 初始化卡尔曼滤波参数(适用于股价这类连续时序数据)
kf = KalmanFilter(
# 状态转移矩阵(假设股价的变化是线性的)
transition_matrices=[[1]],
# 观测矩阵(直接观测股价)
observation_matrices=[[1]],
# 过程噪声协方差(控制趋势平滑程度,值越大越贴合原始数据)
transition_covariance=[[0.01]],
# 观测噪声协方差(控制噪声过滤程度,值越大过滤越明显)
observation_covariance=[[1]],
# 初始状态估计(用第一个收盘价)
initial_state_mean=close_price[0],
# 初始状态协方差
initial_state_covariance=1
)
# 对收盘价进行滤波(得到平滑后的股价)
state_means, state_covariances = kf.filter(close_price)
# 预测下一时刻的股价(可选)
#predicted_mean, predicted_cov = kf.predict(state_means[-1], state_covariances[-1])
# ---------------------- 3. 数据整理与可视化 ----------------------
# 将结果整合到DataFrame中
result = pd.DataFrame({
"Date": dates,
"Original_Close": close_price,
"Kalman_Smoothed": state_means.flatten() # 展平数组
}).set_index("Date")
# 绘制原始股价与卡尔曼滤波后的股价对比图
plt.figure(figsize=(12, 6))
plt.plot(result["Original_Close"], label="原始收盘价", color="gray", alpha=0.6)
plt.plot(result["Kalman_Smoothed"], label="卡尔曼滤波后股价", color="red", linewidth=2)
plt.title(f"{ticker} 股价卡尔曼滤波降噪分析")
plt.xlabel("日期")
plt.ylabel("价格(美元)")
plt.legend()
plt.grid(True, alpha=0.3)
plt.xticks(rotation=45)
plt.tight_layout()
plt.show()
# ---------------------- 4. 简单交易信号生成(示例) ----------------------
# 逻辑:滤波后的股价上穿原始股价,视为买入信号;下穿视为卖出信号
result["Signal"] = 0
# 买入信号:滤波值 > 原始值 且 前一时刻滤波值 <= 原始值
result.loc[(result["Kalman_Smoothed"] > result["Original_Close"]) &
(result["Kalman_Smoothed"].shift(1) <= result["Original_Close"].shift(1)),
"Signal"] = 1
# 卖出信号:滤波值 < 原始值 且 前一时刻滤波值 >= 原始值
result.loc[(result["Kalman_Smoothed"] < result["Original_Close"]) &
(result["Kalman_Smoothed"].shift(1) >= result["Original_Close"].shift(1)),
"Signal"] = -1
# 输出有交易信号的日期
signal_dates = result[result["Signal"] != 0]
print("\n交易信号汇总(1=买入,-1=卖出):")
print(signal_dates[["Original_Close", "Kalman_Smoothed", "Signal"]].head(10))
# 输出下一时刻股价预测值
#print(f"\n预测下一时刻{data.index[-1] + pd.Timedelta(days=1)}的股价估值:{predicted_mean[0]:.2f} 美元")
三、关键代码解释
- 数据获取:使用
yfinance下载免费的美股数据,你也可以替换为A股数据(需调整ticker,如"600000.ss"代表浦发银行)。 - 卡尔曼滤波参数:
transition_covariance:过程噪声,值越小,滤波后的曲线越平滑(对短期波动不敏感);值越大,越贴近原始数据。observation_covariance:观测噪声,值越大,过滤噪声的效果越强。
- 滤波与预测:
kf.filter()输出平滑后的股价序列,kf.predict()可以预测下一个时刻的股价估值。 - 交易信号:通过对比滤波后股价与原始股价的交叉关系,生成简单的买卖信号(仅作示例,实际交易需结合更多指标)。
四、使用注意事项
- 环境要求:Python 3.7+,
pykalman版本建议 0.9.5+(避免版本兼容问题)。 - 数据适配:如果分析A股,需注意交易日非连续(周末/节假日),可先对数据做缺失值处理。
- 参数调优:卡尔曼滤波的参数(如协方差)需要根据不同股票、不同周期(日线/小时线)调整,没有通用最优值。
总结
pykalman核心作用是对带噪声的股价时序数据做平滑降噪,提取核心趋势,比简单的移动平均线更灵活;- 卡尔曼滤波的参数(过程/观测协方差)决定了平滑程度,需根据分析标的调整;
- 基于滤波后的股价可构建简单的趋势跟踪信号,但股市分析需结合基本面、其他技术指标,不可单一依赖卡尔曼滤波。
上面的例子 将 yfinance 改为 tushare , 将 TSLA 改为中国A股: 300308
你希望把之前基于 yfinance 获取美股数据的代码,改成用 tushare 获取中国A股(300308 中际旭创)的数据,同时适配A股的交易规则和数据格式。
一、核心准备
- 安装/升级 tushare:
pip install tushare --upgrade
- tushare 授权:你需要在 tushare 官网(https://tushare.pro/)注册账号,获取你的
token(个人中心-接口TOKEN),替换代码中的your_tushare_token。
二、适配A股的完整代码
# -*- coding: utf-8 -*-
from datetime import datetime
import tushare as ts
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from pykalman import KalmanFilter
import warnings
warnings.filterwarnings('ignore') # 忽略无关警告
# ---------------------- 1. 初始化tushare并获取A股数据 ----------------------
# 替换为你的tushare token
ts.set_token('your_tushare_token')
pro = ts.pro_api()
today = datetime.now().strftime('%Y%m%d')
print(today)
# 获取300308 中际旭创 近1年的日线数据
# 参数说明:
# ts_code: 股票代码(格式:6位代码+交易所,创业板300开头是sz)
# start_date/end_date: 日期格式YYYYMMDD
# adj: 复权类型,qfq=前复权(推荐,消除除权除息影响)
ticker = "300308.SZ"
start_date = "20250101"
end_date = today
# 获取日线数据
df = pro.daily(
ts_code=ticker,
start_date=start_date,
end_date=end_date,
adj='qfq' # 前复权,保证股价连续性
)
# 数据预处理:tushare返回的数据是倒序,需按日期升序排列
df['trade_date'] = pd.to_datetime(df['trade_date'], format='%Y%m%d')
df = df.sort_values('trade_date').reset_index(drop=True)
# 提取收盘价和日期(A股核心字段与美股不同)
close_price = df['close'].values # A股收盘价字段是close
dates = df['trade_date'] # 交易日期
# 检查数据是否获取成功
if len(df) == 0:
print(" 数据获取失败,请检查token有效性或日期范围!")
else:
print(f" 成功获取 {ticker} 共 {len(df)} 条日线数据")
# ---------------------- 2. 构建卡尔曼滤波器(适配A股数据) ----------------------
# 初始化卡尔曼滤波参数(针对A股波动特点微调)
kf = KalmanFilter(
transition_matrices=[[1]], # 状态转移矩阵
observation_matrices=[[1]], # 观测矩阵
transition_covariance=[[0.02]], # 过程噪声(A股波动更大,略调大)
observation_covariance=[[1.5]], # 观测噪声(适配A股噪声特征)
initial_state_mean=close_price[0], # 初始状态(第一个收盘价)
initial_state_covariance=1 # 初始状态协方差
)
# 对收盘价进行滤波(平滑降噪)
state_means, state_covariances = kf.filter(close_price)
# 预测下一交易日股价
#predicted_mean, predicted_cov = kf.predict(state_means[-1], state_covariances[-1])
# ---------------------- 3. 数据整理与可视化(适配A股显示) ----------------------
# 整合结果到DataFrame
result = pd.DataFrame({
"Date": dates,
"Original_Close": close_price,
"Kalman_Smoothed": state_means.flatten()
}).set_index("Date")
# 绘制A股股价对比图(适配中文显示)
plt.rcParams['font.sans-serif'] = ['SimHei'] # 解决中文显示问题
plt.rcParams['axes.unicode_minus'] = False # 解决负号显示问题
plt.figure(figsize=(12, 6))
plt.plot(result["Original_Close"], label="原始收盘价", color="gray", alpha=0.6)
plt.plot(result["Kalman_Smoothed"], label="卡尔曼滤波后股价", color="#FF4500", linewidth=2)
plt.title(f"{ticker} 中际旭创 股价卡尔曼滤波降噪分析", fontsize=14)
plt.xlabel("日期", fontsize=12)
plt.ylabel("价格(元)", fontsize=12)
plt.legend(fontsize=10)
plt.grid(True, alpha=0.3)
plt.xticks(rotation=45)
plt.tight_layout()
plt.show()
# ---------------------- 4. A股交易信号生成(适配A股规则) ----------------------
# 逻辑:滤波股价上穿原始股价=买入信号,下穿=卖出信号(A股T+1,信号仅作参考)
result["Signal"] = 0
# 买入信号:当前滤波值>原始值 且 前一刻滤波值<=原始值
result.loc[(result["Kalman_Smoothed"] > result["Original_Close"]) &
(result["Kalman_Smoothed"].shift(1) <= result["Original_Close"].shift(1)),
"Signal"] = 1
# 卖出信号:当前滤波值<原始值 且 前一刻滤波值>=原始值
result.loc[(result["Kalman_Smoothed"] < result["Original_Close"]) &
(result["Kalman_Smoothed"].shift(1) >= result["Original_Close"].shift(1)),
"Signal"] = -1
# 输出交易信号(仅展示前10条)
signal_dates = result[result["Signal"] != 0]
print("\n 交易信号汇总(1=买入,-1=卖出):")
if len(signal_dates) > 0:
print(signal_dates[["Original_Close", "Kalman_Smoothed", "Signal"]].head(10))
else:
print("暂无交易信号")
# 输出下一交易日预测股价
next_trade_date = df['trade_date'].iloc[-1] + pd.Timedelta(days=1)
# 简单跳过非交易日(实际需结合A股交易日历)
while next_trade_date.weekday() in [5,6]: # 周六/周日跳过
next_trade_date += pd.Timedelta(days=1)
#print(f"\n 预测下一交易日 {next_trade_date.strftime('%Y-%m-%d')} 股价估值:{predicted_mean[0]:.2f} 元")
三、关键适配点解释
-
数据获取适配:
tushare需要token授权,必须替换成你自己的;- A股代码格式是「6位代码+交易所」(300308.SZ 代表深交所创业板);
- 字段名差异:美股
Close→ A股close,日期字段index→trade_date; - 增加了前复权(
adj='qfq'),消除除权除息对股价的影响,这是A股分析的必要步骤。
-
参数微调:
- A股整体波动比美股更大,因此将
transition_covariance从 0.01 调到 0.02,observation_covariance从 1 调到 1.5,让滤波曲线更适配A股特征。
- A股整体波动比美股更大,因此将
-
可视化适配:
- 增加了中文显示配置(
plt.rcParams),解决matplotlib中文乱码问题; - 价格单位从「美元」改为「元」,标题适配A股名称(中际旭创)。
- 增加了中文显示配置(
-
交易规则适配:
- 提示A股「T+1」规则,信号仅作参考;
- 预测下一交易日时,自动跳过周末(简单适配非交易日)。
四、使用注意事项
- token 有效性:如果获取数据失败,先检查
token是否正确,以及tushare账号是否有足够的积分(基础日线数据需要100积分,注册后可免费获取); - 日期范围:tushare的
start_date/end_date格式是YYYYMMDD,且不能超过当前日期; - 非交易日处理:代码中仅简单跳过周末,实际A股还有节假日,如需精准可结合
pro.trade_cal()获取交易日历。
总结
- 核心改动是将数据来源从
yfinance替换为tushare,并适配A股的代码格式(300308.SZ)和字段名; - 针对A股波动特征微调了卡尔曼滤波的协方差参数,同时解决了中文显示、非交易日等A股特有的问题;
- 使用前必须替换自己的tushare token,且确保账号有足够积分获取日线数据。
AttributeError: ‘KalmanFilter’ object has no attribute ‘predict’
你遇到的报错是因为 pykalman 库的版本问题——低版本的 KalmanFilter 类没有独立的 predict 方法,导致代码执行到预测股价这一步时触发 AttributeError。
一、报错原因分析
pykalman 不同版本的API存在差异:
- 旧版本(如0.9.5以下):
predict方法不是独立调用的,而是整合在filter过程中; - 新版本:支持独立的
kf.predict()调用。
你的环境中安装的是旧版本,因此会提示“没有predict属性”。
二、修复后的完整代码
下面是适配低版本 pykalman 的代码,核心改动是移除独立的 predict 调用,改用滤波过程的递推预测,同时保留所有核心功能:
import tushare as ts
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from pykalman import KalmanFilter
import warnings
warnings.filterwarnings('ignore') # 忽略无关警告
# ---------------------- 1. 初始化tushare并获取A股数据 ----------------------
# 替换为你的tushare token
ts.set_token('your_tushare_token')
pro = ts.pro_api()
# 获取300308 中际旭创 近1年的日线数据
ticker = "300308.SZ"
start_date = "20250210"
end_date = "20260210"
# 获取日线数据
df = pro.daily(
ts_code=ticker,
start_date=start_date,
end_date=end_date,
adj='qfq' # 前复权,保证股价连续性
)
# 数据预处理:tushare返回的数据是倒序,需按日期升序排列
df['trade_date'] = pd.to_datetime(df['trade_date'], format='%Y%m%d')
df = df.sort_values('trade_date').reset_index(drop=True)
# 提取收盘价和日期(A股核心字段与美股不同)
close_price = df['close'].values # A股收盘价字段是close
dates = df['trade_date'] # 交易日期
# 检查数据是否获取成功
if len(df) == 0:
print("⚠️ 数据获取失败,请检查token有效性或日期范围!")
else:
print(f"✅ 成功获取 {ticker} 共 {len(df)} 条日线数据")
# ---------------------- 2. 构建卡尔曼滤波器(适配低版本pykalman) ----------------------
# 初始化卡尔曼滤波参数(针对A股波动特点微调)
kf = KalmanFilter(
transition_matrices=[[1]], # 状态转移矩阵
observation_matrices=[[1]], # 观测矩阵
transition_covariance=[[0.02]], # 过程噪声(A股波动更大,略调大)
observation_covariance=[[1.5]], # 观测噪声(适配A股噪声特征)
initial_state_mean=close_price[0], # 初始状态(第一个收盘价)
initial_state_covariance=1 # 初始状态协方差
)
# 对收盘价进行滤波(平滑降噪)
# 低版本pykalman:filter返回的是逐步的预测+更新结果
state_means, state_covariances = kf.filter(close_price)
# 适配低版本的预测逻辑:用最后一次滤波结果递推预测下一时刻
# 核心公式:预测均值 = 状态转移矩阵 × 最后一次滤波均值
# 预测协方差 = 状态转移矩阵 × 最后一次协方差 × 转移矩阵转置 + 过程噪声
last_mean = state_means[-1]
last_cov = state_covariances[-1]
transition_matrix = kf.transition_matrices
# 计算下一时刻预测值(替代原predict方法)
predicted_mean = np.dot(transition_matrix, last_mean)
predicted_cov = np.dot(np.dot(transition_matrix, last_cov), transition_matrix.T) + kf.transition_covariance
# ---------------------- 3. 数据整理与可视化(适配A股显示) ----------------------
# 整合结果到DataFrame
result = pd.DataFrame({
"Date": dates,
"Original_Close": close_price,
"Kalman_Smoothed": state_means.flatten()
}).set_index("Date")
# 绘制A股股价对比图(适配中文显示)
plt.rcParams['font.sans-serif'] = ['SimHei'] # 解决中文显示问题
plt.rcParams['axes.unicode_minus'] = False # 解决负号显示问题
plt.figure(figsize=(12, 6))
plt.plot(result["Original_Close"], label="原始收盘价", color="gray", alpha=0.6)
plt.plot(result["Kalman_Smoothed"], label="卡尔曼滤波后股价", color="#FF4500", linewidth=2)
plt.title(f"{ticker} 中际旭创 股价卡尔曼滤波降噪分析", fontsize=14)
plt.xlabel("日期", fontsize=12)
plt.ylabel("价格(元)", fontsize=12)
plt.legend(fontsize=10)
plt.grid(True, alpha=0.3)
plt.xticks(rotation=45)
plt.tight_layout()
plt.show()
# ---------------------- 4. A股交易信号生成(适配A股规则) ----------------------
# 逻辑:滤波股价上穿原始股价=买入信号,下穿=卖出信号(A股T+1,信号仅作参考)
result["Signal"] = 0
# 买入信号:当前滤波值>原始值 且 前一刻滤波值<=原始值
result.loc[(result["Kalman_Smoothed"] > result["Original_Close"]) &
(result["Kalman_Smoothed"].shift(1) <= result["Original_Close"].shift(1)),
"Signal"] = 1
# 卖出信号:当前滤波值<原始值 且 前一刻滤波值>=原始值
result.loc[(result["Kalman_Smoothed"] < result["Original_Close"]) &
(result["Kalman_Smoothed"].shift(1) >= result["Original_Close"].shift(1)),
"Signal"] = -1
# 输出交易信号(仅展示前10条)
signal_dates = result[result["Signal"] != 0]
print("\n📊 交易信号汇总(1=买入,-1=卖出):")
if len(signal_dates) > 0:
print(signal_dates[["Original_Close", "Kalman_Smoothed", "Signal"]].head(10))
else:
print("暂无交易信号")
# 输出下一交易日预测股价
next_trade_date = df['trade_date'].iloc[-1] + pd.Timedelta(days=1)
# 简单跳过非交易日(实际需结合A股交易日历)
while next_trade_date.weekday() in [5,6]: # 周六/周日跳过
next_trade_date += pd.Timedelta(days=1)
print(f"\n📈 预测下一交易日 {next_trade_date.strftime('%Y-%m-%d')} 股价估值:{predicted_mean[0]:.2f} 元")
三、关键修复点解释
-
移除
kf.predict()调用:
低版本pykalman没有独立的predict方法,因此我们用卡尔曼滤波的核心公式手动计算下一时刻的预测值:- 预测均值:
predicted_mean = 状态转移矩阵 × 最后一次滤波均值 - 预测协方差:
predicted_cov = 转移矩阵 × 最后协方差 × 转移矩阵转置 + 过程噪声
这个计算逻辑和内置predict方法完全一致,只是手动实现适配低版本。
- 预测均值:
-
保留核心功能:
除了预测部分的实现方式,其他功能(数据获取、滤波平滑、可视化、交易信号)完全保留,且结果和原代码一致。
四、可选方案:升级pykalman
如果你想使用原版的 predict 方法,也可以直接升级 pykalman 到最新版本:
pip install --upgrade pykalman
升级后,你之前的代码(带 kf.predict())就能正常运行。
总结
- 报错核心原因是
pykalman版本过低,没有独立的predict方法; - 解决方案有两种:要么用卡尔曼滤波公式手动实现预测(适配低版本),要么升级
pykalman到最新版; - 修复后的代码保留了所有核心功能,且完全适配A股300308的数据分析场景。
魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐



所有评论(0)