test: v9多周期消融(否决) — 周线趋势过滤与回调买入逻辑冲突(weekly_up=True胜率60.9% vs False 78.4%),证据存档不并入

This commit is contained in:
hmo
2026-07-29 02:58:53 +08:00
parent 59ea259f29
commit effed7d7cd
+76 -2
View File
@@ -242,6 +242,17 @@ STRATEGIES.update({
entry_overrides={"vol_ratio_min": 0.9, "vol_ratio_max": 2.0, "sector_slope_max": 1.0,
"hl_only": True, "rsi_delta_min": 6},
exit_overrides={"tp_pct": None, "exit_mode": "swing", "sl_atr": 1.5, "max_hold_days": 40, "reentry_days": 10}),
# H组: 多周期维度
"v9.0": _v40_branch("v9.0", "周线趋势过滤",
"v7.1 + 周线收盘须站上周线MA10(中期趋势向上才买)",
"L2多周期维度消融:日线级的回调买点若周线趋势已坏则是下跌中继;周线MA10上方=中期趋势完好",
entry_overrides={"vol_ratio_min": 0.9, "vol_ratio_max": 2.0, "sector_slope_max": 1.0,
"hl_only": True, "rsi_delta_min": 6, "weekly_up": True}),
"v9.1": _v40_branch("v9.1", "周线多头排列",
"v7.1 + 周线MA10>MA20(周线多头排列,更严的中期趋势要求)",
"比weekly_up更严的变体:不仅要求价在线上,还要求周线均线本身多头排列",
entry_overrides={"vol_ratio_min": 0.9, "vol_ratio_max": 2.0, "sector_slope_max": 1.0,
"hl_only": True, "rsi_delta_min": 6, "weekly_aligned": True}),
})
@@ -396,6 +407,61 @@ def flow_ctx(code, date, bars_dates, idx):
return f
# ══════════════════════════════════════════════════════
# 多周期(周线)上下文
# ══════════════════════════════════════════════════════
_WEEKLY_CTX = {} # code -> sorted [(date, close, ma10w, ma20w)]
def prepare_weekly_context(start_date, end_date):
"""加载 stock_weekly,计算每周 MA10/MA20"""
global _WEEKLY_CTX
_WEEKLY_CTX = {}
conn = sqlite3.connect(DB_PATH)
try:
rows = conn.execute("""
SELECT code, date, close FROM stock_weekly
WHERE date >= ? AND date <= ? ORDER BY code, date
""", (start_date, end_date)).fetchall()
except sqlite3.OperationalError:
rows = []
finally:
conn.close()
from collections import defaultdict
by_code = defaultdict(list)
for code, d, close in rows:
by_code[code].append((d, close))
for code, series in by_code.items():
closes = [c for _, c in series]
out = []
for i, (d, close) in enumerate(series):
ma10 = sum(closes[max(0, i-9):i+1]) / len(closes[max(0, i-9):i+1]) if i >= 4 else None
ma20 = sum(closes[max(0, i-19):i+1]) / len(closes[max(0, i-19):i+1]) if i >= 10 else None
out.append((d, close, ma10, ma20))
_WEEKLY_CTX[code] = out
def weekly_ctx(code, date):
"""取 date 之前最近一根完整周线的状态"""
series = _WEEKLY_CTX.get(code)
if not series:
return {}
last = None
for d, close, ma10, ma20 in series:
if d < date: # 只用已完成的周线(不含当周)
last = (d, close, ma10, ma20)
else:
break
if not last:
return {}
_, close, ma10, ma20 = last
f = {}
if ma10:
f['weekly_up'] = close > ma10 # 周线站上MA10 = 中期趋势向上
f['weekly_dist'] = round((close - ma10) / ma10 * 100, 2)
if ma10 and ma20:
f['weekly_aligned'] = ma10 > ma20 # 周线多头排列
return f
# ══════════════════════════════════════════════════════
# 入场过滤器
# ══════════════════════════════════════════════════════
@@ -437,6 +503,10 @@ def pass_filters(factors, filters):
if not chk('flow_pct', filters.get('flow_pct_min'), filters.get('flow_pct_max')): return False
if not chk('flow_5d', filters.get('flow_5d_min'), filters.get('flow_5d_max')): return False
if not chk('flow_delta', filters.get('flow_delta_min'), filters.get('flow_delta_max')): return False
# 多周期
if filters.get('weekly_up') and factors.get('weekly_up') is not True: return False
if filters.get('weekly_aligned') and factors.get('weekly_aligned') is not True: return False
if not chk('weekly_dist', filters.get('weekly_dist_min'), filters.get('weekly_dist_max')): return False
return True
@@ -500,6 +570,7 @@ def run_backtest(strategy_version, start_date, end_date, capital=1000000, save=T
prepare_market_context(fetch_start, end_date)
prepare_sector_context(start_date, end_date)
prepare_flow_context(fetch_start, end_date)
prepare_weekly_context(fetch_start, end_date)
conn = sqlite3.connect(DB_PATH)
stocks = conn.execute("""
@@ -552,6 +623,8 @@ def run_backtest(strategy_version, start_date, end_date, capital=1000000, save=T
# 资金面因子
fl = flow_ctx(code, date, None, i)
factors.update(fl)
# 周线因子
factors.update(weekly_ctx(code, date))
if pass_filters(factors, filters):
atr_val = last.get('atr') or 0
@@ -866,9 +939,10 @@ def calc_summary(trades, capital):
# ══════════════════════════════════════════════════════
ANALYZE_FACTORS = ['rsi', 'adx', 'macd_hist', 'roc', 'atr_pct', 'dist_ma20', 'vol_ratio',
'ma20_slope', 'macd_hist_delta', 'rsi_delta', 'mkt_slope', 'mkt_roc',
'sector_change', 'sector_rank_pct', 'sector_slope', 'flow_pct', 'flow_5d', 'flow_delta', 'score']
'sector_change', 'sector_rank_pct', 'sector_slope', 'flow_pct', 'flow_5d', 'flow_delta',
'weekly_dist', 'score']
BOOL_FACTORS = ['trend_aligned', 'hh_structure', 'hl_structure', 'adx_rising',
'mkt_above_ma20', 'near_high_20d', 'sector_above_ma20']
'mkt_above_ma20', 'near_high_20d', 'sector_above_ma20', 'weekly_up', 'weekly_aligned']
def analyze_trades(strategy_version):
conn = sqlite3.connect(DB_PATH)