第二十四章:冲击成本模型评估:模型比较、预测误差、稳健性检验

模型建好了,参数也调了,然后呢?

说实话,很多人在这一步就停了。觉得模型跑通了,回测曲线漂亮,就万事大吉。但我个人的经验告诉我——模型评估才是真正见真章的地方。你想想看,一个模型在样本内表现再好,到了实盘里被打脸,那才是真疼。

24.1 为什么要做模型评估?

冲击成本模型,说白了就是预测「我这一单下去,市场会怎么动」。但预测这件事,天生就有误差。我们需要搞清楚三件事:

  • 哪个模型更准?——模型比较
  • 误差有多大?——预测误差分析
  • 换个时间段还灵不灵?——稳健性检验

我在项目中遇到过这样的情况:一个模型在去年表现极好,今年突然就崩了。后来一查,是因为市场微观结构变了。嗯,这就是稳健性没做好的典型。

24.2 模型比较:谁才是真英雄?

常见的冲击成本模型就那么几种:线性模型、平方根模型、I-Star模型、以及一些机器学习模型。怎么比?不能光看R²。

24.2.1 比较框架

我个人习惯用三个维度来比较:

  1. 拟合优度:模型对历史数据的解释能力
  2. 预测精度:样本外预测的误差大小
  3. 经济意义:模型参数是否符合直觉

举个例子,我曾经见过一个模型,R²高达0.95,但参数是负的——交易量越大冲击成本越小?这明显违背常识。这种模型,再好看也不能用。

24.2.2 常用比较指标

指标 含义 适用场景
解释方差比例 模型整体拟合度
MAE 平均绝对误差 误差的直观大小
RMSE 均方根误差 对大误差更敏感
MAPE 平均绝对百分比误差 相对误差比较
我的小技巧: 别只看一个指标。R²高不代表预测准,MAE小不代表稳健。我一般会同时看3-4个指标,综合判断。

24.3 预测误差分析:误差从哪里来?

模型预测值和实际值之间的差距,就是误差。但误差不是随机噪声,它往往有规律可循。

24.3.1 误差分解

我把误差拆成三部分:

  • 偏差(Bias):系统性的高估或低估
  • 方差(Variance):预测值的波动程度
  • 噪声(Noise):不可解释的随机部分

为什么会这样?说白了,偏差大说明模型结构有问题,方差大说明模型对数据太敏感。我见过一个团队,他们的模型偏差一直为正——永远低估冲击成本。后来发现是忘了考虑订单方向的影响。

24.3.2 误差诊断工具

我常用的几个工具:

# 残差分析示例
import numpy as np
import matplotlib.pyplot as plt

# 假设 y_true 和 y_pred 是真实值和预测值
residuals = y_true - y_pred

# 1. 残差 vs 预测值散点图
plt.scatter(y_pred, residuals)
plt.axhline(y=0, color='r', linestyle='--')
plt.xlabel('预测值')
plt.ylabel('残差')
plt.title('残差诊断图')

# 2. 残差自相关检验
from statsmodels.stats.stattools import durbin_watson
dw = durbin_watson(residuals)
print(f'Durbin-Watson统计量: {dw:.3f}')
# 接近2说明无自相关,远离2说明有问题
避坑指南: 我曾经犯过一个错误——只看整体误差,没分时段看。结果发现模型在开盘和收盘时段误差巨大,但被其他时段平均掉了。后来我养成了习惯:按交易时段、按订单规模、按股票流动性分别看误差。

24.4 稳健性检验:换个环境还灵吗?

稳健性检验,说白了就是「折腾」你的模型。看看它在不同条件下还能不能打。

24.4.1 时间维度稳健性

我最常用的方法:

  • 滚动窗口检验:用过去6个月的数据训练,预测下1个月,然后滚动
  • 不同市场状态:牛市、熊市、震荡市分别测试
  • 极端事件测试:比如2020年3月的流动性危机

我记得有一次,一个模型在正常市场下表现完美,但一遇到2020年3月的熔断行情,预测误差直接翻了5倍。嗯,这就是没做极端事件测试的后果。

24.4.2 参数敏感性分析

模型参数稍微变一点,结果会不会大变?如果会,那这个模型就不可靠。

# 参数敏感性分析示例
def sensitivity_analysis(model, param_name, param_range):
    """
    对模型参数进行敏感性分析
    param_name: 参数名称
    param_range: 参数取值范围
    """
    results = []
    for param_value in param_range:
        # 修改模型参数
        model.set_params(**{param_name: param_value})
        # 计算预测误差
        error = evaluate_model(model)
        results.append((param_value, error))
    return results

# 分析衰减因子 lambda 的敏感性
lambda_range = np.linspace(0.5, 0.99, 20)
sensitivity = sensitivity_analysis(model, 'lambda', lambda_range)

核心观点: 一个稳健的模型,参数微调时预测误差应该变化平缓。如果某个参数稍微一动,误差就剧烈波动,那这个模型在实盘中很可能翻车。

24.5 知识体系总览

下面这张图,是我对冲击成本模型评估的完整理解框架:

冲击成本模型评估框架 模型比较 预测误差分析 稳健性检验 比较维度 • 拟合优度(R²) • 预测精度(MAE/RMSE) • 经济意义检验 • 多指标综合判断 误差分解 • 偏差(系统性误差) • 方差(预测波动) • 噪声(随机部分) • 残差诊断工具 检验方法 • 滚动窗口检验 • 不同市场状态 • 极端事件测试 • 参数敏感性分析 模型评估报告 模型选择 + 误差特征 + 稳健性结论 三者缺一不可,共同构成完整的模型评估体系

24.6 实战建议

说了这么多,最后给几条实在的建议:

  1. 别迷信一个指标:R²高不代表一切,我见过R² 0.98的模型在实盘里亏钱
  2. 分场景评估:大单和小单的冲击成本特征完全不同,要分开测
  3. 留足样本外数据:我一般留30%的数据做样本外测试,绝不偷看
  4. 定期重新评估:市场在变,模型也会老化。建议每季度做一次全面评估
最后说一句: 模型评估不是一次性工作,而是持续的过程。我每跑完一轮实盘交易,都会把实际冲击成本记录下来,回头再跟模型预测对比。这样积累个半年,你对自己模型的「脾气」就摸透了。