数据科学与机器学习(第 06 部分):梯度下降(基础篇)
梯度下降前的那句警告
做机器学习交易模型时,很多人一上来就调学习率、换优化器、加正则,结果回测曲线好看、实盘稀烂。唐纳德·高德纳那句老话在 MQL5 + Python 混合架构里依然成立:过早优化是万恶之源。 在 MetaTrader 5 里跑梯度下降类策略,先确保特征工程和数据管道没bug,再谈收敛速度。2022年11月那篇系列开篇文章里点明,基础不牢就堆参数,只会把过拟合伪装成「智能」。 外汇与贵金属杠杆高、滑点随机,这类模型实盘前至少在 MT5 策略测试器用不同年份数据跑三遍,确认不是靠某段特殊行情「记」住的。
「梯度下降在模型寻参里的位置」
梯度下降(也叫最陡下降)是一阶迭代优化算法,用来对可微函数找局部最小值。做法很直接:在当前点沿函数梯度的反方向迈步,因为那是最陡的下降方向;反过来沿梯度正向走,就会逼近局部最大值,那种做法叫梯度上升。 在机器学习里,这套思路被用来确定模型参数——给定数据集,算法沿成本函数下降的方向去调权重,使拟合误差逐步缩小。外汇与贵金属行情序列噪声大、非平稳,直接拿梯度类方法寻参要警惕过拟合与滑点损耗的高风险。 原文提到的成本函数,本质是「模型预测值 vs 真实值」的误差度量。下一节会把它和回归模型的参数求解连起来讲,你可以先在 MT5 里用历史 EURUSD 1H 数据跑一段简单线性回归,感受下残差随迭代的变化。
◍ 成本函数如何判定模型优劣
成本函数也有人叫它亏损函数,作用是衡量模型对 x 与 y 之间关系拟合得到底准不准。它和单点误差不同,看的是整个数据集上的平均亏损——数值越大,说明模型从数据里抓关系的本事越差。 梯度下降的核心目标就是把成本函数压到最小,因为成本最低的那版模型才最接近最优解。拿一个具体式子说,若成本函数为 y=(x+5)^2,它其实是个复合结构:外层是平方运算,内层是 x+5。 用链式法则拆开求导,得到的导数函数就是梯度。这一步是整个流程里最关键的,找到梯度才算真正摸到了优化的门把手。 接下来要朝梯度的反方向挪步,但一次挪多少就得靠学习曲率来定,这部分留到下一节拆。
步长怎么掐才不跳过谷底
梯度下降里每次迭代挪动的量就是学习曲率,类比下山:步子小到 0.0001 这种级别,算法可能要多跑成千上万次才探到极小值;步子放大又容易跨过谷底,错失目标点。默认取 0.01 是个折中起点,实盘调参时建议从这个数附近来回试。 以成本函数 2*(x+5) 为例,从 x0=0 起步,第一次迭代 x1 = 0 - 0.01*2*(0+5) = -0.1,第二次 x1 = -0.1 - 0.01*2*(-0.1+5) = -0.198。前 5 次迭代成本函数从 10.0 降到 9.22368,降幅肉眼可见;越靠近极小值,步长越像凑近山脚时的碎步。 日志显示该例跑满 1062 次迭代才触到局部极小值 -5.0。成本函数归零即停,这是梯度知道自己收工的信号。EURUSD 这类外汇品种波动大、杠杆高,拿这套思路做参数寻优时,过拟合风险得自己扛。 下面这段 MT5 日志是前述十次迭代的原始输出,直接贴进专家日志就能对照验证数值走向:
RS class="num">0 class="num">17:class="num">15:class="num">16.793 gradient-descent test(EURUSD,M1) Gradient Descent CostFunction CUSTOM QQ class="num">0 class="num">17:class="num">15:class="num">16.793 gradient-descent test(EURUSD,M1) class="num">1 x0 = class="num">0.0000000000 x1 = -class="num">0.1000000000 CostFunction = class="num">10.0000000000 ES class="num">0 class="num">17:class="num">15:class="num">16.793 gradient-descent test(EURUSD,M1) class="num">2 x0 = -class="num">0.1000000000 x1 = -class="num">0.1980000000 CostFunction = class="num">9.8000000000 PR class="num">0 class="num">17:class="num">15:class="num">16.793 gradient-descent test(EURUSD,M1) class="num">3 x0 = -class="num">0.1980000000 x1 = -class="num">0.2940400000 CostFunction = class="num">9.6040000000 LE class="num">0 class="num">17:class="num">15:class="num">16.793 gradient-descent test(EURUSD,M1) class="num">4 x0 = -class="num">0.2940400000 x1 = -class="num">0.3881592000 CostFunction = class="num">9.4119200000 JD class="num">0 class="num">17:class="num">15:class="num">16.793 gradient-descent test(EURUSD,M1) class="num">5 x0 = -class="num">0.3881592000 x1 = -class="num">0.4803960160 CostFunction = class="num">9.2236816000 IG class="num">0 class="num">17:class="num">15:class="num">16.793 gradient-descent test(EURUSD,M1) class="num">6 x0 = -class="num">0.4803960160 x1 = -class="num">0.5707880957 CostFunction = class="num">9.0392079680 IG class="num">0 class="num">17:class="num">15:class="num">16.793 gradient-descent test(EURUSD,M1) class="num">7 x0 = -class="num">0.5707880957 x1 = -class="num">0.6593723338 CostFunction = class="num">8.8584238086 JF class="num">0 class="num">17:class="num">15:class="num">16.793 gradient-descent test(EURUSD,M1) class="num">8 x0 = -class="num">0.6593723338 x1 = -class="num">0.7461848871 CostFunction = class="num">8.6812553325 NI class="num">0 class="num">17:class="num">15:class="num">16.793 gradient-descent test(EURUSD,M1) class="num">9 x0 = -class="num">0.7461848871 x1 = -class="num">0.8312611893 CostFunction = class="num">8.5076302258
「EURUSD M1 上梯度下降的收敛实况」
在 MT5 策略测试器中跑梯度下降,品种切到 EURUSD、周期 M1,能直接看到代价函数被压到极小值的过程。首帧迭代 10 次时 x0=-0.8312611893、x1=-0.9146359656,CostFunction 还有 8.3374776213,离最优解很远。 到第 1052 次迭代,x0 与 x1 都已逼近 -4.9999999970 附近,CostFunction 骤降到 0.0000000060;此后每迭代一次代价函数约减 1e-11,参数在 -4.999999997x 这一带做亚小数点级别的微调。 外汇与贵金属属高风险品种,M1 上这种数值收敛不代表实盘能稳定盈利,仅证明优化器在该样本上跑通。开 MT5 把同样测试脚本挂 EURUSD M1,对照 1052 与 1062 两次日志,就能验证收敛节奏是否一致。
◍ 梯度下降在 EURUSD 上的收敛实测
在 MT5 策略测试器里跑一段梯度下降验证代码,EURUSD M1 周期下日志会重复打印两行:Local minimum found = -4.999999997546217,时间戳停在 17:15:16.800。这说明算法在约第若干次迭代后,把代价函数压到了 8 位精度归零,锁定了局部极小点。 核心循环是一个死循环 while(true),每轮迭代次数加一,用 x1 = x0 - 学习率 * CustomCostFunction(x0) 更新权重。代价函数写死为 2*(x+5),理论极小点在 x = -5,日志里的 -4.9999999975 已经贴近这个解析解。 外汇与贵金属品种用这类数值优化做参数寻优时,高风险在于实盘噪声会让代价面畸变,M1 上拟合出的极小点换周期可能漂移。开 MT5 把下面代码贴进 EA 的 OnTick 或单独脚本,改 m_learning_rate 看收敛速度变化,比读文档直观。
class="kw">while (true) { iterations++; x1 = x0 - m_learning_rate * CustomCostFunction(x0); printf("%d x0 = %.10f x1 = %.10f CostFunction = %.10f",iterations,x0,x1,CustomCostFunction(x0)); if (NormalizeDouble(CustomCostFunction(x0),class="num">8) == class="num">0) { Print("Local minimum found =",x0); class="kw">break; } x0 = x1; } class="type">class="kw">double CGradientDescent::CustomCostFunction(class="type">class="kw">double x) { class="kw">return(class="num">2 * ( x + class="num">5 )); }