4. 数据获取与清洗:期权链数据来源与处理
做隐含波动率曲面,第一步不是建模,不是选参数。
是搞到干净的数据。
我见过太多人,模型写得飞起,结果数据里藏着几个异常值,曲面直接崩掉。嗯,这章我们就聊聊数据从哪来,拿到手之后怎么洗。
4.1 数据来源:你总得有个入口
期权数据不像股票行情那么普及。我个人习惯把数据源分成三类:
- 交易所官方API:最权威,但门槛高
- 数据供应商:省心,但要花钱
- 开源/免费接口:练手可以,生产环境慎用
先看交易所。国内的上交所、深交所、中金所,都有期权行情接口。但说实话,直接对接交易所API,你得有机构资质,还得搞定网络专线。我在项目中遇到过一家小私募,为了省成本自己搭了套解析程序,结果行情延迟了200毫秒,做高频根本没法用。
数据供应商就友好多了。Wind、Choice、Bloomberg、Refinitiv,这些都能拿到完整的期权链数据。我建议初学者先用Wind,接口文档写得清楚,Python的WindPy库直接调,省去很多麻烦。
核心数据字段:
- 合约代码、行权价、到期日
- 最新价、买一价、卖一价
- 成交量、持仓量
- 标的资产价格(这个很重要,算隐含波动率要用)
举个例子,用Wind拉数据大概长这样:
from WindPy import w
w.start()
# 获取50ETF期权链
options = w.wset("optionchain",
"date=2024-01-15;uscode=510050.SH;option_var=全部",
usedf=True)
# 获取具体合约行情
data = w.wsq(options['wind_code'].tolist(),
"rt_last,rt_bid1,rt_ask1,rt_vol,rt_oi",
usedf=True)
这里有个坑——数据对齐。期权行情和标的行情的时间戳可能不同步。我吃过这个亏:用收盘价算隐含波动率,结果期权是15:00收盘,标的却是15:30收盘,差了半小时,算出来的曲面全是错的。
避坑指南:
我曾经因为没检查时间戳对齐,给客户交付了一套波动率曲面,结果客户回测发现策略亏损严重。后来排查了两天,才发现是数据时间戳差了1分钟。从那以后,我每次拿到数据第一件事就是检查时间戳。
4.2 数据清洗流程:脏数据是魔鬼
数据拿到手,别急着算。先过一遍清洗流程。我总结了一套「四步清洗法」:
- 去重:同一合约同一时刻出现多条记录
- 补全:缺失的买卖价、成交量
- 过滤:剔除明显不合理的价格
- 对齐:统一时间戳,匹配标的资产
去重这一步,很多人觉得没必要。你想想看,交易所的数据按理说不会重复。但实际中,数据供应商的推送机制偶尔会重发。我习惯用drop_duplicates()按合约代码+时间戳去重,简单粗暴。
补全就比较讲究了。比如某个合约的买一价是空的,但卖一价有。这时候怎么办?
我的做法是:如果买卖价缺一个,用另一个加减最小变动价位来估算。如果两个都缺,那就看上一笔成交价。如果连成交价都没有——嗯,这个合约今天就没交易,直接标记为无效。
def fill_bid_ask(row):
if pd.isna(row['bid']) and not pd.isna(row['ask']):
row['bid'] = row['ask'] - 0.0001 # 最小变动价位
elif not pd.isna(row['bid']) and pd.isna(row['ask']):
row['ask'] = row['bid'] + 0.0001
return row
个人经验:
对于深度虚值期权,流动性很差,买卖价差可能非常大。我一般会设置一个最大价差阈值,比如标的价格的5%。超过这个阈值的,直接剔除。不然这些合约会把曲面尾部拉得奇形怪状。
4.3 异常值处理:那些让你头疼的「坏点」
异常值,说白了就是那些明显不符合市场规律的数据点。
举个例子:某天50ETF价格是2.5元,结果有个行权价2.8元的看涨期权,报价0.5元。这合理吗?
不合理。因为2.8元的看涨期权,内在价值是0,时间价值最多也就0.1-0.2元。0.5元的报价,要么是数据错误,要么是流动性枯竭下的极端报价。
我常用的异常值检测方法有三种:
| 方法 | 适用场景 | 阈值设置 |
|---|---|---|
| 价格边界检查 | 所有合约 | 期权价格 ≤ 标的资产价格 |
| 隐含波动率过滤 | 有成交的合约 | IV < 5% 或 IV > 200% |
| 买卖价差检查 | 流动性差的合约 | 价差/中间价 > 30% |
价格边界检查是最基础的。看涨期权价格不能超过标的资产价格,看跌期权价格不能超过行权价。这个逻辑很简单,但很多人会忽略。
隐含波动率过滤就更有意思了。我先把所有合约的隐含波动率算出来,然后看分布。正常情况下,同一到期日的IV应该在一个合理范围内。如果某个合约的IV突然飙到300%,那大概率是数据有问题。
我曾经遇到过一个案例:某天下午2点半,有个深度虚值合约的IV突然从30%跳到500%。我一开始以为是市场异动,后来查了原始数据,发现是交易所的行情推送出了bug,把价格的小数点位置搞错了。嗯,这种错误,光靠肉眼很难发现,必须靠自动化检测。
我的异常值处理流程:
- 先做硬性边界检查,剔除明显不合理的数据
- 计算每个合约的隐含波动率
- 按到期日和行权价分组,计算IV的中位数和标准差
- 剔除偏离中位数超过3个标准差的合约
- 最后人工复核一下被剔除的合约,防止误杀
这里要特别提醒:不要过度剔除。有时候市场确实会出现极端波动,比如黑天鹅事件。如果你把所有的异常值都剔除了,反而会丢失真实的市场信息。我一般会保留那些虽然异常但成交量很大的合约——成交量说明市场认可这个价格。
4.4 数据清洗的完整流程
说了这么多,我把整个流程串起来。下面这张图是我自己项目里用的数据清洗流水线:
这张图是我自己项目里用的数据清洗流水线。你看,从原始数据到干净数据,中间要经过五道工序。每一步都不能省。
最后说一句:数据清洗这件事,看起来枯燥,但恰恰是量化交易中最值钱的部分。模型可以抄,代码可以复制,但干净的数据和清洗流程,是每个团队的核心资产。
嗯,数据准备好了,下一件事就是算隐含波动率了。不过那是下一章的内容。