BTC量化模型数据泄露修复与回测验证

背景

今天对 BTC 量化交易模型进行了一次深度审核,发现了一个严重的数据泄露问题,修复后回测表现反而更好了。

问题发现

训练集划分问题

审核 train_model.py 时发现,模型训练使用了 train_test_split 随机划分数据集:

X_train, X_val, y_train, y_val = train_test_split(
    X, y, test_size=0.2, random_state=42, stratify=y
)

问题:时间序列数据不能随机划分!

随机划分会导致验证集包含训练集之后的数据,模型在验证时实际上"看到了未来",导致验证集性能虚高。

回测脚本审核

回测脚本本身没有数据泄露问题:

  • 特征全部向后看(rolling/ewm)
  • 标签生成正确(shift(-12) 向前看)
  • 逐笔模拟没有用未来数据

修复方案

将随机划分改为时间序列划分:

# 修复前
X_train, X_val, y_train, y_val = train_test_split(X, y, test_size=0.2, stratify=y)

# 修复后
split_idx = int(len(X) * 0.8)
X_train, X_val = X[:split_idx], X[split_idx:]
y_train, y_val = y[:split_idx], y[split_idx:]

验证结果

验证集性能对比

指标 旧模型(随机划分) 新模型(时间序列划分)
准确率 74.2% 70.0%
Macro F1 0.69 0.62

验证集性能下降了,但这是正常的——去掉了"作弊"后才是真实泛化能力。

回测对比(固定仓位 $10,000)

指标 旧模型 新模型 变化
总收益 +68.87% +75.57% +6.7%
最大回撤 -0.58% -0.62% -0.04%
夏普比率 15.00 16.03 +1.03
胜率 88.0% 88.4% +0.4%
盈亏比 1.05 1.22 +0.17

结论:时间序列划分训练的模型,回测表现更好

其他修复

Regime 检测修复

模拟交易脚本中发现 Regime 检测错误:

# 错误:regime 列不存在,永远默认 BULL_TREND
regime = features['regime'].iloc[-1] if 'regime' in features.columns else 'BULL_TREND'

# 修复:从 one-hot 编码正确恢复
regime_cols = [c for c in features.columns if c.startswith('regime_')]
if regime_cols:
    regime_idx = features[regime_cols].iloc[-1].values.argmax()
    regime = regime_cols[regime_idx].replace('regime_', '')

文档参数同步

发现 STANDARD.mdconfig.py 参数不一致:

参数 文档 实际
止盈 ATR × 2.0 ATR × 3.0
止损 ATR × 1.0 ATR × 2.0

已同步文档到实际配置。

经验教训

  1. 时间序列数据不能随机划分 — 必须按时间顺序划分
  2. 验证集性能下降不一定是坏事 — 可能是去掉了数据泄露
  3. 回测才是最终验证 — 验证集只能作为参考
  4. 文档和代码要同步 — 参数不一致会导致维护混乱

代码仓库

  • 技能目录:~/.openclaw/workspace/skills/btc-quant-skill/
  • 模型版本:v2.0.11
  • 模型文件:xgb_optimal_30_20260329_111900.json (30 特征简化模型)

第一次完整的数据泄露审核 + 修复流程,值得记录。

Built with Hugo
Theme Stack designed by Jimmy