4. 粒子群优化算法:粒子群原理,在参数寻优中的应用
说到参数寻优,很多人第一反应就是网格搜索或者随机搜索。说实话,这两种方法在参数少的时候还行,一旦参数超过三四个,效率就直线下降。我早期做CTA策略时,就吃过这个亏——六个参数用网格搜索,跑了整整两天,结果还不理想。
后来我接触到了粒子群优化算法(PSO),嗯,这玩意儿确实好用。它模拟的是鸟群觅食的行为,你想想看,一群鸟在天空飞,它们不知道食物在哪,但每只鸟都知道自己当前的位置离食物有多远,也知道同伴们的位置。通过不断交流信息,整个鸟群就能快速找到食物。
核心思想:每个“粒子”代表一个候选解,粒子在搜索空间中飞行,通过个体经验和群体经验来调整自己的飞行方向和速度。
4.1 粒子群算法的数学原理
每个粒子有两个关键属性:位置和速度。位置就是参数组合,速度决定了下一步怎么移动。
粒子更新公式其实不复杂:
v_i(t+1) = w * v_i(t) + c1 * r1 * (pBest_i - x_i(t)) + c2 * r2 * (gBest - x_i(t))
x_i(t+1) = x_i(t) + v_i(t+1)
我来拆解一下这个公式:
- w:惯性权重。控制粒子保持原有速度的倾向。w越大,全局搜索能力越强;w越小,局部搜索越精细。
- c1, c2:学习因子。c1是“自我认知”,c2是“社会认知”。
- r1, r2:[0,1]之间的随机数,增加搜索的随机性。
- pBest:粒子自身找到过的最优位置。
- gBest:整个群体找到的最优位置。
我个人习惯把c1和c2都设为2.0,w从0.9线性递减到0.4。为什么这样设?因为前期需要大范围探索,后期需要精细收敛。我在项目中试过固定w=0.7,结果经常陷入局部最优,后来改成动态衰减就好多了。
4.2 算法流程
流程其实很直观,我画了个图帮你理解:
4.3 在参数寻优中的应用
拿我最近做的一个双均线策略来举例。策略有三个参数需要优化:短周期S、长周期L、止损比例SL。如果用网格搜索,假设每个参数取20个值,那就是20³=8000次回测,太慢了。
用PSO的话,我一般这样设置:
# 粒子群优化参数设置
swarm_size = 30 # 粒子数量
max_iter = 50 # 最大迭代次数
w_start = 0.9 # 初始惯性权重
w_end = 0.4 # 最终惯性权重
c1 = 2.0 # 个体学习因子
c2 = 2.0 # 社会学习因子
# 参数范围
param_bounds = {
'S': (5, 50), # 短周期
'L': (20, 200), # 长周期
'SL': (0.01, 0.05) # 止损比例
}
适应度函数怎么设计?我一般用夏普比率,但会加一个惩罚项。为什么?因为纯夏普比率容易选出过拟合的参数组合。我曾经吃过这个亏——优化出来的参数在回测里夏普3.0,实盘直接变成0.5。
我的经验:适应度函数建议用 夏普比率 × (1 - λ × 参数数量/总参数数),λ取0.1~0.3。这样能自动惩罚参数过多的模型,减少过拟合风险。
4.4 避坑指南
我踩过的坑不少,挑几个典型的说说:
- 粒子数量不是越多越好。我曾经设了200个粒子,结果收敛速度反而变慢。一般20-50个就够用了。
- 速度限制很重要。不加限制的话,粒子可能直接飞出边界。我习惯把速度限制在参数范围的20%以内。
- 边界处理要小心。粒子撞到边界时,是反弹还是吸收?我测试下来,反弹策略效果更好。
特别注意:PSO是随机算法,每次运行结果可能不同。我建议至少跑5次,取最优结果。另外,如果连续10次迭代gBest都没变化,可以提前终止——别傻等50次迭代跑完。
4.5 与其他优化算法的对比
| 算法 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 网格搜索 | 简单、可复现 | 维度灾难、效率低 | 参数≤3个 |
| 随机搜索 | 比网格搜索高效 | 精度不够 | 初步探索 |
| 遗传算法 | 全局搜索能力强 | 参数多、收敛慢 | 离散参数优化 |
| 粒子群优化 | 收敛快、实现简单 | 易陷入局部最优 | 连续参数优化 |
| 贝叶斯优化 | 样本效率高 | 计算开销大 | 高维、昂贵评估 |
说实话,没有银弹。我个人的选择标准是:如果参数是连续的且不超过10个,优先用PSO;如果评估函数特别贵(比如一次回测要10分钟),那就用贝叶斯优化。
4.6 实战建议
最后给几个实战中的小技巧:
- 先粗后细:先用大范围、少粒子跑一轮,锁定大致区域后再精细搜索。
- 并行化:PSO天然适合并行,每个粒子的适应度计算互不依赖。我一般开8个线程同时算。
- 记录轨迹:把每次迭代的gBest记录下来,画成收敛曲线。如果曲线抖动剧烈,说明参数设置有问题。
嗯,粒子群优化就讲这么多。它不是什么高深莫测的算法,但用好了确实能省不少时间。下次你面对一堆参数不知道怎么调的时候,不妨试试PSO——至少比瞎猜强多了。