# -*- coding: utf-8 -*- import time import json import os from concurrent.futures import ThreadPoolExecutor, as_completed from random import uniform from typing import List, Dict, Any from core.api_client import WorldQuantBrainSimulate from core.models import SimulationResult from utils.time_utils import format_time from utils.file_utils import save_results_to_file, save_success_alpha class AlphaSimulationManager: def __init__(self, credentials_file='account.txt'): self.credentials_file = credentials_file self.results = [] """模拟单个Alpha因子(线程安全)""" def simulate_single_alpha(self, api: WorldQuantBrainSimulate, expression: str, settings: Dict[str, Any] = None) -> SimulationResult: alpha_start_time = time.time() try: # 模拟Alpha因子 simulation_result = api.simulate_alpha(expression, settings) alpha_end_time = time.time() time_consuming = alpha_end_time - alpha_start_time # 根据模拟结果类型处理 if simulation_result["status"] == "success": # 模拟成功的结果 - 直接使用原始metrics数据 metrics = simulation_result["metrics"] result = SimulationResult( expression=expression, time_consuming=time_consuming, formatted_time=format_time(time_consuming), alpha_id=simulation_result["alpha_id"], status="success", description="/", simulation_timestamp=time.strftime("%Y-%m-%d %H:%M:%S"), metrics=metrics # 直接存储原始metrics数据 ) print(f"✓ 因子模拟成功: {expression}") print(f" 耗时: {format_time(time_consuming)},Alpha ID: {simulation_result['alpha_id']}") # 打印关键指标 self._print_success_metrics(metrics) else: # 模拟失败的结果(API返回的错误) result = SimulationResult( expression=expression, time_consuming=time_consuming, formatted_time=format_time(time_consuming), alpha_id="/", status="error", description=simulation_result["message"], simulation_timestamp=time.strftime("%Y-%m-%d %H:%M:%S"), metrics=None ) print(f"✗ 因子模拟失败: {expression}") print(f" 耗时: {format_time(time_consuming)},错误: {simulation_result['message']}") except Exception as e: # 其他异常情况 alpha_end_time = time.time() time_consuming = alpha_end_time - alpha_start_time result = SimulationResult( expression=expression, time_consuming=time_consuming, formatted_time=format_time(time_consuming), alpha_id="/", status="failed", description=str(e), simulation_timestamp=time.strftime("%Y-%m-%d %H:%M:%S"), metrics=None ) print(f"✗ 因子模拟异常: {expression}") print(f" 耗时: {format_time(time_consuming)},异常: {str(e)}") return result """打印成功因子的关键指标""" def _print_success_metrics(self, metrics: Dict[str, Any]): # 添加空值检查 if not metrics: print(" 无指标数据") return print(" 关键指标 (训练集):") # 从原始metrics数据中提取训练集指标 train_data = metrics.get('train', {}) or {} key_metrics = [ ('夏普比率', train_data.get('sharpe')), ('年化收益', train_data.get('returns')), ('最大回撤', train_data.get('drawdown')), ('换手率', train_data.get('turnover')), ('适应度', train_data.get('fitness')), ('PNL', train_data.get('pnl')), ] for chinese_name, value in key_metrics: if value is not None: if isinstance(value, float): value = f"{value:.4f}" print(f" {chinese_name}: {value}") # 衡量风险调整后的收益 # 年化收益率 # 显示样本外测试的夏普比率(如果存在) # 最大亏损幅度 test_data = metrics.get('test', {}) or {} # 交易频率 if test_data.get('sharpe') is not None: # 策略适应度得分 print(f" 样本外夏普比率: {test_data.get('sharpe'):.4f}") # 净盈亏 """模拟一批Alpha因子(3个一组)""" def simulate_alpha_batch(self, alpha_batch: List[str], batch_number: int) -> List[SimulationResult]: print(f"\n{'=' * 60}") # 只打印存在的指标 print(f"开始第 {batch_number} 批因子模拟 (共 {len(alpha_batch)} 个因子)") # 格式化浮点数显示 print(f"因子列表: {alpha_batch}") print(f"{'=' * 60}") batch_start_time = time.time() batch_results = [] # 检查是否存在测试集夏普比率 # 创建API客户端实例(每个线程独立的客户端) api = WorldQuantBrainSimulate(self.credentials_file) try: if api.login(): # 使用线程池执行3个因子的模拟 with ThreadPoolExecutor(max_workers=3) as executor: # 提交所有任务 future_to_alpha = { executor.submit(self.simulate_single_alpha, api, alpha): alpha for alpha in alpha_batch } # 等待所有任务完成 for future in as_completed(future_to_alpha): alpha = future_to_alpha[future] try: result = future.result() batch_results.append(result) except Exception as e: print(f"因子 {alpha} 执行异常: {e}") except Exception as e: print(f"第 {batch_number} 批模拟过程中出错: {e}") finally: api.close() batch_end_time = time.time() batch_total_time = batch_end_time - batch_start_time print(f"\n第 {batch_number} 批模拟完成!") print(f"本批总耗时: {format_time(batch_total_time)}") print(f"{'=' * 60}") return batch_results """运行批量模拟""" def run_simulation(self, alpha_list: List[str], batch_size: int = 3) -> List[SimulationResult]: print("开始Alpha因子批量模拟...") total_start_time = time.time() # 将因子列表分成每批3个 batches = [alpha_list[i:i + batch_size] for i in range(0, len(alpha_list), batch_size)] all_results = [] for i, batch in enumerate(batches, 1): # 模拟当前批次 batch_results = self.simulate_alpha_batch(batch, i) all_results.extend(batch_results) # 如果不是最后一批,则等待3-5秒 if i < len(batches): sleep_time = uniform(3, 5) print(f"\n等待 {sleep_time:.2f} 秒后开始下一批...") time.sleep(sleep_time) total_end_time = time.time() total_time = total_end_time - total_start_time # 输出最终结果汇总 self.print_summary(all_results, total_time) # 保存结果到文件 save_results_to_file(all_results) return all_results """打印结果汇总""" def print_summary(self, results: List[SimulationResult], total_time: float): print(f"\n{'=' * 60}") print("模拟结果汇总") print(f"{'=' * 60}") success_count = sum(1 for r in results if r.status == 'success') error_count = sum(1 for r in results if r.status == 'error') failed_count = sum(1 for r in results if r.status == 'failed') print(f"总模拟因子数: {len(results)}") print(f"成功: {success_count} 个") print(f"模拟错误: {error_count} 个") print(f"执行异常: {failed_count} 个") print(f"总耗时: {format_time(total_time)}") print(f"{'=' * 60}") success_expression_list = [] for i, result in enumerate(results, 1): status_icon = "✓" if result.status == 'success' else "✗" if result.status == 'success': success_expression_list.append(result.expression) line_parts = [ f"{i}. {status_icon} {result.expression}", f"状态: {result.status}", f"耗时: {result.formatted_time}" ] if result.alpha_id != '/': line_parts.append(f"Alpha ID: {result.alpha_id}") if result.status != 'success': line_parts.append(f"原因: {result.description}") print("\t".join(line_parts)) save_success_alpha(success_expression_list)