import multiprocessing from typing import Tuple, Dict, Any, Optional from src.analysis.result_analyzer import ResultAnalyzer from src.backtest_engine import BacktestEngine from src.data_manager import DataManager # --- 单个回测任务函数 --- # 这个函数将在每个独立的进程中运行,因此它必须是自包含的 def run_single_backtest( combination: Tuple[float, float], # 传入当前参数组合 common_config: Dict[str, Any] # 传入公共配置 (如数据路径, 初始资金等) ) -> Optional[Dict[str, Any]]: """ 运行单个参数组合的回测任务。 此函数将在一个独立的进程中执行。 """ p1_value, p2_value = combination # 从 common_config 中获取必要的配置 symbol = common_config['symbol'] data_path = common_config['data_path'] initial_capital = common_config['initial_capital'] slippage_rate = common_config['slippage_rate'] commission_rate = common_config['commission_rate'] start_time = common_config['start_time'] end_time = common_config['end_time'] roll_over_mode = common_config['roll_over_mode'] # bar_duration_seconds = common_config['bar_duration_seconds'] # 如果DataManager需要,可以再传 param1_name = common_config['param1_name'] param2_name = common_config['param2_name'] # 每个进程内部独立初始化 DataManager 和 BacktestEngine # 确保每个进程有自己的数据副本和模拟状态 data_manager = DataManager( file_path=data_path, symbol=symbol, # bar_duration_seconds=bar_duration_seconds, # 如果DataManager需要,根据数据文件路径推断或者额外参数传入 # start_date=start_time.date(), # DataManager 现在通过 file_path 和 symbol 处理数据 # end_date=end_time.date(), ) # data_manager.load_data() # DataManager 内部加载数据 strategy_parameters = { 'main_symbol': common_config['main_symbol'], 'trade_volume': 1, param1_name: p1_value, # 15分钟扫荡K线下影线占其总范围的最小比例。 param2_name: p2_value, # 15分钟限价单的入场点位于扫荡K线低点到收盘价的斐波那契回撤比例。 'order_direction': common_config['order_direction'], 'enable_log': False, # 建议在调试和测试时开启日志 } # strategy_parameters['spectral_window_days'] = 2 strategy_parameters['low_freq_days'] = strategy_parameters['spectral_window_days'] strategy_parameters['high_freq_days'] = int(strategy_parameters['spectral_window_days'] / 2) strategy_parameters['exit_threshold'] = max(strategy_parameters['trend_strength_threshold'] - 0.3, 0) # 打印当前进程正在处理的组合信息 # 注意:多进程打印会交错显示 print(f"--- 正在运行组合: {strategy_parameters} (PID: {multiprocessing.current_process().pid}) ---") try: # 初始化回测引擎 engine = BacktestEngine( data_manager=data_manager, strategy_class=common_config['strategy'], strategy_params=strategy_parameters, initial_capital=initial_capital, slippage_rate=slippage_rate, commission_rate=commission_rate, roll_over_mode=True, # 保持换月模式 start_time=common_config['start_time'], end_time=common_config['end_time'] ) # 运行回测,传入时间范围 engine.run_backtest() # 获取回测结果并分析 results = engine.get_backtest_results() portfolio_snapshots = results["portfolio_snapshots"] trade_history = results["trade_history"] bars = results["all_bars"] initial_capital_result = results["initial_capital"] if portfolio_snapshots: analyzer = ResultAnalyzer(portfolio_snapshots, trade_history, bars, initial_capital_result) # analyzer.generate_report() # analyzer.plot_performance() metrics = analyzer.calculate_all_metrics() # 将当前组合的参数和性能指标存储起来 result_entry = {**strategy_parameters, **metrics} return result_entry else: print( f" 组合 {strategy_parameters} 没有生成投资组合快照,无法进行结果分析。(PID: {multiprocessing.current_process().pid})") # 返回一个包含参数和默认0值的结果,以便追踪失败组合 return {**strategy_parameters, "total_return": 0.0, "annualized_return": 0.0, "sharpe_ratio": 0.0, "max_drawdown": 0.0, "error": "No portfolio snapshots"} except Exception as e: import traceback error_trace = traceback.format_exc() print( f" 组合 {strategy_parameters} 运行失败: {e}\n{error_trace} (PID: {multiprocessing.current_process().pid})") # 返回错误信息,以便后续处理 return {**strategy_parameters, "error": str(e), "traceback": error_trace}