Files
worldquant-alpha-system/docs/legacy-backtest-module.md

282 lines
33 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 旧系统回测模块功能梳理
整理日期:2026-09-07。目标:为后续将 `worldquant-constract-system` 的回测能力重构到 `wq-alpha-system` 提供功能和实现依据。本阶段仅整理文档,不实施迁移、不启动真实回测。
代码基线:旧仓库提交 `08edb0baa380eeb8102e74f8d0cff7b8987df1e3`,检查时工作区干净。以下“默认值”指该代码基线的默认配置,不代表历史所有版本或生产环境的实际设置。未发现旧仓库根目录及 `apps/backend/` 下的 `.env`,没有读取运行中进程配置或查询真实账户限额。文中 8 个任务、10 条表达式的上限是旧代码的校验和注释口径,未向当前 WorldQuant 平台重新核验。
## 1. 核心结论
旧系统并不是一个所有入口都共用的回测中心,而是三套执行管理方式并存:
- **预回测列表、模板研究**:生产者从数据库取表达式,通过统一 `BacktestQueueService` 提交;默认共享 **6 个任务槽位,每任务通常 8 条表达式**。
- **Factory**:每个执行实例使用独立 `BacktestScheduler` 和模拟器;默认 **3 个任务并发,每任务最多 8 条表达式**。
- **CLI**:从配置文件读取表达式,独立模拟器执行,本地 JSON 文件记录进度。常规命令在默认配置下实际是 **6 个任务并发,每任务 8 条表达式**,因为旧兼容参数 `--limit-multi=6` 会覆盖配置中的 3。
所以不能回答成“整个系统最多并发 6 个”或“最多 48 个 Alpha”。6×8=48 只是统一队列满批时所承载的表达式数;Factory、CLI、其他进程以及浏览器里的平台操作没有纳入这个队列的共享预算。平台真正如何执行批内表达式,也不能由本地槽位数推出。[S1–S5]
旧系统最值得保留的能力是:待回测表达式管理、参数分组与切批、空槽补位、结果回调、业务批次关联、暂停后继续提交,以及基于 progress URL 的结果找回。最需要在重构时重新定义的是:账户级并发、逐表达式状态、任务持久化、结果归属和“回测成功”的口径。
## 2. 管理对象与边界
| 对象 | 在旧系统中的含义 | 主要保存位置 |
| --- | --- | --- |
| 表达式及回测参数 | 一次 Alpha 模拟的输入;相同表达式配不同参数仍可形成不同实验 | `pre_simulate_expressions`、Factory/模板研究表达式表、CLI 输入 JSON |
| 平台提交任务 | 一次向 simulations 接口提交的单个或多个配置;本地并发控制以此为单位 | `BacktestTask` / 模拟器内部 task;统一队列部分主要在内存 |
| 业务批次 | 给表达式和 Alpha 归组的业务标识,并不等于一个平台任务 | `batch_tracking`、表达式 `batch_id`、Alpha 业务字段 |
| 研究执行 | Factory 一次执行、模板一次采样或深度回测;可包含多个平台任务 | 各业务模块专用表 |
| 平台模拟标识 | 提交返回的 `progress_url`;多模拟还有 parent/child simulation ID | 运行时对象、结果对象、部分错误日志 |
| Alpha 结果 | 平台生成的 `alpha_id`、表达式、指标、检查摘要等 | `alphas`,`alpha_id` 唯一 |
`SimulationConfig` 包含 expression、decay、region、universe、neutralization、instrument type、delay、truncation、pasteurization、unit/nan handling、language、visualization、maxTrade。旧序列化固定提交 `type=REGULAR`,不能直接据此认定支持 SUPER 回测。[S6]
同一平台任务按四个字段保持一致:`region / delay / language / instrument_type`。按这些字段分组后再切批;不是把所有参数都相同的配置才合并。模拟器的批量入口负责自动分组,`run_single_task()` 要求上游已经分好组,并再次检查一致性与数量。[S6、S7]
## 3. 用户以前怎样管理回测
### 3.1 预回测列表:从表达式池提交
典型流程是:准备待回测表达式并关联业务批次 → 在列表选择表达式、指定批次或执行全部 → 后台生产者读取数据库 → 分组、按 8 条切批 → 等待队列空位 → 提交任务 → 回调更新状态和 Alpha 归属。
启动支持 `expression_ids`、`batch_id`、`include_completed`。前两者都不传时,范围是全部匹配记录;默认查询只排除 `completed`,因此 `failed` 和遗留 `running` 也可能重新进入提交,而不只是 `pending`。API 先返回,再异步执行。[S8]
状态实际写入 `pending → running → completed/failed`,但 Schema、状态筛选和部分统计只认识 `pending/completed/failed`。这使“正在运行”在列表统计中没有完整表达,不能把统计缺口当作记录丢失。[S8]
页面提供“停止推送”,含义是停止后续批次进入队列。已经提交的任务继续运行;未提交部分保持或恢复为 `pending`。没有针对单个已运行任务的远端取消,也没有预回测列表专用的 pause/resume 工作流;继续执行主要靠再次启动。[S8]
### 3.2 模板研究:采样、评估、深度回测
模板研究采用业务表管理研究任务、采样记录及表达式:
1. 生成采样预览及表达式,研究任务进入 `pending_sampling`。
2. 启动采样,后台生产者以每批 8 条向统一队列提交,进入 `sampling`。
3. 回调逐条保存 Alpha、指标、`done/failed` 和 `passed`;业务层据此统计样本与通过情况,供密度评估使用。
4. 深度回测先生成全量表达式,执行记录进入 `generated`;这个动作本身不启动回测。
5. 用户再启动深度回测,进入 `running`,同样按每批 8 条使用共享队列,最终更新研究与深度执行统计。
暂停通过内存 stop flag 阻止继续推送,已提交部分继续完成。采样恢复从 `stopped` 的 pending 表达式继续;深度启动接受 `generated/stopped`,继续未提交部分。业务记录持久化不等于运行中的队列任务持久化:没有据此证明进程崩溃后可以自动接续所有平台任务。[S9]
### 3.3 Factory:独立的自动研究调度
创建 Factory execution 时,先生成一阶表达式和 JSON,返回 `pending_review`,不会立即回测。用户启动后,独立调度器读取 pending 表达式,混合轮转一阶/二阶任务,维护运行中的批次集合。完成结果写到 `FactoryExpression.alpha_id/backtest_status/passed`,并衔接减枝、通过统计与增量二阶生成;没有待执行和可生成工作时结束 execution。[S3]
暂停 API 写数据库 `paused`,调度循环读取该状态后停止补充任务;停止还会发送内存 stop event,并写 `stopped/end_time`。启动或恢复会把遗留 `running` 表达式重置为 `pending` 后重新调度。这是重新提交候选表达式,不能等同于继续轮询先前已被平台接受的任务。[S10]
### 3.4 CLI:文件驱动回测
CLI 读取配置文件,把未处理配置交给独立模拟器。状态保存在 `src/cli/.progress/{source}.progress.json`,包括最后处理位置、失败配置、状态和时间戳;`--resume` 从已记录位置之后继续。`status` 命令用于查看和清理进度文件。[S4、S11]
第一次 Ctrl+C 设置停止标志;模拟器只在向线程池提交任务时检查它,已经排入线程池的工作不会因该标志自动取消。因为配置会较快地一次性排入线程池,所以“暂停”不保证立即停止后续平台提交。进度主要在模拟器整次返回后更新,并非每个 child 完成后就可靠写检查点。[S7、S11]
CLI 还提供 `retry-timeout`:从失败配置中识别轮询超时,查询原模拟是否完成、找回 Alpha,并输出 `.retry.json` / `.retry_failed.json`。这是结果补取路径,不等于通用自动重试队列。[S11]
## 4. 并发到底是多少
### 4.1 默认值与生效范围
| 层级或入口 | 默认并发任务数 | 默认单任务表达式数 | 配置与边界 |
| --- | ---: | ---: | --- |
| 通用 `SimulationSettings` | 3 | 8 | `max_concurrent_tasks` 校验 1–8;`max_alphas_per_task` 校验 1–10;可从 `.env` 读取 |
| 统一 `BacktestQueueService` | 6 | 输入模型允许 1–10 | 自行初始化 6 个 semaphore、6 个线程和并发为 6 的模拟器;覆盖通用并发默认 3 |
| 预回测列表 | 共享上行 6 | 8 | producer 对 `batch_size` 再取 `min(batch_size, 8)` |
| 模板采样、深度回测 | 共享上行 6 | 8 | 两个服务的 `DEFAULT_BATCH_SIZE=8`,没有各自独立的队列预算 |
| Factory 单个 scheduler | 3 | 最多 8 | API 传 `simulation_settings.max_concurrent_tasks`,批大小取 8 与配置上限的较小值 |
| CLI 常规命令、所有默认值 | 实际 6 | 8 | 默认 `--limit-multi=6` 与通用配置 3 不相等,触发覆盖;实际切批由模拟器配置决定 |
| 裸调用模拟器且不覆盖 | 3 | 8 | 使用通用配置;单个实例内部生效 |
以上均为代码默认值。[S1–S5]
CLI 的兼容逻辑尤其容易误解:它先读取 `--max-concurrent-tasks` 或通用配置,再判断 `limit_multi != simulation_settings.max_concurrent_tasks`,若不相等就用 `limit_multi` 覆盖。因而即使显式指定了新参数,也可能被默认旧参数覆盖;`--limit-children=10` 虽仍显示,却不决定模拟器实际切批的默认 8。[S4、S7]
### 4.2 统一队列如何占槽和补位
```mermaid
flowchart TD
A[数据库表达式:预回测 / 模板研究] --> B[生产者按参数分组并切批]
B --> C[wait_for_slot 等待提交容量]
C --> D[submit_task 创建内存异步任务]
D --> E[获取 asyncio semaphore]
E --> F[线程池调用同步模拟器]
F --> G[模拟器 threading semaphore]
G --> H[提交平台任务并轮询结果]
H --> I[获取 Alpha 详情并保存]
I --> J[队列再次执行结果保存]
J --> K[释放信号量并移除运行登记]
K --> L[通知生产者补位]
K --> M[执行业务完成回调]
L --> C
```
这里有三层容量控制:生产者按未完成任务数量做背压、队列的异步信号量与线程池控制工作数量、模拟器的线程信号量控制该实例内部执行。提交和轮询都在同一个占槽周期内,遇到 429 后 sleep 也继续占槽。不是 POST 返回后就立即释放槽位。[S2、S7]
实际代码在释放执行槽位、移除 `_running_tasks` 并通知生产者后才执行业务回调,因此下一批可以在上一批回调完成前开始。旧设计文档中“回调完成后再补位”的描述不完全符合当前实现。[S2]
生产者 `wait_for_slot()` 使用 condition 等待,完成任务会 `notify_all()`;默认每 60 秒醒来检查关闭状态。它不原子预留名额,`submit_task()` 本身也不保证所有调用者先经过这一等待,因此多生产者唤醒竞争时,已登记任务数量可能超过软限制;实际执行仍被底层信号量约束。没有发现按业务来源分配配额、优先级或持久化公平调度机制。[S2]
### 4.3 动态修改槽位的实际效果
监控界面可以把槽位设置为 1–8,后端 `update_max_slots()` 只修改内存 `_max_slots`:
- 降到 3:使用 `wait_for_slot()` 的生产者会等未完成任务减少后再补充,已有任务继续运行。
- 升到 8:允许更多任务被登记,但初始化的 semaphore、线程池和模拟器仍为 6;不能据此宣称实际执行能力变为 8。
- 进程重启后重新按默认 6 初始化,动态修改没有持久化。
“设置值”“已登记未完成数”“真正执行数”应分别理解,旧监控把它们部分合并显示了。[S2]
### 4.4 为什么不是账户级全局限流
统一队列只是 Python 进程内单例。Factory 和 CLI 创建独立模拟器,不共享它的 semaphore;多个后端进程也会各自创建一份队列。例如统一队列 6 个加一个 Factory 的 3 个,代码上没有共同的 8 槽账户预算来协调。是否被平台接受、何时返回 429,由平台当时状态决定。[S2–S4]
旧代码有并发数量限制和遇限流等待,但没有由这些模块共同使用的账户级请求速率、每日额度预算或自适应降并发控制。不能把“最多 8”理解为自动识别账户剩余名额。
## 5. 提交、轮询和失败处理
### 5.1 正常路径
模拟器对一个配置提交 JSON 对象,对多个配置提交数组;要求返回 HTTP 201 和 `Location`。单模拟直接轮询 progress URL 获取 Alpha;多模拟先轮询父任务得到 children,再在本地逐个轮询 child。这里“逐个”指本地查询顺序,不表示平台按顺序运行表达式。[S7]
成功结果包含 `alpha_id`、表达式、progress URL、simulation ID、parent ID、child index、完成时间和可选完整指标。取得 Alpha 后另行请求详情,尝试写入本地数据库;详情获取或保存异常不会自动把平台已完成结果改为失败。[S6、S7、S12]
### 5.2 重试与超时
| 场景 | 旧实现处理 |
| --- | --- |
| 提交返回 429 | 固定等待 8 秒重试,不采用该响应的 Retry-After;提交循环最多 100 次 |
| 提交返回 401 | 强制重新认证,成功后等待 2 秒重试 |
| 提交网络异常 | 默认等待轮询间隔 5 秒后重试,受提交次数上限约束 |
| 提交其他非 201 或缺少 Location | 抛出 API 异常;不进入正常轮询 |
| 单模拟 / 父模拟轮询 | 最多 300 次;默认间隔 5 秒,依据 Retry-After 调整;429 默认回退 8 秒 |
| child 轮询 | 每个最多 100 次;404 直接生成失败结果 |
| 轮询 401 | 尝试检查会话并重新登录;不同于提交阶段的强制认证路径 |
| child 的 DAILY_SIMULATION_LIMIT WARNING | 旧实现特殊映射为 COMPLETE,并尝试取 Alpha;其他 WARNING 判失败 |
| 队列完成回调 | 最多等待 120 秒,超时/异常记录错误,不自动重试 |
300×5 秒只能作为无额外请求耗时、无 Retry-After 变化时的粗略等待量,**不是严格的 25 分钟墙钟超时**;父任务轮询和各 child 轮询也有各自预算。队列没有独立的整个任务总时限。[S7、S2]
这些机制是 HTTP/轮询层的重试。业务 task 失败后,统一队列不会按 retry_count 自动重新入队;重新提交失败表达式和找回已提交结果是另两类操作,应分开理解。
## 6. 结果、状态和批次如何关联
### 6.1 结果保存
模拟器已经尝试保存完整详情,统一队列随后还会再保存一次。批量保存按 `alpha_id` 去重,用 SQLite `ON CONFLICT DO NOTHING`,遵循先写入者保留的策略;失败时退回查询后插入。因此重复落库通常不会重复插入相同 Alpha,但也不保证把旧记录刷新到最新。[S7、S12]
队列对缺详情的 COMPLETE 结果会构造基础指标,并把部分缺失值写成 0。`_persist_alphas_sync()` 返回的 `alpha_ids` 来自模拟器结果,而不是数据库逐条成功确认;保存函数返回失败统计也不必然抛出。因此“Alpha ID 已返回”不能证明“完整指标已可靠入库”。[S2、S12]
### 6.2 成功统计存在多个口径
| 位置 | 现有口径 | 影响 |
| --- | --- | --- |
| 队列 `completed_count` | 执行未抛异常即加 1 | 一个批内全部结果 FAILED,也可能计入已完成任务 |
| 队列 `failed_count` | 整体执行抛异常才加 1 | 不是失败表达式总数 |
| `BacktestResult.is_success` | `success_count > 0` 且没有整体 error | 部分成功也算任务成功 |
| 预回测完成回调 | 按 task 的 is_success 更新整批表达式 | 只要一条成功,整批可能全被标记 completed |
| 模板研究回调 | 逐结果更新表达式 done/failed 和 passed | 比预回测整批状态更细,但仍依赖回调成功 |
| CLI `SimulationBatchResult` | 成功数按 Alpha 累加,task_count 按平台任务数 | `success_rate` 的分子分母单位不同,不能直接作正确成功率 |
“执行完成”“平台成功”“详情完整”“落库成功”“业务筛选通过”在重构时必须分别定义。[S2、S6–S9]
### 6.3 批次是归组标签,不是执行状态机
`batch_tracking` 保存 batch_id、名称、来源、说明与时间,没有任务状态、重试次数或执行检查点。表达式通过字符串 `batch_id` 归属批次;Alpha 通过 `business_type/business_id` 关联,缺少数据库外键保证。[S13]
批次页提供搜索、分页、详情、改名、删除和统计。统计分两部分:按表达式 batch_id 聚合状态,按 `Alpha.business_type='batch'` 且 business_id 匹配统计 Alpha。删除批次仅删除批次元数据,保留表达式和 Alpha,可能留下悬空业务引用。[S13]
预回测回调还按数据库查出的表达式顺序与成功 `alpha_ids` 顺序进行位置配对。发生部分失败或结果缺失时,不能保证这种配对正确,尤其当同一个 task 包含多个业务批次时;迁移时应使用明确的表达式 ID 与结果对应关系。[S8]
## 7. 停止、恢复与错误找回
| 动作 | 实际改变什么 | 不能据此保证什么 |
| --- | --- | --- |
| 预回测停止推送 | 停止 producer 后续提交 | 不取消已进入队列或平台的任务 |
| 模板研究暂停/继续 | stop flag 停止生产;继续 pending 表达式 | 不保证重启后自动恢复 running 任务 |
| Factory 暂停/停止 | 数据库状态及内存 event 控制调度 | 不代表平台停止;重置 running 再提交可能重复实验 |
| CLI Ctrl+C / resume | 停止标志及本地位置文件 | 不保证已排队工作被取消或逐结果实时保存进度 |
| 队列关闭 | 停止接收,最多等待 30 秒,超时取消异步任务 | `cancel()` 不保证终止线程内同步网络工作,也不保证回调已完成 |
| 错误恢复页 | 查询既有平台任务、补取并保存 Alpha | 不重新提交回测,不修复原表达式状态或原研究任务状态 |
队列运行任务、producer 管理状态、槽位设置和 callback error 列表主要存在内存;数据库虽然保存了表达式状态,却没有完整持久化的统一执行日志。生产者 manager 只有一个当前 producer 指针,启动 API 没有拒绝重复运行的明确保护,重复启动可能覆盖控制对象而让旧 producer 继续运行。[S2、S8–S11]
### 7.1 错误恢复页的范围
错误写到按日期划分的 `apps/backend/src/logs/backtest_errors/backtest_errors_YYYY-MM-DD.jsonl`。每条含时间、task_id、错误文本、progress URL、来源、表达式数和配置摘要。[S14]
恢复资格靠错误文本包含 `429 / rate limit / polling timeout / Too Many Requests`,并能取得 progress URL。用户选择日期、任务和目标批次后,服务查询原父模拟;未完成返回 `still_running`,完成则读取 children、找回 Alpha 详情并更新或插入数据库。它是人工发起的一次结果找回,未完成时要再次发起,不是后台持续恢复器。[S14]
边界:恢复路径按父任务 children 读取,不能据此认定兼容所有单模拟响应;无 progress URL 的失败无法走此路径。恢复不会更新原 `pre_simulate_expressions` 或研究表达式状态,没有任务级恢复闭环。
恢复后的 Alpha 使用 `business_type='error_recovery'`,普通批次页却只统计 `business_type='batch'`,所以恢复成功也可能不出现在目标批次 Alpha 数中。恢复已有 Alpha 会覆盖指标及业务归属;目标 batch_id 直接写入,缺少存在性校验。[S13、S14]
## 8. 页面、接口与可观测性
| 入口 | 功能 | 主要接口或控制位置 |
| --- | --- | --- |
| 预回测列表 | 选中/批次/全部启动、停止推送、状态查看 | `/api/v1/pre-simulate/backtest`、`/backtest/stop`、`/backtest/producer/status` |
| 回测监控 | 槽位、运行任务及表达式配置、progress URL、累计完成/失败、回调错误 | `/api/v1/pre-simulate/backtest/stats`、`/backtest/slots` |
| 错误日志 | 按日期查询原始错误 | `/api/v1/pre-simulate/backtest/error-logs/dates` 及日期查询 |
| 错误恢复 | 日期与任务选择、目标批次、恢复结果 | `/api/v1/backtest-errors/dates`、`/{date}`、`/recover` |
| 批次管理 | 业务归组元数据与统计 | `api/batch_tracking.py` |
| 模板研究 / Factory | 专属执行状态、表达式和通过统计 | 各自 API 与业务表 |
| CLI status | 文件级进度查询、清理 | 本地 `.progress` JSON |
上表省略相同前缀的路径均相对其本行首项;最终接口拼接可从源文件定位。[S8–S11、S13–S15]
监控页自动刷新默认关闭,开启后每 2 秒查询队列统计。预回测列表则在进入页面、启动或人工刷新时加载状态。监控仅涵盖统一队列,不是 Factory/CLI 的全局运行视图。[S15]
`running_tasks` 统计的是已登记、尚未移除的异步 task,其中可能包括等待 semaphore 的任务;不包括已被移除但仍在回调中的任务。启动 API 的 `tasks_submitted` 还按每 10 条表达式估算,实际生产者却按每 8 条并分组,因此返回值不是实际提交任务数。[S2、S8]
## 9. 与旧设计文档的差异
旧仓库 `docs/backtest-queue-service-design.md` 是设计与阶段记录,不能直接作为最新功能说明:
| 旧文档容易造成的理解 | 当前代码事实 |
| --- | --- |
| 统一队列未来统一 Factory/CLI | 两者仍独立;模板研究已经接入共享队列 |
| 6 槽、每 task 最多 10 条即可概括 | 底层配置默认 3/8,队列覆盖为 6,常用 producer 是每批 8 |
| 修改最大槽位即可改变实际并发 | 当前只修改软提交限制,底层执行资源未同步调整 |
| 回调完成后再补位 | 当前移除任务、通知补位后才运行回调 |
| 回调前完成 alphas 保存即数据安全 | 保存失败可只返回统计;回测成功与持久化成功未形成可靠闭环 |
| 已完成计数等于成功回测数 | 队列正常返回、逐 Alpha 成功和业务通过是不同口径 |
以本次源码证据为准;旧文档保留作历史背景,未作修改。
## 10. 后续重构需要保留的功能与待决策事项
以下是从旧功能提炼的后续候选范围,不是已批准的实现方案。当前新项目计划将回测列在后续阶段,本次不改变首期只读平台的边界,也不要求迁移旧数据库。
| 功能主题 | 应保留的用户能力 | 后续需要明确的规则 |
| --- | --- | --- |
| 表达式池 | 待执行列表、按选择/批次启动、参数预览 | 重复实验如何识别;是否允许运行中再次提交 |
| 业务批次 | 命名、来源、结果归组、统计 | 批次与执行记录分开;一个 Alpha 能否归属多个实验 |
| 调度 | 同参数分组、切批、空槽补位 | 单账户共同预算;软等待数与真实运行数分开;公平性 |
| 配置 | 并发和单批数量调整 | 统一配置来源、变更何时生效、是否持久化 |
| 状态 | 查看总体及逐表达式进度 | 平台状态、落库状态、业务通过状态分别存储 |
| 暂停与恢复 | 停止继续提交、恢复未完成工作 | 停止生产/本地取消/远端取消分别定义;崩溃后先对账再决定重提 |
| 错误处理 | 展示原因、重试失败、找回平台结果 | 可重试分类、次数与总时限;有无 progress URL 分流 |
| 结果管理 | Alpha 指标、原输入、结果关联 | ID 映射、缺失值保持未知、可靠保存与重复回调幂等 |
| 研究编排 | 采样、密度评估、深度回测、Factory 后处理 | 哪些首批迁移、哪些保持为业务层;不要把减枝塞进通用执行器 |
| 监控 | 队列、任务详情、错误、运行时间 | 统一覆盖所有入口;重启后历史仍可查询 |
后续设计至少应验证:混合参数分批、单表达式与多表达式响应、多个来源争用名额、运行中升降并发、部分成功、详情/落库失败、429/401/超时、暂停后继续、重复启动、进程重启和找回结果后的原任务状态修复。本轮未执行这些运行验证。
## 11. 源码证据索引与验证范围
以下均为旧仓库本机绝对路径;代码行号对应前述提交。引用提供关键起点,相关逻辑见对应函数及邻近定义。
- **S1 配置**:[SimulationSettings](/Users/yuxuanhui/bcc-github/quant-project/worldquant-constract-system/apps/backend/src/core/config.py:204)。
- **S2 队列**:[初始化](/Users/yuxuanhui/bcc-github/quant-project/worldquant-constract-system/apps/backend/src/services/backtest/queue_service.py:46)、[提交与执行](/Users/yuxuanhui/bcc-github/quant-project/worldquant-constract-system/apps/backend/src/services/backtest/queue_service.py:122)、[保存](/Users/yuxuanhui/bcc-github/quant-project/worldquant-constract-system/apps/backend/src/services/backtest/queue_service.py:326)、[动态槽位与关闭](/Users/yuxuanhui/bcc-github/quant-project/worldquant-constract-system/apps/backend/src/services/backtest/queue_service.py:444)、[背压等待](/Users/yuxuanhui/bcc-github/quant-project/worldquant-constract-system/apps/backend/src/services/backtest/queue_service.py:534)、[任务结果模型](/Users/yuxuanhui/bcc-github/quant-project/worldquant-constract-system/apps/backend/src/services/backtest/models.py:24)。
- **S3 Factory 调度**:[调度器](/Users/yuxuanhui/bcc-github/quant-project/worldquant-constract-system/apps/backend/src/services/factory/backtest_scheduler.py:44)、[创建仅准备](/Users/yuxuanhui/bcc-github/quant-project/worldquant-constract-system/apps/backend/src/api/factory.py:316)、[调用模拟器](/Users/yuxuanhui/bcc-github/quant-project/worldquant-constract-system/apps/backend/src/services/factory/backtest_scheduler.py:335)。
- **S4 CLI 配置**:[参数默认](/Users/yuxuanhui/bcc-github/quant-project/worldquant-constract-system/apps/backend/src/cli/commands/simulate.py:451)、[兼容覆盖](/Users/yuxuanhui/bcc-github/quant-project/worldquant-constract-system/apps/backend/src/cli/commands/simulate.py:614)、[独立模拟器](/Users/yuxuanhui/bcc-github/quant-project/worldquant-constract-system/apps/backend/src/cli/core/executor.py:121)。
- **S5 生产者批量**:[预回测](/Users/yuxuanhui/bcc-github/quant-project/worldquant-constract-system/apps/backend/src/services/pre_simulate/producer.py:139)、[采样](/Users/yuxuanhui/bcc-github/quant-project/worldquant-constract-system/apps/backend/src/services/template_research/sampling_service.py:51)、[深度回测](/Users/yuxuanhui/bcc-github/quant-project/worldquant-constract-system/apps/backend/src/services/template_research/deep_backtest_service.py:51)。
- **S6 模型**:[分组字段及配置](/Users/yuxuanhui/bcc-github/quant-project/worldquant-constract-system/apps/backend/src/core/simulate/models.py:17)、[结果及统计](/Users/yuxuanhui/bcc-github/quant-project/worldquant-constract-system/apps/backend/src/core/simulate/models.py:188)。
- **S7 模拟器**:[实例信号量与会话](/Users/yuxuanhui/bcc-github/quant-project/worldquant-constract-system/apps/backend/src/core/simulate/simulator.py:57)、[批量执行](/Users/yuxuanhui/bcc-github/quant-project/worldquant-constract-system/apps/backend/src/core/simulate/simulator.py:200)、[单任务提交](/Users/yuxuanhui/bcc-github/quant-project/worldquant-constract-system/apps/backend/src/core/simulate/simulator.py:339)、[单模拟轮询](/Users/yuxuanhui/bcc-github/quant-project/worldquant-constract-system/apps/backend/src/core/simulate/simulator.py:648)、[父模拟轮询](/Users/yuxuanhui/bcc-github/quant-project/worldquant-constract-system/apps/backend/src/core/simulate/simulator.py:807)、[子模拟轮询](/Users/yuxuanhui/bcc-github/quant-project/worldquant-constract-system/apps/backend/src/core/simulate/simulator.py:1009)、[分组算法](/Users/yuxuanhui/bcc-github/quant-project/worldquant-constract-system/apps/backend/src/core/simulate/params.py:109)。
- **S8 预回测管理**:[生产者管理](/Users/yuxuanhui/bcc-github/quant-project/worldquant-constract-system/apps/backend/src/services/pre_simulate/producer.py:31)、[提交流程](/Users/yuxuanhui/bcc-github/quant-project/worldquant-constract-system/apps/backend/src/services/pre_simulate/producer.py:167)、[回调及取数](/Users/yuxuanhui/bcc-github/quant-project/worldquant-constract-system/apps/backend/src/services/pre_simulate/producer.py:305)、[启动 API](/Users/yuxuanhui/bcc-github/quant-project/worldquant-constract-system/apps/backend/src/api/pre_simulate_list.py:394)、[控制 API](/Users/yuxuanhui/bcc-github/quant-project/worldquant-constract-system/apps/backend/src/api/pre_simulate_list.py:503)、[Schema 状态](/Users/yuxuanhui/bcc-github/quant-project/worldquant-constract-system/apps/backend/src/schemas/pre_simulate.py:20)。
- **S9 模板研究**:[采样预览](/Users/yuxuanhui/bcc-github/quant-project/worldquant-constract-system/apps/backend/src/services/template_research/sampling_service.py:56)、[采样推送](/Users/yuxuanhui/bcc-github/quant-project/worldquant-constract-system/apps/backend/src/services/template_research/sampling_service.py:357)、[采样恢复](/Users/yuxuanhui/bcc-github/quant-project/worldquant-constract-system/apps/backend/src/services/template_research/sampling_service.py:533)、[深度生命周期](/Users/yuxuanhui/bcc-github/quant-project/worldquant-constract-system/apps/backend/src/services/template_research/deep_backtest_service.py:197)、[完成回调](/Users/yuxuanhui/bcc-github/quant-project/worldquant-constract-system/apps/backend/src/services/template_research/template_research_callback.py:94)、[研究模型](/Users/yuxuanhui/bcc-github/quant-project/worldquant-constract-system/apps/backend/src/models/template_research.py:15)。
- **S10 Factory 控制**:[暂停、启动与恢复](/Users/yuxuanhui/bcc-github/quant-project/worldquant-constract-system/apps/backend/src/api/factory.py:1123)、[停止](/Users/yuxuanhui/bcc-github/quant-project/worldquant-constract-system/apps/backend/src/api/factory.py:1326)、[结果模型](/Users/yuxuanhui/bcc-github/quant-project/worldquant-constract-system/apps/backend/src/models/factory.py:99)。
- **S11 CLI 恢复**:[进度文件](/Users/yuxuanhui/bcc-github/quant-project/worldquant-constract-system/apps/backend/src/cli/core/progress.py:14)、[停止控制](/Users/yuxuanhui/bcc-github/quant-project/worldquant-constract-system/apps/backend/src/cli/core/executor.py:43)、[位置更新](/Users/yuxuanhui/bcc-github/quant-project/worldquant-constract-system/apps/backend/src/cli/core/executor.py:142)、[状态命令](/Users/yuxuanhui/bcc-github/quant-project/worldquant-constract-system/apps/backend/src/cli/commands/status.py:16)、[超时结果找回](/Users/yuxuanhui/bcc-github/quant-project/worldquant-constract-system/apps/backend/src/cli/commands/retry_timeout.py:480)。
- **S12 Alpha 保存**:[详情读取](/Users/yuxuanhui/bcc-github/quant-project/worldquant-constract-system/apps/backend/src/core/simulate/alpha_detail.py:451)、[指标落库字段](/Users/yuxuanhui/bcc-github/quant-project/worldquant-constract-system/apps/backend/src/core/simulate/alpha_detail.py:190)、[批量插入去重](/Users/yuxuanhui/bcc-github/quant-project/worldquant-constract-system/apps/backend/src/core/simulate/alpha_detail.py:1201)。
- **S13 批次**:[批次模型](/Users/yuxuanhui/bcc-github/quant-project/worldquant-constract-system/apps/backend/src/models/batch_tracking.py:20)、[统计](/Users/yuxuanhui/bcc-github/quant-project/worldquant-constract-system/apps/backend/src/services/batch_tracking.py:80)、[删除行为](/Users/yuxuanhui/bcc-github/quant-project/worldquant-constract-system/apps/backend/src/services/batch_tracking.py:253)、[Alpha 业务归属](/Users/yuxuanhui/bcc-github/quant-project/worldquant-constract-system/apps/backend/src/models/alpha.py:43)。
- **S14 错误找回**:[错误日志](/Users/yuxuanhui/bcc-github/quant-project/worldquant-constract-system/apps/backend/src/services/backtest/error_logger.py:18)、[恢复筛选](/Users/yuxuanhui/bcc-github/quant-project/worldquant-constract-system/apps/backend/src/services/backtest/recovery_service.py:24)、[查询原模拟](/Users/yuxuanhui/bcc-github/quant-project/worldquant-constract-system/apps/backend/src/services/backtest/recovery_service.py:239)、[保存及改归属](/Users/yuxuanhui/bcc-github/quant-project/worldquant-constract-system/apps/backend/src/services/backtest/recovery_service.py:403)、[API](/Users/yuxuanhui/bcc-github/quant-project/worldquant-constract-system/apps/backend/src/api/backtest_error.py:22)。
- **S15 监控与生命周期**:[监控页](/Users/yuxuanhui/bcc-github/quant-project/worldquant-constract-system/apps/frontend/src/pages/backtest-management/backtest-monitor.vue:395)、[刷新频率](/Users/yuxuanhui/bcc-github/quant-project/worldquant-constract-system/apps/frontend/src/pages/backtest-management/backtest-monitor.vue:589)、[列表刷新](/Users/yuxuanhui/bcc-github/quant-project/worldquant-constract-system/apps/frontend/src/pages/backtest-management/pre-simulate-list.vue:961)、[应用初始化](/Users/yuxuanhui/bcc-github/quant-project/worldquant-constract-system/apps/backend/src/main.py:152)、[应用关闭](/Users/yuxuanhui/bcc-github/quant-project/worldquant-constract-system/apps/backend/src/main.py:182)。
验证方式:对照旧代码、默认配置、前端控制入口与历史设计文档;关键并发、槽位更新、回调顺序及结果保存逻辑做了直接源码抽查,并检查本文引用的本地文件与行号有效性。没有启动旧服务、调用平台回测/恢复接口、修改旧库或运行真实账户测试。本文描述的是代码现状及其可推导限制,不将其表述为已验证的线上运行效果。