第十四章:波动率曲面套利:静态套利条件、动态套利条件、套利检测与修正

做波动率曲面分析,最刺激也最头疼的事情是什么?

我个人觉得,就是套利检测。

你辛辛苦苦从市场上扒下来一堆期权报价,插值拟合出一个漂漂亮亮的曲面。结果一跑套利检测,满屏的红叉。嗯,这时候你就知道,市场不是教科书,报价里全是坑。

今天我们就来聊聊,怎么把这些坑找出来,再想办法填上。

14.1 什么是波动率曲面套利?

说白了,套利就是「无风险赚钱」的机会。

在波动率曲面上,如果两个期权合约的价格关系不合理,理论上你可以通过买卖组合锁定利润。但现实中,这种机会转瞬即逝。我们做套利检测,更多是为了清洗数据、保证模型输入的质量。

套利分两类:

  • 静态套利:只看当前时刻的截面数据,不依赖时间变化
  • 动态套利:考虑时间维度上的价格演变关系

我在项目中遇到过最典型的情况:某天下午三点,外汇期权市场突然出现一组蝶式价差为负的报价。当时我第一反应是数据错了,但反复确认后发现,确实是市场流动性枯竭导致的畸形报价。这种数据如果不处理,后续的定价模型全得崩。

14.2 静态套利条件

静态套利,你想想看,就是检查同一到期日下,不同行权价的期权价格是否合理。

核心条件有三个:

14.2.1 无蝶式套利条件

这是最基础的。对于三个连续行权价 K₁ < K₂ < K₃,看涨期权的价格必须满足:

C(K₂) ≤ (K₃ - K₂)/(K₃ - K₁) * C(K₁) + (K₂ - K₁)/(K₃ - K₁) * C(K₃)

如果违反了这个条件,就存在蝶式套利机会。

我曾经在整理沪深300ETF期权数据时,发现某天的虚值期权报价居然比平值还贵。这明显不合理——行权价越高,看涨期权应该越便宜才对。后来查出来是交易员手误输错了价格。

14.2.2 无垂直价差套利条件

看涨期权的价格必须随行权价单调递减:

K₁ < K₂  ⇒  C(K₁) ≥ C(K₂)

看跌期权则相反:

K₁ < K₂  ⇒  P(K₁) ≤ P(K₂)

这个条件简单粗暴,但非常有效。我一般会把它作为第一道过滤条件。

14.2.3 凸性条件

波动率曲面在行权价方向上应该是凸的。用数学表达就是二阶导数非负:

∂²σ/∂K² ≥ 0

嗯,这里要注意,实际数据中凸性条件经常被违反,尤其是在深度实值和深度虚值区域。

14.3 动态套利条件

动态套利涉及不同到期日之间的价格关系。说白了,就是检查时间维度上的合理性。

14.3.1 日历价差套利条件

对于相同行权价、不同到期日的看涨期权,到期日越远,价格应该越贵:

T₁ < T₂  ⇒  C(T₁) ≤ C(T₂)

如果违反了这个条件,就可以通过买入远月、卖出近月来套利。

我记得有一次做原油期权分析,发现近月合约因为某个突发事件被炒得比远月还贵。这种时候,日历价差套利条件就被触发了。但要注意,这不一定代表市场错了——可能是市场在定价短期的高波动风险。

14.3.2 无偏预期条件

远期波动率应该等于未来即期波动率的期望值。这个条件在理论上是成立的,但实际中很少严格满足。我一般把它作为参考,而不是硬约束。

14.4 套利检测的实现

讲完理论,我们来看看代码怎么写。

import numpy as np
from scipy.interpolate import CubicSpline

def detect_butterfly_arbitrage(strikes, prices):
    """
    检测蝶式套利
    strikes: 行权价数组
    prices: 对应期权价格数组
    """
    violations = []
    for i in range(1, len(strikes) - 1):
        K1, K2, K3 = strikes[i-1], strikes[i], strikes[i+1]
        C1, C2, C3 = prices[i-1], prices[i], prices[i+1]
        
        # 计算理论价格上限
        w2 = (K3 - K2) / (K3 - K1)
        w1 = (K2 - K1) / (K3 - K1)
        upper_bound = w1 * C1 + w2 * C3
        
        if C2 > upper_bound + 1e-8:  # 加一个小阈值避免数值误差
            violations.append((K2, C2, upper_bound))
    
    return violations

