test: v9多周期消融(否决) — 周线趋势过滤与回调买入逻辑冲突(weekly_up=True胜率60.9% vs False 78.4%),证据存档不并入
This commit is contained in:
+76
-2
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user