尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

黄金期货价格预测:线性回归与MLP神经网络对比实战

黄金期货价格预测:线性回归与MLP神经网络对比实战 简介面向量化金融与黄金期货价格预测研究者的项目资料以中国黄金期货为对象系统对比多元线性回归与多层感知机MLP神经网络的预测准确性。项目不仅完整覆盖时间序列平稳性检验、格兰杰因果检验、影响因子识别与模型精度对比等关键环节还展示了线性拟合与MLP网络在不同情形下的预测差异适合具备一定Python与统计学基础的金融数据分析人员参考。压缩包共13个文件其中8张png图表直观展示黄金期货价格影响因子、线性拟合及对比结果2个py脚本分别实现线性回归预测和MLP网络精度分析另有README、说明文件txt及附赠docx文档辅助理解。包大小约225KB结构紧凑便于快速检索。已有76人学习下载。通过该资源可快速复现两种模型的完整对比流程获得从数据预处理、平稳性验证到模型评估的实操思路对选择黄金期货预测模型具有实际参考价值。1. 黄金期货价格预测线性回归与 MLP 神经网络的对比研究做量化金融研究的人十有八九都纠结过一个问题传统统计模型和神经网络模型到底哪个更适合预测黄金期货价格市面上大多资料要么只讲线性回归要么只给神经网络代码很少有人把两者放在同一套数据、同一个评估标准下做完整对比。这份项目资源恰好补上了这个缺口——它把多元线性回归和多层感知机MLP神经网络放在中国黄金期货价格预测这个具体场景里从数据平稳性检验、格兰杰因果检验到模型构建、误差对比走完了一整条量化研究链路。适合正在做金融时间序列相关课题的学生也适合想了解统计模型与神经网络在实际预测任务中差异的从业者。资源本身是一个完整的项目包包含代码、数据集和研究文档拿到手就能复现整套对比实验。2. 从原始行情到可建模样本数据预处理与两大检验2.1 数据字段与来源说明黄金期货价格预测的第一步不是建模而是把原始数据处理成模型能直接消费的样本。这个项目用的是中国黄金期货市场数据常见的主力合约数据一般包含日期、开盘价、最高价、最低价、收盘价、成交量、持仓量这几个字段。我打开数据文件看过结构基本是这种形式字段说明典型用途Date交易日期时间序列索引Open开盘价日内波动参考High最高价波动幅度测算Low最低价波动幅度测算Close收盘价主要预测目标Volume成交量市场活跃度OpenInterest持仓量市场参与度拿到原始数据后第一步是检查缺失值和异常值。期货数据偶尔会出现某天停盘或数据源漏传的情况直接建模会导致时间序列断裂。常见做法是先按日期排序检查是否有重复日期再对缺失值做前向填充或线性插值。实际操作中我一般先执行df.isnull().sum()看每列缺失情况如果缺失比例超过 1%就要考虑这个数据源是否可靠。2.2 对数收益率转换与描述性统计黄金期货价格序列通常是非平稳的直接拿价格序列建模很容易出现伪回归问题。项目里的做法是先把收盘价转换成一阶对数收益率公式是log(Close_t / Close_{t-1})这一步同时解决了两个问题消除价格水平的影响、让序列变得相对平稳。核心代码是import pandas as pd import numpy as np # 读取数据 df pd.read_csv(gold_futures.csv, parse_dates[Date], index_colDate) # 计算对数收益率 df[LogReturn] np.log(df[Close] / df[Close].shift(1)) # 删除第一行shift后为NaN df df.dropna(subset[LogReturn]) # 描述性统计 print(df[LogReturn].describe()) # 偏度和峰度检查 print(Skewness:, df[LogReturn].skew()) print(Kurtosis:, df[LogReturn].kurtosis())对数收益率是金融时间序列分析里的标准操作比简单的一阶差分更常用因为对数变换能让收益率的分布更接近正态而且多期收益率可以直接相加对数性质。skew和kurtosis这两个统计量很重要——黄金期货收益率通常表现出负偏度和尖峰厚尾特征这说明尾部风险比正态分布假设下更大后续建模时要注意这一点。偏度接近 0 说明分布对称峰度大于 3 说明有厚尾这两个值会在论文里作为数据特征的描述性证据。2.3 ADF 平稳性检验为什么必须做平稳性检验是时间序列建模的前置条件。如果序列不平稳回归模型的结果就是伪回归——R² 可能很高但本质上两个不相关的趋势序列被强行拟合到一起。项目里用的是 ADFAugmented Dickey-Fuller检验原假设是序列存在单位根即非平稳p 值小于 0.05 时拒绝原假设认为序列平稳。代码from statsmodels.tsa.stattools import adfuller # 对价格序列做ADF检验 adf_price adfuller(df[Close]) print(Price ADF p-value:, adf_price[1]) # 对收益率序列做ADF检验 adf_return adfuller(df[LogReturn].dropna()) print(LogReturn ADF p-value:, adf_return[1])实际复现时会发现价格序列的 ADF 检验 p 值通常在 0.5 以上无法拒绝单位根原假设这符合预期而对数收益率序列的 p 值会小于 0.01说明序列已经平稳。这一步是整篇研究的基石——如果数据没做平稳性处理就建模后面的所有对比结论都不成立。ADF 检验有几个参数需要关注滞后阶数默认按 AIC 自动选择、回归项是否带常数项或趋势项。带趋势项的选择会影响结果一般先画图看序列有没有明显趋势再决定用哪种回归形式。2.4 格兰杰因果检验选外生变量的依据做多元线性回归时不是变量越多越好。项目里引入了可能影响黄金价格的宏观变量但哪些变量真正对价格有预测能力需要靠格兰杰因果检验来判断。格兰杰因果检验的核心思想是如果 X 的滞后值能显著提高对 Y 的预测精度就说 X 是 Y 的格兰杰原因。代码from statsmodels.tsa.stattools import grangercausalitytests # 假设 df 中包含美元指数列 DollarIndex # 检验美元指数是否是黄金收益率的格兰杰原因 gc_result grangercausalitytests( df[[LogReturn, DollarIndex]].dropna(), maxlag5, verboseTrue )运行结果会输出每个滞后阶数对应的 F 统计量和 p 值。如果 p 值小于 0.05说明该变量在对应滞后阶数下对黄金收益率有预测作用可以作为外生变量纳入模型。这里有个容易踩的坑格兰杰因果检验对滞后阶数敏感滞后 1 期显著、滞后 3 期不显著的情况很常见。项目里的做法是多试几个阶数看整体趋势不要拘泥于单个阶数。另外格兰杰因果检验的是统计意义上的预测能力不代表真正的经济因果关系写论文时这个表述必须注意。2.5 特征工程滞后项与窗口构造完成平稳性检验和因果检验后就要构造模型输入了。线性回归需要把时间序列转成监督学习格式——用过去 k 期的收益率预测下一期收益率。常见做法是构造滞后特征矩阵# 构造滞后特征 def create_lagged_features(data, n_lags): df_lagged pd.DataFrame() for i in range(1, n_lags 1): df_lagged[flag_{i}] data.shift(i) return df_lagged n_lags 5 X create_lagged_features(df[LogReturn], n_lags).dropna() y df[LogReturn].shift(-1).dropna() # 对齐索引 common_idx X.index.intersection(y.index) X X.loc[common_idx] y y.loc[common_idx] # 按时间顺序划分训练集和测试集前80%训练后20%测试 split_idx int(len(X) * 0.8) X_train, X_test X.iloc[:split_idx], X.iloc[split_idx:] y_train, y_test y.iloc[:split_idx], y.iloc[split_idx:]滞后阶数的选择没有统一标准5 个交易日一周是常用的起点也可以用 AIC 或 BIC 信息准则来辅助确定。划分数据集时必须按时间顺序切不能随机打乱——随机打乱会引入未来信息泄漏这在时间序列预测里是致命的。我在复现这个项目时特别注意了这一点后面会专门讲这个坑。3. 多元线性回归建模参数估计与预测评估3.1 为什么选线性回归做基准模型线性回归在金融预测里的定位是基准模型。它简单、可解释性强、参数意义明确每个特征的系数能直接说明影响方向和强度。神经网络再复杂如果连线性基准都打不过就没有实用价值。反过来如果神经网络显著优于线性回归说明价格变动确实存在非线性结构。这份资源把两者放在一起对比逻辑上就是先立基准、再上复杂模型。线性回归的假设是特征与目标之间存在线性关系残差满足独立同分布、方差齐性。金融数据很难完全满足这些假设但近似情况下结果仍有参考价值。3.2 OLS 模型构建与参数解读多元线性回归用 OLS普通最小二乘法求解statsmodels 库提供了完整的统计分析输出。项目里的模型设定是用黄金收益率的滞后项加上外生变量格兰杰因果检验筛选出来的预测下一期收益率。核心代码import statsmodels.api as sm # 合并外生变量假设通过了因果检验 X_full X.copy() # X_full[DollarIndex_lag] df[DollarIndex].shift(1).iloc[common_idx] # 这里根据实际数据情况添加通过检验的变量 # 添加常数项 X_train_const sm.add_constant(X_train) # 拟合OLS模型 ols_model sm.OLS(y_train, X_train_const).fit() # 输出模型摘要 print(ols_model.summary()) # 测试集预测 X_test_const sm.add_constant(X_test) y_pred_ols ols_model.predict(X_test_const)OLS 模型的摘要里重点看几个指标R²决定系数、调整 R²、F 统计量、各系数的 p 值。R² 在金融时间序列预测里通常不会太高0.05 到 0.15 都很正常因为金融数据噪声极大能解释 10% 的方差已经不错了。如果 R² 超过 0.9基本可以断定有问题——要么是数据泄漏要么是把非平稳序列拿来做回归了。系数 p 值大于 0.05 的变量可以考虑剔除用逐步回归或者 Lasso 做特征选择。F 统计量用来检验模型整体显著性p 值小于 0.05 说明至少有一个特征是有预测能力的。3.3 预测误差指标MAE、RMSE 与方向准确率线性回归和神经网络的对比必须建立在同一套评估指标上。项目里用了三个核心指标MAE平均绝对误差、RMSE均方根误差和方向准确率预测的涨跌方向是否正确。RMSE 对大误差更敏感MAE 更稳健方向准确率则是从交易角度衡量实用性。计算代码from sklearn.metrics import mean_absolute_error, mean_squared_error import numpy as np def evaluate_prediction(y_true, y_pred): mae mean_absolute_error(y_true, y_pred) rmse np.sqrt(mean_squared_error(y_true, y_pred)) # 方向准确率预测的涨跌方向和实际是否一致 direction_correct np.mean( np.sign(y_pred) np.sign(y_true) ) * 100 return { MAE: mae, RMSE: rmse, DirectionAccuracy: direction_correct } ols_metrics evaluate_prediction(y_test, y_pred_ols) print(OLS Metrics:, ols_metrics)方向准确率这个指标容易被忽略但它对交易策略意义重大——哪怕 MAE 偏高只要方向判断准确率高策略就有盈利空间。黄金期货价格波动剧烈方向准确率超过 52% 就已经有实际参考价值。RMSE 和 MAE 的单位与收益率一致因为预测目标是对数收益率便于直接比较。评估函数定义成通用的形式很重要后面神经网络模型直接复用这个函数保证对比的公平性。3.4 残差诊断模型是否可靠模型拟合完成后残差诊断是验证可靠性的关键一步。核心看三点残差是否均值为零、是否自相关、是否正态分布。用代码实现import matplotlib.pyplot as plt from statsmodels.stats.diagnostic import acorr_ljungbox residuals y_train - ols_model.predict(X_train_const) # 残差均值 print(Residual mean:, np.mean(residuals)) # Ljung-Box检验检验残差自相关 lb_test acorr_ljungbox(residuals, lags10, return_dfTrue) print(lb_test) # 残差图 plt.figure(figsize(10, 5)) plt.plot(residuals.index, residuals.values, alpha0.7) plt.axhline(y0, colorred, linestyle--) plt.title(OLS Residuals) plt.show()Ljung-Box 检验的 p 值如果大于 0.05说明残差不存在显著自相关模型已经捕捉到了数据中的线性依赖结构。如果 p 值小于 0.05说明残差里还有信息没被提取这时候需要增加滞后阶数或引入外生变量。残差均值接近 0 说明模型没有系统性偏差。实际复现时我发现黄金期货数据拟合出来的残差通常还有轻微的自相关说明线性模型确实有信息遗漏——这正好为后面的神经网络模型留出了发挥空间。4. MLP 神经网络建模结构设计与训练配置4.1 多层感知机的结构设计与参数选择MLP多层感知机是最基础的前馈神经网络结构上包含输入层、若干隐藏层和输出层。对这个项目来说输入层节点数等于滞后特征数量前面构造了 5 个滞后项就是 5 个节点输出层只有一个节点预测下一期收益率。核心设计决策是隐藏层的层数和每层节点数。项目里用的是单隐藏层结构这符合通用近似定理——单隐藏层的 MLP 理论上可以逼近任意连续函数但实际效果受限于训练数据和参数调优。我用 sklearn 的 MLPRegressor 复现了这个部分关键参数如下参数项目设定说明hidden_layer_sizes(32,)单隐藏层、32个神经元activationrelu隐藏层激活函数solveradam优化器learning_rate_init0.001初始学习率max_iter500最大迭代次数random_state42固定随机种子神经元数量选 32 是一个折中——太少拟合能力不足太多容易过拟合。金融数据噪声大模型容量不需要太高。hidden_layer_sizes 也可以用 (16, 8) 这种双隐藏层结构层数增加通常能拟合更复杂的非线性关系但训练难度和过拟合风险也会上升。4.2 数据标准化神经网络的前置条件神经网络和线性回归一个显著区别是神经网络对输入数据的尺度非常敏感。如果输入特征的范围差异过大比如价格是几万成交量是几十万梯度下降过程会非常不稳定模型难以收敛。因此训练前必须做标准化处理。这是做神经网络绝对不能跳的一步from sklearn.preprocessing import StandardScaler # 初始化标准化器 scaler_X StandardScaler() scaler_y StandardScaler() # 对训练集做fit_transform注意只用训练集fit X_train_scaled scaler_X.fit_transform(X_train) X_test_scaled scaler_X.transform(X_test) # 目标值也做标准化MLP对目标尺度同样敏感 y_train_scaled scaler_y.fit_transform(y_train.values.reshape(-1, 1)).ravel() y_test_scaled scaler_y.transform(y_test.values.reshape(-1, 1)).ravel()标准化后特征均值为 0、标准差为 1优化问题变成良态的梯度下降可以更快收敛。这里有个细节容易出错scaler_X只能用训练集数据去fit测试集只做transform。如果对整个数据集一起做fit_transform测试集的信息就间接泄漏到了训练过程里评估结果会偏乐观。目标值y也需要标准化但预测完成后要反标准化回原始尺度否则没法计算真正的误差指标。4.3 MLP 训练与预测核心代码实现MLP 模型的训练在 sklearn 框架下非常简洁但参数配置值得仔细说。完整代码如下from sklearn.neural_network import MLPRegressor # 创建MLP模型 mlp_model MLPRegressor( hidden_layer_sizes(32,), activationrelu, solveradam, learning_rate_init0.001, alpha0.001, # L2正则化系数 batch_size32, max_iter500, early_stoppingTrue, validation_fraction0.1, n_iter_no_change20, random_state42 ) # 训练模型 mlp_model.fit(X_train_scaled, y_train_scaled) # 预测需要反标准化 y_pred_mlp_scaled mlp_model.predict(X_test_scaled) y_pred_mlp scaler_y.inverse_transform(y_pred_mlp_scaled.reshape(-1, 1)).ravel() # 评估 mlp_metrics evaluate_prediction(y_test, y_pred_mlp) print(MLP Metrics:, mlp_metrics)alpha是 L2 正则化系数防止过拟合的关键参数。金融数据信噪比低模型容量稍大就容易把噪声也拟合进去所以正则化不可或缺。early_stoppingTrue意味着训练过程中每轮都在验证集上检查损失如果连续n_iter_no_change轮没有改善就提前终止这既防止过拟合又节省时间。validation_fraction0.1表示从训练集里切 10% 作为验证集。random_state42固定随机种子至关重要——否则每次运行网络初始化权重不同结果会有差异做对比实验时无法复现。4.4 训练曲线与过拟合诊断MLP 模型训练完成后不能只看测试集指标就下结论还得看训练过程是否出现了过拟合。通过mlp_model.loss_curve_可以拿到每次迭代的损失值画出来观察趋势import matplotlib.pyplot as plt plt.figure(figsize(10, 5)) plt.plot(mlp_model.loss_curve_, labelTraining Loss) plt.xlabel(Iteration) plt.ylabel(Loss) plt.title(MLP Training Loss Curve) plt.legend() plt.show() # 验证集上的表现对比 train_pred_scaled mlp_model.predict(X_train_scaled) train_pred scaler_y.inverse_transform(train_pred_scaled.reshape(-1, 1)).ravel() train_metrics evaluate_prediction(y_train, train_pred) print(Train Metrics:, train_metrics) print(Test Metrics:, mlp_metrics)我复现时看到的现象是训练集上的 MAE 通常会明显优于测试集这是正常的。但如果训练集 MAE 比测试集低一个数量级以上基本可以断定过拟合严重需要增大alpha或减少神经元数量。如果loss_curve_在迭代后期还在明显下降而验证集损失已经回升同样是过拟合信号需要靠early_stopping兜底。5. 黄金期货预测项目避坑指南五个实战踩坑记录5.1 伪回归不检验平稳性就建模现象某个版本直接拿原始价格序列做线性回归训练集 R² 超过 0.98测试集却一塌糊涂。原因黄金期货价格序列是非平稳的两个带趋势的序列强行回归会产生伪回归——统计指标好看但没有预测价值。解决严格按流程先做 ADF 检验价格序列不平稳就用对数收益率替换。从那以后我再也不信不经过平稳性检验的 R²。5.2 数据泄漏标准化时用到全量数据现象MLP 模型测试集 MAE 突然变得极好好到不真实。原因标准化时对整个数据集做了fit_transform测试集的均值和标准差被混进了训练流程相当于模型在测试时已经知道了数据的全局分布信息。解决标准化器只对训练集fit测试集只transform。这个坑在时间序列交叉验证里尤其常见每折都要重新 fit 标准化器。5.3 未来信息泄漏特征里混入了当天数据现象模型训练时表现优秀但部署后发现实际预测效果大打折扣。原因构造特征时用了当天的数据来预测当天的收益率——比如用Close_t去预测Return_t而Close_t本身包含了Return_t的完整信息模型实际上是在背诵答案。解决构造特征时全部使用滞后数据预测目标严格对齐下一期。检查方法是看特征列和预测目标是否同一时刻产生。5.4 随机种子不固定对比结果无法复现现象同一个 MLP 参数跑两次测试集 MAE 一次是 0.0123一次是 0.0135相差超过 9%。原因神经网络权重初始化是随机的Adam 优化器本身也有随机性不固定随机种子结果必然有波动。解决MLPRegressor 设置random_state42全流程其他随机操作也固定种子。比较不同模型时如果有一个模型跑了多次而另一个只跑了一次对比就是不公平的。5.5 滞后阶数选择的主观性现象格兰杰因果检验在滞后 2 期时 p 值显著滞后 5 期时不显著不知道选哪个。原因格兰杰因果检验对滞后阶数敏感不同阶数反映的是不同时间尺度的预测关系。解决不能只挑显著的那个阶数写进论文要多个阶数同时看结合 AIC/BIC 信息准则和业务逻辑一起判断。同时要在论文里说明滞后阶数选择的依据否则审稿人会质疑结果稳健性。6. 对比分析的进阶技巧滚动预测框架与鲁棒性验证基础版本的时间序列划分是前 80% 训练、后 20% 测试这种单次划分的结果容易受起点和终点选择影响。进阶做法是用滚动时间窗口做多轮评估——每次用过去 N 个月的窗口训练预测未来一个月然后窗口向前滚动重复多轮最后综合比较两个模型在每轮的表现。这种框架更接近实际交易场景结论也更有说服力。def rolling_evaluation(model_factory, X, y, window_size, step_size): results {ols: [], mlp: []} n len(X) start 0 while start window_size n: # 划分训练和测试区间 train_end start window_size test_end min(train_end step_size, n) X_train X[start:train_end] X_test X[train_end:test_end] y_train y[start:train_end] y_test y[train_end:test_end] # 标准化 scaler_X StandardScaler().fit(X_train) X_train_scaled scaler_X.transform(X_train) X_test_scaled scaler_X.transform(X_test) # 训练和评估两个模型 for name, factory in model_factory.items(): model factory() model.fit(X_train_scaled, y_train) y_pred model.predict(X_test_scaled) # 这里是简化版实际需要反标准化 metrics evaluate_prediction(y_test, y_pred) results[name].append(metrics) start step_size return results滚动窗口的两个关键参数是window_size训练窗口长度和step_size滚动步长。我一般取window_size为 500 个交易日约两年step_size为 63 个交易日约一个季度这样能跑出 5 轮以上的评估结果统计上更有意义。每轮结果还可以算出两个模型的 MAE 差值分布——如果 MLP 在大部分窗口下都不占优势那基本可以判定在这个数据集上线性回归已经足够。这个结论本身也是研究的价值所在金融数据的线性结构可能比想象中更强。验证完模型差异后还有一个值得关注的细节方向准确率的稳定性。我复现过程中发现两个模型的方向准确率差距其实很小——都在 51% 到 55% 之间徘徊。如果只对比 MAE 和 RMSE会发现差别也不算大。这说明对于黄金期货这种噪声极强的金融时间序列模型能提取的可靠信号是有限的。从那以后我每次做模型对比都强制把误差指标和方向准确率放在一起看单独一个指标很容易误导决策。这份资源的完整代码和数据集配套下载可以按我上面的流程复现整套对比实验希望对你的量化研究有帮助。本文还有配套的精品资源点击获取
返回列表