☰
如何用 prediction-market-backtesting 做参数优化?随机网格与 TPE 采样器对比完整指南
2026/10/14 1:53:53 网站建设 项目流程

【免费下载链接】prediction-market-backtesting

An extension for Nautilus Trader

项目地址:https://gitcode.com/gh_mirrors/pr/prediction-market-backtesting
点击查看免费下载

本指南介绍如何使用 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):

  1. 定义训练窗口(train_windows):若干段历史时间段;
  2. 逐窗口回放:对每组候选参数,在每个训练窗口上完整运行一次回测;
  3. 窗口打分:每个窗口计算一个风险调整分数;
  4. 训练集排名:按各窗口分数的中位数对候选参数排序;
  5. 保留集验证:如果配置了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_gridparameter_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 报告。

八、常见坑与避坑建议 ⚠️

  1. 过拟合是默认结局:参数搜索天然偏向"训练集最漂亮"的参数,务必同时看holdout_median_score,而不是训练分;
  2. 单市场保留窗口 ≠ 跨市场泛化:只从一个回放切分训练/保留窗口时,程序会明确警告这只算"时间切分验证"(见 _optimizer.py);
  3. 长 notebook 先预热缓存:长时间扫描前先用普通 runner 跑一遍目标 markets 与时间段,避免冷缓存下载看起来像"卡死"(见 docs/research.md 的 Cache 预热一节);
  4. 连续区间不自动更好:只有当策略响应在某个维度上平滑时,才用float区间替换网格,否则分类档位更稳;
  5. 可复现性: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

项目地址:https://gitcode.com/gh_mirrors/pr/prediction-market-backtesting
点击查看免费下载

相关推荐

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询