重构回测代码架构,新增批量回测功能
This commit is contained in:
120
backtest_command.py
Executable file
120
backtest_command.py
Executable file
@@ -0,0 +1,120 @@
|
||||
#!/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()
|
||||
Reference in New Issue
Block a user