1
0
Files
leopard-analysis/openspec/specs/batch-backtest/spec.md

14 KiB
Raw Blame History

batch-backtest Specification

Purpose

TBD - created by archiving change refactor-backtest-separate-cli. Update Purpose after archive.

Requirements

Requirement: 多股票回测参数

系统 SHALL 支持通过命令行参数传入多个股票代码进行批量回测。

Scenario: 传入多个股票代码

  • WHEN 用户执行 python backtest_command.py --codes 000001.SZ 600000.SH --start-date 2024-01-01 --end-date 2025-12-31 --strategy-file strategies/macd_strategy.py
  • THEN 系统解析所有股票代码到列表 ['000001.SZ', '600000.SH']
  • THEN 系统按顺序依次执行每个股票的回测
  • THEN 系统为每个股票生成独立的回测结果

Scenario: 传入单个股票代码

  • WHEN 用户执行 python backtest_command.py --codes 000001.SZ --start-date 2024-01-01 --end-date 2025-12-31 --strategy-file strategies/macd_strategy.py
  • THEN 系统解析为单个股票代码列表 ['000001.SZ']
  • THEN 系统执行单个股票回测
  • THEN 系统输出详细格式的回测结果

Scenario: 缺少 --codes 参数

  • WHEN 用户未提供 --codes 参数
  • THEN 系统输出错误信息:"错误: 需要以下参数: --codes"
  • THEN 系统退出并返回非零状态码

Requirement: 批量回测执行

系统 SHALL 串行执行多个股票的回测,每次加载一个股票的数据并执行回测。

Scenario: 成功执行多个股票回测

  • WHEN 用户传入 N 个股票代码
  • THEN 系统循环 N 次,每次加载一个股票的数据
  • THEN 系统每次执行完整的回测流程(数据加载、指标计算、回测执行)
  • THEN 系统每次执行完成后生成 BacktestResult 对象
  • THEN 系统返回包含 N 个 BacktestResult 的列表

Scenario: 每个股票独立预热期

  • WHEN 系统执行第 i 个股票的回测
  • THEN 系统使用 start_date - warmup_days 计算该股票的预热开始日期
  • THEN 系统独立加载该股票的预热期数据
  • THEN 不同股票的预热期互不影响

Scenario: 第一个股票回测失败

  • WHEN 系统执行第一个股票回测时发生错误(数据库连接失败、策略加载失败等)
  • THEN 系统捕获异常并输出错误信息
  • THEN 系统停止执行后续股票的回测
  • THEN 系统退出并返回非零状态码(立即失败策略)

Scenario: 中间股票回测失败

  • WHEN 系统执行第 i 个股票回测时发生错误
  • THEN 系统输出错误信息(包含股票代码)
  • THEN 系统停止执行后续股票的回测
  • THEN 系统退出并返回非零状态码

