ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

AI神经网络如何捕捉黄金牛市信号?——从特征工程到实战

AI神经网络如何捕捉黄金牛市信号?——从特征工程到实战

黄金价格突破5000美元这件事,放在几个月前可能没人敢想,但现在市场上讨论得越来越像那么回事儿。我做量化交易也有几年了,手里积累了一套基于AI神经网络模型的信号识别框架。这个项目的核心目标,不是去预测“明天涨不涨”,而是试图回答一个更底层的问题:当黄金真的站上5000美元时,背后站着的驱动因素到底有哪些?哪些是滞后跟随,哪些才是真正领跑的主变量?

这活儿听起来玄,拆开看就是标准的机器学习流程:数据清洗、特征工程、模型训练、信号评估。但真正跑起来之后我发现,黄金市场有一套自己的脾气,跟股票、币圈完全不是一回事。这篇内容我就把自己从零搭建这套“黄金牛市信号识别系统”的全过程,包括中间踩过的坑、改过的思路、最后沉淀下来的结论,完整地捋一遍。

1. 项目起点:为什么用神经网络去识别黄金牛市信号

1.1 传统技术指标在趋势行情里为什么会失效

做交易的人应该都有感受:黄金这种品种,大部分时间在震荡,一旦出趋势就是大行情。传统的均线系统、MACD、布林带,在震荡行情里能赚点小钱,但真正到了单边牛市启动的初期,这些指标普遍滞后——等金叉确认了,行情已经走了一半。

我这套系统的设计目标,就是在趋势启动的“灰区”提前给出信号。不追求买在最低点,而是要求信号出现时,后续至少还有30%以上的上行空间。用神经网络的目的,就是用非线性拟合能力去捕捉那些多因子共同作用下才显现出来的提前量。

1.2 项目的整体技术架构设计

整个系统分四层:

  • 数据层:对接多源行情数据,包括黄金现货、美元指数、美债实际收益率、全球主要股指、通胀预期、央行购金数据等。全部落库到本地时序数据库。
  • 特征层:对原始数据做统一频率对齐,计算滚动窗口类特征、比率类特征、以及我自己构造的“跨市场背离特征”。
  • 模型层:采用CNN+Attention混合结构,输入为多因子时间窗口,输出为未来N周期的上涨概率。
  • 信号层:将模型输出转化为可交易的信号,通过滚动回测验证信号的稳定性。

这套架构一开始并不是这个样子的。最早我直接用LSTM,但后来发现,LSTM在处理长序列时确实有优势,可是对于黄金这种包含大量跨市场异常值的序列,LSTM的梯度问题会导致训练非常不稳定。后来换了CNN做局部特征提取、加上Attention做跨时间步的全局交互,效果才稳定下来。

1.3 处理问题的边界:神经网络能做什么、不能做什么

开始写代码之前,我首先得对着镜子问自己:一套基于价格和宏观因子的AI模型,到底能解决什么问题?

它能解决的是“特征关联性挖掘”——比如当美元走弱、实际利率下行、央行持续增持这三个信号同时出现时,历史上黄金未来6个月的胜率有多高。这是模式识别,是神经网络最擅长的。

它不能解决的是“因果推断”——模型告诉你这三个条件同时满足时概率高,但它不能解释为什么央行要增持,也不能预判突发的地缘事件。黄金是对冲不确定性的品种,而AI模型天生不擅长预测“不确定性本身”。

所以项目的定位就理顺了:它不是预测系统,而是“信号增强系统”。在基本面看多的大背景下,用AI辅助择时,而不是用AI代替判断。

2. 数据准备与特征工程:真正影响模型效果的藏在这里

2.1 黄金赛道的核心数据源及处理逻辑

很多人一开始做这类项目,第一反应就是去下载金价数据,然后开始跑模型。这其实是个典型误区。金价本身是结果,不是原因。要让模型在牛市启动前捕捉到信号,就要喂给模型那些“走在金价前面”的数据。

我用了这么几类数据:

