第四章:曲面特征工程——从曲面提取期限结构、偏斜度、曲率、波动率水平

好,咱们进入正题。前面几章我们把波动率曲面的数据结构、插值方法都捋了一遍。现在的问题是——曲面本身是个三维对象,你不能直接把它扔进模型里。你得把它拆解成可量化的特征。

说白了,就是给曲面做“体检”。测它的身高、体重、体态、曲线。这些特征,就是我们要提取的:期限结构、偏斜度、曲率、波动率水平

核心观点:曲面特征工程,是把高维曲面降维成低维特征向量的过程。降维不是目的,保留交易逻辑才是。

4.1 波动率水平:曲面的“基准线”

波动率水平,就是整个曲面的“平均海拔”。我习惯用ATM(平值)波动率来代表。为什么?因为ATM期权流动性最好,报价最可靠。

具体做法:

  • 取每个期限的ATM波动率
  • 按成交量加权平均,得到整体水平
  • 或者直接用最近月ATM波动率作为快照
# 提取波动率水平特征
def extract_vol_level(surface, atm_strikes):
    """
    surface: 插值后的波动率曲面 (期限 x 行权价)
    atm_strikes: 每个期限对应的ATM行权价
    """
    levels = []
    for i, strike in enumerate(atm_strikes):
        # 取该期限下ATM附近的波动率
        atm_vol = surface[i, strike]
        levels.append(atm_vol)
    
    # 加权平均(用持仓量或成交量加权)
    weighted_level = np.average(levels, weights=open_interests)
    return weighted_level

个人经验:我在做跨资产波动率套利时,发现直接用简单平均会出问题。短期限波动率波动大,长期限波动率反应慢。我后来改用指数加权移动平均(EWMA),效果好了不少。

4.2 期限结构:曲面的“坡度”

期限结构,就是波动率随到期时间变化的曲线。它反映了市场对未来波动率的预期。

我一般提取三个特征:

  1. 短期斜率:1周 vs 1月
  2. 中期斜率:1月 vs 3月
  3. 长期斜率:3月 vs 1年

为什么要分三段?因为不同期限的驱动因素不同。短期受事件驱动,中期受宏观影响,长期更多是均值回归。

# 提取期限结构特征
def extract_term_structure(surface, tenors):
    """
    tenors: 期限列表,如 [7, 30, 90, 365] 天
    """
    # 取每个期限的ATM波动率
    atm_vols = [surface[i, atm_strike] for i in range(len(tenors))]
    
    # 计算斜率
    short_slope = atm_vols[1] - atm_vols[0]  # 1月 - 1周
    mid_slope = atm_vols[2] - atm_vols[1]    # 3月 - 1月
    long_slope = atm_vols[3] - atm_vols[2]   # 1年 - 3月
    
    return {
        'short_slope': short_slope,
        'mid_slope': mid_slope,
        'long_slope': long_slope
    }

避坑指南:我曾经在2018年做波动率交易时,只用了整体斜率,结果亏了一笔。后来复盘发现,短期和长期斜率方向相反,整体斜率接近零,但实际交易机会很大。所以,一定要分段提取。

4.3 偏斜度:曲面的“不对称性”

偏斜度,就是虚值看跌和虚值看涨的波动率差异。它反映了市场对尾部风险的定价。

我常用的提取方法:

  • 25-delta 偏斜:25-delta put vol 减去 25-delta call vol
  • 10-delta 偏斜:10-delta put vol 减去 10-delta call vol
  • 偏斜斜率:不同delta之间的变化率

你想想看,偏斜度越大,说明市场越恐慌。2020年3月,标普500的25-delta偏斜一度飙到15个点以上,平时也就3-5个点。

# 提取偏斜度特征
def extract_skew(surface, deltas=[0.25, 0.10]):
    """
    deltas: 要提取的delta水平
    """
    skew_features = {}
    for delta in deltas:
        put_vol = surface.get_vol_by_delta(-delta)  # 虚值看跌
        call_vol = surface.get_vol_by_delta(delta)  # 虚值看涨
        skew = put_vol - call_vol
        skew_features[f'{int(delta*100)}d_skew'] = skew
    
    # 计算偏斜斜率
    skew_features['skew_slope'] = (
        skew_features['10d_skew'] - skew_features['25d_skew']
    ) / 0.15  # delta差为0.15
    
    return skew_features

