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)