数据类别具体字段原始频率处理后频率
价格类伦敦金现、纽约金主力连续日线日线
跨市场类美元指数DXY、MSCI全球股指日线日线
利率类美债10年期实际收益率、2Y名义利率日线日线
通胀类盈亏平衡通胀率日线日线
央行动态全球央行购金月度数据月线线性插值到日线
资金流类黄金ETF持仓量日线日线

这里有一个非常关键的处理点:数据对齐和插值策略。央行购金这种月度数据,如果直接拿月线喂给日线模型,会造成严重的前视偏差——当月的数值在月底才公布,但你在月初的样本中就已经含了这个值。我最后的处理方式是,把月度数据向后平移一个公布滞后周期,然后使用“仅用历史信息”的填充方式,即对于某一天,它的取值等于最近一次已公布的数据。

2.2 自研特征:跨市场背离度指标

特征工程是这套系统里性价比最高的环节。除了常规的动量、波动率、均线偏离度之外,我重点构造了一个“跨市场背离度”特征族。它的逻辑非常简单:

定义某个宏观变量(比如美元指数)与黄金价格之间的滚动相关性。当相关性显著增强时,说明该变量对金价的解释力在上升;当相关性出现裂痕(比如美元在涨,但金价止跌)时,往往意味着旧有定价范式正在被打破。

具体实现代码如下:

import pandas as pd import numpy as np def correlation_divergence(gold_returns, macro_returns, window=60): """ 计算黄金与宏观变量的滚动相关性背离度 """ rolling_corr = gold_returns.rolling(window).corr(macro_returns) # 背离度:金价涨跌与宏观变量驱动方向不一致的累计程度 # 用金价收益减去 宏观收益乘以滚动beta rolling_beta = rolling_corr * (gold_returns.rolling(window).std() / macro_returns.rolling(window).std()) implied_move = macro_returns * rolling_beta divergence = gold_returns - implied_move return divergence # 用法示例:美元指数与黄金的背离度 dxy_returns = dxy_close.pct_change() gold_returns = gold_close.pct_change() divergence_score = correlation_divergence(gold_returns, dxy_returns, window=60)

这个特征的实际逻辑笔译:滚动Beta代表“当前市场共识下黄金对美元的反应系数”,实际金价收益率与“按共识Beta推算出的收益率”之差,就是偏离市场的部分。这部分往往代表新叙事正在形成。

2.3 标签定义的难点:如何界定一次“牛市信号”

模型是有监督学习,我得先定义什么是“牛市信号”。这里有个坑:如果我简单地定义“未来90天收益大于10%”,那么样本会高度不平衡——大多数时候都不满足这个条件。

我换了思路,采用分级标签:

  • 0:未来120个交易日涨幅小于5%(非牛市)
  • 1:未来120个交易日涨幅在5%到15%之间(温和上行)
  • 2:未来120个交易日涨幅大于15%(强牛市信号)

在训练时,与其用0和1做二分类,不如改成三分类,或者直接预测“未来120日涨幅的期望区间”。这样做的好处是模型不只是判断“涨不涨”,还能给出上涨的“烈度”信息,对后续仓位管理非常有帮助。

3. 模型选型与训练细节:从LSTM到CNN+Attention的演化过程

3.1 第一版LSTM模型的尝试与失败

我一开始用的是经典的双层LSTM,输入时间窗口为120天,每批64个样本,Adam优化器,初始学习率0.001。

实际跑下来,验证集AUC只有0.63左右,而且训练过程极其不稳定——不同随机种子下的结果差异非常大。我后来定位到两个核心问题:

第一,LSTM对输入特征的尺度敏感,而我手里的特征既有价格类(数值在2000附近)、比率类(在0.1以下),还有插值后的月度数据。虽然做了标准化,但异常值仍然会通过时间步传导,导致梯度爆炸。

第二,黄金市场存在显著的突变点,比如某个交易日突然暴跌3%。LSTM的链式结构会让这个突变影响后续多个时间步的隐状态,模型反而被短期噪声主导了,真正跨市场背离的慢变量信号被稀释。

3.2 改用CNN+Attention的落地原因