Scenario: 资源管理

  • WHEN 系统完成第 i 个股票的回测
  • THEN 系统关闭该股票的数据库连接(engine.dispose()
  • THEN 系统释放该股票的数据内存
  • THEN 系统开始加载第 i+1 个股票的数据

Requirement: 批量回测进度显示

系统 SHALL 使用 tqdm 显示批量回测的实时进度,提供用户反馈。

Scenario: 显示进度条

  • WHEN 系统开始执行 N 个股票的批量回测
  • THEN 系统显示进度条格式:回测进度: 25%|█████▌ | 1/4 [00:30<01:30, 12.5s/it]
  • THEN 系统在完成每个股票回测后更新进度条
  • THEN 进度条显示当前进度i/N、已用时间、预计剩余时间
  • THEN 进度条在所有股票回测完成后消失

Scenario: 单股票回测不显示进度条

  • WHEN 用户传入单个股票代码
  • THEN 系统不显示 tqdm 进度条
  • THEN 系统直接输出回测结果

Scenario: 进度条描述文本

  • WHEN 系统显示批量回测进度
  • THEN 进度条描述 SHALL 为 "回测进度"(中文)
  • THEN 进度条显示已完成/总数(如 "1/4", "2/4"

Requirement: 批量回测结果展示

系统 SHALL 使用 tabulate 将多个股票的回测结果格式化为表格,便于横向对比。

Scenario: 表格化输出多股票结果

  • WHEN 用户传入多个股票代码且回测成功
  • THEN 系统使用 tabulate 生成表格
  • THEN 表格格式 SHALL 为 grid带边框
  • THEN 表格列 SHALL 包含:股票代码、收益率%、胜率%、最大回撤%、交易次数、SQN
  • THEN 系统在表格上方显示表头(中文列名)
  • THEN 数值保留 2 位小数(交易次数为整数)

Scenario: 表格内容填充

  • WHEN 系统格式化第 i 个股票的结果
  • THEN 系统从 BacktestResult 对象提取字段
  • THEN "股票代码" 列填充 result.code
  • THEN "收益率%" 列填充 result.return_pct
  • THEN "胜率%" 列填充 result.win_rate
  • THEN "最大回撤%" 列填充 result.max_drawdown
  • THEN "交易次数" 列填充 result.trades
  • THEN "SQN" 列填充 result.sqn

Scenario: 单股票回测不使用表格

  • WHEN 用户传入单个股票代码
  • THEN 系统不使用 tabulate 生成表格
  • THEN 系统使用详细格式输出(每个指标单独一行)
  • THEN 系统保持原有 print_stats() 的输出格式

Scenario: 表格示例输出

  • WHEN 用户传入 2 个股票代码
  • THEN 系统输出格式 SHALL 为:
    +-------------+-----------+--------+------------+----------+-------+
    | 股票代码    | 收益率%  | 胜率%  | 最大回撤%  | 交易次数 | SQN   |
    +-------------+-----------+--------+------------+----------+-------+
    | 000001.SZ   | 20.35    | 55.00  | -8.50      | 45       | 1.85  |
    | 600000.SH   | 15.00    | 48.00  | -12.30     | 38       | 1.42  |
    +-------------+-----------+--------+------------+----------+-------+
    

Requirement: 多股票图表输出

系统 SHALL 为每个股票生成独立的 HTML 图表文件,文件名格式为 {code}.html

Scenario: 指定 --output-dir 参数

  • WHEN 用户传入 --output-dir output/
  • THEN 系统为每个股票生成 HTML 文件到 output/{code}.html
  • THEN 文件名 SHALL 为股票代码,如 000001.SZ.html, 600000.SH.html
  • THEN 系统自动创建 output/ 目录(exist_ok=True
  • THEN 系统在完成后输出提示:"图表已保存到目录: output/" 后列出所有文件

Scenario: 未指定 --output-dir 参数

  • WHEN 用户未传入 --output-dir 参数
  • THEN 系统不为任何股票生成图表文件
  • THEN 系统仅输出控制台统计信息

Scenario: 图表文件覆盖

  • WHEN 系统再次执行相同的批量回测
  • THEN 系统覆盖已存在的 HTML 文件
  • THEN 系统不提示文件已存在

Requirement: 结构化回测结果

系统 SHALL 返回标准化的 BacktestResult 对象,包含所有关键指标。

Scenario: BacktestResult 对象创建

  • WHEN 系统完成单股票回测
  • THEN 系统从 stats 对象提取指标到 BacktestResult
  • THEN BacktestResult.code 设置为股票代码
  • THEN BacktestResult.start_date 设置为回测开始日期
  • THEN BacktestResult.end_date 设置为回测结束日期
  • THEN BacktestResult.equity_final 设置为最终权益
  • THEN BacktestResult.equity_peak 设置为峰值收益
  • THEN BacktestResult.return_pct 设置为总收益率
  • THEN BacktestResult.buy_hold_return 设置为买入持有收益率
  • THEN BacktestResult.return_annual 设置为年化收益率
  • THEN BacktestResult.volatility_annual 设置为年化波动率
  • THEN BacktestResult.max_drawdown 设置为最大回撤
  • THEN BacktestResult.avg_drawdown 设置为平均回撤
  • THEN BacktestResult.max_drawdown_duration 设置为最大回撤持续时长
  • THEN BacktestResult.avg_drawdown_duration 设置为平均回撤持续时长
  • THEN BacktestResult.sortino_ratio 设置为索提诺比率
  • THEN BacktestResult.calmar_ratio 设置为卡尔玛比率
  • THEN BacktestResult.trades 设置为交易次数
  • THEN BacktestResult.win_rate 设置为胜率
  • THEN BacktestResult.sqn 设置为系统质量数
  • THEN BacktestResult.cash 设置为初始资金
  • THEN BacktestResult.commission 设置为手续费率

Scenario: BacktestResult 列表返回

  • WHEN 系统完成批量回测
  • THEN 系统返回 List[BacktestResult]
  • THEN 列表顺序 SHALL 与输入股票代码顺序一致
  • THEN 列表长度 SHALL 等于输入股票代码数量(成功时)

Scenario: BacktestResult 数据类型

  • WHEN 系统创建 BacktestResult 对象
  • THEN 数值字段 SHALL 为 float 类型(除 trades, max_drawdown_duration 为 int
  • THEN 日期字段 SHALL 为 str 类型YYYY-MM-DD 格式)
  • THEN 系统支持 result.to_dict() 方法dataclass 自动生成)

Requirement: 可复用回测引擎接口

系统 SHALL 提供标准化的函数接口,供其他模块调用回测功能。

Scenario: run_backtest 函数调用

  • WHEN 其他模块调用 run_backtest(code, start_date, end_date, strategy_file, cash, commission, warmup_days, output_file)
  • THEN 函数接收股票代码、日期范围、策略文件、回测参数、输出文件路径
  • THEN 函数执行完整回测流程(数据加载、策略加载、指标计算、回测执行)
  • THEN 函数返回 BacktestResult 对象
  • THEN 函数不打印任何输出(纯函数)

Scenario: run_batch_backtest 函数调用

  • WHEN 其他模块调用 run_batch_backtest(codes, start_date, end_date, strategy_file, cash, commission, warmup_days, output_dir)
  • THEN 函数接收股票代码列表、日期范围、策略文件、回测参数、输出目录
  • THEN 函数串行执行每个股票的回测
  • THEN 函数返回 List[BacktestResult]
  • THEN 函数显示 tqdm 进度条(批量时)

Scenario: 函数参数默认值

  • WHEN 调用者不指定可选参数
  • THEN cash 默认为 100000
  • THEN commission 默认为 0.002
  • THEN warmup_days 默认为 365
  • THEN output_file 默认为 None不生成图表
  • THEN output_dir 默认为 None不生成图表

Scenario: 函数异常抛出

  • WHEN run_backtestrun_batch_backtest 执行时发生错误
  • THEN 函数 SHALL 抛出异常(不捕获)
  • THEN 异常类型 SHALL 为 ValueError、TypeError 或原始异常
  • THEN 异常信息 SHALL 包含具体错误原因
  • THEN 调用者负责捕获和处理异常

Requirement: 集中配置管理

系统 SHALL 在 config.py 中集中管理数据库配置、默认回测参数、图表配色。

Scenario: 数据库配置访问

  • WHEN backtest_core.py 需要数据库连接参数
  • THEN 模块从 config 导入 DB_HOST, DB_PORT, DB_NAME, DB_USER, DB_PASSWORD
  • THEN 模块使用这些常量构建连接字符串
  • THEN 模块不重复定义数据库配置

Scenario: 默认参数访问

  • WHEN backtest_core.py 需要默认回测参数
  • THEN 模块从 config 导入 DEFAULT_CASH, DEFAULT_COMMISSION, DEFAULT_WARMUP_DAYS
  • THEN 模块使用这些常量作为函数默认值
  • THEN 模块不重复定义默认参数

Scenario: 图表配色访问

  • WHEN backtest_core.py 需要设置图表配色
  • THEN 模块从 config 导入 BULL_COLOR, BEAR_COLOR
  • THEN 模块使用这些颜色设置 plotting.BULL_COLORplotting.BEAR_COLOR
  • THEN 模块不重复定义颜色配置

Scenario: 配置文件内容

  • WHEN 查看 config.py 文件
  • THEN 文件包含数据库配置DB_HOST, DB_PORT, DB_NAME, DB_USER, DB_PASSWORD
  • THEN 文件包含默认回测参数DEFAULT_CASH, DEFAULT_COMMISSION, DEFAULT_WARMUP_DAYS
  • THEN 文件包含图表配色BULL_COLOR, BEAR_COLOR
  • THEN 所有配置使用明文常量(不使用环境变量)

Requirement: 错误处理策略

系统 SHALL 在批量回测失败时立即停止执行,不继续处理后续股票。

Scenario: 数据加载失败

  • WHEN 系统加载第 i 个股票数据时失败(数据库错误、数据不存在)
  • THEN 系统捕获异常
  • THEN 系统输出错误信息:"回测失败 [{code}]: {error}"
  • THEN 系统停止执行后续股票的回测
  • THEN 系统退出并返回非零状态码

Scenario: 策略加载失败

  • WHEN 系统加载策略文件时失败(文件不存在、接口不完整)
  • THEN 系统捕获异常
  • THEN 系统输出错误信息:"策略加载失败: {error}"
  • THEN 系统停止执行所有股票的回测
  • THEN 系统退出并返回非零状态码

Scenario: 回测执行失败

  • WHEN 系统执行第 i 个股票回测时失败(策略逻辑错误)
  • THEN 系统捕获异常
  • THEN 系统输出错误信息和完整堆栈跟踪
  • THEN 系统停止执行后续股票的回测
  • THEN 系统退出并返回非零状态码

Scenario: 图表生成失败

  • WHEN 系统生成第 i 个股票图表时失败
  • THEN 系统捕获异常
  • THEN 系统输出警告:"图表生成失败 [{code}]: {error},但回测已完成"
  • THEN 系统继续执行后续股票的回测
  • THEN 系统在返回的 BacktestResult 中设置 error 字段(如果设计支持)

Requirement: 依赖管理

系统 SHALL 在 pyproject.toml 中添加 tabulate 和 tqdm 依赖。

Scenario: 添加 tabulate 依赖

  • WHEN 查看 pyproject.toml 文件
  • THEN 文件包含 tabulate 依赖
  • THEN 依赖版本 SHALL 为兼容当前 Python 版本的版本
  • THEN 系统可以导入 import tabulate 无错误

Scenario: 添加 tqdm 依赖

  • WHEN 查看 pyproject.toml 文件
  • THEN 文件包含 tqdm 依赖
  • THEN 依赖版本 SHALL 为兼容当前 Python 版本的版本
  • THEN 系统可以导入 from tqdm import tqdm 无错误

Scenario: 依赖安装

  • WHEN 用户运行 uv syncpip install -e .
  • THEN 系统自动安装 tabulate 和 tqdm
  • THEN 系统显示依赖安装进度
  • THEN 系统完成安装后可以正常使用回测工具

Scenario: 依赖缺失提示

  • WHEN 系统导入 tabulate 或 tqdm 时失败
  • THEN 系统输出友好错误信息:"缺少依赖: {package_name},请运行: uv add {package_name}"
  • THEN 系统退出并返回非零状态码