14 KiB
14 KiB
Spec: Batch Backtest
ADDED 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_backtest或run_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_COLOR和plotting.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 sync或pip install -e . - THEN 系统自动安装 tabulate 和 tqdm
- THEN 系统显示依赖安装进度
- THEN 系统完成安装后可以正常使用回测工具
Scenario: 依赖缺失提示
- WHEN 系统导入 tabulate 或 tqdm 时失败
- THEN 系统输出友好错误信息:"缺少依赖: {package_name},请运行: uv add {package_name}"
- THEN 系统退出并返回非零状态码