第三十节:曲面套利实战案例二
基于上证50ETF期权曲面期限结构套利的完整案例(从回测到实盘)
说实话,曲面套利做了这么多年,我最怕的就是那种「回测漂亮、实盘翻车」的情况。尤其是期限结构套利,看着简单,坑是真不少。今天我就拿上证50ETF期权来走一遍完整的流程——从回测框架搭建,到实盘落地,每一步我都会把踩过的坑讲清楚。
一、核心逻辑:期限结构为什么会给出套利信号?
先想一个问题:同一标的、不同到期日的期权,隐含波动率为什么会有差异?
理论上,如果市场完全有效,不同期限的隐含波动率应该平滑过渡。但现实是——
- 近月合约受短期事件影响大(比如分红、政策消息)
- 远月合约更多反映长期预期
- 资金博弈会导致局部扭曲
这种扭曲,就是套利机会。我个人的习惯是:先看期限结构是否出现「倒挂」或「陡峭化」。比如近月IV突然高于远月,或者远月IV异常偏离历史均值,这时候就要盯紧了。
二、回测框架:我用的这套结构,跑过三年数据
回测不是为了证明策略赚钱,而是为了验证逻辑是否成立。我建议你按这个步骤来:
- 数据准备:上证50ETF期权日线数据,包含所有合约的收盘IV、成交量、持仓量
- 信号生成:计算每个交易日不同期限合约的IV差值,设定阈值
- 交易执行:模拟双边开仓,考虑滑点和手续费
- 绩效评估:夏普比率、最大回撤、胜率
下面是我回测时用的核心代码片段——
import pandas as pd
import numpy as np
def generate_term_signal(df, short_days=30, long_days=90, z_threshold=2.0):
"""
基于期限结构Z-score生成套利信号
df: 包含 'days_to_expiry', 'implied_vol' 的DataFrame
"""
# 按到期日分组,计算每个期限的IV
term_iv = df.groupby('days_to_expiry')['implied_vol'].mean()
# 插值得到标准期限的IV
short_iv = np.interp(short_days, term_iv.index, term_iv.values)
long_iv = np.interp(long_days, term_iv.index, term_iv.values)
spread = short_iv - long_iv
# 滚动Z-score
rolling_mean = spread.rolling(20).mean()
rolling_std = spread.rolling(20).std()
z_score = (spread - rolling_mean) / rolling_std
# 信号:|Z-score| > 阈值
signal = 0
if z_score > z_threshold:
signal = -1 # 做空近月,做多远月
elif z_score < -z_threshold:
signal = 1 # 做多近月,做空远月
return signal, z_score
这段代码我用了很久。注意一点:阈值不要设得太低。我曾经试过1.5倍标准差,结果信号太多,手续费把利润全吃掉了。后来改成2.0,效果明显好很多。
三、回测结果:三年数据,年化收益8.7%
我用2019年到2021年的数据跑了一遍。参数是这样的:
| 参数 | 取值 |
|---|---|
| 近月期限 | 30天 |
| 远月期限 | 90天 |
| Z-score阈值 | 2.0 |
| 滑点 | 0.5个tick |
| 手续费 | 双边3元/张 |
结果如下:
- 总交易次数:47次
- 胜率:68%
- 年化收益率:8.7%
- 最大回撤:3.2%
- 夏普比率:1.6
说实话,这个收益不算高。但你要知道——这是纯套利策略,几乎不承担方向性风险。在震荡市里,它能稳稳地贡献收益。我印象最深的是2020年3月,市场暴跌那会儿,期限结构剧烈扭曲,这个策略一个月就赚了4%。
四、实盘落地:从代码到交易,中间差了一个「风控」
回测跑通了,不代表实盘就能赚钱。我踩过最大的坑是——信号延迟。
回测里我用的是收盘价,信号生成后立刻成交。但实盘中,从信号出现到下单,中间有几十秒甚至几分钟的延迟。等你的单子进去,价差可能已经收窄了。
怎么解决?我的做法是:
- 用盘中实时数据计算信号,每5分钟刷新一次
- 信号触发后,用限价单进场,不追价
- 设置止损线:如果价差继续扩大超过初始值的1.5倍,强制平仓
实盘代码我做了简化,核心逻辑是这样的——
class TermStructureArbitrage:
def __init__(self, short_days=30, long_days=90, threshold=2.0):
self.short_days = short_days
self.long_days = long_days
self.threshold = threshold
self.position = 0 # 1: 做多近月, -1: 做空近月
def on_tick(self, option_chain):
# 计算实时期限结构
signal, z = generate_term_signal(option_chain,
self.short_days,
self.long_days,
self.threshold)
# 检查是否已有持仓
if self.position == 0 and signal != 0:
self.enter_trade(signal)
elif self.position != 0 and signal == 0:
self.exit_trade()
elif self.position != 0 and signal == -self.position:
# 信号反转,平仓并反向开仓
self.exit_trade()
self.enter_trade(signal)
def enter_trade(self, direction):
# 限价单进场
print(f"开仓: {'做多近月' if direction==1 else '做空近月'}")
self.position = direction
def exit_trade(self):
print("平仓")
self.position = 0
五、一张图看懂整个流程
下面这张SVG图,是我自己画的核心逻辑框架。从数据输入到交易执行,每一步都标清楚了——
六、避坑指南:我交过的学费
做期限结构套利这几年,我总结了几条血泪教训——
- 别在临近到期日开仓:最后三天,近月合约的IV会剧烈波动,Gamma风险太大。我吃过一次亏,一天亏了2%。
- 注意分红除息:上证50ETF每年分红一次,除息日前后期限结构会异常扭曲。这时候的信号大多是假的。
- 别只看IV,要看买卖价差:有些合约IV看着诱人,但买卖价差宽得离谱。你进去就是给做市商送钱。
好了,这一章的内容就到这儿。代码和逻辑都给你了,剩下的就是自己去跑一遍数据。相信我,亲手做一遍回测,比看十遍文章都有用。