项目实战(一):从零搭建一个完整的曲面套利策略

说实话,做期权交易这么多年,我最怕的就是学员问我:「老师,曲面套利到底能不能赚钱?」

我的回答永远是:能,但前提是你得有一套完整的流程。不是拍脑袋看到曲面有个凸起就冲进去,那叫赌博,不叫套利。

今天这一章,我们就从零开始,把整个曲面套利策略的流水线搭起来。数据怎么拿、信号怎么算、回测怎么做、分析怎么搞,一步到位。

一、整体框架:先看地图再上路

我个人习惯,做任何项目之前先画一张图。脑子里的想法再漂亮,落不了地就是白搭。

曲面套利策略的完整流程:

数据获取 → 曲面构建 → 信号生成 → 交易执行 → 回测验证 → 绩效分析

这六个环节,缺一个都不行。

下面这张SVG图,是我自己项目里一直用的框架。你把它存下来,以后做任何套利策略都能往上套。

曲面套利策略完整流程 数据获取 期权链+标的 曲面构建 插值+平滑 信号生成 偏差检测 交易执行 对冲+下单 回测验证 历史模拟 绩效分析 指标评估 反馈优化 • 实时行情 • 历史数据 • 合约信息 • 隐含波动率 • 期限结构 • 偏斜曲线 • 统计套利 • 阈值触发 • 多信号融合 • Delta对冲 • 仓位管理 • 滑点控制 • 样本外测试 • 参数稳健性 • 压力测试

二、数据获取:地基打不牢,房子会塌

你想想看,曲面套利的核心是什么?是找到曲面上的「异常点」。但如果你拿到的数据本身就是错的,那找出来的异常点就是笑话。

我在项目中遇到过最坑的一次:某数据商提供的期权行情,行权价居然有两位小数点的误差。我跑了一周的信号,全是假的。从那以后,我养成了一个习惯——数据清洗比策略本身更重要。

2.1 需要哪些数据?

数据类型 具体字段 频率要求
期权行情 合约代码、行权价、到期日、买卖价、成交量、持仓量 分钟级/日频
标的资产 最新价、前收盘、股息率、无风险利率 实时/日频
合约信息 合约乘数、交易时间、行权方式 静态

我的小技巧:数据源至少准备两个。一个做主数据,一个做校验。我常用Wind做主数据,用Tushare做交叉验证。两个对不上?那肯定有一个有问题。

2.2 数据清洗的坑

嗯,这里要注意几个点:

  • 剔除异常报价:买卖价差超过正常范围3倍以上的,直接扔掉。我曾经遇到过某合约买一价0.001,卖一价999,这种数据留着干嘛?
  • 处理缺失值:深度虚值合约经常没有成交。我的做法是:如果连续3个时间点都没有报价,就用前向填充。超过5个点,直接剔除该合约。
  • 时间对齐:期权数据和标的数据的时间戳必须对齐。差一秒钟,算出来的隐含波动率可能差好几个点。

三、曲面构建:把散点变成连续面

数据拿到手了,接下来就是构建波动率曲面。说白了,就是把不同行权价、不同到期日的隐含波动率,拟合成一个光滑的曲面。

我个人习惯用SVI(Stochastic Volatility Inspired)模型来做。为什么?因为它参数少、拟合快、而且对微笑曲线的刻画很到位。

3.1 SVI模型的核心公式

# SVI模型参数化
# w(k) = a + b * (rho * (k - m) + sqrt((k - m)^2 + sigma^2))

# 其中:
# k = log(K / F)  # 对数行权价
# a: 水平参数
# b: 倾斜参数
# rho: 偏斜参数
# m: 偏移参数
# sigma: 平滑参数

def svi_vol(k, a, b, rho, m, sigma):
    """计算SVI模型下的方差"""
    return a + b * (rho * (k - m) + np.sqrt((k - m)**2 + sigma**2))

关键点:SVI拟合的是方差,不是波动率。拟合完之后要开方才能得到波动率。这个坑我踩过,当时死活对不上市场数据,后来才发现是单位问题。

