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, }