# Tasks: Refactor Backtest Script

## 1. 项目设置和依赖

- [x] 1.1 创建 requirements.txt 文件，列出所有必需的 Python 包（pandas, numpy, backtesting, sqlalchemy）
- [ ] 1.2 安装项目依赖（pip install -r requirements.txt）
- [x] 1.3 配置数据库凭证（在 backtest.py 中硬编码）
  - 设置 DB_HOST = '81.71.3.24'
  - 设置 DB_NAME = 'leopard_dev'
  - 设置 DB_USER = 'your_username'
  - 设置 DB_PASSWORD = 'your_password'
  - 根据实际开发环境修改这些值

---

## 3. 策略模板实现

- [x] 3.1 创建 strategy.py 文件，包含策略模板和示例
- [x] 3.2 实现 calculate_indicators(data) 函数
  - 计算 SMA10, SMA30, SMA60, SMA120 指标
  - 使用 data['Close'].rolling(window=N).mean() 方法
  - 将结果添加到 DataFrame（data['sma10'] 等）
  - 返回添加了指标列的 DataFrame
- [x] 3.3 实现 get_strategy() 函数
  - 返回 SmaCross 类
  - 添加函数文档字符串说明用途
- [x] 3.4 实现 SmaCross 策略类
  - 继承 backtesting.Strategy
  - 定义类属性：short_period = 10, long_period = 30
  - 实现 init() 方法：使用 self.I() 注册 sma10 和 sma30 指标
  - 实现 next() 方法：使用 crossover() 检测金叉和死叉，执行买卖操作
- [x] 3.5 添加详细的代码注释和文档字符串
  - 文件开头描述策略逻辑
  - 每个函数添加参数和返回值说明
  - 策略类参数添加注释（如 short_period 的含义）

## 4. 策略动态加载功能

- [x] 4.1 在 backtest.py 中实现 load_strategy(strategy_file) 函数
  - 使用 importlib.util.spec_from_file_location() 加载模块
  - 使用 importlib.util.module_from_spec() 创建模块对象
  - 使用 spec.loader.exec_module() 执行模块
- [x] 4.2 实现接口验证逻辑
  - 检查模块是否有 calculate_indicators 属性（hasattr 检查）
  - 检查模块是否有 get_strategy 属性
  - 验证 get_strategy() 返回的是类对象（isinstance 检查）
  - 验证策略类继承自 backtesting.Strategy（issubclass 检查）
- [x] 4.3 实现异常处理
  - 捕获 FileNotFoundError（策略文件不存在）
  - 捕获 ImportError（模块导入失败）
  - 捕获 AttributeError（接口不完整）
  - 输出清晰的错误信息："策略文件 {file} 加载失败: {error}"
- [x] 4.4 返回策略组件
  - 返回元组：(calculate_indicators 函数, strategy_class)

## 5. 命令行参数解析

- [x] 5.1 实现 parse_arguments() 函数
  - 使用 argparse.ArgumentParser 创建解析器
  - 添加 --code 参数（必需，help: 股票代码）
  - 添加 --start-date 参数（必需，help: 回测开始日期）
  - 添加 --end-date 参数（必需，help: 回测结束日期）
  - 添加 --strategy-file 参数（必需，help: 策略文件路径）
  - 添加 --cash 参数（可选，default=100000，help: 初始资金）
  - 添加 --commission 参数（可选，default=0.002，help: 手续费率）
  - 添加 --output 参数（可选，help: HTML 输出文件路径）
  - 添加 --warmup-days 参数（可选，default=365，help: 预热天数，默认一年）
- [x] 5.2 实现参数验证
  - 检查日期格式（YYYY-MM-DD），使用 datetime.strptime() 验证
  - 检查策略文件是否存在（os.path.isfile()）
  - 验证数值参数为正数（cash, commission）
- [x] 5.3 添加友好的错误提示
  - 参数错误时显示帮助信息
  - 日期格式错误时提示正确格式

## 6. 结果输出功能

- [x] 6.1 实现 print_stats(stats) 函数
  - 创建 INDICATOR_MAPPING 字典（英文键 → 中文标签）
  - 遍历 stats 对象的键值对
  - 使用中文标签格式化输出
