3、参数空间探索:网格搜索法、随机搜索法、贝叶斯优化入门
做市策略的参数优化,说白了就是在一堆数字里找到最赚钱的那组组合。我见过不少新手上来就凭感觉调参数,结果回测曲线好看,实盘一跑就崩。嗯,这里要明确一点:参数空间探索不是瞎蒙,是有方法论支撑的。
我个人习惯把参数优化分成三个层次。第一层是暴力枚举,第二层是随机抽样,第三层是智能搜索。今天咱们就把这三层都过一遍,看看它们各自适合什么场景。
核心观点:没有最好的搜索方法,只有最合适的。参数少用网格,参数多用随机,计算资源充裕用贝叶斯。
3.1 网格搜索法:最笨但最可靠
网格搜索,顾名思义,就是把参数空间切成一张网。每个交叉点都跑一次回测。比如你有两个参数:订单间隔(5秒到30秒)和挂单深度(1档到5档),那就形成一个二维网格。
我在项目中遇到过这样的情况:一个同事用网格搜索优化了三个参数,跑了整整两天。结果发现最优解就在网格边界上。为什么?因为网格太粗了,错过了中间区域。所以网格搜索的关键在于步长选择。
# 网格搜索示例代码
import numpy as np
# 定义参数网格
interval_grid = np.arange(5, 31, 5) # 5秒步长
depth_grid = np.arange(1, 6, 1) # 1档步长
best_sharpe = -np.inf
best_params = None
for interval in interval_grid:
for depth in depth_grid:
# 这里调用回测函数
sharpe = run_backtest(interval, depth)
if sharpe > best_sharpe:
best_sharpe = sharpe
best_params = (interval, depth)
print(f"最优参数: 间隔={best_params[0]}秒, 深度={best_params[1]}档")
print(f"最优夏普: {best_sharpe:.2f}")
我的经验:网格搜索适合参数少于4个的场景。超过4个,网格数量会爆炸式增长。比如每个参数取10个值,4个参数就是10^4=10000次回测。你想想看,这得跑多久?
3.2 随机搜索法:用概率换效率
随机搜索的思路很简单:在参数空间里随机撒点。每个点代表一组参数组合,跑回测,记录结果。重复N次,取最优。
你可能会问:随机搜索能比网格搜索更好吗?其实,从数学上看,随机搜索在高维空间里效率更高。为什么?因为网格搜索的采样点均匀分布,但最优解往往集中在某个区域。随机搜索虽然看起来乱,但能在更少的采样次数里覆盖更多有价值的区域。
我曾经用随机搜索优化一个5参数的做市策略。网格搜索需要10^5=10万次回测,而随机搜索只用了2000次就找到了接近最优的解。效率提升了50倍。
# 随机搜索示例代码
import random
def random_search(n_iterations=2000):
best_sharpe = -np.inf
best_params = None
for i in range(n_iterations):
# 在合理范围内随机采样
interval = random.uniform(5, 30)
depth = random.randint(1, 5)
spread_mult = random.uniform(0.5, 2.0)
order_size = random.randint(1, 10)
cancel_time = random.uniform(1, 10)
sharpe = run_backtest(interval, depth, spread_mult, order_size, cancel_time)
if sharpe > best_sharpe:
best_sharpe = sharpe
best_params = (interval, depth, spread_mult, order_size, cancel_time)
return best_params, best_sharpe
避坑指南:我曾经犯过一个错误——随机搜索的采样范围设得太宽。结果大部分采样点都在无效区域,白白浪费了计算资源。建议先用少量采样确定有效区域,再缩小范围精细搜索。
3.3 贝叶斯优化入门
贝叶斯优化,听起来高大上,其实核心思想很简单:用历史采样结果来指导下一步采样。它不像网格搜索那样盲目,也不像随机搜索那样完全随机。它有个「记忆」,知道哪些区域可能更好。
贝叶斯优化的两个核心组件:
- 概率代理模型:通常用高斯过程(GP)来拟合参数与目标函数的关系。说白了,就是根据已有的采样点,预测整个参数空间的「地形图」。
- 采集函数:决定下一步去哪里采样。常用的有期望改进(EI)、置信上界(UCB)等。它会平衡「探索」(去未知区域)和「利用」(去已知好区域)。
我个人习惯用贝叶斯优化来处理计算成本高的场景。比如每次回测需要10分钟,那网格搜索和随机搜索都不现实。贝叶斯优化通常只需要几十次迭代就能找到不错的解。
# 贝叶斯优化示例(使用scikit-optimize库)
from skopt import gp_minimize
from skopt.space import Real, Integer
# 定义参数空间
space = [
Real(5, 30, name='interval'),
Integer(1, 5, name='depth'),
Real(0.5, 2.0, name='spread_mult'),
Integer(1, 10, name='order_size'),
Real(1, 10, name='cancel_time')
]
# 定义目标函数(最大化夏普比率)
def objective(params):
interval, depth, spread_mult, order_size, cancel_time = params
sharpe = run_backtest(interval, depth, spread_mult, order_size, cancel_time)
return -sharpe # gp_minimize默认最小化,所以取负
# 执行贝叶斯优化
result = gp_minimize(
objective,
space,
n_calls=50, # 迭代次数
random_state=42
)
print(f"最优参数: {result.x}")
print(f"最优夏普: {-result.fun:.2f}")
我的建议:贝叶斯优化不是万能的。如果参数空间非常崎岖(有很多局部最优),高斯过程的拟合效果会变差。这时候可以试试随机森林作为代理模型,或者增加初始采样点。
3.4 三种方法的对比
| 方法 | 适用参数数量 | 计算效率 | 找到全局最优的概率 | 实现难度 |
|---|---|---|---|---|
| 网格搜索 | 1-3个 | 低(指数增长) | 高(步长足够细时) | 低 |
| 随机搜索 | 3-10个 | 中(线性增长) | 中(依赖采样次数) | 低 |
| 贝叶斯优化 | 5-20个 | 高(智能采样) | 高(理论保证) | 中 |
嗯,这里要注意:表格只是参考。实际项目中,我经常混合使用。比如先用随机搜索粗筛,再用贝叶斯优化精调。或者先用网格搜索确定大致范围,再用贝叶斯优化深入挖掘。
3.5 实战中的选择策略
说了这么多理论,到底怎么选?我总结了一个简单的决策流程:
- 参数少于4个,计算资源充足:用网格搜索。步长取细一点,确保不遗漏最优解。
- 参数4-8个,计算资源有限:用随机搜索。采样次数设为参数数量的100-200倍。
- 参数多于8个,或每次回测很耗时:用贝叶斯优化。迭代次数设为参数数量的10-20倍。
- 不确定选哪个:先跑100次随机搜索,看看目标函数的分布。如果分布集中,说明参数空间比较平滑,贝叶斯优化效果会好。如果分布分散,说明空间崎岖,可能需要更多采样。
核心提醒:参数优化不是一劳永逸的事。市场在变,最优参数也在变。我建议每周或每月重新优化一次参数,或者设置一个监控机制,当策略表现下降时自动触发重新优化。
最后说一句:别迷信任何一种方法。工具是死的,人是活的。理解每种方法的原理和适用场景,才能在实战中做出正确的选择。