#!/usr/bin/env python3 import argparse import sys import tabulate import backtest_core def parse_arguments(): parser = argparse.ArgumentParser(description="量化回测工具", formatter_class=argparse.RawDescriptionHelpFormatter) parser.add_argument("--codes", type=str, nargs="+", required=True, help="股票代码列表 (如: 000001.SZ 600000.SH)", ) parser.add_argument("--start-date", type=str, required=True, help="回测开始日期 (格式: YYYY-MM-DD)", ) parser.add_argument("--end-date", type=str, required=True, help="回测结束日期 (格式: YYYY-MM-DD)", ) parser.add_argument("--strategy-file", type=str, required=True, help="策略文件路径 (如: strategy.py)", ) parser.add_argument("--cash", type=float, default=100000, help="初始资金 (默认: 100000)", ) parser.add_argument("--commission", type=float, default=0.002, help="手续费率 (默认: 0.002)", ) parser.add_argument("--warmup-days", type=int, default=365, help="预热天数 (默认: 365,约一年)", ) parser.add_argument("--output-dir", type=str, default=None, help="HTML 图表输出目录 (可选,为每个股票生成 {code}.html)", ) return parser.parse_args() def format_single_result(result: backtest_core.BacktestResult): print("=" * 60) print(f"股票代码: {result.code}") print("=" * 60) indicator_mapping = { "最终收益": f"{result.equity_final:.2f}", "峰值收益": f"{result.equity_peak:.2f}", "总收益率(%)": f"{result.return_pct:.2f}", "买入并持有收益率(%)": f"{result.buy_hold_return_pct:.2f}", "年化收益率(%)": f"{result.return_ann_pct:.2f}", "年化波动率(%)": f"{result.volatility_ann_pct:.2f}", "索提诺比率": f"{result.sortino_ratio:.2f}", "卡尔玛比率": f"{result.calmar_ratio:.2f}", "最大回撤(%)": f"{result.max_drawdown_pct:.2f}", "平均回撤(%)": f"{result.avg_drawdown_pct:.2f}", "最大回撤持续时长": f"{result.max_drawdown_duration:.0f} 天", "平均回撤持续时长": f"{result.avg_drawdown_duration:.0f} 天", "总交易次数": f"{result.num_trades:.0f}", "胜率(%)": f"{result.win_rate_pct:.2f}", "系统质量数": f"{result.sqn:.2f}", } for name, value in indicator_mapping.items(): print(f"{name}: {value}") print("=" * 60) def format_batch_results(results: list[backtest_core.BacktestResult]): table_data = [] for result in results: table_data.append( [ result.code, f"{result.return_pct:.2f}", f"{result.buy_hold_return_pct:.2f}", f"{result.return_ann_pct:.2f}", f"{result.volatility_ann_pct:.2f}", f"{result.win_rate_pct:.2f}", f"{result.max_drawdown_pct:.2f}", f"{result.sortino_ratio:.2f}", f"{result.num_trades:.0f}", f"{result.sqn:.2f}", ] ) headers = [ "股票代码", "收益率%", "买入持有%", "年化收益%", "年化波动%", "胜率%", "最大回撤%", "索提诺比率", "交易次数", "SQN", ] print(tabulate.tabulate(table_data, headers=headers, tablefmt="grid")) def main(): args = parse_arguments() try: results = backtest_core.run_batch_backtest( codes=args.codes, start_date=args.start_date, end_date=args.end_date, strategy_file=args.strategy_file, cash=args.cash, commission=args.commission, warmup_days=args.warmup_days, output_dir=args.output_dir, show_progress=True, ) if len(results) == 1: format_single_result(results[0]) else: format_batch_results(results) if args.output_dir: print(f"\n图表已保存到: {args.output_dir}/") except Exception as e: print(f"\n错误: {e}") import traceback traceback.print_exc() sys.exit(1) if __name__ == "__main__": main()