11. 实战案例:股票期权曲面异常检测(使用真实市场数据)
好了,终于到了动手环节。
前面讲了那么多理论,什么插值方法、异常点定义、风险敞口计算……说实话,不拿真实数据跑一遍,你心里肯定没底。我当年刚入行时也是这样,看了好几本教材,结果第一次面对真实的期权报价数据,直接懵了——数据太脏了。
这一章,我们就用真实的股票期权市场数据,完整走一遍异常检测流程。我会用我自己的代码库里的一个案例,带你看看实际工作中到底会遇到哪些坑。
11.1 数据准备:先看看真实数据长什么样
我习惯先从交易所拿原始的期权报价数据。以某只蓝筹股的期权为例,数据大概长这样:
# 示例数据加载代码
import pandas as pd
import numpy as np
from datetime import datetime
# 模拟真实市场数据
data = pd.DataFrame({
'strike': [2.80, 2.85, 2.90, 2.95, 3.00, 3.05, 3.10, 3.15],
'expiry': ['2024-03-15', '2024-03-15', '2024-03-15', '2024-03-15',
'2024-04-19', '2024-04-19', '2024-04-19', '2024-04-19'],
'implied_vol': [0.35, 0.33, 0.32, 0.31, 0.30, 0.31, 0.33, 0.36],
'bid': [0.12, 0.15, 0.18, 0.22, 0.25, 0.21, 0.17, 0.13],
'ask': [0.13, 0.16, 0.19, 0.23, 0.26, 0.22, 0.18, 0.14],
'volume': [100, 200, 150, 300, 500, 80, 120, 60]
})
print(data.head())
嗯,这里要注意:真实数据里,implied_vol 这一列往往不是直接给的。你需要自己用期权定价模型反推。我一般用 BS 模型,但遇到深度实值或深度虚值的合约,BS 模型会有点抽风——这个后面再说。
11.2 构建波动率曲面:从散点到曲面
数据准备好了,下一步就是构建曲面。说白了,就是把不同行权价、不同到期日的隐含波动率,映射到一个二维网格上。
我个人习惯用 三次样条插值,但要注意边界处理。你看这张图就明白了:
你想想看,如果直接用原始散点去插值,那些异常点会把整个曲面拉变形。我见过最夸张的一次,一个错误的报价导致整个曲面在某个期限上凸起了一个「包」,差点让交易台多亏了 200 万。
11.3 异常检测:两种方法双保险
我一般用两种方法做异常检测,互相验证:
- Z-score 方法:计算每个点与曲面预测值的偏差,标准化后看是否超过阈值。
- 局部离群因子(LOF):看一个点周围邻居的密度,如果密度明显低于邻居,那就是异常。
直接上代码:
from scipy import stats
from sklearn.neighbors import LocalOutlierFactor
# 计算 Z-score
data['z_score'] = np.abs(stats.zscore(data['implied_vol']))
data['is_anomaly_z'] = data['z_score'] > 2.5 # 阈值可调
# LOF 检测
lof = LocalOutlierFactor(n_neighbors=5, contamination=0.05)
data['is_anomaly_lof'] = lof.fit_predict(data[['strike', 'implied_vol']]) == -1
# 综合判断
data['is_anomaly'] = data['is_anomaly_z'] | data['is_anomaly_lof']
print(data[data['is_anomaly']])
11.4 风险规避:发现异常后怎么办?
检测出异常点,不是直接删掉就完事了。你得搞清楚:这个异常是数据错误,还是市场真的在发生变化?
我遇到过一种情况:某天下午 2:30,一个深度虚值看涨期权的隐含波动率突然飙升到 80%。Z-score 和 LOF 都报警了。但后来发现,是因为有大户在集中买入,市场在赌某个消息。这种情况下,异常点反而是交易信号。
所以我的处理流程是:
| 异常类型 | 可能原因 | 处理方式 |
|---|---|---|
| 孤立点(单合约异常) | 数据录入错误、流动性不足 | 剔除,用插值填补 |
| 区域异常(多个合约同时异常) | 市场事件、大单交易 | 保留,但标记为「高波动区域」 |
| 时间序列异常(同一合约连续异常) | 模型参数变化、分红/拆股 | 调整模型参数后重新计算 |
11.5 完整流程复盘
最后,我把整个实战流程总结一下:
- 第一步:获取真实市场数据,注意清洗 bid/ask 倒挂、零成交量等脏数据。
- 第二步:用 BS 模型反推隐含波动率,注意处理边界合约。
- 第三步:用三次样条插值构建波动率曲面,检查插值结果是否平滑。
- 第四步:用 Z-score + LOF 双方法检测异常点,设置合理阈值。
- 第五步:分析异常原因,决定是剔除还是保留。
- 第六步:更新曲面,输出风险预警报告。
说实话,这套流程我用了快五年,中间迭代了无数次。最开始我连数据清洗都没做,直接插值,结果曲面长得跟心电图似的。后来慢慢加上了异常检测、原因分析、自动预警……现在基本能做到每天开盘前自动跑一遍,10 分钟出报告。
你如果刚开始做,别追求完美。先跑通流程,再慢慢优化。毕竟,真实市场的魅力就在于——你永远不知道下一个异常点会出现在哪里。