diff --git a/sanguo_portfolio/providers/sanguo_fundamentals.py b/sanguo_portfolio/providers/sanguo_fundamentals.py index 7e87b62..927f5be 100644 --- a/sanguo_portfolio/providers/sanguo_fundamentals.py +++ b/sanguo_portfolio/providers/sanguo_fundamentals.py @@ -163,15 +163,11 @@ class SanguoMiniQmtProvider(MiniQMTProvider): # type: ignore[misc] qmt_stocks = [self._normalize_security_code(s) for s in stocks] try: if self.auto_download: - try: - # 实证 signature: download_financial_data(stock_list, table_list=[]) - # trading hours Income/CashFlow 常超时,主拿 PershareIndex/Balance/Capital - xt.download_financial_data( - qmt_stocks, - ["PershareIndex", "Balance", "Capital"], - ) - except Exception as exc: - logger.debug("download_financial_data 失败(继续读缓存): %s", exc) + # download_financial_data 阻塞无超时,休市/服务不响应会卡死整个回测; + # 包 threading 超时,超时则跳过读缓存(数据可能不全但回测不卡死) + self._download_financial_safe( + qmt_stocks, ["PershareIndex", "Balance", "Capital"] + ) fin_data = xt.get_financial_data(qmt_stocks) except Exception as exc: logger.warning("get_financial_data 失败,返空表: %s", exc) @@ -193,6 +189,35 @@ class SanguoMiniQmtProvider(MiniQMTProvider): # type: ignore[misc] df = df.set_index("code", drop=False) return df + def _download_financial_safe( + self, qmt_stocks: List[str], tables: List[str], timeout: float = 120.0 + ) -> None: + """download_financial_data 包 threading 超时。 + + xtdata.download_financial_data 阻塞且无超时参数,休市/服务不响应时卡死 + 整个回测。用线程 + join(timeout):超时则放弃(读缓存),daemon 线程随进程退出清理。 + """ + import threading + xt = self._ensure_xtdata() + err: List[str] = [] + + def _worker() -> None: + try: + xt.download_financial_data(qmt_stocks, tables) + except Exception as exc: + err.append(str(exc)) + + t = threading.Thread(target=_worker, daemon=True) + t.start() + t.join(timeout) + if t.is_alive(): + logger.warning( + "download_financial_data 超时 %.0fs (%d 只),跳过读缓存", + timeout, len(qmt_stocks), + ) + elif err: + logger.debug("download_financial_data 失败(继续读缓存): %s", err[0]) + # ------------------------ 内部组装 ------------------------ def _build_row( self,