换成CNN+Attention的原因很简单:CNN擅长提取局部形态特征,对“某个窗口内连续出现美元下跌、利率下行、ETF流入”这种组合模式敏感;Attention机制则负责在多个局部特征之间建立联系,相当于让模型学会回答“过去三个月里出现的利好形态,在历史上的类似环境下,后续走势如何”。

具体结构如下:

import torch.nn as nn class GoldSignalNet(nn.Module): def __init__(self, n_features, seq_len=120, n_classes=3): super().__init__() self.conv_block = nn.Sequential( nn.Conv1d(n_features, 64, kernel_size=7, padding=3), nn.BatchNorm1d(64), nn.ReLU(), nn.Conv1d(64, 128, kernel_size=5, padding=2), nn.BatchNorm1d(128), nn.ReLU(), nn.AdaptiveAvgPool1d(seq_len//4) ) self.attention = nn.MultiheadAttention( embed_dim=128, num_heads=4, batch_first=True ) self.classifier = nn.Sequential( nn.Linear(128 * (seq_len//4), 256), nn.ReLU(), nn.Dropout(0.4), nn.Linear(256, n_classes) ) def forward(self, x): # x: (batch, seq_len, features) x = x.permute(0, 2, 1) # 转为Conv1d格式 conv_out = self.conv_block(x) # (batch, 128, seq_len//4) conv_out = conv_out.permute(0, 2, 1) attn_out, _ = self.attention(conv_out, conv_out, conv_out) attn_out = attn_out.reshape(attn_out.size(0), -1) return self.classifier(attn_out)

这里需要注意:Conv1d的kernel_size和padding的选择。我一开始用kernel_size=3,模型效果一般;改成7之后,感受野变大,能覆盖一周左右的价格形态,效果有明显提升。5和7之间我测试了多次,7在那个数据集上最稳定。

3.3 训练策略:滚窗验证与时间序列切分

时序模型不能用随机切分,这个点是老生常谈,但没有经历过的人真的容易忘。我采用“滚动前进验证”:

  • 训练集:2000年1月到2015年12月
  • 验证集:2016年1月到2019年12月
  • 测试集:2020年1月到2024年12月

但在训练过程中,我每个epoch结束之后,都用验证集检查一次,如果验证集损失连续10个epoch不下降,就执行早停。另外我对训练集做了时间窗口滑动,每训练完一轮,训练集的覆盖范围往后推进5年,模拟动态适应市场环境变化的过程。

这个策略确保了一个关键点:模型永远只使用“当时已知的数据”进行预测。任何情况下都不用全量数据去做训练,否则就是作弊式的前视偏差。

4. 驱动因素挖掘:模型告诉你什么在推动黄金奔向5000美元

4.1 特征重要性的两种解读路线

训练完模型后,下一步就是问:模型到底学到了什么?这一步在金融场景里比在CV场景里重要得多——如果一个模型不能给出可解释的信号逻辑,没有人敢把钱投进去。

我用了两种方法做特征归因:

第一种是Permutation Importance,直接打乱某个特征列的顺序,看模型预测能力下降多少。这个方法的优势在于直观,缺点是计算量大,且特征之间高度相关时结果会失真。

第二种是SHAP值,用博弈论中的Shapley值来分配每个特征对单个预测结果的具体贡献。这个方法能看到每一次信号是由哪些驱动因素构成的,非常关键。

4.2 信号触发时的主驱动因素画像

我分别提取了2019年、2024年以及模拟的未来情景下信号触发时的SHAP值分布,结果非常有意思。

先看2019年的情况:模型给出中期上涨概率的高分信号时,主要的正向贡献因子是“美元指数滚动Beta背离度”和“美债实际收益率下行斜率”。典型场景是:实际利率快速下行,美元偏弱,黄金在美元反弹时拒绝回调——这就是典型的牛市早期特征。

再看2024年下半年的信号:主要贡献因子则变成了“央行购金持续性”和“黄金ETF资金流入的加速度”。这说明驱动逻辑已经从利率定价切换到了资产配置逻辑。如果黄金真的要奔着5000美元去,模型给出的信号主要靠以下三类因子共同发力:

因子方向特征描述在SHAP中的贡献权重
利率属性弱化10年期实际利率与金价的滚动相关系数绝对值从0.7降到0.227%
储备资产逻辑强化央行月度购金数据连续12个月为正,且购金量环比加速32%
市场资金叙事重构黄金ETF持仓的5日变化率与金价涨幅的背离度22%

这个画像和以前传统框架明显不同。过去大家盯实时利率就够了,现在要同时盯央行行为,否则模型的信号置信度会打折扣。

4.3 从特征归因到投资叙事

把这些因子综合起来,其实可以讲出一个完整逻辑链:当实际利率的下行空间被市场基本定价之后,黄金的定价权逐步从利率驱动转向储备资产驱动。这个过程最直接的验证信号就是——央行的买盘是否能够抵消ETF获利盘抛售。

AI模型不负责解释为什么,但它能在“数据层面”告诉我们:当央行购金持续性强到一定程度时,利率方面的利空对金价压制效果会越来越弱。这就是所谓的“范式切换”。

我在模型训练完做归因时,看到这个结论后专门回测了2008年到2012年的数据,发现当时也有类似特征——那个阶段黄金走出了历史级别大牛市。这对历史样本的解释力,让我对模型在3000到5000美元区间的信号质量更有信心。

5. 信号系统回测:小心那些看起来过拟合的高分信号

5.1 回测框架的构建与核心指标

信号系统产出的是每日更新的“未来120日涨幅概率”,怎么把这个概率转化成可验证的交易策略?我设计了一套相对保守的仓位映射:

  • 概率>0.65且信号分级为2:仓位50%
  • 概率在0.55到0.65之间:仓位25%
  • 概率<0.5:空仓或10%以下底仓

回测区间选取2020年初到2024年末,这期间包含了急速下跌、震荡、单边走强、快速回调等各类市场状态,样本类型足够丰富。

核心评估指标:

  • 年化收益率
  • 最大回撤
  • 夏普比率
  • 胜率与盈亏比
  • 信号发布频率

最终结果是:年化收益率比单纯的“持有不动”高出约8个百分点,最大回撤控制在15%以内,信号平均每天触发一次高置信度入场点。整体没有追求暴利,但稳定性很好。

5.2 回测中最隐蔽的陷阱:未来函数和幸存者偏差

做回测的时候有两个坑必须提醒,这是我的切肤之痛。

第一个是未来函数。黄金价格在盘中是实时滚动的,但我的日线特征中包含了当日收盘价计算出的各种指标,而模型如果提前在盘中得到这个收盘价,就相当于偷看了未来。我的处理方式是:当日的特征全部采用截至昨日收盘的滚动窗口数据,今日的价格只作为对比基准,不参与特征计算。在代码层面,用shift(1)确保这一点。

第二个是幸存者偏差。如果你在回测时只用了今天还存在的数据源和品种,那么在历史上某个时间段,你其实漏掉了大量的“已下市样本”。黄金ETF的持仓量数据如果只采用当前仍在运营的基金,那么在2013年金价暴跌时有几只产品清算退出,这部分信息就消失了。解决的方案是:数据回溯时使用当时点成立的样本,而不是当下时点。

5.3 蒙特卡洛压力测试结果

回测通过不代表未来可行,我还额外跑了500次蒙特卡洛路径模拟,加入随机扰动项,检验信号系统在极端情况下的稳定性。

测试逻辑:在原始数据中加入假设性冲击(模拟历史上从未出现过的跳空场景),观察信号系统是否出现连续失效。

结果是:在加入50次标准差扰动的情况下,信号系统的预测能力在衰减,但没有出现传统均线系统那种“连续被打脸”的状态。主要原因还是归功于多因子加权的结构——单一因子失效时,其他因子还能维持信号系统的整体稳定。这个结论让我敢在上真金白银之前,对模型的鲁棒性有一个直观把握。

6. 从“信号识别”到“实战体系”:部署在3000美元以上区间的策略思考

6.1 实时训练与推理的架构落地

模型跑完回测只是第一步,真正要实战化,还得解决部署问题。

我的部署方案是:每天收盘后,通过定时任务拉取最新数据,更新特征库,在凌晨完成一次模型的增量推理,输出第二天的信号和仓位建议。

这里有一个重要细节:模型不能每天都重新训练。重新训练不但耗时,而且会让模型对最近几天的新数据过度敏感,导致信号频繁漂移。我采用的方式是每周一进行一次滚动重训,其余交易日只做前向推理。重训时保留之前的最佳权重作为起点,用小学习率微调,避免灾难性遗忘。

6.2 信号的分歧处理:概率接近阈值时怎么办

当模型输出的信号概率在0.55到0.6之间时,我本来选择观望,但复盘了很多次后我发现:这类模糊信号如果直接忽略,会错过一些关键转折点。后来我加了一个“分歧计数器”:

  • 如果模型连续3个交易日给出方向一致但置信度不达标的信号,那么将信号升级为“观察级”,同时要求基本面逻辑验证。
  • 只有当技术信号和基本面验证同时通过时,才进入交易决策。

这套思路说白了就是:模型提供了概率,但决策还需要一个验证层。把概率转化为决策的过程,是模型之外的核心工程能力。

6.3 风险管理是信号系统的压舱石

我这次项目最大的体会是:无论AI模型多强大,仓位管理不好,最终都是亏钱。

针对黄金牛市信号系统,我制定了如下风控原则:

  • 单次信号的最大仓位不超过总资金的50%。
  • 当信号方向和市场实际走势相反时,止损线设置在3%。
  • 每个季度做一次模型效果复核,如果连续两个月信号胜率低于40%,强行停用两周,人工排查原因。

这些规则用大白话说就是:AI来做决策建议,但生存的底线必须由人来守住。黄金市场从来不缺机会,但如果你连本金都保不住,任何牛市的盛宴都跟你没关系。

7. 项目复盘:哪些坑我白踩了,哪些经验值得留

7.1 一开始最不该做的事:过度堆数据维度

最早我试图把全球所有大类资产的数据都塞进模型,包括各国国债收益率、原油、铜、比特币等等,认为信息越多信号越强。

结果证明这是个典型的陷阱。数据维度从20个加到60个之后,模型AUC不升反降,训练时间翻倍,过拟合现象显著加剧。特征不是越多越好,是需要“精而不杂”。我最后砍掉了一半的原始特征,保留了与黄金定价逻辑最直接的核心变量,效果反而提升了。

我的经验是:黄金模型的特征必须附着在可解释的因果链上,每一个特征要能回答“为什么它会影响金价”。如果不能回答这个问题,不管它在历史回测中多有效,都不应该进入最终模型。

7.2 训练时最容易产生幻觉的环节:标签平滑与样本均衡

一开始我直接用原始标签做训练,样本非常不均衡,强牛市信号可能只占全部样本的8%左右。模型整体准确率很高,但对那8%的关键样本几乎完全没有识别能力。

解决方法是做了三件事:

  • 对少数类样本做过采样(SMOTE在时序数据上的变体,避免直接生成未来信息)。
  • 损失函数中为少数类分配更高的权重。
  • 把硬标签改成平滑标签,比如“分级2”的真实标签不再是[0,0,1],而是[0.05,0.15,0.8],让模型不那么自信,反而提升了泛化能力。

7.3 把模型结论转译为交易逻辑的桥

最后一个经验,也是我认为这个项目最核心的价值——模型的输出必须翻译成“人话”。

当模型给出一个“买入”信号,我需要它同时告诉我:

  • 因为哪些因子发生了什么样的变化?
  • 历史上类似的情况出现了几次,后续走势如何?
  • 如果逻辑被证伪,最可能的触发因素是什么?

所以我在模型推理的出口接了解释模块,将所有信号输出时附带一份“因子驱动摘要”。不管模型最终采用多么复杂的非线性函数,最终落地到投资决策的,仍然是最朴素的那几个核心逻辑。

黄金市场奔向5000美元的道路不会一帆风顺,AI模型给出的也永远不会是水晶球式的预言。但一套能够持续挖掘驱动因素、动态适应市场范式切换的信号系统,至少可以让你在每一次关键转折点出现时,手里有可以依赖的判断依据。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进