4. 数据获取与预处理:获取期权链数据、计算隐含波动率、清洗异常数据

做事件驱动交易,说白了就是赌事件发生前后的波动率变化。但有个前提——你得先拿到干净的数据。我见过太多人,策略逻辑写得天花乱坠,结果数据源一塌糊涂,最后亏得莫名其妙。

这一章,咱们就聊聊怎么把期权链数据搞到手,怎么算隐含波动率,以及怎么把那些坑爹的异常数据清洗掉。嗯,这里要注意,数据预处理花的时间,往往比写策略本身还多。

核心观点: 数据质量决定了策略的上限。再牛的模型,喂进去垃圾数据,出来的只能是垃圾结果。

4.1 获取期权链数据

期权链数据,说白了就是一张大表。每一行代表一个期权合约,列包含行权价、到期日、合约代码、最新价、买卖价、成交量、持仓量等等。我个人习惯,先拿到这张表,再做后续处理。

数据来源嘛,国内常用的是万得、聚宽、Tushare,国外就是彭博、路透、IB。我建议你至少准备两个数据源,做交叉验证。为什么?因为单一数据源偶尔会抽风,我曾经遇到过某平台某天的数据全部偏移了一个Tick,差点把策略带沟里去。

获取数据时,有几个关键字段必须拿到:

  • 合约代码:唯一标识,用于后续匹配
  • 行权价:K值,计算价内外状态用
  • 到期日:计算剩余期限,单位年
  • 最新价/收盘价:期权价格,用于反推隐含波动率
  • 标的资产价格:当前标的价格,S值
  • 无风险利率:通常用SHIBOR或国债收益率

你想想看,如果缺少了标的资产价格,隐含波动率根本算不出来。所以数据获取阶段,就要把标的行情一起拉下来。

4.2 计算隐含波动率

隐含波动率,是市场对未来的预期。它不是直接能看到的,得从期权价格反推。怎么反推?用BS模型。

BS公式长这样:

C = S * N(d1) - K * e^(-rT) * N(d2)
其中:
d1 = [ln(S/K) + (r + σ²/2) * T] / (σ * √T)
d2 = d1 - σ * √T

但这里有个问题——公式里有个σ,就是我们要求的隐含波动率。而公式左边C是已知的(市场价格)。所以这是个反问题:已知C,求σ。

解法很简单,用牛顿迭代法或者二分法。我习惯用二分法,稳定,不容易发散。代码实现大概这样:

def implied_volatility(price, S, K, r, T, option_type='call'):
    """
    使用二分法计算隐含波动率
    price: 期权市场价格
    S: 标的资产价格
    K: 行权价
    r: 无风险利率
    T: 剩余期限(年)
    option_type: 'call' 或 'put'
    """
    sigma_low = 0.001
    sigma_high = 5.0
    tolerance = 1e-6
    
    for i in range(100):
        sigma_mid = (sigma_low + sigma_high) / 2
        bs_price = black_scholes(S, K, r, T, sigma_mid, option_type)
        
        if bs_price > price:
            sigma_high = sigma_mid
        else:
            sigma_low = sigma_mid
            
        if abs(bs_price - price) < tolerance:
            return sigma_mid
    
    return sigma_mid
小技巧: 迭代次数设100次足够了。如果100次还不收敛,说明数据本身有问题,直接标记为异常。

这里有个坑——深度虚值期权的价格非常低,可能只有0.01元。这种价格算出来的隐含波动率往往不稳定,甚至出现负值。我建议你设置一个价格阈值,比如低于0.05元的期权,直接跳过不计算。

4.3 清洗异常数据

数据清洗,是这章里最磨人的环节。我做过一个统计,原始期权数据里,大约有3%-5%的数据是有问题的。如果不处理,这些脏数据会直接污染你的波动率曲面。

常见的异常情况有:

  • 价格倒挂:看涨期权价格低于内在价值,或者看跌期权价格低于内在价值。这明显不合理,直接剔除。
  • 波动率异常:算出来的隐含波动率超过100%或者低于5%。这种要么是数据错误,要么是极端行情。我建议先标记,再人工复核。
  • 流动性不足:成交量小于10手,或者买卖价差超过价格的20%。这种数据没有参考意义。
  • 到期日太近:剩余期限小于3天的期权,时间价值衰减极快,隐含波动率容易失真。我一般会过滤掉。

我曾经遇到过一件事:某只股票在财报公布前,深度虚值期权的隐含波动率突然飙到300%。乍一看像是机会,但仔细检查发现,是数据源把行权价搞错了,少了一个零。嗯,从那以后,我每次拿到数据都会先做一轮行权价合理性检查

清洗流程我总结成三步:

  1. 格式检查:确保所有字段都是数值型,没有空值或NaN
  2. 逻辑检查:价格是否在合理范围内,是否满足无套利条件
  3. 统计检查:用3σ原则或IQR方法,剔除离群值
警告: 不要一次性把所有异常数据都删掉。建议先标记,再分析异常数据的分布。如果某个行权价附近异常数据特别多,可能是数据源本身有问题,需要换源。

4.4 知识体系总览

下面这张图,把整个数据获取与预处理的流程串起来了。你可以把它当作一个检查清单,每次做数据准备时对照着走一遍。

数据获取与预处理流程 数据获取 期权链 + 标的行情 计算隐含波动率 BS模型 + 二分法 数据清洗 三步检查法 干净数据 → 波动率曲面 常见异常类型 ● 价格倒挂 ● 波动率异常(>100% 或 <5%) ● 流动性不足 ● 到期日太近(<3天) ● 行权价错误 ● 数据源偏移 清洗三步法 ① 格式检查 字段类型、空值、NaN ② 逻辑检查 无套利条件、价格范围 ③ 统计检查 3σ原则、IQR方法 建议:每次获取数据后,先跑一遍清洗流程,再进入策略计算 数据质量 = 策略生命线

4.5 实战中的几个坑

最后,分享几个我踩过的坑,希望能帮你省点时间:

  • 分红除权:股票分红后,期权合约的行权价和合约乘数会调整。如果你没做复权处理,算出来的隐含波动率会莫名其妙地跳变。我建议用调整后的行权价来计算。
  • 非交易日:到期日计算要用交易日历。我曾经直接用自然日算,结果在春节前后数据全乱了。嗯,后来我专门写了个交易日历函数。
  • 数据对齐:期权数据和标的行情数据的时间戳要对齐。如果期权是15:00收盘,标的也是15:00收盘,但数据源可能一个用15:00,一个用15:00:01,差一秒就可能差出几个点。
我的习惯: 每次跑策略前,先随机抽10个合约,手动算一遍隐含波动率,跟程序结果对比。如果对不上,说明数据预处理环节有问题,赶紧排查。

数据准备这一步,确实枯燥,但它是整个波动率曲面交易的地基。地基不稳,楼盖得再高也得塌。我个人觉得,花在数据清洗上的时间,永远不亏。

专注资料整理