diff --git a/static/index.html b/static/index.html index d284ab1c..1cfadec2 100644 --- a/static/index.html +++ b/static/index.html @@ -2029,6 +2029,7 @@ function renderStrategyTable(strategies) { }; let html = '
| 版本 | 名称 | ' + + '仓位 | ' + '综合 | ' + '普适 | ' + '总收益 | ' + @@ -2051,6 +2052,7 @@ function renderStrategyTable(strategies) { html += '
|---|---|---|---|---|---|
| ' + s.version + (isCurrent ? ' 当前' : '') + ((s.market && s.market !== 'all') ? ' ' + (s.market === 'hk' ? '港' : 'A') + '' : '') + ' | ' + '' + (s.name || '') + (smallSample ? ' ⚠️' : '') + ' | ' + + '' + (st.sizing_slots ? st.sizing_slots + '仓' : '10仓') + ' | ' + cell('composite', s._composite, v => v, 'font-bold text-amber-300') + cell('universality_score', (st.universality || {}).score, v => v + '/' + (st.universality || {}).months + '月') + cell('total_return_pct', pf.total_return_pct, v => v + '%', 'font-bold ' + retCls + ' ' + hl(pf.total_return_pct, best.total_return_pct)) + diff --git a/strategy_lab.py b/strategy_lab.py index 6ccb0029..e7c4f12c 100644 --- a/strategy_lab.py +++ b/strategy_lab.py @@ -323,6 +323,21 @@ def get_strategy(version): return STRATEGIES[version] +# 各策略的最优仓位模型(仓位扫描实证,2026-07-29) +# 波段/结构出场适合大仓少股,固定出场适合小仓多股 +STRATEGY_SIZING = { + 'v7.1': 4, # 固定15%出场,4仓+74.6%最优(10仓+59.8%) + 'v7.2': 3, # 分批止盈,3仓+60.7% + 'v8.0': 3, # 结构持有,3仓+53.2% + 'v8.1': 3, # 波段MA10,3仓+102.9% + 'v8.3': 3, # 波段40天,3仓+62.1% + 'v9.2': 5, # 周线破位,5仓+47.6% + 'v6.1': 5, # 板块不追高,5仓+47.3% + 'v11.0': 3, # 枢轴波段,3仓+116.4% + 'v11.1': 3, # 枢轴强压/弱撑,3仓+55.8% +} + + # ══════════════════════════════════════════════════════ # 大盘 / 行业上下文 # ══════════════════════════════════════════════════════ @@ -706,6 +721,11 @@ def run_backtest(strategy_version, start_date, end_date, capital=1000000, save=T factors.update(weekly_ctx(code, date)) if pass_filters(factors, filters): + # ── 次日开盘价入场(杜绝"信号日收盘买"的未来幻觉)── + if i + 1 >= len(bars): + i += step + continue + ep = bars[i+1].get('open') or close atr_val = last.get('atr') or 0 if exit_cfg.get('use_pivot_sr'): # 实盘口径:强压止盈 + 弱支撑止损(枢轴点体系) @@ -850,14 +870,14 @@ def run_backtest(strategy_version, start_date, end_date, capital=1000000, save=T for l in legs: total_ret *= (1 + l) pnl = (total_ret - 1) * 100 - exit_price = close * total_ret + exit_price = ep * total_ret hold_days = len(future) if future else 0 elif exit_cfg.get('exit_mode') == 'swing_pivot': # ── 波段·枢轴版:破弱支撑先出,收复弱压且创新高再进 ── reentry_window = exit_cfg.get('reentry_days', 10) legs = [] in_pos = True - entry_p = close + entry_p = ep stop_cur = stop wait = 0 exit_reason = 'keep' @@ -891,7 +911,7 @@ def run_backtest(strategy_version, start_date, end_date, capital=1000000, save=T for l in legs: total_ret *= (1 + l) pnl = (total_ret - 1) * 100 - exit_price = close * total_ret + exit_price = ep * total_ret hold_days = len(future) if future else 0 else: exit_price = exit_reason = None @@ -916,7 +936,7 @@ def run_backtest(strategy_version, start_date, end_date, capital=1000000, save=T if exit_price is None: exit_price = future[-1].get('close') if future else close exit_reason, hold_days = 'keep', len(future) - pnl = (exit_price - close) / close * 100 if close > 0 else 0 + pnl = (exit_price - ep) / ep * 100 if ep > 0 else 0 trades.append({ 'code': code, 'name': name, 'entry_date': date, @@ -936,9 +956,11 @@ def run_backtest(strategy_version, start_date, end_date, capital=1000000, save=T i += step summary = calc_summary(trades, capital) - # 组合级资产模拟(统一标准:等额仓位、最多10仓) + # 组合级资产模拟:用该策略自己的最优仓位模型(波段策略大仓少股,固定出场小仓多股) if summary: - summary['portfolio'] = portfolio_sim(trades, capital, 10) + slots = STRATEGY_SIZING.get(strategy_version, 10) + summary['portfolio'] = portfolio_sim(trades, capital, slots) + summary['sizing_slots'] = slots result = { 'strategy': strat['version'], 'strategy_name': strat['name'],