25. 无套利约束:确保插值后的曲面不存在蝶式/日历套利

做波动率曲面插值,最怕什么?

不是精度不够,也不是速度慢。我最怕的是——插值出来的曲面,居然存在套利机会。

你想想看,一个交易员拿着你给的曲面去定价,结果发现能无风险赚钱。这问题就大了。轻则被风控叫去喝茶,重则整个模型被推翻重来。我在一家自营公司就遇到过这种事,那次之后,我把无套利约束写进了所有插值代码的基因里。

什么是蝶式套利?

说白了,蝶式套利就是利用同一到期日、不同行权价的期权价格关系。如果三个行权价K1 < K2 < K3,对应的隐含波动率算出来的价格,违反了凸性条件,就能套利。

数学上,蝶式套利对应的是:

∂²C/∂K² ≥ 0

这个二阶导数,其实就是风险中性密度。如果它为负,说明市场给了你一个免费午餐——买入两端、卖出中间,稳赚不赔。

我习惯用离散形式来检查:

Butterfly(K1, K2, K3) = C(K1) - 2*C(K2) + C(K3) ≥ 0

其中C是看涨期权价格。注意,这里用的是价格,不是波动率。很多人搞混这一点。

核心要点:蝶式套利检查的是同一到期日下,不同行权价之间的价格凸性。插值后的曲面,必须保证所有相邻三个行权价都满足这个条件。

日历套利又是什么?

日历套利,也叫时间套利。它利用的是不同到期日之间的关系。

如果T1 < T2,那么看涨期权价格必须满足:

C(T2) ≥ C(T1)

为什么?因为时间越长,不确定性越大,期权应该越贵。如果T2的期权比T1还便宜,那就套利了——买入便宜的长期期权,卖出贵的短期期权,持有到期就能赚钱。

嗯,这里要注意。日历套利检查的是同一行权价下,不同到期日的价格单调性。插值时,如果时间维度处理不好,很容易出现这种问题。

我曾经踩过的坑:有一次用三次样条对期限结构插值,结果在短期和长期之间出现了凹陷。表面上看曲线很平滑,但仔细一算,存在日历套利。后来我强制加入了单调性约束,才彻底解决。

如何确保无套利?

方法其实不复杂。我总结了三个步骤:

  1. 先检查原始数据——输入的数据本身不能有套利。如果原始数据就有问题,插值后只会更糟。
  2. 选择合适的插值方法——不是所有方法都适合。比如线性插值在总方差空间上做,天然满足无套利条件。
  3. 后处理修正——如果插值后出现了套利,用优化方法强制修正。

我个人最推荐的是在总方差空间做插值。总方差定义为:

w(K, T) = σ²(K, T) * T

在这个空间里,蝶式套利对应的是w对K的凸性,日历套利对应的是w对T的单调性。而且,总方差随到期日单调递增,这是个天然的好性质。

代码实现思路

下面是我常用的检查函数。它不复杂,但很实用:

def check_no_arbitrage(strikes, maturities, prices):
    """
    检查期权价格是否存在套利
    strikes: 行权价数组
    maturities: 到期日数组
    prices: 价格矩阵,shape=(len(maturities), len(strikes))
    """
    # 检查蝶式套利
    for t_idx in range(len(maturities)):
        for k_idx in range(1, len(strikes)-1):
            butterfly = (prices[t_idx, k_idx-1] 
                        - 2*prices[t_idx, k_idx] 
                        + prices[t_idx, k_idx+1])
            if butterfly < -1e-8:  # 容忍小误差
                return False, f"蝶式套利: T={maturities[t_idx]}, K={strikes[k_idx]}"
    
    # 检查日历套利
    for k_idx in range(len(strikes)):
        for t_idx in range(1, len(maturities)):
            if prices[t_idx, k_idx] < prices[t_idx-1, k_idx] - 1e-8:
                return False, f"日历套利: K={strikes[k_idx]}, T={maturities[t_idx]}"
    
    return True, "无套利"
小技巧:检查时留一点容忍度(比如1e-8),因为浮点数计算有误差。但别太大,否则真套利会被漏掉。

插值后的修正方法

如果插值后发现了套利,怎么办?

我一般用约束优化来修正。目标是最小化修正后的曲面与原曲面的差异,同时满足无套利约束。

具体来说:

  • 对于蝶式套利,约束是每个相邻三点的价格凸性非负
  • 对于日历套利,约束是每个行权价上的价格随到期日单调递增

这个优化问题可以用二次规划求解。虽然计算量大了点,但换来的是曲面的可靠性——值了。

知识体系总览

下面这张图,把无套利约束的核心逻辑串起来了:

无套利约束知识体系 蝶式套利(同一到期日) 日历套利(同一行权价) 条件:∂²C/∂K² ≥ 0 检查:C(K1)-2C(K2)+C(K3) ≥ 0 条件:C(T2) ≥ C(T1) 当 T2 > T1 检查:价格随到期日单调递增 解决方案:总方差空间插值 + 约束优化修正 原始数据清洗 选择无套利插值方法 后处理强制修正

实战中的几点体会

做了这么多年,我总结了几条经验:

  • 别等插值完了再检查——应该在每一步都做检查。原始数据、插值中间结果、最终曲面,层层把关。
  • 总方差空间是好朋友——在这个空间做插值,很多套利问题自动就避免了。我建议你优先考虑。
  • 容忍度要合理——太严了,市场微观结构噪声会让你误报;太松了,真套利会溜过去。1e-8到1e-6之间比较合适。
一句话总结:无套利约束不是锦上添花,而是波动率曲面插值的底线。没有它,你的曲面再平滑、再精确,也是废纸一张。

好了,关于无套利约束就聊这么多。记住,做金融模型,第一要务是逻辑自洽。套利检验,就是守住这条底线的最强武器。