第十二章:模拟退火调优——从“热锅上的蚂蚁”到“精准落子”

说到参数调优,很多朋友第一反应就是网格搜索或者随机搜索。这两种方法简单粗暴,但有个致命伤——容易陷入局部最优。就像你爬山,爬到一个小山头就以为到顶了,其实旁边还有更高的山峰。

今天聊的模拟退火,就是专门解决这个问题的。它的灵感来自冶金学里的退火工艺——先把金属加热到高温,再慢慢冷却,让原子有足够时间找到能量最低的排列。说白了,就是先让参数“乱跑”,再慢慢“收网”。

核心思想: 模拟退火允许算法在初期“接受差解”,从而跳出局部最优;随着温度降低,接受差解的概率越来越小,最终收敛到全局最优附近。

12.1 模拟退火原理——热力学给量化交易的礼物

模拟退火算法模拟的是固体退火过程。高温时,粒子动能大,可以自由移动;温度降低,粒子逐渐稳定在低能态。对应到参数调优:

  • 状态 = 一组参数组合(比如均线周期、止损比例)
  • 能量 = 目标函数值(比如夏普比率、年化收益)
  • 温度 = 控制参数搜索的“随机性”

我刚开始接触这个算法时,总觉得它像个“醉汉走路”——明明找到了好参数,还要故意往坏的方向走。后来才明白,这正是它的高明之处。

我的经验: 模拟退火特别适合那种“参数多、目标函数不平滑”的场景。比如基差交易里,同时优化入场阈值、止损倍数、持仓周期三个参数,网格搜索要跑几千次,模拟退火几百次就能找到不错的解。

12.2 温度衰减函数——降温的节奏很重要

温度怎么降,直接决定了算法能不能找到好参数。常见的衰减方式有几种:

衰减方式 公式 特点
指数衰减 T = T₀ × α^k 最常用,α通常取0.8~0.99
线性衰减 T = T₀ - k × ΔT 降温太快,容易陷入局部最优
对数衰减 T = T₀ / ln(1 + k) 降温慢,理论上能保证收敛到全局最优

我个人习惯用指数衰减,α取0.95左右。为什么?因为前期降温快一点可以快速排除明显不好的区域,后期降温慢一点可以在好区域精细搜索。你想想看,这跟交易里“先大周期定方向,再小周期找入场”是一个道理。

避坑指南: 我曾经把α设成0.99,结果跑了2000次迭代温度还没降下来,参数一直在乱跳。后来改成0.95,效果好了很多。α太接近1,等于没降温;α太小,又等于直接变爬山算法。建议从0.95开始试。

12.3 Metropolis准则——接受差解的智慧

这是模拟退火最核心的部分。简单说:

  • 如果新参数比旧参数好(能量更低),100%接受
  • 如果新参数比旧参数差,以概率 P = exp(-ΔE / T) 接受

其中ΔE是能量差(新解减旧解),T是当前温度。温度高时,P接近1,差解也容易被接受;温度低时,P接近0,基本只接受好解。

嗯,这里要注意:ΔE是负的(新解更差),所以exp(-ΔE/T) = exp(|ΔE|/T),这个值在0到1之间。我刚开始写代码时搞反了符号,结果算法一直在接受差解,永远不收敛。调试了一下午才发现。

# Metropolis准则的Python实现
def metropolis(old_energy, new_energy, temperature):
    if new_energy < old_energy:
        return True  # 新解更好,直接接受
    else:
        delta = new_energy - old_energy
        probability = np.exp(-delta / temperature)
        return np.random.random() < probability

12.4 模拟退火在参数调优中的应用

拿基差交易举个例子。假设我们要优化三个参数:

  • 入场阈值(基差偏离均值的标准差倍数):1.0 ~ 3.0
  • 止损倍数(ATR的倍数):1.5 ~ 4.0
  • 持仓周期(交易日数):5 ~ 30

目标函数是夏普比率。模拟退火的流程:

  1. 随机初始化一组参数,计算夏普比率
  2. 在当前参数附近随机扰动,得到新参数
  3. 用Metropolis准则判断是否接受新参数
  4. 按衰减函数降低温度
  5. 重复2-4步,直到温度降到接近0

我记得有一次做螺纹钢的基差策略,网格搜索跑了整整一个周末,结果还不如模拟退火跑3小时找到的参数好。为什么?因为网格搜索的步长是固定的,很容易跳过最优区域;而模拟退火在好区域会自动加密搜索。

关键点: 模拟退火不是“精确求解”,而是“近似最优”。对于量化交易来说,这完全够用了——你不需要找到理论上的最优参数,只需要找到一组在样本外也能稳定盈利的参数。

12.5 调优技巧——让模拟退火更实用

做了这么多年参数调优,我总结了几条实战技巧:

  • 初始温度怎么定? 先跑几十次随机搜索,看目标函数值的波动范围。初始温度设为这个范围的10倍左右。比如夏普比率波动在0.5~1.5之间,初始温度设10~15。
  • 扰动步长要自适应: 温度高时步长大,温度低时步长小。我一般用 T / T₀ × 初始步长 来控制。
  • 多次运行取最优: 模拟退火有随机性,跑一次可能运气不好。我习惯跑5~10次,取最好的结果。
  • 结合局部搜索: 模拟退火结束后,再用爬山法在最优解附近精细搜索一下。这叫“退火+精炼”,效果很好。

我的一个小技巧: 在目标函数里加入“惩罚项”。比如参数太极端(止损倍数设到4.0)就扣分。这样算法会自动避开那些在样本内表现好、但实际交易中容易爆仓的参数。

12.6 模拟退火流程图

下面这张图展示了模拟退火的核心逻辑,我画得比较简洁,方便你理解整个流程:

模拟退火参数调优流程图 初始化参数 & 温度 生成新参数(扰动) 新解更好? Metropolis准则 接受新参数 拒绝,保留旧参数 温度衰减 温度 < 阈值? 继续迭代 输出最优参数

这张图把整个流程串起来了。你从“初始化”开始,沿着箭头走一遍,就能理解模拟退火是怎么一步步找到好参数的。说白了,就是“先乱跑,再收网”。

最后说一句: 模拟退火不是万能药。如果你的目标函数特别平坦(所有参数组合都差不多),或者参数之间完全独立,那它可能不如网格搜索。但大多数情况下,尤其是基差交易这种参数相互影响的场景,模拟退火是我最常用的调优工具。


公众号:蓝海资料掘金营,微信deep3321