- [x] 6.2 实现格式化逻辑
  - 实现 format_value(value, cn_name, key) 辅助函数
  - 百分比和比率类值保留 2 位小数
  - 金额类值保留 2 位小数
  - 次数类值取整
  - 其他值保留 4 位小数
- [x] 6.3 添加输出格式化
  - 输出标题："回测结果"（使用 "=" * 60 分隔）
  - 每个指标独占一行
  - 确保中英文对齐美观

## 7. 主流程编排

- [x] 7.1 实现 main() 函数，编排完整流程
  - 调用 parse_arguments() 解析参数
  - 调用 load_data_from_db() 加载数据
  - 调用 load_strategy() 加载策略
  - 调用 calculate_indicators() 计算指标
  - 创建 Backtest 对象并执行
  - 调用 print_stats() 输出结果
- [x] 7.2 添加进度提示信息
  - 数据加载前：输出 "加载股票数据: {code} ({start_date} ~ {end_date})"
  - 数据加载后：输出 "数据加载完成，共 {N} 条记录"
  - 策略加载前：输出 "加载策略: {strategy_file}"
  - 指标计算后：输出 "指标计算完成"
  - 回测开始：输出 "开始回测..."
  - 回测完成：输出 "回测完成！"
- [x] 7.3 实现回测执行
  - 使用 Backtest(data, strategy_class, cash=args.cash, commission=args.commission, finalize_trades=True)
  - 调用 bt.run() 执行回测
  - 保存返回的 stats 对象

## 8. HTML 图表生成

- [x] 8.1 实现可选的图表生成逻辑
  - 检查 args.output 参数是否指定
  - 仅当指定时才调用 bt.plot()
- [x] 8.2 生成 HTML 图表文件
  - 使用 bt.plot(filename=args.output, show=False) 生成文件
  - show=False 确保在无头环境中也能生成
  - 输出提示："图表已保存到: {filepath}"
- [x] 8.3 添加异常处理
  - 捕获图表生成异常
  - 输出警告："图表生成失败，但回测已完成: {error}"
  - 不影响统计信息的正常输出
  - 确保主流程正常退出（状态码 0）

## 9. 全局错误处理

- [x] 9.1 在 main() 函数外层添加 try-except
  - 捕获所有未预期的异常
  - 输出错误信息和堆栈跟踪（traceback.print_exc()）
  - 使用非零状态码退出
- [x] 9.2 实现特定错误的状态码映射
  - 数据库错误：状态码 2
  - 文件操作错误：状态码 3
  - 参数错误：状态码 4
  - 其他错误：状态码 1
- [x] 9.3 添加 `if __name__ == '__main__':` 入口
  - 调用 main() 函数
  - 确保脚本可直接执行和作为模块导入

## 10. 文档和示例（可选）

- [ ] 10.1 创建 README.md 文档（可选）
- [ ] 10.2 添加内联文档到 backtest.py
- [ ] 10.3 添加使用示例到 README

## 11. 测试和验证

- [ ] 11.1 测试基础回测流程
- [ ] 11.2 测试 HTML 图表生成
- [ ] 11.3 测试错误处理
- [ ] 11.4 测试不同策略
- [ ] 11.5 验证输出格式

## 12. 代码质量检查

- [ ] 12.1 运行代码检查工具（可选）
- [ ] 12.2 验证依赖版本兼容性
- [ ] 12.3 最终代码审查

---

## 3. 策略模板实现

- [x] 3.1 创建 strategy.py 文件，包含策略模板和示例
- [x] 3.2 实现 calculate_indicators(data) 函数
  - 计算 SMA10, SMA30, SMA60, SMA120 指标
  - 使用 data['Close'].rolling(window=N).mean() 方法
  - 将结果添加到 DataFrame（data['sma10'] 等）
  - 返回添加了指标列的 DataFrame
- [x] 3.3 实现 get_strategy() 函数
  - 返回 SmaCross 类
  - 添加函数文档字符串说明用途
