import asyncio import logging import sys from pathlib import Path import yaml from universe_selector import UniverseEngine # 定位项目根目录(main.py 所在目录),保证配置/输出路径与执行位置无关 PROJECT_ROOT = Path(__file__).resolve().parent LOG_FILE = PROJECT_ROOT / "use_engine.log" logging.basicConfig( level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', handlers=[ logging.StreamHandler(sys.stdout), logging.FileHandler(LOG_FILE, encoding='utf-8'), ], ) def load_config(path: Path | None = None) -> dict: cfg_path = path or PROJECT_ROOT / "config" / "config.yaml" with open(cfg_path, 'r', encoding='utf-8') as f: return yaml.safe_load(f) def resolve_output_path(raw: str) -> Path: """支持相对路径(相对项目根)和绝对路径。""" p = Path(raw) if p.is_absolute(): return p return PROJECT_ROOT / p async def main(): logging.info("=== 启动 Universe Selection Engine ===") config = load_config() # 输出路径统一解析为绝对路径,避免 cwd 影响 if 'output' in config and 'save_path' in config['output']: config['output']['save_path'] = str(resolve_output_path(config['output']['save_path'])) engine = UniverseEngine(config) results = await engine.run_pipeline() if results: print("\n" + "=" * 50) print(f"运行时间: {results['timestamp']}") print(f"趋势标的数: {len(results['trend_universe'])}") print(f"均值回归标的数: {len(results['mr_universe'])}") print(f"套利配对数: {len(results['starb_pairs'])}") print("=" * 50 + "\n") if __name__ == "__main__": if sys.platform == 'win32': asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy()) asyncio.run(main())