8、参数优化方法:网格搜索、随机搜索、贝叶斯优化

做市策略写好了,参数怎么调?

这是每个做市商都会头疼的问题。我见过不少团队,策略逻辑没问题,就是参数没调好,回测结果差一大截。说白了,参数优化就是给策略找最合适的「旋钮位置」。

今天咱们聊聊三种主流方法:网格搜索、随机搜索、贝叶斯优化。每种都有它的脾气,用对了事半功倍。

8.1 网格搜索:简单粗暴,但别滥用

网格搜索是最直观的方法。你把每个参数的可能取值列出来,然后穷举所有组合。

举个例子,假设我们要优化两个参数:

  • 订单簿深度:取 5、10、15 层
  • 报价更新频率:取 100ms、200ms、500ms

网格搜索会跑 3×3 = 9 次回测,找出最优组合。

优点:实现简单,结果可复现,适合参数少的情况。

缺点:参数一多就爆炸。5 个参数,每个取 10 个值,就是 10 万次回测。

# 网格搜索示例
import itertools

param_grid = {
    'depth': [5, 10, 15],
    'update_ms': [100, 200, 500]
}

best_score = -float('inf')
best_params = None

for depth, update_ms in itertools.product(param_grid['depth'], param_grid['update_ms']):
    score = run_backtest(depth, update_ms)
    if score > best_score:
        best_score = score
        best_params = {'depth': depth, 'update_ms': update_ms}

print(f"最优参数: {best_params}, 得分: {best_score}")

我的经验:网格搜索适合做「粗调」。先用大步长扫一遍,找到大致区域,再缩小范围细调。别一上来就搞精细网格,那是在浪费算力。

8.2 随机搜索:更聪明的穷举

随机搜索的思路很简单:既然穷举太慢,那就随机采样。

你想想看,网格搜索在参数空间里均匀打点,但很多点其实没必要跑。随机搜索在指定范围内随机选参数组合,跑 N 次后取最优。

为什么随机搜索往往比网格搜索好?

  • 网格搜索的采样点分布均匀,但维度高时「稀疏」得厉害
  • 随机搜索能覆盖更多「有希望」的区域
  • 同样的计算次数,随机搜索找到好参数的概率更高
# 随机搜索示例
import random

param_ranges = {
    'depth': (5, 20),
    'update_ms': (50, 1000)
}

n_iterations = 100
best_score = -float('inf')
best_params = None

for _ in range(n_iterations):
    depth = random.randint(*param_ranges['depth'])
    update_ms = random.randint(*param_ranges['update_ms'])
    
    score = run_backtest(depth, update_ms)
    if score > best_score:
        best_score = score
        best_params = {'depth': depth, 'update_ms': update_ms}

print(f"最优参数: {best_params}, 得分: {best_score}")

注意:随机搜索的结果不稳定。同样的代码跑两次,可能得到不同结果。我建议多跑几轮,取平均或取最优中的稳定值。

8.3 贝叶斯优化:用历史指导未来

网格搜索和随机搜索都是「盲人摸象」。每次跑完回测,结果就扔了,下次从头再来。

贝叶斯优化不一样。它会记住每次回测的结果,用这些信息指导下一次采样。说白了,它知道哪些区域「有希望」,就多去那里看看。

核心思想:

  1. 用高斯过程(GP)拟合参数与得分的关系
  2. 根据拟合结果,计算「采集函数」
  3. 在采集函数最大的地方采样
  4. 重复直到收敛
# 贝叶斯优化示例(使用 scikit-optimize)
from skopt import gp_minimize
from skopt.space import Integer

def objective(params):
    depth, update_ms = params
    return -run_backtest(depth, update_ms)  # 最小化负得分

space = [
    Integer(5, 20, name='depth'),
    Integer(50, 1000, name='update_ms')
]

result = gp_minimize(
    objective, 
    space, 
    n_calls=50,  # 跑 50 次
    random_state=42
)

print(f"最优参数: depth={result.x[0]}, update_ms={result.x[1]}")
print(f"最优得分: {-result.fun}")

贝叶斯优化的优势

  • 收敛快,通常 30-50 次就能找到不错的参数
  • 适合高维参数空间
  • 能处理噪声(回测结果有随机性)

8.4 三种方法对比

方法 适用场景 计算量 结果稳定性 实现难度
网格搜索 参数少(≤3个),范围明确 高(指数增长)
随机搜索 参数中等(3-6个) 中(线性增长)
贝叶斯优化 参数多(≥5个),计算昂贵 低(智能采样) 中高

我的建议

  • 刚开始做回测,先用网格搜索找感觉
  • 参数多了,换随机搜索
  • 如果一次回测要跑几分钟甚至几小时,果断上贝叶斯优化

8.5 避坑指南

我在项目中遇到过不少坑,分享几个典型的:

  • 过拟合:优化出来的参数在回测里表现很好,实盘一塌糊涂。解决办法:用交叉验证,或者留一段数据做验证集。
  • 参数相关性:有些参数是相关的,比如订单簿深度和报价频率。单独优化一个,另一个跟着变。建议用贝叶斯优化,它能自动处理相关性。
  • 计算资源浪费:我曾经用网格搜索优化 8 个参数,跑了整整一周。后来发现,前 3 个参数就决定了 90% 的性能。先做敏感性分析,找到关键参数再优化。

重要提醒:参数优化不是一劳永逸的。市场环境变了,最优参数也会变。我建议每季度重新优化一次,或者用自适应参数。

8.6 知识体系图

下面这张图展示了三种优化方法的核心逻辑和适用场景:

参数优化方法知识体系 参数优化方法 网格搜索 穷举所有参数组合 适合参数少(≤3个) 结果稳定,实现简单 随机搜索 随机采样参数组合 适合参数中等(3-6个) 结果有随机性 贝叶斯优化 用历史指导采样 适合参数多(≥5个) 收敛快,实现复杂 选择建议 参数少 → 网格搜索(简单可靠) 参数中等 → 随机搜索(效率更高) 参数多/计算昂贵 → 贝叶斯优化(智能高效)

嗯,三种方法各有千秋。我个人习惯是:先用网格搜索做粗调,再用贝叶斯优化做精调。这样既快又稳。

记住,参数优化不是终点。优化出来的参数要在不同市场环境下验证,才能放心实盘。


交易系统化学习资料 微信Strategy888888