- [x] 3.4 实现 SmaCross 策略类
  - 继承 backtesting.Strategy
  - 定义类属性：short_period = 10, long_period = 30
  - 实现 init() 方法：使用 self.I() 注册 sma10 和 sma30 指标
  - 实现 next() 方法：使用 crossover() 检测金叉和死叉，执行买卖操作
- [x] 3.5 添加详细的代码注释和文档字符串
  - 文件开头描述策略逻辑
  - 每个函数添加参数和返回值说明
  - 策略类参数添加注释（如 short_period 的含义）

---

## 4. 策略动态加载功能

- [x] 4.1 在 backtest.py 中实现 load_strategy(strategy_file) 函数
  - 使用 importlib.util.spec_from_file_location() 加载模块
  - 使用 importlib.util.module_from_spec() 创建模块对象
  - 使用 spec.loader.exec_module() 执行模块
- [x] 4.2 实现接口验证逻辑
  - 检查模块是否有 calculate_indicators 属性（hasattr 检查）
  - 检查模块是否有 get_strategy 属性
  - 验证 get_strategy() 返回的是类对象（isinstance 检查）
  - 验证策略类继承自 backtesting.Strategy（issubclass 检查）
- [x] 4.3 实现异常处理
  - 捕获 FileNotFoundError（策略文件不存在）
  - 捕获 ImportError（模块导入失败）
  - 捕获 AttributeError（接口不完整）
  - 输出清晰的错误信息："策略文件 {file} 加载失败: {error}"
- [x] 4.4 返回策略组件
  - 返回元组：(calculate_indicators 函数, strategy_class)

---

## 5. 命令行参数解析

- [x] 5.1 实现 parse_arguments() 函数
  - 使用 argparse.ArgumentParser 创建解析器
  - 添加 --code 参数（必需，help: 股票代码）
  - 添加 --start-date 参数（必需，help: 回测开始日期）
  - 添加 --end-date 参数（必需，help: 回测结束日期）
  - 添加 --strategy-file 参数（必需，help: 策略文件路径）
  - 添加 --cash 参数（可选，default=100000，help: 初始资金）
  - 添加 --commission 参数（可选，default=0.002，help: 手续费率）
  - 添加 --output 参数（可选，help: HTML 输出文件路径）
  - 添加 --warmup-days 参数（可选，default=365，help: 预热天数，默认一年）
- [x] 5.2 实现参数验证
  - 检查日期格式（YYYY-MM-DD），使用 datetime.strptime() 验证
  - 检查策略文件是否存在（os.path.isfile()）
  - 验证数值参数为正数（cash, commission）
- [x] 5.3 添加友好的错误提示
  - 参数错误时显示帮助信息
  - 日期格式错误时提示正确格式

---

## 6. 结果输出功能

- [x] 6.1 实现 print_stats(stats) 函数
  - 创建 INDICATOR_MAPPING 字典（英文键 → 中文标签）
  - 遍历 stats 对象的键值对
  - 使用中文标签格式化输出
- [x] 6.2 实现格式化逻辑
  - 实现 format_value(value, cn_name, key) 辅助函数
  - 百分比和比率类值保留 2 位小数
  - 金额类值保留 2 位小数
  - 次数类值取整
  - 其他值保留 4 位小数
- [x] 6.3 添加输出格式化
  - 输出标题："回测结果"（使用 "=" * 60 分隔）
  - 每个指标独占一行
  - 确保中英文对齐美观

---

## 7. 主流程编排

- [x] 7.1 实现 main() 函数，编排完整流程
  - 调用 parse_arguments() 解析参数
  - 调用 load_data_from_db() 加载数据
  - 调用 load_strategy() 加载策略
  - 调用 calculate_indicators() 计算指标
  - 创建 Backtest 对象并执行
  - 调用 print_stats() 输出结果
- [x] 7.2 添加进度提示信息
  - 数据加载前：输出 "加载股票数据: {code} ({start_date} ~ {end_date})"
  - 数据加载后：输出 "数据加载完成，共 {N} 条记录"
  - 策略加载前：输出 "加载策略: {strategy_file}"
  - 指标计算后：输出 "指标计算完成"
  - 回测开始：输出 "开始回测..."
  - 回测完成：输出 "回测完成！"