3.2 拟合步骤

  1. 计算隐含波动率:用BS公式反推每个合约的IV
  2. 筛选有效合约:剔除剩余期限小于7天的合约(临近到期波动太大)
  3. 参数初始化:用最小二乘法给SVI参数赋初值
  4. 非线性优化:用Levenberg-Marquardt算法迭代求解
  5. 插值扩展:对拟合好的曲面做二维插值,得到任意行权价和期限的波动率

四、信号生成:找到曲面的「褶皱」

曲面建好了,接下来就是找套利机会。说白了,就是看市场报价和曲面理论值之间的偏差。

我常用的方法是Z-score统计套利:

# 计算偏差信号
def generate_signal(market_iv, surface_iv, window=20):
    """
    market_iv: 市场实际隐含波动率
    surface_iv: 曲面理论隐含波动率
    """
    # 计算偏差
    deviation = market_iv - surface_iv
    
    # 滚动Z-score
    mean_dev = deviation.rolling(window).mean()
    std_dev = deviation.rolling(window).std()
    z_score = (deviation - mean_dev) / std_dev
    
    # 生成信号
    # z_score > 2: 市场IV偏高,做空波动率
    # z_score < -2: 市场IV偏低,做多波动率
    signal = np.where(z_score > 2, -1, np.where(z_score < -2, 1, 0))
    
    return signal, z_score

警告:Z-score的窗口期不能随便选。我测试过,20个交易日对于日频数据效果最好。太短了噪音多,太长了反应迟钝。你可以根据自己的交易频率调整。

五、回测验证:别让历史数据骗了你

回测是检验策略的唯一标准。但我要说一句:回测做得好,不代表实盘能赚钱。为什么?因为回测有太多坑。

我曾经做过一个策略,回测年化收益30%,夏普比率2.5,漂亮得不得了。结果实盘跑了三个月,亏了8%。后来一查,问题出在滑点上——回测时我假设能以中间价成交,但实盘里深度虚值合约的流动性差得要命。

5.1 回测的核心要素

要素 说明 我的建议
滑点模型 买卖价差+市场冲击 至少按买卖价差的50%计算滑点
交易成本 手续费+印花税+保证金占用 按实际费率上浮20%
流动性限制 持仓量不足的合约无法成交 日均持仓量低于1000手的合约不交易
对冲频率 Delta对冲的时间间隔 日频对冲即可,太频繁成本太高

5.2 回测代码框架

class SurfaceArbitrageBacktest:
    def __init__(self, data, initial_capital=1000000):
        self.data = data
        self.capital = initial_capital
        self.positions = {}
        self.trades = []
        
    def run(self):
        """执行回测"""
        for date in self.data.index:
            # 1. 获取当日信号
            signals = self.generate_signals(date)
            
            # 2. 执行交易
            self.execute_trades(date, signals)
            
            # 3. 日终对冲
            self.delta_hedge(date)
            
            # 4. 记录持仓
            self.record_positions(date)
            
        return self.calculate_performance()

六、绩效分析:别只看收益率

很多人做回测,一看年化收益30%就兴奋得不行。我劝你冷静。收益率只是冰山一角,水面下的东西才要命。

我一般看这几个指标:

  • 夏普比率:至少要大于1.5,低于1的策略不值得实盘
  • 最大回撤:不能超过15%,否则你拿不住
  • 胜率:曲面套利的胜率一般在55%-65%之间,太高或太低都不正常
  • 盈亏比:至少1.5:1,不然赚的钱不够亏的
  • 资金曲线平滑度:这个很多人忽略。曲线越平滑,说明策略越稳健

我的经验:绩效分析不是一次性的事。每跑完一轮回测,都要回头去调整参数。曲面套利策略的参数敏感性很高,行权价筛选范围、Z-score阈值、对冲频率,每一个参数都值得反复测试。

七、写在最后

好了,从数据到回测的完整流程,我已经给你捋了一遍。你可能会觉得内容有点多,但做量化交易就是这样——80%的时间花在数据清洗和回测验证上,只有20%的时间在真正做策略。

下一章我们会用真实数据,手把手带你跑一遍这个流程。到时候你会发现,纸上谈兵和真刀真枪的差距有多大。

记住一句话:曲面套利不是印钞机,它是一把需要精心打磨的手术刀。刀磨好了,才能精准地切下市场的「脂肪」。


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