Files
2026-03-28 12:07:55 +08:00

219 lines
6.6 KiB
Python
Executable File

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
通用自动化回测脚本
自动保存结果到:
1. 全局目录: /volume1/stock/sanguo_vnpy/backtest_results/
2. 策略目录: ./strategies/{your_strategy}/backtest_results/ 便于和策略放在一起查看
"""
import sys
import os
import argparse
from datetime import datetime
from pathlib import Path
# 添加路径
sys.path.insert(0, '/volume1/stock/sanguo_vnpy')
sys.path.insert(0, '/volume1/stock/sanguo_vnpy/strategies')
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from vnpy.trader.constant import Interval
from vnpy_ctabacktester import BacktesterEngine
def run_backtest(
strategy_class,
strategy_name: str,
vt_symbol: str = "IF888.CFFEX",
interval: Interval = Interval.DAILY,
start_date: str = "20200101",
end_date: str = "20251231",
capital: int = 1000000,
rate: float = 0.3 / 10000,
slippage: float = 0.2,
size: int = 300,
pricetick: float = 0.2,
strategy_config: dict = None,
):
"""运行单个策略回测"""
# 创建结果保存目录
# 1. 全局目录
GLOBAL_RESULT_DIR = Path('/volume1/stock/sanguo_vnpy/backtest_results')
GLOBAL_RESULT_DIR.mkdir(exist_ok=True, parents=True)
# 2. 策略目录(和策略放在一起便于查看)
# 找到策略目录
strategy_file = sys.modules[strategy_class.__module__].__file__
strategy_dir = Path(strategy_file).parent
STRATEGY_RESULT_DIR = strategy_dir / "backtest_results"
STRATEGY_RESULT_DIR.mkdir(exist_ok=True, parents=True)
print("=" * 60)
print(f" 开始回测: {strategy_name}")
print(f" 结果保存:")
print(f" 全局: {GLOBAL_RESULT_DIR}")
print(f" 策略: {STRATEGY_RESULT_DIR}")
print("=" * 60)
print()
# 打印配置
print(f"📋 回测配置:")
print(f" 标的: {vt_symbol}")
print(f" 周期: {interval}")
print(f" 时间: {start_date} - {end_date}")
print(f" 初始资金: {capital:,}")
print()
# 创建回测引擎
print("🚀 创建回测引擎...")
engine = BacktesterEngine()
# 添加策略
print("🧩 添加策略...")
if strategy_config is None:
strategy_config = {}
engine.add_strategy(strategy_class, strategy_config)
# 运行回测
print("🔄 开始运行回测...")
start_time = datetime.now()
engine.run_backtest(
vt_symbol=vt_symbol,
interval=interval,
start=start_date,
end=end_date,
rate=rate,
slippage=slippage,
size=size,
pricetick=pricetick,
capital=capital
)
end_time = datetime.now()
duration = (end_time - start_time).total_seconds()
print(f"✅ 回测完成!耗时: {duration:.2f}")
print()
# 获取结果文本
import io
from contextlib import redirect_stdout
output = io.StringIO()
with redirect_stdout(output):
engine.show_results()
result_text = output.getvalue()
# 保存结果到全局目录
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
global_result_file = GLOBAL_RESULT_DIR / f"{strategy_name}_{timestamp}.txt"
with open(global_result_file, 'w', encoding='utf-8') as f:
f.write(f"{strategy_name} 回测结果\n")
f.write("=" * 50 + "\n")
f.write(f"时间: {timestamp}\n")
f.write(f"标的: {vt_symbol}\n")
f.write(f"周期: {interval}\n")
f.write(f"时间范围: {start_date} - {end_date}\n")
f.write(f"初始资金: {capital:,}\n")
f.write("\n")
f.write(result_text)
print(f"💾 全局结果已保存: {global_result_file}")
# 保存结果到策略目录
strategy_result_file = STRATEGY_RESULT_DIR / f"{strategy_name}_{timestamp}.txt"
with open(strategy_result_file, 'w', encoding='utf-8') as f:
f.write(f"{strategy_name} 回测结果\n")
f.write("=" * 50 + "\n")
f.write(f"时间: {timestamp}\n")
f.write(f"标的: {vt_symbol}\n")
f.write(f"周期: {interval}\n")
f.write(f"时间范围: {start_date} - {end_date}\n")
f.write(f"初始资金: {capital:,}\n")
f.write("\n")
f.write(result_text)
print(f"📂 策略结果已保存: {strategy_result_file}")
print()
# 保存图表
print("📈 绘制资金曲线...")
plt.figure(figsize=(12, 6))
engine.plot_chart()
# 保存到全局目录
global_chart_file = GLOBAL_RESULT_DIR / f"{strategy_name}_{timestamp}.png"
plt.savefig(global_chart_file)
print(f"📊 全局图表已保存: {global_chart_file}")
# 保存到策略目录
strategy_chart_file = STRATEGY_RESULT_DIR / f"{strategy_name}_{timestamp}.png"
plt.savefig(strategy_chart_file)
print(f"📊 策略图表已保存: {strategy_chart_file}")
print()
print("=" * 60)
print(f" 🎉 回测完成!")
print(f" 📄 全局结果: {global_result_file}")
print(f" 📂 策略结果: {strategy_result_file}")
print("=" * 60)
return global_result_file, strategy_result_file
def main():
"""主函数"""
parser = argparse.ArgumentParser(description='自动化运行策略回测')
parser.add_argument('strategy', help='策略模块名,例如: strategies.guanyu_value_tech_strategy')
parser.add_argument('--symbol', default='IF888.CFFEX', help='回测标的')
parser.add_argument('--start', default='20200101', help='开始日期')
parser.add_argument('--end', default='20251231', help='结束日期')
parser.add_argument('--capital', type=int, default=1000000, help='初始资金')
args = parser.parse_args()
# 导入策略模块
import importlib
module = importlib.import_module(args.strategy)
# 找到策略类(假设第一个类就是策略类)
strategy_class = None
for name, obj in module.__dict__.items():
if isinstance(obj, type) and 'Strategy' in name:
strategy_class = obj
break
if strategy_class is None:
print(f"❌ 在模块 {args.strategy} 中没找到策略类")
sys.exit(1)
strategy_name = strategy_class.__name__
# 获取策略配置(如果有)
strategy_config = {}
if hasattr(module, 'STRATEGY_CONFIG'):
strategy_config = module.STRATEGY_CONFIG
# 运行回测
run_backtest(
strategy_class=strategy_class,
strategy_name=strategy_name,
vt_symbol=args.symbol,
start_date=args.start,
end_date=args.end,
capital=args.capital,
strategy_config=strategy_config,
)
if __name__ == "__main__":
main()