RQAlpha 项目研究站 · 参数调优与批量回测
RQAlpha 参数调优:把参数注入 context,批量回测再排序
官方文档给了一条清晰路径:策略里把可调参数存成 context 属性(如长短均线周期),启动时通过 --extra-vars 或配置里的 extra.context_vars 传值;再用多进程把参数组合批量跑完,最后把每个结果文件的 summary 汇总排序。这样「调参」就从手工改代码变成了可重复的流程。
context.XXX
extra-vars/context_vars
结果写 results/
按指标选区间
依据官方参数调优文档整理的四步闭环示意;非官方流程图。
两种参数注入方式
RQAlpha 官方文档给出的两条路:命令行传 --extra-vars,或配置里写 extra.context_vars。
| 方式 | 写法 | 适合 | 注意点 |
|---|---|---|---|
命令行 --extra-vars | 传 JSON 字符串,如 --extra-vars '{"SHORTPERIOD": 5, "LONGPERIOD": 40}' | 脚本批量循环、外部调度 | 注意引号与转义;JSON 里的 key 要与策略中读取的一致 |
配置 extra.context_vars | {"extra": {"context_vars": {"SHORTPERIOD": 5}}} | 用 run_file 在 Python 里循环生成配置 | 结构清晰、不需要拼命令行字符串 |
| 策略侧读取 | 把参数挂在 context 上:context.SHORTPERIOD = 20 | 策略内部随处可用 | 策略里尽量不要硬编码;官方示例在 init 里设置默认值 |
多进程批量回测
RQAlpha 官方文档给了两种实现:Python 内调用与 Shell 循环,都靠系统多核并行。
方式一:在 Python 里调用(官方示例结构)
1. 双重循环生成参数组合,每组构造一个 config 字典(含 extra.context_vars、base.start_date/end_date、base.accounts、mod.sys_analyser.output_file);
2. 把所有 config 收集进列表;
3. 用 concurrent.futures.ProcessPoolExecutor(max_workers=multiprocessing.cpu_count()) 提交任务,每个任务里调用 from rqalpha import run; run(config);
4. 官方示例里把 log_level 设为 error 降低日志噪音,并把输出文件命名为 results/out-{short}-{long}.pkl。
方式二:拼命令行交给系统执行
官方同样给出「命令行传参」的示例:循环生成 rqalpha run -fq 1d -f 策略.py --start-date … --end-date … -o results/out-xx.pkl --account stock 100000 --progress -bm 000001.XSHE --extra-vars '{...}',再用 os.system 在进程池中执行。适合把批量任务交给已有调度系统。
multiprocessing.cpu_count(),但实际可用核数取决于机器与数据包读取的 IO 开销。建议先用较小并行数跑通流程、确认输出文件命名不冲突,再逐步加并行。汇总结果:把 pkl 摊平成对比表
RQAlpha 官方示例的分析写法,三步就能得到可排序的参数表。
| 步骤 | 做法 | 产出 |
|---|---|---|
| 1. 收集文件 | glob.glob("results/*.pkl") | 本次批量回测的全部结果 |
| 2. 提取指标 | 逐个 pd.read_pickle,取 summary 中的年化收益、sharpe、回撤幅度(max_drawdown) | 每行 = 一组参数 + 一组指标 |
| 3. 排序观察 | 分别按 sharpe 与 annualized_returns 排序,打印前若干行 | 识别「参数高原」而非单点领先 |
调优的六条纪律
这一节是方法层面的边界提示,与 RQAlpha 的功能实现无关,但更影响结论质量。
| 纪律 | 为什么 |
|---|---|
| 固定数据与撮合口径后再比参数 | 否则差异可能来自撮合引擎、滑点或数据版本,而不是参数 |
| 至少看收益与风险两类指标 | 官方示例同时按 sharpe 与年化收益排序,单指标领先往往不可用 |
| 把数据分成训练段与验证段 | 在全部历史上挑表现好的参数,等同于用未来信息做决策 |
| 控制参数个数 | 组合爆炸会拖长回测时间,也更容易拟合噪声 |
| 记录每次回测的完整配置 | 结果文件命名带参数是官方示例的做法,便于追溯 |
| 把调优结果当假设而非结论 | 历史表现不构成未来收益承诺;本站不对任何策略结果作评价或推荐 |
批量回测排查表
RQAlpha 的并行与传参是最容易出问题的地方。
| 现象 | 原因 | 处理 |
|---|---|---|
| 结果文件互相覆盖 | 输出文件名没有带参数 | 按官方示例命名:results/out-{short}-{long}.pkl |
| 参数传了但结果没变 | 策略里写死了参数(优先级最高),或 JSON 的 key 名不一致 | 先确认策略用 context.XXX 读取;核对其命名 |
| 命令行传 JSON 报错 | 引号转义问题(尤其 Windows cmd) | 改用 run_file 传 config 字典,绕开字符串拼接 |
| 批量跑不动 / 机器卡死 | 并行数过高、内存不足 | 降低 max_workers,分批跑;长周期回测先缩区间验证流程 |
| 日志淹没关键信息 | 默认日志级别太详细 | 按官方示例设 extra.log_level: error,关掉 progress 输出 |
| 汇总时报结果文件缺失 | 部分组合因数据区间不足或报错未产出 | 在汇总脚本里跳过缺失文件并登记失败组合,别静默当成功 |
参数注入链路:从 context_vars 到最终成绩表,一共要配哪些键?
官方《参数调优》文档给的链路是「策略留出参数 → 传进 context → 批量跑组合 → 汇总排序」。下表把每个环节落到哪个配置键、哪个文件名摊开,字段名照官方文档与 config.yml 模板原文排列。
| 配置键 | 写在哪 | 作用 | 注意点 |
|---|---|---|---|
base.strategy_file | config 字典,或命令行 -f | 指定要跑的策略文件 | 官方批量示例指向 rqalpha/examples/golden_cross.py |
base.start_date / base.end_date | config,或命令行 -s / -e | 回测起止日期 | 所有组合必须完全一致,否则指标之间不可比 |
base.frequency | config,或命令行 -fq | 回测频率 1d / 1m | 文档明确开源版不提供分钟级数据源,换频率前先解决数据(获取方式见 安装与数据) |
base.matching_type | config,或命令行 -me | 撮合引擎 current_bar / next_bar | 官方批量示例固定 current_bar;改撮合方式等于换掉全部结果 |
base.benchmark | config,或命令行 -bm | 基准指数 | 运行文档写明「如果不设置,默认没有基准参照」,相对类指标就失去参照 |
base.accounts.stock | config,或命令行 -a | 账户类型与初始资金 | 官方示例为 100000;调整资金等于换了一套结果,别与参数变量混在一起改 |
extra.context_vars | config 字典,或命令行 --extra-vars 传 JSON | 把预定义变量传进 context | 配置模板里的注释就是这句;key 要与策略里读取的 context.XXX 完全一致 |
extra.log_level | config,或命令行 -l | verbose / info / warning / error | 官方批量示例设成 error,把回测过程日志压掉 |
mod.sys_analyser.output_file | config 的 mod 段 | 回测结果 pkl 的输出路径 | 官方按参数命名 results/out-{short_period}-{long_period}.pkl,避免多组结果互相覆盖 |
mod.sys_progress.enabled / show | config 的 mod 段,或命令行 --progress | 命令行进度条 | 批量阶段通常关掉,输出更干净、也少一层干扰 |
五步链路:每一步的命令与预期输出
1. 在策略里留出可调项:官方示例在 init 里给默认值 context.SHORTPERIOD = 20、context.LONGPERIOD = 120 —— 预期:策略单独也能跑通,读取端始终是 context.SHORTPERIOD;
2. 命令行注入单组参数:rqalpha run -f rqalpha/examples/golden_cross.py --extra-vars '{"SHORTPERIOD": 5, "LONGPERIOD": 40}' —— 预期:同一份策略这次使用 5 / 40,结果与默认值不同;
3. 或改用配置注入:{"extra": {"context_vars": {"SHORTPERIOD": 5, "LONGPERIOD": 40}}} —— 预期:run(config) 或 run_file(path, config) 生效,不必拼命令行字符串;
4. 生成参数组合:官方示例用 for short_period in range(3, 10, 2) 套 for long_period in range(30, 90, 5) —— 预期:4 × 12 = 48 个 config 进入任务列表;
5. 汇总排序:glob.glob("results/*.pkl") → pd.read_pickle(name)["summary"] 取 annualized_returns / sharpe / max_drawdown → sort_values(..., ascending=False)[:10] —— 预期:先打印按 sharpe 排序的表,再打印按年化收益排序的表(字段含义见 回测指标)。
run_file | run_code | run_func 函数传参 > 用户配置文件 > 系统默认配置文件」。所以批量注入之前先确认策略里没有写死参数:写死了,你传进去的值永远不会生效。批量调参容易踩的七个点:结果看起来跑完了,为什么结论不能用?
这些不是框架缺陷,而是「批量场景」特有的口径问题。每条都给一个可以立刻执行的检查动作。
| 现象 | 原因 | 处理 |
|---|---|---|
| 组合数比手算的少 | range(3, 10, 2) 只取 3、5、7、9 四个值,range(30, 90, 5) 取 30 到 85 共 12 个 | 批量启动前打印 len(tasks),与手算的组合数对账 |
| Windows 上进程反复新建、数量失控 | 多进程入口没有放在 if __name__ == '__main__': 之后,子进程导入模块时又触发一次提交 | 照官方示例的写法保护入口,再提交进程池任务 |
| 两批结果放在一起比不出来 | 批与批之间改了撮合方式、回测区间或初始资金 | 把 base / mod 的公共段抽成一个字典,只替换参数相关字段 |
| 相对类指标算不出来 | 没有设置 base.benchmark,文档写明默认没有基准参照 | 两批都固定同一个 -bm,再比较排序结果 |
| 跑到后半段读不到数据 | 回测区间落在数据包覆盖范围之外(免费数据包每月月初更新一次) | 先用 1 组确认区间内有数据(数据包与更新节奏见 安装与数据),再放大到全部组合 |
| 整批因频率失败 | 批量脚本里写了 -fq 1m,而分钟级数据需要自备数据源 | 批量阶段固定 1d,把频率当成单独一次变量实验来做 |
| 靠文件时间分辨不出哪组参数 | output_file 是自定义字符串模板,不会自动带时间戳或参数 | 在文件名里写进参数组合(官方示例就是短周期与长周期),别依赖文件修改时间 |
run(config),同一个进程可以连续跑多组回测;命令行版是 os.system(cmd),一条命令一个独立进程,外面套 ProcessPoolExecutor(max_workers=multiprocessing.cpu_count()) 并行。两种写法混用时,日志会交叉、输出文件名更不能重复。建议先用 4 组把链路跑通,再放大到全部组合。常见问题
参数组合应该取多密?
官方示例用的是「短周期 3 到 10、步长 2;长周期 30 到 90、步长 5」这类粗扫方式。建议先粗后细:粗扫定位有希望的区域,再在小范围内加密验证稳定性,避免一次性生成大量组合。
批量回测很慢,有什么优化思路?
三个方向:缩短单次回测区间先验证流程;提高并行度但别超过物理核数太多;降低日志与绘图输出(批量阶段通常不需要 plot)。官方示例用进程池并行,本身就是在利用多核。
如何避免过拟合?
RQAlpha 不会替你防过拟合。至少做三件事:留出样本外区间、优先选择「参数高原」、把参数个数控制在能解释的范围内。任何「历史表现拔尖的参数」都不能直接当作未来收益依据。
可以把调优结果再做可视化吗?
可以:把摊平后的 DataFrame 用 matplotlib 画热力图或折线(RQAlpha 的依赖里已有 matplotlib),也可以导出 CSV 用别的工具看。RQAlpha 本身不提供专门的调优可视化界面。
调参需要多久、要跑多少组?
取决于数据区间、频率与机器性能,官方文档没有给时间承诺。经验上先保证「流程可复现、结果可追溯」,再考虑扩大搜索范围。
不想自己搭这套批量调参流程,有别的方式吗?
可以看 EasyClaw 本机的 quant-analyst 技能方向(覆盖回测与风险指标建模),用自然语言发起研究任务;但它不是 RQAlpha 的运行环境,两者无已证实集成。详见对比页。