- [x] 7.3 实现回测执行
  - 使用 Backtest(data, strategy_class, cash=args.cash, commission=args.commission, finalize_trades=True)
  - 调用 bt.run() 执行回测
  - 保存返回的 stats 对象
- [x] 8.1 实现可选的图表生成逻辑
  - 检查 args.output 参数是否指定
  - 仅当指定时才调用 bt.plot()
- [x] 8.2 生成 HTML 图表文件
  - 使用 bt.plot(filename=args.output, show=False) 生成文件
  - show=False 确保在无头环境中也能生成
  - 输出提示："图表已保存到: {filepath}"
- [x] 8.3 添加异常处理
  - 捕获图表生成异常
  - 输出警告："图表生成失败，但回测已完成: {error}"
  - 不影响统计信息的正常输出
  - 确保主流程正常退出（状态码 0）

---

## 9. 全局错误处理

- [ ] 9.1 在 main() 函数外层添加 try-except
  - 捕获所有未预期的异常
  - 输出错误信息和堆栈跟踪（traceback.print_exc()）
  - 使用非零状态码退出
- [ ] 9.2 实现特定错误的状态码映射
  - 数据库错误：状态码 2
  - 文件操作错误：状态码 3
  - 参数错误：状态码 4
  - 其他错误：状态码 1
- [ ] 9.3 添加 `if __name__ == '__main__':` 入口
  - 调用 main() 函数
  - 确保脚本可直接执行和作为模块导入

---

## 10. 文档和示例

- [ ] 10.1 创建 README.md 文档（可选）
  - 说明项目用途和功能
  - 提供安装步骤（pip install -r requirements.txt）
  - 提供使用示例（基础用法、自定义参数、不同策略）
  - 说明策略文件接口规范
  - 说明环境变量配置（DB_USER, DB_PASSWORD）
- [ ] 10.2 添加内联文档到 backtest.py
  - 文件开头添加模块文档字符串
  - 说明命令行参数和用法
  - 提供使用示例
- [ ] 10.3 添加使用示例到 README
  ```bash
  # 基础用法
  python backtest.py --code 000001.SZ --start-date 2024-01-01 --end-date 2025-12-31 --strategy-file strategy.py

  # 自定义参数
  python backtest.py --code 000001.SZ --start-date 2024-01-01 --end-date 2025-12-31 --strategy-file strategy.py --cash 500000 --commission 0.001 --output result.html
  ```

---

## 11. 测试和验证

- [ ] 11.1 测试基础回测流程
  - 执行 `python backtest.py --code 000001.SZ --start-date 2024-01-01 --end-date 2025-12-31 --strategy-file strategy.py`
  - 验证数据加载成功
  - 验证策略加载成功
  - 验证回测执行成功
  - 验证统计信息输出正确
- [ ] 11.2 测试 HTML 图表生成
  - 执行带 `--output` 参数的命令
  - 验证 HTML 文件成功生成
  - 验证图表内容正确（价格曲线、资金曲线等）
- [ ] 11.3 测试错误处理
  - 测试无效股票代码（应提示未找到数据）
  - 测试无效日期格式（应提示格式错误）
  - 测试策略文件不存在（应提示文件不存在）
  - 测试数据库连接失败（应提示连接错误）
  - 测试策略接口不完整（应提示缺少函数）
- [ ] 11.4 测试不同策略
  - 创建 strategies/macd_strategy.py
  - 使用新策略执行回测
  - 验证动态加载功能正常
- [ ] 11.5 验证输出格式
  - 检查控制台输出使用中文标签
  - 检查数值格式化正确（小数位数）
  - 检查 HTML 文件可正常打开

---

## 12. 代码质量检查

- [ ] 12.1 运行代码检查工具（可选）
  - 使用 pylint 或 flake8 检查代码风格
  - 修复警告和错误
- [ ] 12.2 验证依赖版本兼容性
  - 检查 backtesting 库版本兼容性
  - 检查 pandas 和 numpy 版本要求
- [ ] 12.3 最终代码审查
  - 对照设计文档检查实现是否完整
  - 对照规范文档检查所有场景是否覆盖
  - 确保代码遵循设计决策
