# 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 最终代码审查 - 对照设计文档检查实现是否完整 - 对照规范文档检查所有场景是否覆盖 - 确保代码遵循设计决策