/~learn/s/a9783c30
> 背景:当前回测评估函数使用指数衰减时间加权(decay=0.92),在全量历史上优化参数。此方法在 regime switch(牛熊切换)时会系统性失效——如果近年是熊市,筛选出的策略会偏向保守,导致牛市踏空。
---
Strategy.calculate_exponential_decay_annual_returns(decay=0.92) 按自然年划分数据,最近年份权重为 1,每早一年权重乘以 0.92。
权重分布(decay=0.92):
今年(2026): 1.000
去年(2025): 0.920
前年(2024): 0.846
3年前(2023): 0.779
5年前(2021): 0.659
10年前(2016): 0.434
失效场景:如果 2023-2025 是熊市,这三年合计权重占主导,筛选出的策略会高度适应熊市特征(低仓位频率、高避险偏好)。2026 年一旦牛市来临,这些特征全部变为劣势。
核心矛盾:指数衰减的假设是"近期规律更可能延续",但在 regime switch 时,近期规律恰恰是最不可靠的。
---
方案优先级:2 > 1 > 3 > 4 > 5
原则:先止血(加 floor + benchmark),再治本(walk-forward)
| # | 方案 | 难度 | 效果 | 心理收益 | 状态 |
| --- | ------ | :---: | :---: | :---: | :---: |
| 1 | 回测评价分段化(按 regime 分报告) | 低 | 中 | 理解策略在什么环境下表现好 | 待实现 |
| 2 | 加入 Buy & Hold Benchmark | 低 | 高 | 知道择时的边际价值 | 待实现 |
| 3 | 仓位区间可见性 + 子策略特征 | 低 | 高 | 消除踏空焦虑 | ✅ 已实现 |
| 4 | Walk-Forward 滚动窗口 | 中 | 高 | 验证策略在不同区段的稳定性 | 待实现 |
| 5 | Regime Detection 元策略 | 高 | 高 | 牛市用牛市策略、熊市用熊市策略 | 远期 |
---
在全量回测报告之外,额外按市场状态切片输出子报告:
═══════════════════════════════════════
策略: RSIAndMAStrategy 分段回测报告
═══════════════════════════════════════
📈 牛市区间 (如: 2019-01 ~ 2021-02)
年化收益: 15.2% | 最大回撤: -12.3%
胜率: 62% | 交易次数: 45
📉 熊市区间 (如: 2021-03 ~ 2024-01)
年化收益: -3.1% | 最大回撤: -8.5%
胜率: 48% | 交易次数: 52
↔️ 震荡区间 (如: 2024-02 ~ 2026-06)
年化收益: 5.7% | 最大回撤: -6.2%
胜率: 55% | 交易次数: 38
close > MA200 = 牛市)
约 30 行(在 evaluate_strategy_metrics 中增加分段输出)。
---
当前策略池没有"满仓不动"作为参照系。你无法回答:择时策略比 buy & hold 到底好在哪里?好多少?
在策略池中注册一个 BuyAndHoldStrategy:
class BuyAndHoldStrategy(Strategy):
"""基准策略:始终满仓,不做任何择时"""
def generate_signals(self):
self.df['position'] = 1.0
self.df['signal'] = 0
推送报告中增加一行对比:
─────────────────────────────────────────────
📊 策略组合 vs 基准
─────────────────────────────────────────────
择时加权仓位: 0.40% 基准(buy&hold): 100.00%
择时年化收益: 3.2% 基准年化收益: 12.5%
择时最大回撤: -4.1% 基准最大回撤: -18.3%
择时夏普比率: 0.85 基准夏普比率: 0.62
─────────────────────────────────────────────
当你的择时仓位=0.4% 而大盘涨了 5% 时,你会看到:
这个对比让你清晰地看到:你付出的"踏空代价"换来了"低回撤"。这不是系统错了,这是你做的 trade-off。
---
你的择时策略会把仓位压到 ≈0%。当市场上涨时,你完全没参与,且看不到策略还要多久才会切换回来,产生焦虑。
之前考虑过 Core-Satellite(设仓位下限,永远不空仓),但这在超级大熊市中会一直亏损,违背了趋势跟踪的本质。正确的方式不是强行改变仓位,而是让你看到转换周期。
推送中现在会自动显示每个品种的:
📊 仓位区间分布与转换周期
历史仓位分布:
极低仓位(<20%): 49.4% ██████████░░░░░░░░░░ 平均39.5天 最长46天
高仓位(>80%): 39.4% ███████░░░░░░░░░░░░░ 平均31.5天 最长32天
低→高仓位转换周期:
极低(<20%) → 高(>80%): 平均 40.5 天, 最长 42 天
🔍 当前状态: 极低仓位(<20%), 已连续 12 天
⏳ 历史平均还需 28 天恢复至高仓位(最长 42 天)
以及每个子策略的:
📋 子策略交易特征:
RSIAndMAStrategy-open-8-63 [趋势策略]: 平均持仓23天, 资占45.2%, 年交易8次, 胜率62.3%
MomentumBounceStrategy [反转策略]: 平均持仓5天, 资占12.1%, 年交易42次, 胜率55.1%
---
不在全量历史上优化参数,而是用滚动窗口模拟"随时间推移不断重新优化"的过程:
训练窗口[2016-2019] → 验证窗口[2020]
训练窗口[2017-2020] → 验证窗口[2021]
训练窗口[2018-2021] → 验证窗口[2022]
训练窗口[2019-2022] → 验证窗口[2023]
训练窗口[2020-2023] → 验证窗口[2024]
训练窗口[2021-2024] → 验证窗口[2025]
↓
汇总所有验证窗口的表现 → 这才是策略的"真实预期表现"
class WalkForwardOptimizer:
def __init__(self, strategy_class, param_grid, train_years=4, step_years=1):
self.train_years = train_years # 训练窗口长度(年)
self.step_years = step_years # 步长(年)
def run(self, df):
all_results = []
start_year = df.index.year.min()
end_year = df.index.year.max()
for test_start in range(start_year + self.train_years, end_year + 1, self.step_years):
train_end = test_start - 1
train_start = train_end - self.train_years + 1
# 训练窗口
df_train = df[(df.index.year >= train_start) & (df.index.year <= train_end)]
# 验证窗口
df_test = df[df.index.year == test_start]
# 在训练窗口上做网格搜索 → 找最优参数
best_params = self.grid_search(df_train)
# 用最优参数在验证窗口上跑一次
test_result = self.evaluate(df_test, best_params)
all_results.append({
'train_window': f'{train_start}-{train_end}',
'test_year': test_start,
'best_params': best_params,
'test_return': test_result,
})
return all_results
Walk-Forward 跑完后,看两个东西:
---
┌─→ 如果判断为牛市 → 使用牛市策略池(高仓位、低避险)
市场状态检测 ────┤
└─→ 如果判断为熊市 → 使用熊市策略池(低仓位、高避险)
def detect_regime(df):
"""用最简单的均线关系判断牛熊"""
ma_60 = df['close'].rolling(60).mean().iloc[-1]
ma_200 = df['close'].rolling(200).mean().iloc[-1]
current_price = df['close'].iloc[-1]
if current_price > ma_60 > ma_200:
return 'bull' # 牛市:价格在均线之上,短期均线在长期之上
elif current_price < ma_60 < ma_200:
return 'bear' # 熊市
else:
return 'range' # 震荡
| 市场状态 | 择时仓位上限 | Core仓位 | 说明 |
| --------- | :----------: | :------: | ------ |
| 牛市 | 100% | 50% | 充分参与 |
| 震荡 | 70% | 40% | 保留部分现金 |
| 熊市 | 40% | 30% | 防御为主 |
---
第一优先级(已实现):
✅ 方案3: 仓位区间可见性 + 子策略交易特征摘要
第二优先级(本周或下周,小改代码):
□ 方案2: 推送中增加 buy & hold benchmark 对比行
□ 方案1: 评估报告中按牛市/熊市/震荡分段输出
□ 降低 eval 的 decay 系数: 0.92 → 0.98(让历史年份权重更均匀)
第三优先级(下周+,中改代码):
□ 方案4: 实现 Walk-Forward 滚动窗口优化器
□ 对比 Walk-Forward 结果与全量回测结果的差距
远期探索:
□ 方案5: Regime Detection 元策略
---
| 现有系统组件 | 本方案的影响 |
| ------------ | ------------ |
StrategyOptimizer.py | 新增 WalkForwardOptimizer 类 |
Strategy.evaluate_strategy_metrics() | 增加分段输出 |
show_marker.py / allocation_utils.py | 增加 CORE_POSITION 参数和 benchmark 对比 |
消息推送.txt | 输出格式增加 benchmark 对比行 |
---
03-约束自己.md:修正 Position Floor 建议,改为仓位区间可见性方案