def detect_calendar_arbitrage(maturities, prices):
    """
    检测日历价差套利
    maturities: 到期时间数组
    prices: 对应期权价格数组
    """
    violations = []
    for i in range(len(maturities) - 1):
        if prices[i] > prices[i+1] + 1e-8:
            violations.append((maturities[i], maturities[i+1], 
                             prices[i], prices[i+1]))
    return violations

这段代码看起来简单,但实际用的时候有几个坑:

  • 阈值设置很关键。设太小了全是误报,设太大了漏报严重。我一般用1e-8作为基准,然后根据数据量级调整
  • 插值后的曲面更容易出现套利。因为插值方法本身不保证无套利性质

14.5 套利修正方法

检测出套利之后怎么办?不能直接删数据吧?

我常用的修正方法有几种:

方法 原理 适用场景
价格调整法 将违规价格调整到边界值 轻微违规,数据量少
局部平滑法 用周围数据加权平均替代 孤立异常点
全局优化法 在无套利约束下重新拟合曲面 大面积违规,需要整体修正

我个人最推荐的是全局优化法。虽然计算量大一点,但能保证整个曲面的一致性。

def arbitrage_free_correction(strikes, prices, method='global'):
    """
    无套利修正
    """
    if method == 'global':
        # 使用凸优化方法,在无套利约束下最小化与原始数据的偏差
        from scipy.optimize import minimize
        
        def objective(p):
            return np.sum((p - prices) ** 2)
        
        # 约束条件:凸性 + 单调性
        constraints = []
        for i in range(1, len(strikes) - 1):
            def con_butterfly(p, i=i):
                K1, K2, K3 = strikes[i-1], strikes[i], strikes[i+1]
                w2 = (K3 - K2) / (K3 - K1)
                w1 = (K2 - K1) / (K3 - K1)
                return w1 * p[i-1] + w2 * p[i+1] - p[i]
            constraints.append({'type': 'ineq', 'fun': con_butterfly})
        
        # 单调性约束
        for i in range(len(strikes) - 1):
            def con_mono(p, i=i):
                return p[i] - p[i+1]
            constraints.append({'type': 'ineq', 'fun': con_mono})
        
        result = minimize(objective, prices, constraints=constraints)
        return result.x
    
    elif method == 'local':
        # 局部调整法
        corrected = prices.copy()
        for i in range(1, len(strikes) - 1):
            K1, K2, K3 = strikes[i-1], strikes[i], strikes[i+1]
            w2 = (K3 - K2) / (K3 - K1)
            w1 = (K2 - K1) / (K3 - K1)
            upper = w1 * corrected[i-1] + w2 * corrected[i+1]
            if corrected[i] > upper:
                corrected[i] = upper - 1e-8
        return corrected
注意:全局优化法虽然效果好,但计算成本高。如果你的数据量很大(比如全市场期权数据),建议先用局部调整法快速清洗,再用全局优化做精细修正。

14.6 知识体系总览

下面这张图,是我自己总结的套利检测与修正的完整流程:

波动率曲面套利检测与修正流程 原始期权报价 静态套利检测 蝶式套利 | 垂直价差 | 凸性条件 同一到期日,不同行权价 动态套利检测 日历价差 | 无偏预期条件 不同到期日,相同行权价 套利修正 价格调整法 | 局部平滑法 | 全局优化法 输出:无套利波动率曲面 截面数据 时间序列
实战建议:我一般会先跑静态套利检测,再跑动态套利检测。因为静态检测计算量小,能快速过滤掉大部分异常数据。动态检测计算量大,适合在静态检测通过后再做精细化检查。

做套利检测这件事,说白了就是跟市场数据「斗智斗勇」。你永远不知道下一个异常点会出现在哪里。但只要你把检测逻辑写扎实了,修正方法备齐了,就能保证你的波动率曲面是干净、可用的。

嗯,今天就聊到这里。记住一句话:无套利是理想,有套利是常态。关键是你怎么处理它。


公众号:蓝海资料掘金营,微信deep3321