Python 金融时间序列实战:股票数据分析 + 线性回归 + ARIMA 双模型股价预测(附完整代码)
一、前言
在量化金融领域,股票价格预测是时间序列分析最经典的落地场景之一。股票数据具备典型的时序特征:价格、成交量、涨跌幅等指标随时间连续变化,同时存在趋势性、波动性等规律。
本文将基于 Python 完成一套全流程股票时序分析项目,包含数据读取、数据预处理、多维度可视化(均线、K 线、成交量、涨跌幅分布)、特征工程、模型训练、效果对比、未来股价预测等环节。分别使用线性回归和ARIMA 时间序列模型构建预测模型,并对比两者效果,适合 Python 数据分析、时序建模、量化入门学习者参考。
技术栈:pandas(数据处理)、matplotlib(可视化)、pyecharts(交互式 K 线)、scikit-learn(线性回归 + 模型评估)、statsmodels(ARIMA 时序模型)
数据集:本地 Excel 股票行情数据(包含交易日期、开盘价、收盘价、最高价、最低价、成交量、涨跌幅、5/10/20 日均线等字段)
二、环境准备与依赖安装
运行代码前,确保安装所需第三方库,打开终端执行以下命令:
bash
运行
# 基础数据分析库
pip install pandas numpy matplotlib
# 交互式K线图
pip install pyecharts
# 机器学习+时序模型
pip install scikit-learn statsmodels
三、完整项目实战(分步代码 + 详细讲解)
3.1 导入库 + 全局配置(解决中文 / 负号乱码)
Matplotlib 默认不支持中文,首先进行全局配置,避免图表中文、负号显示异常。
python
运行
# 导入基础库
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
# 全局设置:解决Matplotlib中文、负号显示问题
plt.rcParams["font.family"] = "SimHei" # 黑体(Windows)
plt.rcParams["axes.unicode_minus"] = False # 关闭负号Unicode编码
3.2 读取数据 + 数据探查
读取本地股价数据.xlsx文件,查看数据结构、样本量、缺失值,掌握数据基本情况。
python
运行
# 1. 读取Excel股票数据
df = pd.read_excel("股价数据.xlsx")
# 2. 查看前5行数据
print("数据前5行:")
print(df.head())
# 3. 查看数据基本信息(字段类型、样本数)
print("\n数据基本信息:")
df.info()
# 4. 统计每列缺失值数量
print("\n各字段缺失值统计:")
print(df.isnull().sum())
输出说明: 数据集共 611 条交易数据,包含 14 个字段,所有字段均无缺失值,数据质量良好,无需额外填充缺失值。核心字段说明:
date:交易日期(字符串类型,后续需转为时间格式)open/high/close/low:开盘价、最高价、收盘价、最低价volume:成交量;p_change:单日涨跌幅ma5/ma10/ma20:5/10/20 日移动平均线(股票常用技术指标)
3.3 数据预处理(时序分析核心步骤)
股票时间序列必须保证数据按时间升序排列,同时转换日期格式、精简字段、重置索引,这是后续建模的基础。
python
运行
# 1. 将日期列转为标准datetime时间格式(时序分析必备)
df['date'] = pd.to_datetime(df['date'])
# 2. 按交易日期升序排序(从早到晚,修正原始数据乱序问题)
df.sort_values(by='date', inplace=True)
# 3. 保留核心业务字段,剔除冗余列
df = df[['date','open','close','high','low',
'volume','p_change','ma5','ma10','ma20']]
# 4. 重置行索引(排序后索引错乱,重新生成连续索引)
df.reset_index(drop=True, inplace=True)
# 查看预处理后数据
print("预处理后数据前5行:")
print(df.head())
3.4 数据可视化探索(多维度图表分析)
通过可视化挖掘股价、成交量、涨跌幅的分布与趋势规律,共实现4 类经典图表。
3.4.1 收盘价 + 均线趋势图
绘制收盘价与 5/10/20 日均线,观察股价中长期走势与均线支撑 / 压力作用。
python
运行
# 设置画布大小
plt.figure(figsize=(14,6))
# 绘制曲线
plt.plot(df['date'], df['close'], label="收盘价", linewidth=2)
plt.plot(df['date'], df['ma5'], label='5日均线', linestyle='--')
plt.plot(df['date'], df['ma10'], label='10日均线', linestyle='--')
plt.plot(df['date'], df['ma20'], label='20日均线', linestyle='--')
# 图表美化
plt.grid(alpha=0.3) # 半透明网格
plt.legend() # 图例
plt.title('收盘价与均线走势图')
plt.show()
3.4.2 交互式 K 线图(pyecharts)
K 线图是股票分析标配,使用pyecharts绘制交互式 K 线,支持缩放、下载、数据查看,适配 Jupyter Notebook。
python
运行
# 导入pyecharts组件
from pyecharts.charts import Kline
from pyecharts import options as opts
# 构造K线数据:顺序必须为 open、close、high、low
y = df[['open','close','high','low']].values.tolist()
# 构建K线图
kline = (
Kline()
.add_xaxis(df['date'].tolist()) # X轴:交易日期
.add_yaxis('股票K线图', y) # Y轴:K线四要素
.set_global_opts(
title_opts=opts.TitleOpts(title='股票K线图'),
toolbox_opts=opts.ToolboxOpts(is_show=True) # 开启工具箱(缩放、下载)
)
)
# 在Notebook中渲染图表
kline.render_notebook()
3.4.3 成交量柱状图
用柱状图展示每日成交量变化,结合股价可分析量价关系(放量上涨、缩量下跌等)。
python
运行
plt.figure(figsize=(14,6))
plt.bar(df['date'], df['volume'])
plt.title('股票成交量柱状图')
plt.show()
3.4.4 涨跌幅分布直方图
统计单日涨跌幅的分布情况,红色虚线标记涨跌分界线(0%),观察股票涨跌概率分布。
python
运行
plt.figure(figsize=(14,6))
# 绘制直方图,bins=40 划分40个统计区间
plt.hist(df['p_change'], bins=40)
# 绘制涨跌分界线(X=0,红色虚线)
plt.axvline(0, color='red', linestyle='--', label='涨跌分界线')
plt.legend()
plt.title('股票涨跌幅分布直方图')
plt.show()
3.5 特征工程 + 划分训练集 / 测试集
时间序列建模不能随机划分数据集(会破坏时序连续性),本文采用前 80% 为训练集,后 20% 为测试集的划分方式。同时构造滞后特征(前一日收盘价),提升模型精度。
python
运行
# 1. 构造滞后特征:前1天收盘价(时序经典特征)
df["close_lag1"] = df["close"].shift(1)
# 2. 剔除滞后特征产生的空值(第一行无昨日数据)
df = df.dropna()
# 3. 按时间比例划分数据集:80%训练集,20%测试集
split = int(len(df) * 0.8)
train = df.iloc[:split] # 前80% 训练集
test = df.iloc[split:] # 后20% 测试集
# 4. 定义特征列与预测标签
# 特征:前一日收盘价、开盘价、5日均线
feature_cols = ["close_lag1", "open", "ma5"]
X_train = train[feature_cols]
y_train = train["close"] # 标签:当日收盘价
X_test = test[feature_cols]
y_test = test["close"]
# 输出数据集规模
print(f"训练集样本数:{len(train)} 条 | 测试集样本数:{len(test)} 条")
3.6 模型一:线性回归模型(传统机器学习)
使用线性回归构建股价预测模型,封装统一评估函数,通过 MAE、RMSE、R² 三大指标评估模型效果。
python
运行
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_absolute_error, mean_squared_error, r2_score
# 定义模型评估函数(统一计算三大回归指标)
def eval_model(y_true, y_pred):
mae = mean_absolute_error(y_true, y_pred) # 平均绝对误差
rmse = np.sqrt(mean_squared_error(y_true, y_pred))# 均方根误差
r2 = r2_score(y_true, y_pred) # 拟合优度
print(f"MAE(平均绝对误差): {mae:.2f}")
print(f"RMSE(均方根误差): {rmse:.2f}")
print(f"R²(拟合度): {r2:.2f}")
# 1. 初始化并训练线性回归模型
lr = LinearRegression()
lr.fit(X_train, y_train)
# 2. 测试集预测
y_pred_lr = lr.predict(X_test)
# 3. 模型评估
print("===== 线性回归模型评估结果 =====")
eval_model(y_test, y_pred_lr)
# 4. 可视化:真实收盘价 VS 线性回归预测值
plt.figure(figsize=(14, 6))
plt.plot(test["date"], y_test, label="真实收盘价", linewidth=2)
plt.plot(test["date"], y_pred_lr, label="线性回归预测", linestyle="--")
plt.title("线性回归股价预测结果")
plt.xlabel("日期")
plt.ylabel("股价")
plt.legend()
plt.grid(alpha=0.3)
plt.show()
指标解读:
MAE/RMSE:数值越小,代表预测值与真实值偏差越小;R²:取值 0~1,越接近 1 说明模型拟合效果越好,本文模型 R² 达到 0.98,拟合效果优秀。
3.7 模型二:ARIMA 时间序列模型(专业时序算法)
ARIMA 是时间序列领域经典模型,本文采用滚动单步预测(模拟真实行情:预测一天后,将真实数据纳入模型再预测下一天),贴合股票实时预测场景。
python
运行
from statsmodels.tsa.arima.model import ARIMA
# 1. 初始化历史数据与预测列表
history = list(train["close"]) # 初始历史数据:训练集收盘价
predictions = [] # 存储测试集预测结果
# 2. 滚动单步预测(核心逻辑)
for i in range(len(test)):
# 构建ARIMA模型,order=(p,d,q)=(10,1,0)
model = ARIMA(history, order=(10, 1, 0))
model_fit = model.fit() # 模型训练
yhat = model_fit.forecast()[0] # 预测未来1步
predictions.append(yhat)
# 关键:将当日真实收盘价加入历史数据,更新模型
history.append(test["close"].iloc[i])
# 转为数组,适配评估函数
y_pred_arima = np.array(predictions)
# 3. ARIMA模型评估
print("\n===== ARIMA模型评估结果 =====")
eval_model(y_test, y_pred_arima)
3.8 双模型预测效果同图对比
将真实值、线性回归预测值、ARIMA 预测值绘制在同一张图表中,直观对比两个模型的优劣。
python
运行
# 双模型综合对比图
plt.figure(figsize=(15, 6))
plt.plot(test["date"], y_test, label="真实收盘价", linewidth=2)
plt.plot(test["date"], y_pred_lr, label="线性回归", linestyle="--")
plt.plot(test["date"], y_pred_arima, label="ARIMA", linestyle="--", color="red")
plt.title("线性回归 VS ARIMA 双模型预测效果对比")
plt.legend()
plt.grid(alpha=0.3)
plt.show()
3.9 ARIMA 模型预测未来 10 个交易日股价
使用全量历史数据训练 ARIMA 模型,预测未来 10 个交易日收盘价,实现落地预测需求。
python
运行
# 1. 全量收盘价数据训练ARIMA模型
full_series = df["close"]
final_arima = ARIMA(full_series, order=(5, 1, 0)).fit()
# 2. 预测未来10步(10个交易日)
future_pred = final_arima.get_forecast(steps=10).predicted_mean
# 3. 格式化输出预测结果
print("\n==== 未来10个交易日收盘价预测 ====")
for i, val in enumerate(future_pred, 1):
print(f"第{i}天预测股价: {val:.2f} 元")
补充说明:代码运行会出现
ValueWarning,原因是数据集未设置时间索引,不影响预测结果,可忽略该警告。
四、项目结果分析与总结
4.1 模型指标对比
表格
| 模型 | MAE(平均绝对误差) | RMSE(均方根误差) | R²(拟合优度) |
|---|---|---|---|
| 线性回归 | 0.16 | 0.21 | 0.98 |
| ARIMA | 0.18 | 0.25 | 0.97 |
- 精度对比:线性回归模型整体误差略低于 ARIMA,拟合效果更优;两个模型 R² 均接近 0.97 以上,对该股票短期走势预测能力较强。
- 场景差异
- 线性回归:依赖人工特征工程(滞后特征、均线、开盘价),适合特征维度较多的场景,训练速度快;
- ARIMA:纯时序模型,仅依赖历史价格序列,无需复杂特征,适合单变量时序预测,滚动预测耗时更长。
4.2 可视化结论
- 股价与均线走势高度同步,5 日均线贴合短期价格波动,20 日均线反映中长期趋势;
- 该股票涨跌幅主要集中在 0 附近,小幅涨跌为常态,大幅涨跌样本较少;
- 两个模型的预测曲线均与真实股价走势高度重合,无明显偏离。
4.3 项目亮点与拓展方向
项目亮点
- 完整闭环:从数据读取→预处理→可视化→特征工程→建模→评估→未来预测,覆盖时序项目全流程;
- 双模型对比:结合传统机器学习与时序专用算法,适合学习不同建模思路;
- 实战性强:滚动预测、滞后特征、K 线图等均为量化金融行业通用方案。
拓展优化(进阶玩法)
- 模型优化:调优 ARIMA 的
order(p,d,q)参数、使用网格搜索优化线性回归;尝试 LSTM、Prophet 等更先进的时序模型; - 特征升级:新增成交量、换手率、RSI、MACD 等金融指标,提升模型精度;
- 数据增强:使用
tushare/akshare接口抓取实时股票数据,替代本地 Excel; - 异常处理:针对股市停牌、涨跌停等特殊数据做清洗优化。
五、完整代码汇总
将以上所有代码整合,可直接复制到 Jupyter Notebook / PyCharm 中运行:
python
运行
# ========== 1. 库导入 + 全局配置 ==========
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
from pyecharts.charts import Kline
from pyecharts import options as opts
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_absolute_error, mean_squared_error, r2_score
from statsmodels.tsa.arima.model import ARIMA
# 解决中文、负号乱码
plt.rcParams["font.family"] = "SimHei"
plt.rcParams["axes.unicode_minus"] = False
# ========== 2. 数据读取与探查 ==========
df = pd.read_excel("股价数据.xlsx")
print("数据前5行:")
print(df.head())
print("\n数据基本信息:")
df.info()
print("\n缺失值统计:")
print(df.isnull().sum())
# ========== 3. 数据预处理 ==========
df['date'] = pd.to_datetime(df['date'])
df.sort_values(by='date', inplace=True)
df = df[['date','open','close','high','low','volume','p_change','ma5','ma10','ma20']]
df.reset_index(drop=True, inplace=True)
print("\n预处理后数据:")
print(df.head())
# ========== 4. 数据可视化 ==========
# 4.1 均线走势图
plt.figure(figsize=(14,6))
plt.plot(df['date'], df['close'], label="收盘价", linewidth=2)
plt.plot(df['date'], df['ma5'], label='5日均线', linestyle='--')
plt.plot(df['date'], df['ma10'], label='10日均线', linestyle='--')
plt.plot(df['date'], df['ma20'], label='20日均线', linestyle='--')
plt.grid(alpha=0.3)
plt.legend()
plt.title('收盘价与均线走势图')
plt.show()
# 4.2 K线图
y = df[['open','close','high','low']].values.tolist()
kline = (
Kline()
.add_xaxis(df['date'].tolist())
.add_yaxis('股票K线图', y)
.set_global_opts(
title_opts=opts.TitleOpts(title='股票K线图'),
toolbox_opts=opts.ToolboxOpts(is_show=True)
)
)
kline.render_notebook()
# 4.3 成交量柱状图
plt.figure(figsize=(14,6))
plt.bar(df['date'], df['volume'])
plt.title('股票成交量柱状图')
plt.show()
# 4.4 涨跌幅直方图
plt.figure(figsize=(14,6))
plt.hist(df['p_change'], bins=40)
plt.axvline(0, color='red', linestyle='--', label='涨跌分界线')
plt.legend()
plt.title('股票涨跌幅分布直方图')
plt.show()
# ========== 5. 特征工程 + 数据集划分 ==========
df["close_lag1"] = df["close"].shift(1)
df = df.dropna()
split = int(len(df) * 0.8)
train = df.iloc[:split]
test = df.iloc[split:]
feature_cols = ["close_lag1", "open", "ma5"]
X_train = train[feature_cols]
y_train = train["close"]
X_test = test[feature_cols]
y_test = test["close"]
print(f"\n训练集:{len(train)} 条 | 测试集:{len(test)} 条")
# ========== 6. 模型评估函数 ==========
def eval_model(y_true, y_pred):
mae = mean_absolute_error(y_true, y_pred)
rmse = np.sqrt(mean_squared_error(y_true, y_pred))
r2 = r2_score(y_true, y_pred)
print(f"MAE(平均绝对误差): {mae:.2f}")
print(f"RMSE(均方根误差): {rmse:.2f}")
print(f"R²(拟合度): {r2:.2f}")
# ========== 7. 线性回归模型 ==========
lr = LinearRegression()
lr.fit(X_train, y_train)
y_pred_lr = lr.predict(X_test)
print("\n===== 线性回归模型评估 =====")
eval_model(y_test, y_pred_lr)
# 线性回归可视化
plt.figure(figsize=(14, 6))
plt.plot(test["date"], y_test, label="真实收盘价", linewidth=2)
plt.plot(test["date"], y_pred_lr, label="线性回归预测", linestyle="--")
plt.title("线性回归股价预测结果")
plt.xlabel("日期")
plt.ylabel("股价")
plt.legend()
plt.grid(alpha=0.3)
plt.show()
# ========== 8. ARIMA时序模型 ==========
history = list(train["close"])
predictions = []
for i in range(len(test)):
model = ARIMA(history, order=(10, 1, 0))
model_fit = model.fit()
yhat = model_fit.forecast()[0]
predictions.append(yhat)
history.append(test["close"].iloc[i])
y_pred_arima = np.array(predictions)
print("\n===== ARIMA模型评估 =====")
eval_model(y_test, y_pred_arima)
# ========== 9. 双模型对比可视化 ==========
plt.figure(figsize=(15, 6))
plt.plot(test["date"], y_test, label="真实收盘价", linewidth=2)
plt.plot(test["date"], y_pred_lr, label="线性回归", linestyle="--")
plt.plot(test["date"], y_pred_arima, label="ARIMA", linestyle="--", color="red")
plt.title("线性回归 VS ARIMA 双模型预测效果对比")
plt.legend()
plt.grid(alpha=0.3)
plt.show()
# ========== 10. 预测未来10个交易日 ==========
full_series = df["close"]
final_arima = ARIMA(full_series, order=(5, 1, 0)).fit()
future_pred = final_arima.get_forecast(steps=10).predicted_mean
print("\n==== 未来10个交易日收盘价预测 ====")
for i, val in enumerate(future_pred, 1):
print(f"第{i}天预测股价: {val:.2f} 元")
六、结语
本文完成了一套落地可用的股票时间序列分析与预测项目,兼顾代码实操、原理讲解与结果分析,非常适合 Python 数据分析、量化交易、时间序列入门学习。金融时序数据具有高波动性、非线性的特点,单一模型很难做到 100% 精准预测,在实际量化场景中,通常会采用多模型融合 + 风控策略提升稳定性。
更多推荐



所有评论(0)