1
0
Files
leopard-analysis/openspec/specs/backtest-cli/spec.md
2026-01-27 18:30:41 +08:00

196 lines
8.1 KiB
Markdown
Raw 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.
# Spec: Backtest CLI
## ADDED Requirements
### Requirement: 命令行参数解析
回测脚本 SHALL 通过命令行参数接收用户输入,参数 SHALL 包含股票代码、时间范围、策略文件、回测参数等。
#### Scenario: 基础回测执行
- **WHEN** 用户执行 `python backtest.py --code 000001.SZ --start-date 2024-01-01 --end-date 2025-12-31 --strategy-file strategy.py`
- **THEN** 系统解析所有必需参数,无错误提示
- **THEN** 开始执行回测流程
- **THEN** 回测完成后输出统计信息到控制台
#### Scenario: 可选参数未指定
- **WHEN** 用户未指定 `--cash` 参数
- **THEN** 系统使用默认值 100000 作为初始资金
- **WHEN** 用户未指定 `--commission` 参数
- **THEN** 系统使用默认值 0.002 作为手续费率
- **WHEN** 用户未指定 `--output` 参数
- **THEN** 系统不生成 HTML 图表文件
#### Scenario: 必需参数缺失
- **WHEN** 用户未提供 `--code` 参数
- **THEN** 系统输出错误信息:"错误: 需要以下参数: --code"
- **THEN** 系统退出并返回非零状态码
- **WHEN** 用户未提供 `--start-date``--end-date` 参数
- **THEN** 系统输出对应的错误信息
- **THEN** 系统退出并返回非零状态码
#### Scenario: 自定义参数值
- **WHEN** 用户指定 `--cash 500000 --commission 0.001 --output result.html`
- **THEN** 系统使用指定的 500000 作为初始资金
- **THEN** 系统使用指定的 0.001 作为手续费率
- **THEN** 回测完成后生成 HTML 图表到 result.html
---
### Requirement: 数据库数据加载
回测脚本 SHALL 从 PostgreSQL 数据库加载指定股票的历史价格数据,并自动处理复权。
#### Scenario: 成功加载数据
- **WHEN** 用户指定有效的股票代码和时间范围
- **THEN** 系统连接数据库并执行查询
- **THEN** 返回 DataFrame包含列: [Open, High, Low, Close, Volume, factor]
- **THEN** DataFrame 的索引为 trade_date (DatetimeIndex)
- **THEN** 数据已应用复权计算price * factor
#### Scenario: 数据库连接失败
- **WHEN** 数据库连接失败(凭证错误、网络问题等)
- **THEN** 系统捕获异常并输出错误信息:"数据库连接失败: {error}"
- **THEN** 系统退出并返回非零状态码
#### Scenario: 未找到股票数据
- **WHEN** 指定的股票代码或时间范围内无数据
- **THEN** 系统抛出 ValueError: "未找到股票 {code} 在指定时间范围内的数据"
- **THEN** 主流程捕获异常并输出友好错误信息
- **THEN** 系统退出并返回非零状态码
#### Scenario: 数据验证
- **WHEN** 数据库返回的 DataFrame 为空
- **THEN** 系统提示数据为空并退出
- **WHEN** 数据库返回的 DataFrame 少于 10 条记录
- **THEN** 系统提示数据不足并退出
---
### Requirement: 策略动态加载
回测脚本 SHALL 支持动态加载指定路径的策略文件,并验证策略接口。
#### Scenario: 加载有效策略文件
- **WHEN** 用户指定 `--strategy-file strategy.py`
- **THEN** 系统通过 importlib 加载该模块
- **THEN** 系统获取模块的 `calculate_indicators` 函数
- **THEN** 系统调用模块的 `get_strategy()` 函数获取策略类
- **THEN** 系统返回 (calculate_indicators, strategy_class) 元组
#### Scenario: 策略文件不存在
- **WHEN** 用户指定的策略文件路径不存在
- **THEN** 系统捕获 FileNotFoundError
- **THEN** 输出错误信息:"策略文件 {file} 不存在"
- **THEN** 系统退出并返回非零状态码
#### Scenario: 策略接口不完整
- **WHEN** 策略文件缺少 `calculate_indicators` 函数
- **THEN** 系统捕获 AttributeError
- **THEN** 输出错误信息:"策略文件 {file} 缺少 calculate_indicators 函数"
- **THEN** 系统退出并返回非零状态码
- **WHEN** 策略文件缺少 `get_strategy` 函数
- **THEN** 系统捕获 AttributeError
- **THEN** 输出错误信息:"策略文件 {file} 缺少 get_strategy 函数"
- **THEN** 系统退出并返回非零状态码
#### Scenario: 加载子目录中的策略
- **WHEN** 用户指定 `--strategy-file strategies/macd_strategy.py`
- **THEN** 系统正确加载子目录中的策略模块
- **THEN** 系统成功获取策略类和指标计算函数
---
### Requirement: 指标计算
回测脚本 SHALL 在执行回测前调用策略的指标计算函数,将技术指标添加到数据集中。
#### Scenario: 成功计算指标
- **WHEN** 系统调用 `calculate_indicators(data)`
- **THEN** 函数接收包含 [Open, High, Low, Close, Volume, factor] 的 DataFrame
- **THEN** 函数计算策略所需的指标(如 SMA, MACD, RSI
- **THEN** 函数返回添加了指标列的 DataFrame
- **THEN** DataFrame 保留原始列,新增指标列
#### Scenario: 指标计算产生 NaN 值
- **WHEN** 滚动窗口计算导致前 N 行的指标值为 NaN
- **THEN** DataFrame 包含 NaN 值(系统不自动删除)
- **THEN** Backtest 框架在回测时会跳过 NaN 值的行
#### Scenario: 指标计算函数抛出异常
- **WHEN** `calculate_indicators(data)` 执行时抛出异常
- **THEN** 主流程捕获异常
- **THEN** 输出错误信息:"指标计算失败: {error}"
- **THEN** 系统退出并返回非零状态码
---
### Requirement: 回测执行
回测脚本 SHALL 使用 backtesting 库执行回测,传入数据、策略和参数。
#### Scenario: 成功执行回测
- **WHEN** 系统调用 `Backtest(data, strategy_class, cash=..., commission=...).run()`
- **THEN** Backtest 初始化时调用策略类的 `init()` 方法
- **THEN** Backtest 逐个时间步调用策略类的 `next()` 方法
- **THEN** 系统返回包含回测统计信息的 stats 对象
#### Scenario: 回测参数传递
- **WHEN** 用户指定 `--cash 500000 --commission 0.001`
- **THEN** Backtest 实例化时使用 cash=500000
- **THEN** Backtest 实例化时使用 commission=0.001
- **THEN** Backtest 实例化时使用 finalize_trades=True
#### Scenario: 回测运行时错误
- **WHEN** 策略的 `next()` 方法执行时抛出异常
- **THEN** backtesting 库捕获异常
- **THEN** 系统输出错误信息和堆栈跟踪
- **THEN** 系统退出并返回非零状态码
---
### Requirement: 结果输出
回测脚本 SHALL 将回测统计信息格式化输出到控制台,并可选生成 HTML 图表文件。
#### Scenario: 控制台输出
- **WHEN** 回测成功完成
- **THEN** 系统调用 `print_stats(stats)` 函数
- **THEN** 系统输出回测统计信息,使用中文标签
- **THEN** 输出内容包括:最终收益、总收益率、年化收益率、最大回撤、胜率等
- **THEN** 数值格式化(保留 2 位小数)
#### Scenario: 生成 HTML 图表
- **WHEN** 用户指定 `--output result.html`
- **THEN** 系统调用 `bt.plot(filename='result.html', show=False)`
- **THEN** 系统生成 HTML 文件到 result.html
- **THEN** 系统输出提示:"图表已保存到: result.html"
- **THEN** 图表包含价格曲线、资金曲线、买卖信号等
#### Scenario: 不生成 HTML 图表
- **WHEN** 用户未指定 `--output` 参数
- **THEN** 系统不调用 bt.plot() 方法
- **THEN** 系统不生成任何图表文件
- **THEN** 系统仅输出控制台统计信息
#### Scenario: 图表生成失败
- **WHEN** bt.plot() 方法执行时抛出异常
- **THEN** 系统捕获异常
- **THEN** 系统输出警告:"图表生成失败,但回测已完成: {error}"
- **THEN** 系统不影响控制台统计信息的输出
- **THEN** 系统正常退出(返回状态码 0
---
### Requirement: 错误处理
回测脚本 SHALL 对所有可能的错误进行捕获和处理,提供友好的错误提示。
#### Scenario: 数据库错误
- **WHEN** 数据库操作抛出 sqlalchemy.exc.SQLAlchemyError
- **THEN** 系统输出错误信息:"数据库错误: {error}"
- **THEN** 系统退出并返回状态码 2
#### Scenario: 文件操作错误
- **WHEN** 图表文件保存失败(权限、磁盘空间等)
- **THEN** 系统输出错误信息:"文件操作错误: {error}"
- **THEN** 系统退出并返回状态码 3
#### Scenario: 未预期的错误
- **WHEN** 发生其他未捕获的异常
- **THEN** 系统输出错误信息:"未知错误: {error}"
- **THEN** 系统输出完整的堆栈跟踪
- **THEN** 系统退出并返回状态码 1