【免费下载链接】prediction-market-backtesting
An extension for Nautilus Trader
本指南介绍如何使用 prediction-market-backtesting 内置的参数优化器(parameter search)对预测市场策略做自动化调参:只需在策略配置中写入__SEARCH__:占位符,定义训练/保留时间窗口,然后选择random(随机网格)或tpe(Optuna 树状结构帕森估计器)采样器,即可批量回放历史订单簿并生成排行榜 CSV 与汇总 JSON。两个开箱即用的示例 notebook 已随仓库提供:backtests/generic_optimizer_research.ipynb 和 backtests/generic_tpe_research.ipynb。
一、优化器的工作流程
优化器把调参视为一次 walk-forward 实验,整体流程如下(详见 docs/research.md):
- 定义训练窗口(
train_windows):若干段历史时间段; - 逐窗口回放:对每组候选参数,在每个训练窗口上完整运行一次回测;
- 窗口打分:每个窗口计算一个风险调整分数;
- 训练集排名:按各窗口分数的中位数对候选参数排序;
- 保留集验证:如果配置了
holdout_windows,只让训练集 Top-K(holdout_top_k)进入保留窗口复测,再按保留分中位数最终排名。
每个 trial 都运行在独立子进程中(见 _optimizer.py),策略崩溃不会污染主进程——某个参数组合跑挂只会拿到一个极低的无效分数。
二、快速上手:三步完成一次参数搜索
第 1 步:用__SEARCH__:占位符标记待优化参数
在策略配置的任意位置写"__SEARCH__:参数名",运行优化时会被自动替换成采样到的值。以示例 notebook 中的 microprice 策略为例(摘自 backtests/generic_optimizer_research.ipynb):
strategy_spec = { "strategy_path": "strategies:BookMicropriceImbalanceStrategy", "config_path": "strategies:BookMicropriceImbalanceConfig", "config": { "depth_levels": "__SEARCH__:depth_levels", "entry_imbalance": "__SEARCH__:entry_imbalance", "stop_loss": "__SEARCH__:stop_loss", # ... 其余参数保持固定 }, }注意:占位符必须与搜索空间中的键一一对应,多一个或少一个都会在配置校验时直接报错(见 _optimizer.py)。
第 2 步:定义训练窗口与保留窗口
用ParameterSearchWindow切分时间段,训练和保留窗口在时间上前后相邻:
train_windows = ( ParameterSearchWindow(name="train-2026-04", start_time="2026-04-05T00:00:00Z", end_time="2026-04-05T23:59:59Z"), ) holdout_windows = ( ParameterSearchWindow(name="holdout-2026-04", start_time="2026-04-06T00:00:00Z", end_time="2026-04-06T23:59:59Z"), )第 3 步:选择采样器并运行
summary = run_parameter_search(ParameterSearchConfig( name="notebook_optimizer", data=data, # 数据源配置(平台/类型/供应商) base_replays=base_replays, # 要回放的 markets strategy_spec=strategy_spec, parameter_grid=parameter_grid, # 随机网格用 # parameter_space=parameter_space, # TPE 用 train_windows=train_windows, holdout_windows=holdout_windows, max_trials=20, # 最多评估的 trial 数 sampler="random", # "random" 或 "tpe" ))run_parameter_search从 prediction_market_extensions/backtesting/optimizers/ 导出。运行结束后终端会打印被选中的参数、Top 5 候选,并生成两份产物文件。
三、随机网格采样器(sampler="random")详解
适用场景:参数是离散取值(几个候选档位),且候选总数不太大。
- 配置方式:
parameter_grid,即「参数名 → 候选值元组」,优化器取笛卡尔积得到全部候选; - 采样逻辑:若候选总数 ≤
max_trials就全部评估(等价于全网格搜索);否则用random_seed做确定性洗牌,取前max_trials个(见 _optimizer.py); - 特点:无记忆、无偏,每次评估互相独立,可复现,但不能表达连续区间或对数尺度;
- 限制:只能用于离散网格或全 categorical 空间,混入连续参数会直接报错。
示例网格(摘自示例 notebook,10 个参数各 3~4 个档位,候选池超过 6 万种组合,max_trials=2时只抽 2 组做冒烟测试):
parameter_grid = { "depth_levels": (1, 3, 5), "entry_imbalance": (0.58, 0.62, 0.66), "min_holding_seconds": (300.0, 900.0, 1_800.0, 3_600.0), "take_profit": (0.01, 0.02, 0.04), "stop_loss": (0.015, 0.025, 0.04), # ... }四、TPE 采样器(sampler="tpe")详解
适用场景:参数是连续区间(如entry_imbalance ∈ [0.58, 0.72]),希望采样器"越搜越聪明"。
- 依赖:需要额外安装 Optuna,
uv pip install optuna; - 配置方式:
parameter_space,支持三种规格:
| 规格 | 写法 | 说明 |
|---|---|---|
| 整数 | {"type": "int", "low": 1, "high": 5} | 支持log对数采样、step步长 |
| 浮点 | {"type": "float", "low": 0.0005, "high": 0.004} | 跨数量级的参数强烈建议"log": True |
| 分类 | {"type": "categorical", "choices": [300.0, 900.0, 3600.0]} | 离散档位 |
- 工作原理:Optuna 的 TPE 会根据历史 trial 的得分来提议下一组参数(方向为 maximize),因此本仓库以顺序方式运行——每个 trial 的分数通过
study.tell喂回 study 后才提议下一个(见 _optimizer.py)。这意味着 TPE 比随机网格慢(无法并行),但同样预算下往往更贴近最优区; - 混合空间:
int/float区间与categorical可以自由混用,示例 notebook 中「连续阈值 + 离散持仓时长」就是这么配的(见 backtests/generic_tpe_research.ipynb)。
五、随机网格 vs TPE:怎么选?
| 维度 | sampler="random" | sampler="tpe" |
|---|---|---|
| 参数形态 | 离散网格 / 全分类 | 连续区间、对数尺度、混合空间 |
| 配置入口 | parameter_grid | parameter_space |
| 是否依赖历史结果 | 否(无记忆) | 是(sequential,越跑越聚焦) |
| 依赖 | 无 | uv pip install optuna |
| 评估方式 | 可并行/一次性抽样 | 顺序 ask/tell |
| 复现性 | random_seed完全确定 | random_seed传入 TPESampler |
| 典型用法 | 候选 ≤max_trials时即穷举 | 高维连续空间、预算有限 |
经验法则:候选总数少(几百以内)时直接用 random,穷举最稳;参数是连续阈值、或维度高到网格爆炸时,用 TPE。注意两者互斥——parameter_grid与parameter_space不能同时提供。
六、读懂打分公式与排行榜
每个训练窗口的分数为(见 docs/research.md):
score = pnl - 0.5 * max_drawdown_currency - 罚金罚金覆盖三类情况:提前终止、数据覆盖不足(低于 98%)、成交数不满足min_fills_per_window。多市场(联合组合)模式下,PnL 和成交数跨市场求和,而回撤是在合并后的总权益曲线上计算的——分散化能降低联合回撤,这正是组合优化的意义所在。
排行榜(leaderboard)按训练窗口分数中位数排序;配置了保留窗口后,则以保留分中位数为第一排序键、训练分为平局裁决键。终端输出的 Top 5 表格与示例 notebook 中的样式一致:
trial train_score holdout_score median_pnl median_dd median_fills median_cov params 1 12.3405 10.2100 15.0000 3.2000 12.0 1.000 {"depth_levels": 3, ...}七、输出产物:在哪里看结果?
每次搜索会在artifact_root(默认output/)下生成两个文件:
{name}_leaderboard.csv:全部 trial 的训练/保留中位分数、PnL、回撤、成交数、覆盖率,以及params_json列;{name}_summary.json:selected_params(最终选中的参数)、最优候选详情、窗口列表、种子等元信息。
想复查某一组参数的表现,可以用build_parameter_search_window_backtest单独重建某个窗口的回测(同样从 optimizers 导出),生成标准 HTML 报告。
八、常见坑与避坑建议 ⚠️
- 过拟合是默认结局:参数搜索天然偏向"训练集最漂亮"的参数,务必同时看
holdout_median_score,而不是训练分; - 单市场保留窗口 ≠ 跨市场泛化:只从一个回放切分训练/保留窗口时,程序会明确警告这只算"时间切分验证"(见 _optimizer.py);
- 长 notebook 先预热缓存:长时间扫描前先用普通 runner 跑一遍目标 markets 与时间段,避免冷缓存下载看起来像"卡死"(见 docs/research.md 的 Cache 预热一节);
- 连续区间不自动更好:只有当策略响应在某个维度上平滑时,才用
float区间替换网格,否则分类档位更稳; - 可复现性:
random_seed保证抽样/采样可复现,但引擎与子进程的非确定性仍可能带来分数小幅抖动。
九、延伸阅读
- 优化器方法论与打分细节:docs/research.md
- 优化器核心实现:prediction_market_extensions/backtesting/_optimizer.py
- 随机网格示例:backtests/generic_optimizer_research.ipynb
- TPE 示例:backtests/generic_tpe_research.ipynb
- 回测 runner 总览:docs/backtests.md
按照「占位符 → 时间窗口 → 采样器」三步配置,你就可以把人工调参变成一个可复现、可对比、带保留验证的自动化实验——先用 random 摸清参数敏感度,再用 TPE 精搜连续空间,是仓库作者在示例 notebook 中给出的推荐路径。
【免费下载链接】prediction-market-backtesting
An extension for Nautilus Trader
相关推荐
机器学习超参数优化终极指南:网格搜索与随机搜索的完整对比
机器学习超参数优化终极指南:网格搜索与随机搜索的完整对比 在机器学习项目中,超参数优化是提升模型性能的关键步骤。本文将为您提供一份完整的超参数优化指南,重点对比
教程Hyperopt三大优化算法终极指南:随机搜索、TPE和Adaptive TPE深度对比
Hyperopt三大优化算法终极指南:随机搜索、TPE和Adaptive TPE深度对比 Hyperopt是一个强大的Python分布式异步超参数优化库,专门用
机器学习AutoMLformik-antd性能优化秘诀:何时该用fast属性开启FastField加速
formik antd性能优化秘诀:何时该用fast属性开启FastField加速 如果你在用 formik antd 为 Ant Design 表单接入 Fo
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考