25. 机器学习在曲面构建中的应用:神经网络拟合曲面、高斯过程回归、深度学习模型
说实话,传统插值方法用了这么多年,确实够用。但做量化时间久了你会发现——市场数据太脏了。报价缺失、买卖价差不对称、异常点频发,传统方法处理起来很吃力。这时候,机器学习就派上用场了。
我个人习惯把机器学习方法看作「带正则化的智能插值器」。它们不仅能拟合曲面,还能告诉你哪里数据不可靠、哪里需要平滑。今天咱们就聊聊三种主流方案:神经网络、高斯过程、深度学习。
25.1 神经网络拟合曲面:从MLP到残差网络
先说说最直接的方法——用神经网络直接学习隐含波动率曲面。输入是行权价、剩余期限,输出就是波动率。听起来简单,但坑不少。
我记得第一次用MLP做曲面拟合时,模型在训练集上表现完美,一上测试集就崩了。后来发现是激活函数选错了。ReLU在边界处会产生「死区」,导致远价外期权区域完全拟合不了。
下面是一个简单的MLP实现,注意看输入特征的处理:
import torch
import torch.nn as nn
class IVSurfaceMLP(nn.Module):
def __init__(self, hidden_dim=128):
super().__init__()
# 输入:moneyness, time_to_maturity, 可选:delta, vega
self.net = nn.Sequential(
nn.Linear(3, hidden_dim),
nn.SiLU(), # Swish激活
nn.Linear(hidden_dim, hidden_dim),
nn.SiLU(),
nn.Linear(hidden_dim, hidden_dim),
nn.SiLU(),
nn.Linear(hidden_dim, 1) # 输出隐含波动率
)
# 残差连接:我习惯加一个跳跃连接
self.skip = nn.Linear(3, hidden_dim)
def forward(self, x):
out = self.net(x)
skip = self.skip(x)
return out + skip # 残差连接防止梯度消失
25.2 高斯过程回归:自带置信区间的曲面
神经网络虽然强大,但它有个致命问题——你不知道它什么时候在「瞎猜」。高斯过程回归(GPR)就不一样了,它天生自带不确定性估计。
说白了,GPR 不仅告诉你波动率是多少,还告诉你这个估计有多可靠。这在期权做市里太重要了。你想想看,如果某个区域数据稀疏,GPR 给出的置信区间会自然变宽,提醒你「这里别太自信」。
我曾经用 GPR 处理过一只冷门股票的波动率曲面。传统插值在远月合约上完全跑偏,但 GPR 因为能自动调整核函数的长度尺度,反而给出了合理的平滑结果。
核心代码其实不复杂:
from sklearn.gaussian_process import GaussianProcessRegressor
from sklearn.gaussian_process.kernels import RBF, WhiteKernel, ConstantKernel
# 构建核函数:趋势项 + 噪声项
kernel = ConstantKernel(1.0) * RBF(length_scale=[0.5, 0.3]) + WhiteKernel(noise_level=0.1)
gpr = GaussianProcessRegressor(
kernel=kernel,
alpha=1e-6, # 数值稳定性
normalize_y=True,
n_restarts_optimizer=10 # 多次优化避免局部最优
)
# X: [moneyness, time_to_maturity]
# y: 隐含波动率
gpr.fit(X_train, y_train)
# 预测并获取置信区间
y_pred, y_std = gpr.predict(X_test, return_std=True)
25.3 深度学习模型:LSTM与Transformer的尝试
说到深度学习,很多人第一反应是「杀鸡用牛刀」。但如果你做的是高频做市或者跨资产曲面预测,传统方法确实不够用。
我试过用 LSTM 建模波动率曲面的时序演化。输入是过去 20 个交易日的曲面快照,输出是下一个交易日的曲面。效果嘛……说实话,比简单的时间序列模型好,但提升有限。
真正让我眼前一亮的是 Transformer。它的自注意力机制能自动捕捉不同行权价、不同期限之间的长程依赖关系。比如,远月平值期权的波动率变化,往往会影响到近月深度价外期权——这种跨区域的相关性,传统模型很难刻画。
下面是一个简化版的 Transformer 曲面预测器:
import torch.nn.functional as F
class SurfaceTransformer(nn.Module):
def __init__(self, d_model=64, nhead=4, num_layers=3):
super().__init__()
# 将曲面展平为序列:每个点是一个 token
self.pos_encoding = nn.Parameter(torch.randn(1, 100, d_model))
encoder_layer = nn.TransformerEncoderLayer(
d_model=d_model, nhead=nhead, dim_feedforward=256, dropout=0.1
)
self.transformer = nn.TransformerEncoder(encoder_layer, num_layers=num_layers)
self.output_proj = nn.Linear(d_model, 1)
def forward(self, x):
# x: [batch, seq_len, features]
x = x + self.pos_encoding[:, :x.size(1), :]
x = self.transformer(x)
return self.output_proj(x).squeeze(-1)
25.4 三种方法的对比与选择
说了这么多,到底该用哪个?我整理了一个对比表,方便你根据实际情况选:
| 方法 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 神经网络 (MLP) | 训练快、泛化好、可处理大数据 | 缺乏不确定性估计、需要调参 | 数据量大、需要快速推理 |
| 高斯过程回归 | 自带置信区间、小样本表现好 | 计算慢、不适合大数据 | 数据稀疏、需要可靠性评估 |
| 深度学习 (Transformer) | 捕捉时序依赖、跨区域关联 | 训练成本高、容易过拟合 | 曲面预测、高频场景 |
嗯,机器学习这块内容确实不少。但核心就一句话:不要为了用机器学习而用机器学习。先搞清楚你的业务需求是什么,再选合适的方法。数据量大、要求速度快,就上神经网络;数据稀疏、需要知道可靠性,就用高斯过程;要做预测、捕捉复杂关系,再考虑深度学习。
我曾经犯过一个错误——在只有 200 个数据点的情况下硬上 Transformer,结果过拟合得一塌糊涂。后来换成 GPR,效果立竿见影。所以啊,选方法之前,先看看你的数据长什么样。