4、网格搜索法:暴力搜索、步长选择、并行计算优化

网格搜索,说白了就是最笨也最靠谱的方法。

我刚开始做套利策略那会儿,总觉得应该有更聪明的办法。后来被市场反复教育,才明白一个道理——在参数空间足够小的时候,暴力搜索反而是最不容易出错的。你想想看,那些花里胡哨的优化算法,万一收敛到局部最优,你连哭的地方都没有。

4.1 暴力搜索:简单粗暴但有效

网格搜索的核心思想,就是把所有可能的参数组合都试一遍。比如你的套利策略有两个参数:窗口大小和入场阈值。窗口大小从10到50,步长5;阈值从0.5到2.0,步长0.1。那么总共就是 (50-10)/5+1 = 9 个窗口值,乘以 (2.0-0.5)/0.1+1 = 16 个阈值,一共 144 种组合。

嗯,144种组合,单机跑也就几分钟的事。但如果你有5个参数呢?每个参数10个值,那就是10万种组合。这时候你就得考虑怎么优化了。

核心原则:网格搜索不是无脑遍历,而是有策略地覆盖参数空间。先粗搜,再精搜,这是我最常用的套路。

我在项目中遇到过这样一个案例:一个跨期套利策略,参数多达7个。如果全量网格搜索,组合数超过200万。我当时的第一反应是——这得跑到猴年马月?后来我用了两阶段法:先大步长粗搜,锁定最优区域,再小步长精搜。最终只跑了不到1万次,就找到了接近全局最优的解。

4.2 步长选择:粗与细的平衡

步长选多大?这是个好问题。

步长太大,容易错过最优参数。步长太小,计算量爆炸。我个人习惯这样判断:

  • 先看参数敏感度——有些参数微调一点,收益就剧烈波动,这种必须用小步长
  • 再看参数范围——范围大的参数,步长可以适当放大
  • 最后看计算资源——资源充裕就细搜,紧张就粗搜

举个例子,我做过一个统计套利策略,其中有个参数叫「回归周期」,范围是5到120天。我一开始步长设了5天,结果跑了整整一天。后来我发现,这个参数在30天附近表现最好,但30到40天之间的差异其实很小。于是我改成:先以10天为步长粗搜,锁定30-40区间,再以2天为步长精搜。效率提升了5倍。

我的经验:步长选择没有标准答案。我一般先做一次敏感性分析,画出参数-收益曲线,看看哪些区域变化剧烈,哪些区域比较平坦。剧烈区域用小步长,平坦区域用大步长。

4.3 并行计算优化:让多核CPU干活

网格搜索最大的痛点是什么?慢。但好消息是,网格搜索天然适合并行化——每个参数组合的计算是独立的,互不依赖。

我曾经用单核跑一个10万次搜索的任务,跑了整整一个周末。后来改成8核并行,一个晚上就搞定了。你想想看,这效率差距有多大。

下面是我常用的Python并行代码模板:

from multiprocessing import Pool
import numpy as np

def evaluate_params(params):
    """评估一组参数的表现"""
    window, threshold = params
    # 这里放你的策略回测逻辑
    sharpe = run_backtest(window, threshold)
    return (params, sharpe)

# 生成参数网格
windows = range(10, 51, 5)
thresholds = np.arange(0.5, 2.1, 0.1)
param_grid = [(w, t) for w in windows for t in thresholds]

# 并行计算
if __name__ == '__main__':
    with Pool(processes=8) as pool:
        results = pool.map(evaluate_params, param_grid)
    
    # 找出最优参数
    best_params, best_sharpe = max(results, key=lambda x: x[1])
    print(f"最优参数: 窗口={best_params[0]}, 阈值={best_params[1]}")
    print(f"最优夏普: {best_sharpe:.3f}")

注意:并行不是万能的。如果你的回测函数本身就很慢(比如涉及大量IO操作),并行提升有限。另外,Python的GIL锁对CPU密集型任务有影响,建议用multiprocessing而不是threading。

4.4 网格搜索的完整流程

说了这么多,我们来梳理一下完整的网格搜索流程。我一般按这个步骤走:

  1. 确定参数范围——根据业务逻辑和经验,划定每个参数的合理区间
  2. 选择步长策略——先粗后精,或者根据敏感度动态调整
  3. 设计并行方案——根据CPU核心数,合理分配计算任务
  4. 执行搜索——跑起来,同时监控进度(我习惯加个进度条)
  5. 结果分析——不只是看最优值,还要看参数稳定性、敏感度等

下面这张图展示了网格搜索的核心逻辑:

网格搜索核心流程 步骤1:定义参数空间 窗口、阈值、周期... 步骤2:选择步长策略 粗搜→精搜 步骤3:并行执行 多核/分布式 步骤4:收集结果 参数→绩效映射 步骤5:分析优化 稳定性、敏感度 不满足要求?调整参数范围或步长,重新搜索 输出最优参数 网格搜索本质:用计算资源换参数确定性

4.5 避坑指南

做网格搜索这些年,我踩过的坑不少。挑几个典型的说说:

坑1:过拟合

我曾经把网格搜索跑出来的最优参数直接上实盘,结果亏得一塌糊涂。后来才明白,网格搜索找到的「最优」很可能只是历史数据上的过拟合。我的解决方案是:用滚动窗口验证,或者加一个正则化惩罚项。

坑2:忽略计算成本

有一次我为了追求精度,把步长设得非常小,结果跑了三天三夜。最后发现,最优参数和粗搜结果相差不到1%。从那以后,我给自己定了个规矩:先粗搜,再精搜,精搜范围不超过粗搜最优值的±20%。

我的建议:网格搜索不是终点,而是起点。找到最优参数后,一定要做稳定性测试——在最优参数附近随机采样,看看绩效波动大不大。如果波动很大,说明这个参数不可靠,需要重新设计策略。

好了,网格搜索就讲到这里。记住一句话:暴力搜索不可怕,可怕的是不知道什么时候该用暴力。

核心要点回顾:

  • 网格搜索适合参数空间较小的情况
  • 步长选择要「先粗后精」,根据敏感度动态调整
  • 并行计算能大幅提升效率,但要注意GIL限制
  • 结果分析比搜索本身更重要,警惕过拟合

公众号:蓝海数据掘金营,微信 deep3321