新闻详情

新闻详情

首页 / 资讯中心 / 详情

相关性分析结合CNN-Attention-LSTM的期货价格预测方法

发布时间:2026/9/12 23:43:48来源:尧图网络
相关性分析结合CNN-Attention-LSTM的期货价格预测方法
简介一套面向计算机课程设计与期末大作业的CNN-Attention-LSTM期货价格预测Python项目整合相关性分析、卷积、注意力与长短期记忆网络解决金融时间序列预测中的特征筛选与趋势建模问题适合正在做课程设计、期末大作业或项目实战练习的学生使用。压缩包内共29个文件包含8个Python源码模块涉及训练、预测、Web API、6个Numpy数据文件、3个Excel数据表、2个TensorFlow模型权重文件、2份PDF使用教程、SQL数据库备份与热力图等辅助材料整体约30.29MB目录结构清晰便于按模块检索。目前已有258人学习下载。项目附带详细中文注释、训练好的模型权重及预处理好的数据集可直接运行复现从原始SQL数据导入、Excel预处理、相关性分析、时间步处理到CNN-Attention-LSTM模型训练与预测全流程均有对应脚本和独立算法说明尤其适合作为课程设计或毕业设计的完整参考。1. 期货价格预测为什么需要“先相关性分析再进 CNN-Attention-LSTM”期货价格预测和普通的时间序列预测不一样同样是分钟线或日线数据期货市场里既有成交量、持仓量这些自身量价指标也有跨品种、跨周期的传导关系特征维度动辄几十个。直接把这一堆指标塞进 LSTM模型很容易记住噪声而不是规律——期货数据的信噪比本来就低特征里面真正对下一根K线有方向性指示的可能只有三五个。所以我在做这类预测模型时会把特征筛选放到模型之前先用相关性分析把无效特征和冗余特征去掉再把筛选后的序列交给 CNN 提取局部形态、Attention 聚焦关键时间步、LSTM 建模长期依赖。这条流水线并不算新但它对期货这种高噪声场景非常有效比单独用 LSTM 或者完全依赖 Transformer 都更容易在本地源码级别调通。适合有 Python 和深度学习基础、想把量化特征工程和序列模型真正衔接起来的人。2. 特征工程用相关性分析选出真正影响期货价格的因素2.1 相关性分析的三种口径线性相关、秩相关与互信息做相关性选择前要先明确一个事期货价格和特征之间很少是干净的线性关系。比如持仓量和价格的关系在上涨趋势和下跌趋势里方向可能完全不同整体算出来皮尔逊系数往往趋近于零但这不代表它没用。所以我会同时看三种口径的相关性。皮尔逊相关系数衡量的是线性相关计算快、解释直观适合先做一轮粗筛。它最大的问题是受离群值影响大期货数据里经常有极端行情一根大阳线的离群值就能把相关系数拉得很高。斯皮尔曼秩相关系数把原始值换成排名再算相关对单调非线性关系更敏感也不怕离群值适合作为第二个口径。互信息不假设任何函数关系能捕捉到非单调的依赖但计算成本高对连续变量需要先做离散化。实际操作中我一般用“皮尔逊绝对值 斯皮尔曼绝对值”双阈值筛选互信息只用来复核那些两个系数都不高但理论上可能有关系的特征。2.2 用 pandas 实现相关性筛选与滞后相关性计算下面的代码基于 pandas 和 scipy 完成相关性分析输出每个特征与目标变量下一周期收益率的三个相关性指标并额外计算滞后相关性。import pandas as pd import numpy as np from scipy.stats import pearsonr, spearmanr def compute_correlation(df, feature_cols, target_col, lags5): 计算特征与目标变量的相关性并输出滞后相关性。 参数: df: 包含特征和目标变量的 DataFrame feature_cols: 特征列名列表 target_col: 目标变量列名建议用下一周期收益率 lags: 最大滞后天数 rows [] for col in feature_cols: # 去掉空值再计算避免 NaN 污染相关系数 valid df[[col, target_col]].replace([np.inf, -np.inf], np.nan).dropna() if len(valid) 30: continue p, _ pearsonr(valid[col], valid[target_col]) s, _ spearmanr(valid[col], valid[target_col]) row {feature: col, pearson: round(p, 4), spearman: round(s, 4)} # 滞后相关性特征提前 target_col 若干天 for lag in range(1, lags 1): shifted df[col].shift(lag) valid_lag pd.concat([shifted, df[target_col]], axis1).replace( [np.inf, -np.inf], np.nan).dropna() if len(valid_lag) 30: continue lp, _ pearsonr(valid_lag.iloc[:, 0], valid_lag[target_col]) row[flag_{lag}] round(lp, 4) rows.append(row) result pd.DataFrame(rows) result[max_abs] result[[pearson, spearman]].abs().max(axis1) return result.sort_values(max_abs, ascendingFalse) # 使用示例: df 为已经对齐好的日线数据 # features [open_ret, volume_ret, oi_ret, high_low_range] # target next_ret # 下一交易日收益率 # result compute_correlation(df, features, target) # result.to_csv(correlation_result.csv, indexFalse)这段代码先对每个特征做皮尔逊和斯皮尔曼相关性再通过shift(lag)把特征整体向后移动模拟“特征提前于价格变化”的情况。shift(1)表示用前一天的该特征预测今天的收益率数值大说明这个特征有先行性。注意dropna和replace两步不能省期货数据里除零、涨跌停造成的无穷值如果不过滤相关系数会直接变成 NaN 或错误数值。max_abs这一列是我用来排序的参考值它取皮尔逊和斯皮尔曼绝对值中的较大者能同时照顾线性关系和单调非线性关系。2.3 筛选完成后的特征组合与装配相关性分析只是第一步筛完后要检查特征之间的共线性不然两个高度相关的特征同时进模型对 CNN 来说就是重复信息。我会加一步对通过相关性阈值的特征再算两两相关系数超过 0.8 的只保留与目标变量相关性更高的那个。下表是一个典型的期货日线特征组合示例。特征类别具体特征与目标的相关性参考筛选动作量价类成交量变化率、持仓量变化率、振幅0.1 ~ 0.3保留相关性和稳定性都达标的价格结构类收盘价相对 MA5/MA20 的偏离、RSI、布林带位置0.05 ~ 0.25同类特征去重后保留一个跨品种类关联品种的相对强弱、价差变化0.1 ~ 0.35滞后相关性高的优先保留日历类星期几、距交割日天数0.05 以下相关性低但逻辑有效可选保留这里要注意一个常见误用相关性低不代表特征没用非线性关系在相关性矩阵里可能显示为零。所以我在表格里保留了“日历类”这种相关性不高但逻辑上可能影响期货价格的变量让它靠模型自己学习。反过来相关性高也不代表一定稳定滚动窗口里的相关性如果忽高忽低这个特征对模型来说依然不可靠。我通常会把训练集按时间切成三段分别计算相关性只有三段都同号且绝对值都超过阈值的特征才留下来。3. CNN-Attention-LSTM 模型结构从局部特征到长时序依赖3.1 为什么 CNN 在前面、Attention 在中间、LSTM 在后CNN、Attention、LSTM 三者组合的先后顺序决定了模型看到数据的方式。一维 CNN 通过卷积核在时间维度上滑动等价于在原始序列上提取局部形态比如连续三根K线的组合、放量突破后的短期量价特征。如果把纯序列直接给 LSTM这些局部形态要靠 LSTM 自己慢慢学收敛慢而且容易过拟合。把 CNN 放在最前面相当于先做了一层特征提取器让后面的时序单元处理更干净的信息。Attention 层放在哪有不同的做法。常见的架构有两种一种是 Attention 接在 LSTM 之后对 LSTM 输出序列的每个时间步计算权重这样模型可以重点关注某一个时间段内的关键状态另一种是 Attention 直接对 CNN 的输出做时间步加权再送入 LSTM。这两者相比前者更常见因为 LSTM 输出的高维隐状态里已经包含了一定的上下文信息Attention 在这些隐状态上做加权更稳定。我通常选前者正好符合标题里“CNN-Attention-LSTM”的顺序CNN 提取局部特征LSTM 建模时序依赖Attention 对 LSTM 的各个时间步输出做重要性加权。对比 Transformer它用自注意力替代了循环结构理论上能捕捉更长距离的依赖但期货日线数据通常只有几千个样本Transformer 的参数量很容易把模型撑爆。CNN-Attention-LSTM 的参数量小得多在中小规模数据集上训练更快也更容易用普通 GPU 甚至 CPU 跑通。3.2 用 TensorFlow/Keras 手写可运行的 CNN-Attention-LSTM下面给出一个可以直接套用的 Keras 模型实现。代码里自定义了一个 Attention 层输出是 LSTM 隐状态的加权和。import tensorflow as tf from tensorflow.keras import layers, Model class AttentionLayer(layers.Layer): 自定义 Attention 层: 对 LSTM 隐状态序列做加权求和 def __init__(self, **kwargs): super(AttentionLayer, self).__init__(**kwargs) def build(self, input_shape): # input_shape: (batch_size, time_steps, lstm_units) self.W self.add_weight(nameattention_weight, shape(input_shape[-1], 1), initializerglorot_uniform, trainableTrue) self.b self.add_weight(nameattention_bias, shape(input_shape[1], 1), initializerzeros, trainableTrue) super(AttentionLayer, self).build(input_shape) def call(self, inputs): # 计算每个时间步的得分: (batch, time_steps, 1) score tf.tanh(tf.matmul(inputs, self.W) self.b) score tf.squeeze(score, axis-1) # (batch, time_steps) weights tf.nn.softmax(score, axis-1) # 归一化权重 weights tf.expand_dims(weights, axis-1) # (batch, time_steps, 1) # 加权求和: (batch, lstm_units) context tf.reduce_sum(inputs * weights, axis1) return context def build_cnn_attention_lstm(seq_len, n_features, filters64, kernel_size3, lstm_units64, dense_units32): 构建 CNN-Attention-LSTM 模型 inputs layers.Input(shape(seq_len, n_features)) # 1D CNN 提取局部形态 x layers.Conv1D(filtersfilters, kernel_sizekernel_size, paddingsame, activationrelu)(inputs) x layers.BatchNormalization()(x) x layers.MaxPooling1D(pool_size2)(x) # 时间步减半 # LSTM 建模时序依赖 x layers.LSTM(lstm_units, return_sequencesTrue, dropout0.2)(x) # Attention 对每个时间步加权 x AttentionLayer()(x) # 全连接输出 x layers.Dense(dense_units, activationrelu)(x) x layers.Dropout(0.2)(x) # 预测下一周期收益率的方向用 sigmoid 做二分类 outputs layers.Dense(1, activationsigmoid, namedirection_output)(x) model Model(inputs, outputs) return model model build_cnn_attention_lstm(seq_len60, n_features10) model.compile(optimizertf.keras.optimizers.Adam(learning_rate0.001), lossbinary_crossentropy, metrics[accuracy]) model.summary()这段代码里有两个细节值得说明。第一Conv1D的paddingsame保证卷积后时间步不变后面的MaxPooling1D(pool_size2)再把时间步压缩一半这样 LSTM 接收到的序列长度从 60 变为 30训练速度更快也能让 LSTM 关注更粗粒度的模式。第二AttentionLayer内部用tanh做线性变换后接softmax归一化权重值域始终在 0 到 1 之间且所有时间步加起来等于 1这样模型可以理解为“哪几个时间步对预测最有用”。return_sequencesTrue是必须的如果省掉LSTM 只输出最后一步的隐状态Attention 就没有序列可加权了。3.3 关键参数与调参顺序模型结构确定后先跑通再调参。我建议按下面的顺序调整而不是一次性把所有参数都改了。参数推荐初始值作用调参建议seq_len60每个样本包含的历史K线数量日线数据 30~120分钟线可以更长n_features10 ~ 20相关性筛选后的特征数特征太多时模型容易过拟合filtersCNN 卷积核数64提取局部特征的维度从 32 开始试Ascending 到 128 看验证集变化kernel_size3卷积核覆盖的时间步数日线用 3 或 5覆盖一个短周期的形态lstm_units64LSTM 隐状态维度数据量小时不要超过 128dropout0.2防止过拟合验证集 loss 上升时可逐步加到 0.4dense_units32输出层前的特征维度最小值 16最大值不超过 lstm_units这里最容易被忽视的是seq_len。期货日线数据一年只有 250 个交易日左右seq_len60意味着样本之间高度重叠训练集和验证集切分不当就会造成数据泄漏。后面一章专门讲数据集如何构造这不是模型结构能解决的问题。4. 数据集构造与训练评估从源码到可复现的预测流程4.1 预处理缺失值、归一化与滑动窗口样本生成期货数据天然有缺失问题节假日、涨跌停、主力合约换月都会造成序列断裂。我的做法是先用ffill填充缺失值再剔除连续缺失超过 3 根的样本段。归一化阶段有一个最常见的坑不能用全量数据的均值和标准差去归一化否则会把未来的统计信息泄露给训练过程。正确做法是只用训练集拟合 scaler再分别应用到训练集、验证集和测试集。下面用代码演示这段完整的预处理流程。import numpy as np from sklearn.preprocessing import MinMaxScaler def prepare_samples(df, feature_cols, seq_len60): 生成滑动窗口样本。 注意: 归一化的 scaler 只能用训练集 fit不能用全量数据。 data df[feature_cols].replace([np.inf, -np.inf], np.nan) data data.fillna(methodffill).fillna(methodbfill) # 这里假设已经单独调用 scaler.fit(train_data) 完成拟合 # 传入的 df 应该是已经被训练集 scaler 转换过的数据 X, y [], [] values data.values # next_ret 表示标签: 下一周期收益率为正记 1否则记 0 labels (df[next_ret].values 0).astype(int) for i in range(seq_len, len(values)): X.append(values[i - seq_len:i]) y.append(labels[i]) return np.array(X), np.array(y) # 使用示例 # scaler MinMaxScaler() # train_scaled scaler.fit_transform(train_df[feature_cols]) # X_train, y_train prepare_samples(train_df, feature_cols, seq_len60)prepare_samples的循环里X取的是i - seq_len到i这一段窗口y取的是窗口结束之后的标签。这样每个样本都只由过去的信息构成不会看到未来数据。这里标签用了二分类因为期货价格预测方向比预测具体数值更稳健数值预测受手续费、滑点影响大方向对了才有交易价值。4.2 训练集、验证集、测试集划分的时序约束很多人在这一步犯错直接调用train_test_split随机划分。对时序数据来说随机划分等于把未来样本混进训练集模型相当于提前看到了答案。正确做法是按时间顺序硬切前 70% 训练、中间 15% 验证、最后 15% 测试。下面给出一个按时间切分的代码片段。def temporal_split(X, y, train_ratio0.7, val_ratio0.15): n len(X) train_end int(n * train_ratio) val_end int(n * (train_ratio val_ratio)) X_train, y_train X[:train_end], y[:train_end] X_val, y_val X[train_end:val_end], y[train_end:val_end] X_test, y_test X[val_end:], y[val_end:] return (X_train, y_train), (X_val, y_val), (X_test, y_test)这里还要注意样本重叠的问题。seq_len60时第 100 个样本和第 101 个样本有 59 个时间步是重合的训练集和验证集边界处的样本实际上共享了半段历史。为了把这种泄漏影响降到最低我会在temporal_split之前把验证集起始位置往前多留出seq_len个样本或者直接丢弃边界处重叠的样本。实际写代码时把train_end提前seq_len个位置是最省事的做法。4.3 训练配置、模型保存与加载预测训练配置的核心是用回调把训练过程稳住。Keras 里我配合EarlyStopping、ReduceLROnPlateau和ModelCheckpoint这样模型不会因为跑太多轮而过拟合也能在验证集 loss 不再下降时自动降低学习率。模型训练完成后保存为h5或keras文件后续直接load_model加载做滚动预测。from tensorflow.keras.callbacks import EarlyStopping, ReduceLROnPlateau, ModelCheckpoint callbacks [ EarlyStopping(monitorval_loss, patience15, restore_best_weightsTrue), ReduceLROnPlateau(monitorval_loss, factor0.5, patience5, min_lr1e-6), ModelCheckpoint(best_model.keras, monitorval_loss, save_best_onlyTrue) ] history model.fit( X_train, y_train, validation_data(X_val, y_val), epochs100, batch_size64, callbackscallbacks, verbose1 ) # 加载保存好的模型做预测 # from tensorflow.keras.models import load_model # model load_model(best_model.keras, custom_objects{AttentionLayer: AttentionLayer})两个容易出问题的点第一EarlyStopping的patience不宜太小日线数据训练时 loss 下降是锯齿状的patience 设 5 经常刚跳过最优轮就停掉15 更合适。第二自定义的AttentionLayer在load_model时必须通过custom_objects显式传入否则 Keras 反序列化时会报找不到自定义层。评估时除了看 accuracy还要看预测方向的一致性后面一章专门聊这部分的验证技巧。5. 模型投入验证前先做这 3 个技巧5.1 技巧一滚动窗口回测防止未来函数模型在测试集上准确率不错不代表实盘可用。常见做法是做滚动回测每次用过去 300 根K线训练预测接下来 20 根等 20 根走完后把真实数据加入到训练集重新训练。这个流程模拟真实交易中每隔一段时间重训一次的场景能看出模型在不同行情状态下的稳定性。执行回测时要注意新的输入样本必须经过与训练集相同参数归一化即沿用最初训练集的 scaler。5.2 技巧二时序交叉验证代替单次随机切分单次划分的测试集结果具有偶然性。我倾向于做扩展窗口交叉验证第一折用第 1~300 根训练、第 301~320 根测试第二折用第 1~320 根训练、第 321~340 根测试。这样保证训练集永远只包含过去数据且每次训练样本逐步增加更贴近真实重训过程。如果模型在每一折的方向准确率都在 0.52 以下基本可以直接判定为无效模型不用再花时间调参。5.3 技巧三特征相关性稳定性检查模型上线后特征和价格的相关性会随时间漂移。我每隔一个季度重算一次第 2 章的相关性矩阵重点看两个东西训练时排名前五的特征当前是否仍然与目标变量同号相关相关性绝对值是否从 0.2 掉到接近 0。如果发生明显的相关性衰减就要考虑替换特征或缩短重训周期。这套检查本身不需要训练模型用 pandas 在历史数据上滚动算一遍就能得出漂移曲线是所有模型上线维护里成本最低、收益最明显的一步。本文还有配套的精品资源点击获取
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

