fix: 研究Tab近1月/6月/1年数据空——list_strategies加切窗口fallback,从最长区间trades按时间窗口切重算summary(无需单独回测)
This commit is contained in:
+42
-4
@@ -2088,6 +2088,41 @@ def list_strategies(period_tag=None):
|
||||
ON sr.id = latest.max_id
|
||||
ORDER BY sr.version
|
||||
""").fetchall()
|
||||
|
||||
# ── 2026-08-12:1m/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-12:1m/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 拆分当前/历史区域)
|
||||
|
||||
Reference in New Issue
Block a user