perf: prepare_sector_context ADX计算O(N^2)修复——calc_trend_strength移到板块外层只算一次(296板块x490天卡死), _get_external_factors补conn连接

This commit is contained in:
hmo
2026-08-11 23:40:42 +08:00
parent 052d8218da
commit dba24a2bde
+22 -19
View File
@@ -681,36 +681,39 @@ def _get_external_factors(code, dt):
return _EXTERNAL_CACHE[key]
result = {}
try:
import sqlite3
_conn = sqlite3.connect(DB_PATH)
# 行业动量 sec_ret20sector_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_total<?", (_mcap,)).fetchone()[0]
_tot = conn.execute("SELECT COUNT(*) FROM stock_fundamentals WHERE mcap_total>0").fetchone()[0]
_t = _conn.execute("SELECT COUNT(*) FROM stock_fundamentals WHERE mcap_total>0 AND mcap_total<?", (_mcap,)).fetchone()[0]
_tot = _conn.execute("SELECT COUNT(*) FROM stock_fundamentals WHERE mcap_total>0").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 pe<?", (_pe,)).fetchone()[0]
_tot = conn.execute("SELECT COUNT(*) FROM stock_fundamentals WHERE pe>0").fetchone()[0]
_t = _conn.execute("SELECT COUNT(*) FROM stock_fundamentals WHERE pe>0 AND pe<?", (_pe,)).fetchone()[0]
_tot = _conn.execute("SELECT COUNT(*) FROM stock_fundamentals WHERE pe>0").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,
}