15. 曲面质量评估:拟合误差分析、交叉验证、经济合理性检验
曲面建好了,参数也调了,然后呢?
说实话,我见过太多人把曲面一画出来就觉得完事了。其实真正的活儿才刚刚开始。你想想看,一个波动率曲面,如果只是数学上拟合得好,但经济意义上说不通,那它就是一张废纸。
这一章,我们就聊聊怎么给曲面「体检」。我把它分成三个维度:拟合误差、交叉验证、经济合理性。缺一不可。
15.1 拟合误差分析:别被R²骗了
很多人喜欢盯着R²看,觉得0.99就是好模型。嗯,这里要注意——R²高不代表曲面好用。
我在项目中遇到过这样的情况:一个SVI模型在ATM附近拟合得完美,但两端的尾部完全跑偏。R²是0.98,可实际交易中,深度虚值期权的定价偏差能到5%以上。
我常用的误差指标有这几个:
| 指标 | 公式 | 说明 |
|---|---|---|
| MAE | mean(|σ_model - σ_market|) | 平均绝对误差,直观 |
| RMSE | sqrt(mean((σ_model - σ_market)²)) | 对大偏差更敏感 |
| MAPE | mean(|σ_model - σ_market| / σ_market) | 百分比误差,适合比较 |
| Bias | mean(σ_model - σ_market) | 系统性偏差,正负号重要 |
我个人习惯把误差按期限和行权价画成热力图。这样一眼就能看出哪里出了问题。
import numpy as np
import matplotlib.pyplot as plt
def plot_error_heatmap(strikes, maturities, errors):
"""
绘制拟合误差热力图
strikes: 行权价数组
maturities: 期限数组
errors: 二维误差矩阵
"""
fig, ax = plt.subplots(figsize=(10, 6))
im = ax.imshow(errors, cmap='RdYlBu_r', aspect='auto')
ax.set_xticks(range(len(strikes)))
ax.set_yticks(range(len(maturities)))
ax.set_xticklabels([f'{s:.0f}' for s in strikes])
ax.set_yticklabels([f'{m:.2f}' for m in maturities])
plt.colorbar(im, label='拟合误差 (bps)')
plt.title('波动率曲面拟合误差热力图')
plt.xlabel('行权价')
plt.ylabel('期限 (年)')
plt.show()
# 示例:假设我们有5个行权价和4个期限
strikes = np.array([3800, 4000, 4200, 4400, 4600])
maturities = np.array([0.1, 0.3, 0.6, 1.0])
# 模拟误差数据
errors = np.random.randn(4, 5) * 10 # 单位:bps
plot_error_heatmap(strikes, maturities, errors)
15.2 交叉验证:别让模型「死记硬背」
说白了,交叉验证就是看看你的模型有没有「死记硬背」市场数据。
我见过一个团队,他们的曲面在样本内误差只有2个bps,但一到样本外就崩到50个bps。这就是典型的过拟合。
我常用的交叉验证方法有三种:
- 时间序列交叉验证:用前N天的数据拟合,预测第N+1天的曲面
- 行权价留一法:每次去掉一个行权价,用剩下的数据拟合,预测被去掉的那个
- 随机子集验证:随机抽取80%的数据拟合,在剩下的20%上测试
我个人最推荐时间序列交叉验证。为什么?因为交易中我们永远是在用历史数据预测未来。这个场景最贴近实战。
def time_series_cv(data, fit_func, window=20):
"""
时间序列交叉验证
data: 按时间排序的波动率数据列表
fit_func: 拟合函数,输入训练数据,返回模型
"""
errors = []
for i in range(window, len(data)):
train = data[i-window:i]
test = data[i:i+1]
model = fit_func(train)
pred = model.predict(test)
error = np.abs(pred - test['vol'])
errors.append(error)
return np.mean(errors), np.std(errors)
# 使用示例
mean_err, std_err = time_series_cv(vol_data, fit_svi_model)
print(f'平均预测误差: {mean_err:.2f} bps')
print(f'误差标准差: {std_err:.2f} bps')
15.3 经济合理性检验:曲面要「讲人话」
这是最容易被忽略的一步,但也是最重要的一步。
你想想看,一个波动率曲面,如果它的斜率是负的、曲率是正的,但市场明明在恐慌中——那这个曲面就是错的。数学上再完美也没用。
我总结了几条经济合理性的「红线」:
- 无套利条件:曲面不能存在日历套利或蝶式套利机会
- 期限结构单调性:短期波动率通常高于长期(除非市场极度平静)
- 微笑对称性:正常情况下,虚值看跌和虚值看涨的波动率应该大致对称
- 尾部行为:深度虚值期权的波动率不应该出现异常跳跃
我记得有一次,一个同事的曲面在某个行权价附近出现了「凹陷」。数学上拟合得很好,但经济上完全说不通——那个行权价附近根本没有流动性。后来我们查了一下,是那个交易员报了一个错误的价格。
- 检查所有行权价和期限组合是否存在套利机会
- 对比曲面隐含的远期波动率与历史波动率
- 检查曲面在不同市场状态下的稳定性(涨、跌、震荡)
- 与同类资产或相关市场的波动率曲面做横向对比
15.4 综合评估框架
说了这么多,怎么把这些东西串起来?
我习惯用一个综合评分卡来评估曲面质量。每个维度打分,最后加权平均。
| 评估维度 | 权重 | 评分标准 |
|---|---|---|
| 拟合误差 (MAE) | 30% | <5 bps: 10分, 5-10 bps: 7分, >10 bps: 4分 |
| 交叉验证稳定性 | 25% | 预测误差 <10 bps: 10分, 10-20 bps: 7分, >20 bps: 4分 |
| 无套利条件 | 25% | 完全无套利: 10分, 少量可忽略: 7分, 存在明显套利: 0分 |
| 经济合理性 | 20% | 完全合理: 10分, 基本合理: 7分, 存在疑问: 4分 |
总分低于7分的曲面,我建议重新拟合或者换模型。别舍不得,有时候重新来过比修修补补更快。
15.5 本章小结
曲面质量评估,说白了就是三个字:准、稳、合理。
- 准:拟合误差要小,但不能只看整体,要看局部
- 稳:交叉验证要过,模型不能过拟合
- 合理:经济上要讲得通,不能出现无套利漏洞
这三步走下来,你的曲面才算真正「能用」。别嫌麻烦,我见过太多人因为跳过这一步,在实盘中吃了大亏。