第二十七讲:做市算法参数优化——网格搜索、贝叶斯优化、遗传算法、在线学习与自适应参数调整
做市算法的参数调优,说白了就是给策略找一套最舒服的“姿势”。
我刚开始做做市的时候,总觉得参数设得越精细越好。后来被市场狠狠教育了几次才明白——参数不是越复杂越好,而是越“适应”越好。今天咱们就把几种主流的参数优化方法掰开揉碎了聊一聊。
一、参数优化的本质问题
做市策略的参数,比如报价深度、价差宽度、库存阈值、撤单频率等等,它们之间是相互耦合的。你调高了一个参数,可能另一个参数的效果就变了。
我习惯把参数优化看作一个“黑盒寻优”问题:
- 输入:一组参数向量 θ = (θ₁, θ₂, ..., θₙ)
- 输出:某个评价指标,比如夏普比率、PnL、库存风险等
- 目标:找到使评价指标最优的那组参数
但这里有个坑——做市策略的评价函数通常是非凸的、多峰的,甚至带噪声。所以简单的梯度下降法基本没用。
核心观点:参数优化不是一次性工作,而是一个持续迭代的过程。市场变了,最优参数也会变。
二、网格搜索(Grid Search)
网格搜索是最朴素的方法。你把每个参数的可能取值列出来,然后穷举所有组合,跑一遍回测,选最好的。
我在项目中遇到过这种情况:一个策略有5个参数,每个参数取10个值,那就是10⁵ = 10万次回测。如果一次回测需要1分钟,那就是将近70天。嗯,显然不现实。
适用场景:
- 参数数量少(≤3个)
- 参数取值范围明确
- 回测速度快
# 网格搜索示例(伪代码)
import itertools
param_grid = {
'spread_multiplier': [0.5, 1.0, 1.5, 2.0],
'order_size': [100, 200, 500, 1000],
'max_inventory': [500, 1000, 2000]
}
best_score = -float('inf')
best_params = None
for spread, size, inv in itertools.product(
param_grid['spread_multiplier'],
param_grid['order_size'],
param_grid['max_inventory']
):
score = backtest(spread, size, inv)
if score > best_score:
best_score = score
best_params = (spread, size, inv)
避坑指南:我曾经用网格搜索优化一个高频做市策略,结果发现最优参数全在边界上。这说明我的参数范围设窄了,或者策略本身有问题。网格搜索只能告诉你“哪个最好”,不能告诉你“为什么最好”。
三、贝叶斯优化(Bayesian Optimization)
贝叶斯优化比网格搜索聪明得多。它不会盲目地试所有组合,而是根据已有的结果,推测哪里可能更优,然后“有目的”地去试。
说白了,它像是一个有经验的交易员——试了几次之后,大概知道哪个方向可能赚钱,就往那个方向多试试。
核心思想:
- 用高斯过程(GP)建模目标函数的后验分布
- 用采集函数(如EI、UCB)决定下一个采样点
- 在探索(exploration)和利用(exploitation)之间平衡
# 使用scikit-optimize进行贝叶斯优化
from skopt import gp_minimize
from skopt.space import Real, Integer
def objective(params):
spread_mult, order_size, max_inv = params
return -backtest(spread_mult, order_size, max_inv) # 最小化负收益
space = [
Real(0.5, 2.0, name='spread_multiplier'),
Integer(100, 1000, name='order_size'),
Integer(500, 2000, name='max_inventory')
]
result = gp_minimize(objective, space, n_calls=50, random_state=42)
print("最优参数:", result.x)
print("最优得分:", -result.fun)
个人经验:贝叶斯优化在参数数量5-10个时效果最好。少于3个,网格搜索就够了;多于15个,贝叶斯优化的收敛速度也会变慢。我一般先用贝叶斯优化跑50-100次,找到大致区域,再用网格搜索做局部精细调优。
四、遗传算法(Genetic Algorithm)
遗传算法模拟了自然选择的过程。你想想看,一群参数组合就像一群生物,好的基因(参数)会遗传下去,差的会被淘汰。
基本流程:
- 初始化:随机生成一批参数组合(种群)
- 评估:计算每个个体的适应度(回测得分)
- 选择:适应度高的个体有更大概率被选中
- 交叉:选中的个体交换部分参数(类似基因重组)
- 变异:以一定概率随机改变某些参数
- 迭代:重复2-5步,直到收敛
# 遗传算法核心逻辑(简化版)
import random
def genetic_algorithm(pop_size=50, generations=30):
# 初始化种群
population = [random_params() for _ in range(pop_size)]
for gen in range(generations):
# 评估适应度
scores = [backtest(p) for p in population]
# 选择(轮盘赌)
selected = []
for _ in range(pop_size):
idx = random.choices(range(pop_size), weights=scores, k=1)[0]
selected.append(population[idx])
# 交叉和变异
new_population = []
for i in range(0, pop_size, 2):
p1, p2 = selected[i], selected[i+1]
child1 = crossover(p1, p2)
child2 = crossover(p2, p1)
child1 = mutate(child1, mutation_rate=0.1)
child2 = mutate(child2, mutation_rate=0.1)
new_population.extend([child1, child2])
population = new_population
# 返回最优个体
best_idx = max(range(pop_size), key=lambda i: backtest(population[i]))
return population[best_idx]
为什么我喜欢遗传算法? 因为它不容易陷入局部最优。网格搜索和贝叶斯优化都可能被某个局部峰值“骗”住,但遗传算法通过种群多样性和变异操作,有更大机会跳出局部陷阱。
五、在线学习与自适应参数调整
前面几种方法都是离线优化——你先跑回测,找到最优参数,然后上线用。但市场是动态的,今天的最优参数,明天可能就变成最差的了。
所以,真正的做市系统需要在线学习能力。我把它叫做“边做边学”。
自适应调整的常见方法:
- 滑动窗口重优化:每隔一段时间(比如每小时),用最近的数据重新跑一次优化
- 在线梯度下降:根据实时反馈,对参数做微调
- 强化学习:把参数调整看作一个动作,用Q-learning或策略梯度来学习
- 贝叶斯在线学习:用贝叶斯方法实时更新参数的后验分布
# 滑动窗口自适应调整示例
class AdaptiveMarketMaker:
def __init__(self, window_size=1000):
self.window_size = window_size
self.data_buffer = []
self.current_params = self.initial_params()
def on_tick(self, tick):
self.data_buffer.append(tick)
if len(self.data_buffer) > self.window_size:
self.data_buffer.pop(0)
# 每500个tick重新优化一次
if len(self.data_buffer) % 500 == 0:
self.optimize_params()
def optimize_params(self):
# 用最近的数据做贝叶斯优化
result = gp_minimize(
lambda p: -self.backtest_on_buffer(p),
self.param_space,
n_calls=20
)
self.current_params = result.x
我曾经踩过的坑:在线学习最怕的是“过度适应”。有一次我让系统每10分钟就重新优化一次参数,结果它完全跟着短期噪声走,反而亏得更惨。后来我加了一个“冷却期”——参数调整后至少运行30分钟,才能再次调整。这样既保持了适应性,又避免了过度反应。
六、四种方法的对比与选择
| 方法 | 适用参数数量 | 计算成本 | 全局搜索能力 | 在线适应性 |
|---|---|---|---|---|
| 网格搜索 | 1-3 | 低(但随参数数量指数增长) | 中等 | 差 |
| 贝叶斯优化 | 3-10 | 中等 | 好 | 中等(可扩展为在线版本) |
| 遗传算法 | 5-20 | 高 | 非常好 | 差(通常离线使用) |
| 在线学习 | 1-5(实时调整) | 低(每次调整) | 依赖基础方法 | 非常好 |
我个人习惯的组合方式是:先用遗传算法做一次全局搜索,找到大致的最优区域;然后用贝叶斯优化在这个区域做精细调优;最后上线时,配合在线学习做实时微调。这样既保证了全局最优性,又兼顾了实时适应性。
七、知识体系图
下面这张图展示了参数优化的完整知识体系,以及各种方法之间的关系:
最后说一句:参数优化不是一劳永逸的事。市场结构在变,流动性在变,波动率在变,你的参数也得跟着变。我见过太多团队花三个月调出一套“完美参数”,上线后一个月就失效了。保持敬畏,保持迭代,这才是做市算法的生存之道。
交易系统化学习资料 微信Strategy888888