From dba24a2bde2e5b2ff6fca8decddf2ab3f9c475c9 Mon Sep 17 00:00:00 2001 From: hmo Date: Tue, 11 Aug 2026 23:40:42 +0800 Subject: [PATCH] =?UTF-8?q?perf:=20prepare=5Fsector=5Fcontext=20ADX?= =?UTF-8?q?=E8=AE=A1=E7=AE=97O(N^2)=E4=BF=AE=E5=A4=8D=E2=80=94=E2=80=94cal?= =?UTF-8?q?c=5Ftrend=5Fstrength=E7=A7=BB=E5=88=B0=E6=9D=BF=E5=9D=97?= =?UTF-8?q?=E5=A4=96=E5=B1=82=E5=8F=AA=E7=AE=97=E4=B8=80=E6=AC=A1(296?= =?UTF-8?q?=E6=9D=BF=E5=9D=97x490=E5=A4=A9=E5=8D=A1=E6=AD=BB),=20=5Fget=5F?= =?UTF-8?q?external=5Ffactors=E8=A1=A5conn=E8=BF=9E=E6=8E=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- strategy_lab.py | 41 ++++++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/strategy_lab.py b/strategy_lab.py index b52e321c..0cf35511 100644 --- a/strategy_lab.py +++ b/strategy_lab.py @@ -681,36 +681,39 @@ def _get_external_factors(code, dt): return _EXTERNAL_CACHE[key] result = {} try: + import sqlite3 + _conn = sqlite3.connect(DB_PATH) # 行业动量 sec_ret20(sector_index_daily 20日涨跌) - _srow = conn.execute("SELECT sector_name FROM stock_sectors WHERE code=? LIMIT 1", (code,)).fetchone() + _srow = _conn.execute("SELECT sector_name FROM stock_sectors WHERE code=? LIMIT 1", (code,)).fetchone() if _srow and _srow[0]: _sector = _srow[0] - _prev = conn.execute( + _prev = _conn.execute( "SELECT close FROM sector_index_daily WHERE sector=? AND date<=? ORDER BY date DESC LIMIT 21", (_sector, dt)).fetchall() if len(_prev) >= 20 and _prev[-1][0] and _prev[-1][0] > 0: result['sec_ret20'] = round((_prev[0][0] - _prev[-1][0]) / _prev[-1][0] * 100, 2) # 新闻 3 日计数 news3 - _nrow = conn.execute( + _nrow = _conn.execute( "SELECT COUNT(*) FROM stock_news WHERE code=? AND date>? AND date<=?", (code, _days_ago(dt, 3), dt)).fetchone() if _nrow: result['news3'] = _nrow[0] # 基本面分位 mcap_q/pe_q - _frow = conn.execute( + _frow = _conn.execute( "SELECT mcap_total, pe FROM stock_fundamentals WHERE code=?", (code,)).fetchone() if _frow and _frow[0]: _mcap = _frow[0] - _t = conn.execute("SELECT COUNT(*) FROM stock_fundamentals WHERE mcap_total>0 AND mcap_total0").fetchone()[0] + _t = _conn.execute("SELECT COUNT(*) FROM stock_fundamentals WHERE mcap_total>0 AND mcap_total0").fetchone()[0] if _tot: result['mcap_q'] = round(_t / _tot, 3) if _frow and _frow[1]: _pe = _frow[1] - _t = conn.execute("SELECT COUNT(*) FROM stock_fundamentals WHERE pe>0 AND pe0").fetchone()[0] + _t = _conn.execute("SELECT COUNT(*) FROM stock_fundamentals WHERE pe>0 AND pe0").fetchone()[0] if _tot: result['pe_q'] = round(_t / _tot, 3) + _conn.close() except Exception: pass _EXTERNAL_CACHE[key] = result @@ -744,6 +747,16 @@ def prepare_sector_context(start_date, end_date): sec_hl[sec].append((d, row[4], row[5])) for sec, series in by_sector.items(): closes = [c for _, c, _ in series] + # 2026-08-11 性能修复:ADX 全序列只算一次(原代码内层每天重算=O(N²),296板块×490天卡死) + from backtest_framework import calc_trend_strength + _hl = sec_hl.get(sec, []) + _av = None + if len(_hl) >= 20: + _hs = [x[1] for x in _hl] + _ls = [x[2] for x in _hl] + _cs = [c for _, c, _ in series] + if len(_cs) == len(_hl): + _av = calc_trend_strength(_hs, _ls, _cs, 14) for i, (d, close, chg) in enumerate(series): above = slope = None if i >= 19: @@ -753,17 +766,7 @@ def prepare_sector_context(start_date, end_date): ma20_5 = sum(closes[i-24:i-4]) / 20 if ma20_5 > 0: slope = round((ma20 - ma20_5) / ma20_5 * 100, 3) - _adx = None - _hl = sec_hl.get(sec, []) - if len(_hl) >= 20 and i >= 14: - from backtest_framework import calc_trend_strength - _hs = [x[1] for x in _hl] - _ls = [x[2] for x in _hl] - _cs = [c for _, c, _ in series] - if len(_cs) == len(_hl): - _av = calc_trend_strength(_hs, _ls, _cs, 14) - if i < len(_av): - _adx = _av[i] + _adx = _av[i] if (_av is not None and i < len(_av)) else None _SECTOR_CTX.setdefault(d, {})[sec] = { 'change': chg, 'above_ma20': above, 'slope': slope, 'adx': _adx, }