fix: 研究Tab近1月/6月/1年数据空——list_strategies加切窗口fallback,从最长区间trades按时间窗口切重算summary(无需单独回测)

This commit is contained in:
hmo
2026-08-12 12:56:52 +08:00
parent 7b9b9c4244
commit 2c8aa5ca5d
+42 -4
View File
@@ -2088,6 +2088,41 @@ def list_strategies(period_tag=None):
ON sr.id = latest.max_id
ORDER BY sr.version
""").fetchall()
# ── 2026-08-121m/6m/1y 无独立回测记录时,从最长区间 trades 切时间窗口重算 summary ──
# 研究 Tab 期间筛选按 period_tag 查 DB,但 v_weak/v_oversold 只有 2y/5y/10y——
# 选近1月/6月/1年时查不到记录显示空。改为从最长区间 trades 切窗口算,无需单独回测。
PERIOD_SLICE_DAYS = {'1m': 30, '6m': 185, '1y': 365}
sliced_summaries = {} # version -> (summary, trades_count)
if period_tag in PERIOD_SLICE_DAYS:
days = PERIOD_SLICE_DAYS[period_tag]
have_period = {r['version'] for r in rows}
from datetime import datetime as _dt, timedelta as _td
for v in list(STRATEGIES.keys()) + [x for x in STRATEGY_DESCRIPTIONS.keys() if x not in STRATEGIES]:
if v in have_period:
continue # 已有该 period 记录,不用切
row = conn.execute(
"SELECT results_json FROM strategy_research WHERE version=? ORDER BY "
"CASE COALESCE(period_tag,'2y') WHEN '10y' THEN 3 WHEN '5y' THEN 2 ELSE 1 END DESC, id DESC LIMIT 1",
(v,)).fetchone()
if not row:
continue
try:
res = json.loads(row[0])
except Exception:
continue
trades = res.get('trades', [])
if not trades:
continue
max_date = max(t.get('entry_date', '') for t in trades)
try:
cutoff = (_dt.strptime(max_date, '%Y-%m-%d') - _td(days=days)).strftime('%Y-%m-%d')
except Exception:
continue
sliced = [t for t in trades if t.get('entry_date', '') >= cutoff]
if not sliced:
continue
sliced_summaries[v] = (calc_summary(sliced, 1000000), len(sliced), period_tag)
conn.close()
out = []
for r in rows:
@@ -2104,22 +2139,25 @@ def list_strategies(period_tag=None):
existing = {(d['version'], d['market']) for d in out}
for v, s in STRATEGIES.items():
if (v, 'all') not in existing and not any(d['version'] == v for d in out):
# 2026-08-121m/6m/1y 优先用切窗口算的 summary(无独立记录时),否则空
_ss, _tc, _pt = sliced_summaries.get(v, ({}, 0, None))
out.append({
'version': v, 'name': s['name'], 'summary': s['summary'],
'hypothesis': s['hypothesis'], 'parent': s.get('parent'),
'config_json': json.dumps(s['config'], ensure_ascii=False),
'summary_stats': {}, 'insights': [], 'created_at': s.get('created'),
'market': 'all',
'summary_stats': _ss, 'insights': [], 'created_at': s.get('created'),
'market': 'all', 'period_tag': _pt or period_tag, 'trades_count': _tc,
})
# 2026-08-11:补充仅在 STRATEGY_DESCRIPTIONS 的策略(如 v_oversold 预测扫描策略,无回测 config)
for v, s in STRATEGY_DESCRIPTIONS.items():
if v not in STRATEGIES and not any(d['version'] == v for d in out):
_ss, _tc, _pt = sliced_summaries.get(v, ({}, 0, None))
out.append({
'version': v, 'name': s.get('title', v), 'summary': s.get('algorithm', ''),
'hypothesis': s.get('rationale', ''), 'parent': None,
'config_json': '{}',
'summary_stats': {}, 'insights': [], 'created_at': None,
'market': 'all',
'summary_stats': _ss, 'insights': [], 'created_at': None,
'market': 'all', 'period_tag': _pt or period_tag, 'trades_count': _tc,
})
out.sort(key=lambda x: (x['version'], x.get('market', 'all')))
# 2026-08-11:标记当前实盘/新策略(研究 Tab 拆分当前/历史区域)