From d6162d1928c19fa392520a3235bfefdc27690c29 Mon Sep 17 00:00:00 2001 From: claude_dev Date: Fri, 17 Jul 2026 17:06:57 +0800 Subject: [PATCH] =?UTF-8?q?fix(factor):=20=E5=9B=A0=E5=AD=90=E4=BB=BB?= =?UTF-8?q?=E5=8A=A1=E6=8C=81=E4=B9=85=E5=8C=96=E5=88=B0=20backtest=5Fresu?= =?UTF-8?q?lts.db(type=3Dfactor)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 此前 FactorReport 无 id,_on_done 不存 DB → 因子任务不进任务列表、重启丢失 (用户:历史任务列表看不到因子分析)。_on_done 现对 FactorReport 调 _persist_factor 存 backtest_stats(type=factor, strategy=因子名, symbol=标的池, statistics={ic_summary, report_paths})。FactorReport 加 symbols/start/end 字段。 --- sanguo_factor/analyzer.py | 8 +++++++- sanguo_orchestrator/runner.py | 22 ++++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/sanguo_factor/analyzer.py b/sanguo_factor/analyzer.py index 7f2320d..36f2268 100644 --- a/sanguo_factor/analyzer.py +++ b/sanguo_factor/analyzer.py @@ -54,6 +54,9 @@ class FactorReport: output_dir: str ic_summary: dict = field(default_factory=dict) report_paths: dict = field(default_factory=dict) + symbols: list[str] = field(default_factory=list) + start: str = "" + end: str = "" def run_factor_analysis( @@ -371,5 +374,8 @@ def run_factor_analysis( factor_names=factor_names, output_dir=output_dir, ic_summary=ic_summary, - report_paths=report_paths + report_paths=report_paths, + symbols=symbols, + start=start, + end=end, ) diff --git a/sanguo_orchestrator/runner.py b/sanguo_orchestrator/runner.py index 973faf2..14b8dbb 100644 --- a/sanguo_orchestrator/runner.py +++ b/sanguo_orchestrator/runner.py @@ -144,8 +144,30 @@ class Orchestrator: # load_result(result.id). FactorReport (no .id) falls back to None until S2. task.complete(result_id=getattr(result, "id", None)) task.raw_result = result # S2: keep in-memory result (FactorReport) for ic-summary/report + # S2: persist factor result so it appears in task list & survives restart + if getattr(result, "ic_summary", None) and getattr(result, "factor_names", None) is not None: + self._persist_factor(task_id, result) await self._notify_stage(task_id, "完成") + def _persist_factor(self, task_id: str, fr) -> None: + """Persist FactorReport to backtest_results.db (type=factor) so it shows + in task list and survives API restart. Mirrors cta/optimize persistence.""" + from sanguo_backtest.result_store import save_result, BacktestResult + try: + save_result(BacktestResult( + task_id=task_id, type="factor", status="done", + strategy=",".join(fr.factor_names), + symbol=",".join(getattr(fr, "symbols", []) or []), + params={"factor_names": fr.factor_names}, + start=getattr(fr, "start", "") or "", + end=getattr(fr, "end", "") or "", + statistics={"ic_summary": fr.ic_summary, "report_paths": fr.report_paths}, + equity_curve=None, trades=None, + ), db_path=self.db_path) + except Exception as e: + import logging + logging.getLogger(__name__).warning("persist factor %s failed: %s", task_id, e) + def get_status(self, task_id: str) -> TaskState | None: """Get task status by ID""" return self.pool.get_status(task_id)