资讯动态

数学建模黄金价格预测:特征工程、时序验证与XGBoost实战

发布时间:2026/9/23 1:18:05 来源:尧图企业网站定制
简介一份围绕厦门‘博雅杯’数学建模C题的完整赛题解析资料聚焦黄金价格走势分析与预测面向高校师生、科研人员及对贵金属市场感兴趣的投资者适用于课堂教学、学术研讨和投资者教育。内容从黄金基本属性与市场价格决定机制切入阐述数学模型的选择与构建过程基于宏观经济、美元汇率、供需关系等因素展开定量分析并给出2024—2030年金价预测的方法论以及不同经济情景下的投资策略建议。资源为单个PDF文档压缩包仅117KB轻量易读文中配有具体的问题导向任务列表涉及关键因素建模、金价预测与情景策略分析便于学习者自主探究、建立实战模型。同时强调经济学、统计学等跨学科视角有助于提升定量分析与风险管理能力。目前已有465人学习下载是理解数学建模在金融领域应用的实用参考。1. 这类赛题失分点从来不是算法不够新“数学建模用于黄金价格走势分析与预测”——拿到这道题多数队伍的第一反应是上LSTM、Transformer恨不得把深度学习全家桶搬上去。但如果去翻一翻往年的数学建模优秀论文你会发现评阅老师真正看重的东西恰恰被忽略了数据怎么清洗、特征怎么构造、训练集和验证集怎么切分才不犯未来函数错误、模型预测的结果用什么指标衡量、误差来源是否讲得清。黄金价格序列是典型的高噪声、非平稳、受突发事件冲击的金融数据它不像工业过程数据那样有稳定的物理规律建模难点集中在“信号弱、噪声大、可解释性要求高”。这篇文章按 C 题的常见解题路径把数据、特征、模型、评估、呈现从头拆到尾目标是让一支队伍在三天比赛周期内能稳定复现一套完整方案而不是在调参和画图里耗尽时间。2. 黄金价格走势分析的数据建模基础特征构造与数据切分2.1 先从行情数据中提取“能被模型学习的结构”比赛题目给出的通常是一段日频或分钟频的黄金价格序列有时会附带成交量、开盘价、收盘价等信息。不要一上来就喂原始价格模型学不到东西反而会把趋势项和噪声一起拟合进去。第一步是把原始序列转成收益率序列这是黄金价格走势分析的标准预处理return_t (close_t - close_{t-1}) / close_{t-1}。有了收益率序列之后特征工程围绕三个方向展开。第一类是行情自相关特征包括过去 5 日、10 日、20 日的滚动收益率均值、滚动标准差、最高价与最低价的偏离幅度第二类是动量与均线结构特征例如金价与 MA5、MA20、MA60 的偏离率短期均线是否上穿长期均线第三类是波动率聚集特征用 GARCH(1,1) 拟合日收益率的条件方差序列或者直接用滚动标准差近似。先生成这些基础列后续模型才能开始捕捉“波动率高的时段之后往往还是高波动”这类金融序列的典型规律。2.1.1 用 Python 构造黄金价格分析基础特征集import pandas as pd import numpy as np # 假设 df 已读入包含 date, open, high, low, close, volume 六列 df[return] df[close].pct_change() # 日收益率 # 行情自相关特征过去 5 日与 20 日的滚动收益均值 df[ret_ma5] df[return].rolling(5).mean() df[ret_ma20] df[return].rolling(20).mean() # 波动率特征滚动标准差衡量近期价格震荡幅度 df[volatility_10] df[return].rolling(10).std() # 均线偏离率当前价格相对均线的偏离程度正值代表短期偏热 df[close_ma5_ratio] df[close] / df[close].rolling(5).mean() - 1 df[close_ma20_ratio] df[close] / df[close].rolling(20).mean() - 1 # 删除前 20 行滚动窗口期内的值不参与训练 df_feat df.dropna().reset_index(dropTrue) df_feat.head()pct_change()计算的是相邻两期收益率天然消除了价格序列的非平稳性rolling窗口如果换成分钟级数据就把数字调成对应的分钟数close_ma20_ratio这类偏离率特征本质是在衡量价格短期是否偏离其价值中枢这在均值回归类模型中非常有效。注意最后一行dropna()不能省否则滚动窗口初始阶段的空值会直接污染后续训练。2.2 用滚动窗口切分训练集与验证集杜绝未来函数这是建模环节里最容易犯也最致命的错误。标准的时间序列建模训练数据永远只能来自预测时刻之前如果直接用随机划分的train_test_split会把未来的价格信息泄漏给模型回测时准确率虚高真实预测时立刻崩盘。对于黄金这类受宏观事件强影响的序列我一般用两种切分方式组合第一层按时间顺序切出前 70% 做训练、后 30% 做验证第二层在训练集内部再用滚动窗口做多轮交叉验证。2.2.1 用 TimeSeriesSplit 做时间序列交叉验证from sklearn.model_selection import TimeSeriesSplit # 假设 X 是特征矩阵y 是目标变量 tscv TimeSeriesSplit(n_splits5, gap5) for train_index, val_index in tscv.split(X): X_train, X_val X.iloc[train_index], X.iloc[val_index] y_train, y_val y.iloc[train_index], y.iloc[val_index] # 每个折内训练集永远早于验证集这是时间序列验证的核心约束n_splits5表示把训练数据切成 5 段逐次扩展训练集并验证下一段时间gap5是刻意在训练集和验证集之间留出 5 天的间隔因为金融序列有短期自相关性紧挨着的样本之间信息重叠严重留出间隔能减少这种泄漏。如果比赛数据量小可以手工调整 gap 的范围但原则是宁多勿少。2.3 目标函数设计直接预测涨跌方向比预测价格更稳健对黄金这类噪声极大的序列直接回归预测未来一天的价格误差会非常大10 美元以内的波动很难被任何模型稳定预测。我更推荐把任务转换成二分类未来 5 个交易日的累计收益率是否为正。这样模型输出的是一个概率值既有业务含义又比纯数值预测稳定得多。标签构造方式如下y 1 if (close[t5] / close[t] - 1) 0 else 0。预测区间设为 5 日是因为 1 日方向几乎接近随机而 20 日以上又太长比赛中很难在有限数据上验证5 日是个折中选择。3. 黄金价格预测模型的数学建模选型从基线模型到 XGBoost3.1 先跑两个低成本基线Naive 预测与 ARIMA做建模的第一个 skill是永远先跑基线模型而不是直接上复杂模型。基线模型的作用是给后续所有模型设定一个及格线如果你的 XGBoost 连 Naive 都打不过那说明特征工程有问题不是模型的问题。对于黄金价格预测Naive 模型就是“预测明天的价格等于今天的价格”这是金融序列预测里最强悍的基准之一高噪声序列往往很难稳定超越它。第二个基线是 ARIMA。对黄金这种非平稳序列直接用 ARIMA 建模拟合价格水平值容易产生伪回归正确做法是对收益率序列建模再用积分项还原价格。比赛时间有限我的建议是只跑auto_arima做快速定阶然后把结果当作参考基准记录在论文里不要花太多时间手工调 ARIMA 参数。3.1.1 ARIMA 最小验证代码from statsmodels.tsa.arima.model import ARIMA # 使用收益率序列建模注意是收益率不是原始价格 model ARIMA(df[return].dropna(), order(2, 0, 2)) result model.fit() print(result.summary()) # 预测未来 5 日收益率并还原成价格 forecast_diff result.forecast(steps5) last_price df[close].iloc[-1] forecast_price last_price * (1 forecast_diff).cumprod() print(forecast_price)上面order(2, 0, 2)中三个参数分别对应 AR 阶数、差分阶数、MA 阶数。因为输入已经是收益率序列所以差分阶数是 0如果你直接输入原始价格需要先把差分阶数设为 1但那样很容易把趋势和噪声混在一起。预测未来 5 日收益率后用累积乘积还原成价格水平值这个还原过程才是对“未来金价是多少”这个问题的直接回答。3.2 用 XGBoost 做黄金价格涨跌方向预测当基线成绩记录完毕下一步就是主体模型。近几年各类数学建模竞赛的优秀论文里XGBoost 出现的频率远高于深度学习原因很实际表格型特征上它的表现稳定、训练速度快、不需要大量调参就能有不错的效果而且特征重要性可以直接输出方便在论文里解释模型逻辑。用 XGBoost 做二分类预测的是“未来 5 日黄金价格上涨的概率”输出可以直接映射成模型置信度比回归输出更利于决策解释。import xgboost as xgb model xgb.XGBClassifier( n_estimators300, max_depth4, learning_rate0.05, subsample0.8, colsample_bytree0.8, eval_metricauc, early_stopping_rounds20, random_state42, ) model.fit( X_train, y_train, eval_set[(X_val, y_val)], verboseFalse, )eval_metricauc用来衡量模型对涨跌方向的排序能力AUC 为 0.5 等于随机猜黄金这类噪声数据上 AUC 能到 0.55 以上就说明模型捕捉到了真实信号early_stopping_rounds20的作用是当验证集 AUC 连续 20 轮不再提升时自动停止训练既防过拟合也节省时间。如果比赛数据量不大max_depth建议不要超过 5深度太大模型会把训练集中的噪声一并记住。3.3 网格搜索找出黄金数据上的 3 个必调参数XGBoost 有一堆参数可以调但按我的经验在黄金价格预测这个场景下真正值得花时间调的只有三个max_depth、learning_rate、subsample。其余参数用默认值或者固定值就好调多了既浪费时间又容易过拟合。参数建议搜索范围在黄金数据上的影响max_depth3, 4, 5控制单棵树复杂度深度过大模型会捕捉到纯噪声learning_rate0.01, 0.05, 0.1步长越小拟合越稳但需要更多树比赛时间有限不建议低于 0.01subsample0.6, 0.7, 0.8, 0.9每轮随机采样比例降低过拟合0.8 是比较通用的起点n_estimators200, 300, 500配合 early_stopping_rounds 使用不需要单独精细调用sklearn的GridSearchCV或者Optuna搜索都行比赛时间紧张时直接手写三层循环也能跑完。注意交叉验证的划分策略必须用第 2 章提到的TimeSeriesSplit如果GridSearchCV默认用 KFold它的参数搜索结果在金融数据上是不可信的这一点务必写进论文的技术说明里反而是加分项。调参完成后把最优参数组合重新在全部训练数据上训练一遍再预测验证集记录最终的 AUC 和方向准确率。4. 用 Python 复现黄金价格预测的最小实验循环与结果验证4.1 数据处理与特征矩阵构造一个函数打通流程比赛中最容易出问题的环节是数据管道不完整这里写了特征那里又改了标签最后模型训练时报维度不一致。建议把所有步骤封装成一个函数输入原始数据输出可直接训练的特征矩阵和目标变量这样不管是在本地复现还是换数据重新跑一遍都不会出错。def build_features(df, label_window5): 从原始行情数据构建特征矩阵与标签返回 (X, y) data df.copy() # 价格序列转收益率 data[return] data[close].pct_change() # 自相关特征 data[ret_ma5] data[return].rolling(5).mean() data[ret_ma10] data[return].rolling(10).mean() data[volatility_5] data[return].rolling(5).std() data[volatility_10] data[return].rolling(10).std() # 动量特征 data[ma5] data[close].rolling(5).mean() data[ma20] data[close].rolling(20).mean() data[close_ma5] data[close] / data[ma5] - 1 data[close_ma20] data[close] / data[ma20] - 1 # 标签未来 label_window 天收益率是否为上涨 data[future_return] data[close].shift(-label_window) / data[close] - 1 data[label] (data[future_return] 0).astype(int) # 去掉没有未来标签的尾部数据 data data.dropna().reset_index(dropTrue) feature_cols [ return, ret_ma5, ret_ma10, volatility_5, volatility_10, close_ma5, close_ma20, ] return data[feature_cols], data[label], data函数的输入输出边界非常关键label_window参数控制了预测视野实验中可以用同一份代码测试 1 日、5 日、10 日不同窗口的预测效果shift(-label_window)生成标签时意味着数据最后一行的未来数据不可见函数用dropna()把尾部无标签的行清理掉防止训练时混入空值。4.2 用一个统一回溯测试流程验证模型有效性比赛论文里只写训练集 AUC 是不太有说服力的真正让评阅老师认可的是“模拟真实交易场景的回溯测试”从历史数据的某一时间点开始只用当时已有的数据训练模型预测未来然后逐步滚动记录每一次预测结果。这和金融领域常用的事后验证思路完全一致也是对未来函数问题最彻底的检验方式。4.2.1 滚动回溯测试的实现思路import xgboost as xgb import numpy as np def backtest_xgboost(X, y, start_index800, step20): 滚动回溯每 step 天重新训练一次模型并预测 predictions [] for i in range(start_index, len(X), step): X_train, y_train X.iloc[:i], y.iloc[:i] # 只预测下一个时间点的涨跌概率 X_test X.iloc[i:i1] model xgb.XGBClassifier( n_estimators200, max_depth4, learning_rate0.05, subsample0.8, eval_metricauc, use_label_encoderFalse, ) model.fit(X_train, y_train) pred model.predict_proba(X_test)[0, 1] predictions.append(pred) return np.array(predictions)这里有两个细节值得注意。第一start_index800表示前 800 个样本只做训练不验证保证模型见过足够的数据step20表示每 20 天重新训练一次这是效率与时效性的折中——频率太高训练时间长频率太低模型跟不上市场结构变化。第二predict_proba输出的是正类概率也就是“预测上涨的概率”后续无论是做方向判断还是画图都用这个概率值不要用predict输出的离散类别离散值会丢失置信度信息。回溯测试结束后把预测概率序列与实际未来涨跌方向对齐计算三个指标方向准确率预测概率大于 0.5 且实际上涨记为正确、AUC、平均概率与实际涨跌幅的相关性。方向准确率达到 54% 以上在黄金这种近乎随机游走的序列上就值得写进论文了不用刻意追求 70% 以上那不现实反而会让评阅老师怀疑数据泄漏。4.3 迭代实验的组织方式让每一步都可复现三天比赛中建议所有实验记录都集中在一个结果表里每次改了一个变量就追加一行记录包括特征版本、模型参数、窗口大小、验证集 AUC、回测方向准确率。这不仅能避免第二天发现前一天的结果和代码对不上更是论文附录里“实验记录表”的原始素材。实验编号特征组合模型参数回测准确率AUC备注E1基础 7 特征XGB, depth4, lr0.050.5270.544基线E2E1 波动率特征XGB, depth4, lr0.050.5410.562波动率有效E3E2 特征XGB, depth6, lr0.010.5330.551过拟合E4E2 特征 宏观变量XGB, depth4, lr0.050.5490.571引入外生变量有效这份表的横向对比就是第 5 章论文讨论部分的核心素材比单纯的“我用了某个模型所以准确率高”有说服力得多。5. 数学建模竞赛论文的技术呈现把模型讲清楚比模型本身更重要5.1 模型局限性分析怎么写才不扣分论文里最容易翻车的部分是“模型评价与改进”很多队伍要么只写“模型效果较好”要么把局限性写成套话。黄金价格预测的模型最值得写的局限有三点。其一是突发事件冲击的不可建模性地缘冲突、央行政策这类信息既没有历史数据佐证也无法从价格序列中提前捕捉模型在极端行情下失效是必然的把这个说明白反而体现对金融数据的理解。其二是样本内的统计显著性不足黄金序列的自由度低模型表现好可能只是运气所以一定要在论文里明确写出“方向准确率与 50% 基准差异的显著性检验”。其三是特征窗口的静态设定模型固定使用过去 5 日和 20 日数据市场结构变化后窗口长度不再最优可以写”使用自适应窗口是后续改进方向“注意这是一句正常的几句话内的技术陈述不要展开太多。5.2 用 Python 把模型输出画成预测区间图数学建模画图 python 是很多队伍拿到高分的关键评阅老师看一篇文章首先看图和表格再决定要不要细看文字。黄金价格预测题最值得画的一张图是“预测概率与实际走势对照图”上半部分是价格曲线和预测信号标注下半部分是模型输出的上涨概率。import matplotlib.pyplot as plt # prob 是回溯测试得到的上涨概率序列 # 对齐到对应的日期索引 fig, ax1 plt.subplots(figsize(12, 6)) ax1.plot(valid_dates, gold_price, colorgray, linewidth1, label实际金价) ax1.set_xlabel(日期) ax1.set_ylabel(价格, colorgray) ax2 ax1.twinx() ax2.plot(valid_dates, prob, colorblue, linewidth1, alpha0.7, label预测上涨概率) ax2.axhline(y0.5, colorred, linestyle--, linewidth0.8) ax2.set_ylabel(上涨概率, colorblue) # 标注方向判断正确的位置预测概率和实际方向一致时画一个点 correct (prob 0.5) (actual_direction 1) ax1.scatter(valid_dates[correct], gold_price[correct], colorgreen, s10, label方向判断正确, zorder3) plt.title(黄金价格走势分析与预测模型概率输出与回溯验证) plt.legend(locupper left) plt.tight_layout() plt.savefig(gold_price_forecast.png, dpi150) plt.show()图中灰线是价格蓝线是预测概率红色虚线是 0.5 的概率分界线。绿色散点是方向判断正确的样本点能一眼看出模型的预测在哪些时段更敏感。画图时注意把valid_dates做成统一的日期索引两张图用twinx()共享横轴避免上下两张子图的时间轴错位。这张图画出来论文的结果呈现已经完成了一大半。5.3 附录里放数据表与代码正文放图表结论每届数学建模大赛的评阅细则都有差异但有一条通用原则正文结论与附录代码、数据文件能对应上评阅老师认可度就会明显提高。表格建议做成上面第 4 章那样的实验记录表把参数、指标、结论一一对应代码附录做三部分就够了——数据预处理、模型训练、回溯测试。这三部分代码和你正文里的三个核心图能一一对上整篇论文就是完整的、可复现的数学建模黄金价格分析与预测方案。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价