第21章 曲面一致性检验:无套利条件、日历价差与蝶式价差检验
波动率曲面这东西,看着挺漂亮,对吧?但漂亮不代表能用。
我见过不少交易员,拿着一个看似完美的曲面去定价,结果一算套利空间,发现全是漏洞。说白了,曲面如果不满足一致性条件,你用它做出来的策略,可能一开始就输在起跑线上。
这一章,我们就来聊聊怎么给波动率曲面做「体检」。重点看三个指标:无套利条件、日历价差检验、蝶式价差检验。
21.1 为什么曲面需要一致性检验?
先问个问题:你凭什么相信一个波动率曲面是合理的?
凭它拟合得好?凭它平滑?不够。真正的检验标准是——它能不能被用来构造无风险套利。
如果存在套利机会,说明曲面内部有矛盾。要么是数据错了,要么是模型错了。无论哪种,你都不能用它做交易决策。
我个人习惯,拿到一个新曲面,第一件事不是看形状,而是跑一遍一致性检验。这就像开车前检查刹车,虽然麻烦,但能救命。
核心原则:一个有效的波动率曲面,必须同时满足日历价差无套利和蝶式价差无套利。否则,它就是一张废纸。
21.2 无套利条件的基本框架
无套利条件,说白了就是「不能白捡钱」。在期权市场里,这体现为两个维度:
- 时间维度(日历价差):同一行权价、不同到期日的期权,价格不能出现倒挂。
- 截面维度(蝶式价差):同一到期日、不同行权价的期权,价格不能出现凸性违反。
这两个条件,一个管纵向,一个管横向。交叉起来,就构成了曲面的「骨架」。
我曾经遇到过一个团队,他们用机器学习拟合曲面,结果R²高达0.99。但一跑日历价差检验,发现超过30%的节点存在套利机会。为什么?因为模型只关注拟合精度,没考虑金融约束。这就是典型的「过拟合但无效」。
21.3 日历价差检验
日历价差,也叫时间价差。它检验的是:对于同一个行权价,远月期权的价格是否应该高于近月?
答案是:应该。因为远月期权有更多的时间价值。如果远月比近月还便宜,那就存在套利机会——买入远月、卖出近月,锁定利润。
具体检验方法如下:
def check_calendar_arbitrage(surface, strike):
"""
检验给定行权价的日历价差无套利条件
surface: 波动率曲面对象,包含不同到期日的隐含波动率
strike: 行权价
返回: True 表示无套利,False 表示存在套利
"""
# 获取该行权价下所有到期日的隐含波动率
ivs = surface.get_iv_by_strike(strike)
# 按到期日排序
maturities = sorted(ivs.keys())
for i in range(len(maturities) - 1):
t1 = maturities[i]
t2 = maturities[i + 1]
iv1 = ivs[t1]
iv2 = ivs[t2]
# 核心条件:远月隐含波动率 >= 近月隐含波动率
# 注意:这里用方差形式更严谨
var1 = iv1 ** 2 * t1
var2 = iv2 ** 2 * t2
if var2 < var1 - 1e-6: # 容忍小误差
print(f"发现日历套利: 行权价={strike}, 到期日={t1}->{t2}")
return False
return True
这里有个细节要注意:直接用隐含波动率比较是不对的。因为不同到期日的波动率水平天然不同,应该比较的是「总方差」,也就是 IV² × T。
为什么?你想想看,波动率是年化概念。一个30天到期的期权,年化波动率20%,和一个60天到期的期权,年化波动率19%,哪个更贵?算一下总方差就知道了。
实战技巧:我在做日历价差检验时,通常会给一个容忍度(比如1e-6)。因为市场微观结构会导致微小偏差,完全零容忍反而会误报。但容忍度不能太大,否则会漏掉真正的套利机会。
21.4 蝶式价差检验
蝶式价差检验的是凸性条件。它要求:对于同一到期日,隐含波动率关于行权价的二阶导数不能为负。
换句话说,波动率微笑必须是凸的。如果出现凹形区域,就可以构造蝶式套利。
蝶式价差的构造很简单:买入一个低行权价期权,买入一个高行权价期权,卖出两个中间行权价期权。如果这个组合的价格为负,就存在套利。
def check_butterfly_arbitrage(surface, maturity):
"""
检验给定到期日的蝶式价差无套利条件
surface: 波动率曲面对象
maturity: 到期日
返回: True 表示无套利,False 表示存在套利
"""
# 获取该到期日下所有行权价的隐含波动率
ivs = surface.get_iv_by_maturity(maturity)
# 按行权价排序
strikes = sorted(ivs.keys())
for i in range(1, len(strikes) - 1):
k1 = strikes[i - 1]
k2 = strikes[i]
k3 = strikes[i + 1]
iv1 = ivs[k1]
iv2 = ivs[k2]
iv3 = ivs[k3]
# 计算蝶式价差价格(用Black-Scholes近似)
# 核心条件:中间行权价的隐含波动率不能高于两端插值
# 即:波动率曲线必须是凸的
# 线性插值得到中间点的理论波动率
weight = (k3 - k2) / (k3 - k1)
iv_interp = weight * iv1 + (1 - weight) * iv3
if iv2 > iv_interp + 1e-6:
print(f"发现蝶式套利: 到期日={maturity}, 行权价={k1},{k2},{k3}")
return False
return True
这段代码的逻辑是:如果中间行权价的隐含波动率高于两端插值,说明曲线是凹的,存在套利。
嗯,这里要注意一个坑。蝶式价差检验对数据质量非常敏感。如果输入数据有噪音,很容易误报。我建议先对曲面做平滑处理,再做检验。
警告:蝶式价差检验不能只看隐含波动率,还要考虑行权价间距。如果行权价间距不均匀,直接比较波动率会出错。正确的做法是计算期权价格,再构造蝶式组合。
21.5 完整的曲面一致性检验流程
在实际项目中,我不会只做单项检验。我会把日历价差和蝶式价差结合起来,形成一个完整的检验流水线。
下面是我常用的流程:
- 数据清洗:剔除异常报价,处理缺失值
- 曲面拟合:用SVI或样条方法构建初始曲面
- 日历价差检验:遍历所有行权价,检查时间维度一致性
- 蝶式价差检验:遍历所有到期日,检查截面维度一致性
- 套利修正:对违反条件的区域进行局部调整
- 重新检验:迭代直到所有条件满足
这个流程看起来简单,但做起来很考验耐心。我记得有一次,为了修正一个外汇期权曲面的套利问题,我迭代了7轮才通过所有检验。
21.6 知识体系结构图
下面这张图,把曲面一致性检验的核心逻辑串起来了。你可以把它当作一个检查清单。
21.7 实战中的常见问题
做一致性检验这么多年,我踩过不少坑。挑几个典型的说说:
- 数据频率问题:用日频数据做检验,结果全是套利。换成分钟频数据,套利就消失了。为什么?因为日频数据是收盘价,包含了隔夜信息,而分钟频数据更能反映实时市场。
- 行权价稀疏问题:有些品种行权价间距很大,蝶式价差检验会漏掉中间区域的套利。我建议用插值方法补全中间行权价,再做检验。
- 到期日不匹配问题:不同到期日的交易日数不同,直接用日历天数会出错。应该用实际交易日数或更精确的时间度量。
我的经验:一致性检验不是一次性工作。每次更新曲面后,都应该重新跑一遍。我习惯把它写成自动化脚本,每天开盘前自动运行一次。如果发现套利,就暂停使用该曲面,直到问题解决。
好了,关于曲面一致性检验,核心就是这些。记住一句话:一个不能通过检验的曲面,再漂亮也是摆设。做交易,首先要保证你的工具是可靠的。
公众号:蓝海资料掘金营,微信deep3321