关键点:偏斜度不是越大越好。要结合历史分位数来看。我习惯把当前偏斜度除以过去60天的滚动标准差,得到“偏斜Z-score”,这样更客观。

4.4 曲率:曲面的“弯曲程度”

曲率,就是偏斜度的变化率。它反映了波动率微笑的“微笑程度”。

提取方法:

  1. 取三个点:25-delta put、ATM、25-delta call
  2. 用二次函数拟合:vol = a * (delta - 0.5)^2 + b * (delta - 0.5) + c
  3. 二次项系数 a 就是曲率

曲率大,说明市场对极端行情的定价很贵。我记得2022年俄乌冲突期间,原油期权的曲率翻了3倍。

# 提取曲率特征
def extract_curvature(surface, delta_points=[-0.25, 0, 0.25]):
    """
    用二次拟合提取曲率
    """
    vols = [surface.get_vol_by_delta(d) for d in delta_points]
    deltas = np.array(delta_points)
    
    # 二次拟合
    coeffs = np.polyfit(deltas, vols, 2)
    curvature = coeffs[0]  # 二次项系数
    
    # 归一化:除以ATM波动率
    atm_vol = surface.get_vol_by_delta(0)
    normalized_curvature = curvature / atm_vol
    
    return {
        'curvature': curvature,
        'normalized_curvature': normalized_curvature
    }

我的习惯:曲率这个特征,我一般会做差分处理。因为曲率本身有很强的自相关性,直接使用会导致模型过拟合。差分后的曲率变化量,预测能力更强。

4.5 特征矩阵构建:把一切串起来

好,现在我们把所有特征整合起来。每个时间点,我们得到一个特征向量:

特征类别 具体特征 数量
波动率水平 ATM波动率、加权平均波动率 2
期限结构 短期斜率、中期斜率、长期斜率 3
偏斜度 25-delta偏斜、10-delta偏斜、偏斜斜率 3
曲率 曲率、归一化曲率 2

一共10个特征。当然,你可以根据具体需求增加。比如加入不同期限的偏斜度,或者加入曲面局部曲率。

# 构建完整特征矩阵
def build_feature_matrix(surface_history):
    """
    surface_history: 历史曲面数据,shape = (时间, 期限, 行权价)
    """
    features = []
    for t in range(len(surface_history)):
        surface = surface_history[t]
        
        # 提取各类特征
        level = extract_vol_level(surface, atm_strikes)
        term = extract_term_structure(surface, tenors)
        skew = extract_skew(surface)
        curv = extract_curvature(surface)
        
        # 合并特征
        feature_vector = [
            level,
            term['short_slope'], term['mid_slope'], term['long_slope'],
            skew['25d_skew'], skew['10d_skew'], skew['skew_slope'],
            curv['curvature'], curv['normalized_curvature']
        ]
        features.append(feature_vector)
    
    return np.array(features)

重要提醒:特征提取后,一定要做标准化。不同特征的量纲差异很大——波动率水平可能是20%,偏斜度可能是5%,曲率可能是0.1。不标准化,模型会偏向量纲大的特征。

4.6 知识体系总览

下面这张图,把曲面特征工程的整个流程串起来了。从原始曲面到最终特征矩阵,每一步都有对应的处理逻辑。

曲面特征工程知识体系 原始波动率曲面 波动率水平 ATM波动率 期限结构 短期/中期/长期斜率 偏斜度 25d/10d偏斜 曲率 二次拟合系数 加权平均 分段差分 Z-score标准化 归一化处理 特征矩阵 (10维特征向量) → 波动率预测 | 套利策略 | 风险对冲

嗯,这张图把整个流程讲清楚了。从原始曲面出发,经过四个维度的特征提取,再经过处理,最终汇聚成特征矩阵。这个矩阵,就是后续所有模型的基础输入。

总结一下:曲面特征工程不是简单的数学变换,而是对市场微观结构的量化表达。波动率水平告诉你市场有多“贵”,期限结构告诉你市场预期如何变化,偏斜度告诉你市场在害怕什么,曲率告诉你市场对极端事件的定价有多贵。这四个维度,缺一不可。

我个人习惯,在提取完特征后,会做一个相关性分析。看看哪些特征冗余,哪些特征互补。比如,偏斜度和曲率往往高度相关,可以考虑合并或降维。但这是后话了,咱们后面章节再细聊。


公众号:蓝海数据掘金营,微信deep3321