数据采集实战全指南:从网页爬取到工业设备数据接入 2026/9/13 3:56:25

数据采集实战全指南:从网页爬取到工业设备数据接入

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
内蒙古四级行政区划矢量数据校验与ArcGIS加载制图全流程 2026/9/13 3:56:25

内蒙古四级行政区划矢量数据校验与ArcGIS加载制图全流程

简介:2024年内蒙古自治区行政区划矢量图层数据,涵盖省级、市级、县级、乡镇四级行政边界,面向GIS数据应用人员、地图制图开发者以及区域规划分析者,可直接用于专题地图绘制、空间查询、叠加分析与政区统计等场景。整套数据由32个文…

阅读更多 →
RAG工程化实战:从分块策略到混合召回与质量评估 2026/9/13 3:56:25

RAG工程化实战:从分块策略到混合召回与质量评估

构建RAG系统的时候,很多人一开始都觉得这事挺简单:把文档切一切塞进向量库,查询的时候做一次相似度检索,把结果丢给大模型就能回答私有问题了。但凡是真正上手做过的人,多少都被教训过。切分错了,检索结果看…

阅读更多 →
ROS2入门指南:从环境搭建到第一个节点实战 2026/9/13 3:56:25

ROS2入门指南:从环境搭建到第一个节点实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
Web端ER图工具选型指南:从协作建模到数据库即代码 2026/9/13 3:56:25

Web端ER图工具选型指南:从协作建模到数据库即代码

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
Compose Multiplatform 跨平台性能基准测试指南:模式、参数与运行脚本全解析 2026/9/13 3:53:25

Compose Multiplatform 跨平台性能基准测试指南:模式、参数与运行脚本全解析

Compose Multiplatform 跨平台性能基准测试指南:模式、参数与运行脚本全解析 【免费下载链接】compose-multiplatform Compose Multiplatform, a modern UI framework for Kotlin that makes building performant and beautiful user interfaces easy and enjoyable…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