From b66a6c59584e0a39e549a54b464f8934c2fa05dc Mon Sep 17 00:00:00 2001 From: claude_dev Date: Sun, 2 Aug 2026 21:48:33 +0800 Subject: [PATCH] =?UTF-8?q?fix(ashare=5Fengine):=20load=5Fdata=20=E7=9B=B4?= =?UTF-8?q?=E6=9F=A5=20dbbardata=20=E7=BB=95=20vnpy=20peewee(=E6=B2=BB=20C?= =?UTF-8?q?TA=20=E6=AD=BB=E7=AE=97)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 根因:vnpy 父类 load_data 走 get_database().load_bar_data()(peewee ORM), get_database init 时 create_indexes 对 26G dbbardata 库 → spawn 建 26G 索引 CPU 死算 1:27+ / web 并发 database is locked(2026-08-02 根因, vnpy_db 指向 v2 大库 2cb2ab0 后触发)。load_data 读 0 bars → 回测空/卡。 修复:load_data 统一直查 dbbardata(原仅 5m/15m 走 _load_intraday_data, 扩展到日线 d),绕 vnpy peewee get_database。sqlite3 busy_timeout=30s 防并发锁。d → BarData(interval=Interval.DAILY)。 验证:日线 600519 2024H1 load_data 0.1s bars=116(was database locked 5.2s/0 bars) interval=DAILY;run_backtesting 5.6s(was 死算 1:27+); 000001 compute_metrics 完成 daily_df=(116,25) benchmark=116(5图metrics恢复)。 --- sanguo_backtest/ashare_engine.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/sanguo_backtest/ashare_engine.py b/sanguo_backtest/ashare_engine.py index 7a700d7..17f92eb 100644 --- a/sanguo_backtest/ashare_engine.py +++ b/sanguo_backtest/ashare_engine.py @@ -183,7 +183,7 @@ class AShareBacktestingEngine(BacktestingEngine): ) def load_data(self) -> None: - """覆写父类:支持 5m/15m 周期(绕过 vnpy Interval enum 限制)。 + """覆写父类:直查 dbbardata(绕 vnpy peewee get_database 对大库锁/死算 + enum 限制)。 vnpy Interval enum 只有 MINUTE('1m')/HOUR('1h')/DAILY('d') 等,不认 '5m'/'15m'。 父类 load_data 调 ``INTERVAL_DELTA_MAP[self.interval]`` 和 @@ -194,9 +194,8 @@ class AShareBacktestingEngine(BacktestingEngine): 时,直接 sqlite 查 dbbardata 表,把每行转 BarData(interval=Interval.MINUTE), 绕过 vnpy database_manager 的 enum 限制;其余周期(d/1m 等)走 vnpy 原生路径。 """ - if self.raw_interval not in ("5m", "15m"): - super().load_data() - return + # 统一直查 dbbardata(绕 vnpy peewee get_database 对大库 create_indexes 锁/死算; + # 2026-08-02 根因:vnpy_db 指向 v2 26G 库后 super().load_data 建 26G 索引 spawn 死算 1:27+) self._load_intraday_data() def _load_intraday_data(self) -> None: @@ -228,7 +227,8 @@ class AShareBacktestingEngine(BacktestingEngine): symbol, exchange_str = self.vt_symbol.split(".") # peewee DateTimeField 存的是 ISO 字符串;start/end 用 datetime 比较即可 # (SQLite 会把参数转成可比较的字符串形式)。 - conn = sqlite3.connect(db_path) + conn = sqlite3.connect(db_path, timeout=30) + conn.execute("PRAGMA busy_timeout = 30000") try: cur = conn.execute( "SELECT datetime, volume, turnover, open_interest, " @@ -257,7 +257,7 @@ class AShareBacktestingEngine(BacktestingEngine): symbol=symbol, exchange=exchange, datetime=dt, - interval=Interval.MINUTE, # 5m/15m 不在 enum,统一标 MINUTE + interval=(Interval.DAILY if self.raw_interval == "d" else Interval.MINUTE), volume=float(vol or 0), turnover=float(turnover or 0), open_interest=float(oi or 0),