如何获取期权市场数据快照
来源:https://uqer.io/community/share/550274e4f9f06c7a9ae9a535
在本文中,我们将通过实际的市场的例子,展示如何在量化实验室中计算和展示期权的隐含波动率微笑。
import pandas as pd
from matplotlib import pylab
pd.options.display.float_format = '{:,>.4f}'.format
1. 获取市场数据
在本节中,我们使用数据API获取数据,并进行一些必要的数据转换。这里我们获取的是实时报价,是本 notebook 运行时的市场快照。
dataDate
交易日dataTime
快照时间戳optionId
期权代码instrumentID
期权交易代码contractType
期权类型,CO为看着,PO为看跌strikePrice
行权价expDate
到期日lastPrice
最新价
optionSnapShot = OptionsDataSnapShot()
optionSnapShot[optionSnapShot.expDate == Date(2015,9,23)]
dataDate | dataTime | optionId | instrumentID | contractType | strikePrice | expDate | lastPrice | |
---|---|---|---|---|---|---|---|---|
30 | 2015-03-13 | 13:24:12 | 10000031 | 510050C1509M02200 | CO | 2.2000 | September 23rd, 2015 | 0.3388 |
31 | 2015-03-13 | 13:24:17 | 10000032 | 510050C1509M02250 | CO | 2.2500 | September 23rd, 2015 | 0.3019 |
32 | 2015-03-13 | 13:24:22 | 10000033 | 510050C1509M02300 | CO | 2.3000 | September 23rd, 2015 | 0.2816 |
33 | 2015-03-13 | 13:24:27 | 10000034 | 510050C1509M02350 | CO | 2.3500 | September 23rd, 2015 | 0.2484 |
34 | 2015-03-13 | 13:24:32 | 10000035 | 510050C1509M02400 | CO | 2.4000 | September 23rd, 2015 | 0.2070 |
35 | 2015-03-13 | 13:24:36 | 10000036 | 510050P1509M02200 | PO | 2.2000 | September 23rd, 2015 | 0.0690 |
36 | 2015-03-13 | 13:24:41 | 10000037 | 510050P1509M02250 | PO | 2.2500 | September 23rd, 2015 | 0.0804 |
37 | 2015-03-13 | 13:24:47 | 10000038 | 510050P1509M02300 | PO | 2.3000 | September 23rd, 2015 | 0.0955 |
38 | 2015-03-13 | 13:24:52 | 10000039 | 510050P1509M02350 | PO | 2.3500 | September 23rd, 2015 | 0.1194 |
39 | 2015-03-13 | 13:24:58 | 10000040 | 510050P1509M02400 | PO | 2.4000 | September 23rd, 2015 | 0.1322 |
46 | 2015-03-13 | 13:24:52 | 10000047 | 510050C1509M02450 | CO | 2.4500 | September 23rd, 2015 | 0.1889 |
47 | 2015-03-13 | 13:24:58 | 10000048 | 510050P1509M02450 | PO | 2.4500 | September 23rd, 2015 | 0.1555 |
54 | 2015-03-13 | 13:24:32 | 10000055 | 510050C1509M02500 | CO | 2.5000 | September 23rd, 2015 | 0.1629 |
55 | 2015-03-13 | 13:24:36 | 10000056 | 510050P1509M02500 | PO | 2.5000 | September 23rd, 2015 | 0.1900 |
62 | 2015-03-13 | 13:24:32 | 10000063 | 510050C1509M02550 | CO | 2.5500 | September 23rd, 2015 | 0.1443 |
63 | 2015-03-13 | 13:24:36 | 10000064 | 510050P1509M02550 | PO | 2.5500 | September 23rd, 2015 | 0.2169 |
2. 计算隐含波动率以及相关Greeks
接着我们可以方便的使用内置函数 BSMImpliedVolatity 计算期权的隐含波动率。
price
市场报价或者模型价格delta
期权价格关于标的价格的一阶导数gamma
期权价格关于标的价格的二阶导数rho
期权价格关于无风险利率的一阶导数theta
期权价格关于到期时间的一阶导数(每日)vega
期权价格关于波动率的一阶导数
analyticResult = OptionsAnalyticResult()
analyticResult.loc[:10, ['optionId', 'contractType', 'strikePrice', 'expDate', 'lastPrice', 'vol', 'delta', 'gamma', 'rho', 'theta', 'vega']]
optionId | contractType | strikePrice | expDate | lastPrice | vol | delta | gamma | rho | theta | vega | |
---|---|---|---|---|---|---|---|---|---|---|---|
1 | 10000002 | CO | 2.2500 | March 25th, 2015 | 0.2184 | 0.2259 | 0.9886 | 0.2947 | 0.0730 | -0.0458 | 0.0133 |
2 | 10000003 | CO | 2.3000 | March 25th, 2015 | 0.1730 | 0.2867 | 0.9165 | 1.1965 | 0.0687 | -0.2996 | 0.0687 |
3 | 10000004 | CO | 2.3500 | March 25th, 2015 | 0.1229 | 0.2177 | 0.8963 | 1.8495 | 0.0687 | -0.2670 | 0.0806 |
4 | 10000005 | CO | 2.4000 | March 25th, 2015 | 0.0814 | 0.2166 | 0.7676 | 3.1504 | 0.0596 | -0.4503 | 0.1367 |
8 | 10000009 | PO | 2.3500 | March 25th, 2015 | 0.0076 | 0.2482 | -0.1332 | 1.9373 | -0.0111 | -0.3633 | 0.0963 |
9 | 10000010 | PO | 2.4000 | March 25th, 2015 | 0.0159 | 0.2346 | -0.2488 | 3.0197 | -0.0207 | -0.5061 | 0.1419 |
10 | 10000011 | CO | 2.2000 | April 22nd, 2015 | 0.2778 | 0.2703 | 0.9081 | 0.7466 | 0.2152 | -0.1661 | 0.1347 |
3. 构造波动率曲面
但是对于市场参与者而言,像刚才这样仅仅观察的线的结构不够。他们需要看到整个市场以到期时间,行权价为轴的波动率曲面(Volatility Surface)。除此之外,他们更想知道,波动率曲面上,那些并不是市场报价点的值,至少是个估计。这样的波动率曲面构造,往往需要依赖某种模型,或者某种插值方法。在这一节中,我们将介绍使用 CAL 中的波动率曲面构造函数。
以下的例子基于 CAL 函数: VolatilitySurfaceSnapShot
3.1 基于SABR模型的波动率曲面
volInterpolatorSABR = VolatilitySurfaceSnapShot(optionType = 'CALL', interpType = 'SABR')
volInterpolatorSABR.plotSurface(startStrike = 2.2,endStrike = 2.6)
volInterpolatorSABR.volalitltyProfileFromPeriods([2.2, 2.3, 2.4, 2.5, 2.6], ['1M', '2M', '3M', '6M', '9M'])
1M | 2M | 3M | 6M | 9M | |
---|---|---|---|---|---|
2.2000 | 0.2720 | 0.2406 | 0.2327 | 0.2531 | 0.2545 |
2.3000 | 0.2048 | 0.2207 | 0.2345 | 0.2546 | 0.2557 |
2.4000 | 0.2245 | 0.2341 | 0.2389 | 0.2525 | 0.2533 |
2.5000 | 0.2241 | 0.2328 | 0.2381 | 0.2479 | 0.2484 |
2.6000 | 0.2311 | 0.2356 | 0.2362 | 0.2425 | 0.2429 |
3.2 基于SVI模型的波动率曲面
volInterpolatorSVI = VolatilitySurfaceSnapShot(optionType = 'CALL', interpType = 'SVI')
volInterpolatorSVI.plotSurface(startStrike = 2.2,endStrike = 2.6)
volInterpolatorSVI.volalitltyProfileFromPeriods([2.2, 2.3, 2.4, 2.5, 2.6], ['1M', '2M', '3M', '6M', '9M'])
1M | 2M | 3M | 6M | 9M | |
---|---|---|---|---|---|
2.2000 | 0.2769 | 0.2476 | 0.2369 | 0.2566 | 0.2580 |
2.3000 | 0.2121 | 0.2223 | 0.2340 | 0.2535 | 0.2545 |
2.4000 | 0.2170 | 0.2292 | 0.2365 | 0.2504 | 0.2512 |
2.5000 | 0.2290 | 0.2357 | 0.2389 | 0.2474 | 0.2479 |
2.6000 | 0.2401 | 0.2417 | 0.2413 | 0.2508 | 0.2514 |
3.3 基于Balck波动率插值的波动率曲面
volInterpolatorVariance = VolatilitySurfaceSnapShot(optionType = 'CALL', interpType = 'BlackVariance')
volInterpolatorVariance.plotSurface(startStrike = 2.2,endStrike = 2.6)
volInterpolatorVariance.volalitltyProfileFromPeriods([2.2, 2.3, 2.4, 2.5, 2.6], ['1M', '2M', '3M', '6M', '9M'])
1M | 2M | 3M | 6M | 9M | |
---|---|---|---|---|---|
2.2000 | 0.2676 | 0.2380 | 0.2202 | 0.2516 | 0.2537 |
2.3000 | 0.2082 | 0.2270 | 0.2441 | 0.2660 | 0.2672 |
2.4000 | 0.2277 | 0.2325 | 0.2341 | 0.2404 | 0.2408 |
2.5000 | 0.2278 | 0.2363 | 0.2408 | 0.2463 | 0.2466 |
2.6000 | 0.2252 | 0.2324 | 0.2365 | 0.2517 | 0.2526 |
4. 组合计算
在本节中,我们假设客户已经拥有了自己的期权头寸,希望利用量化实验室的功能进行风险监控。我们假设有以下的期权头寸:
期权代码 | 数量 | 行权价(¥) | 到期时间 |
---|---|---|---|
10000004 | -7000 | 2.35 | 2015-03-25 |
10000011 | 2000 | 2.20 | 2015-04-22 |
10000027 | 5000 | 2.25 | 2015-06-24 |
10000047 | 3000 | 2.45 | 2015-09-23 |
然后我们构造 OptionBook
:
optionIDs = ['10000011', '10000027', '10000004', '10000047']
amounts = [2000, 5000, -7000, 3000]
optBook = OptionBook(optionIDs, amounts)
print u'期权头寸:'
optBook.description()
期权头寸:
dataDate | dataTime | optionId | instrumentID | contractType | strikePrice | expDate | lastPrice | amount | |
---|---|---|---|---|---|---|---|---|---|
0 | 2015-03-13 | 13:24:58 | 10000004 | 510050C1503M02350 | CO | 2.3500 | March 25th, 2015 | 0.1229 | -7000 |
1 | 2015-03-13 | 13:24:32 | 10000011 | 510050C1504M02200 | CO | 2.2000 | April 22nd, 2015 | 0.2778 | 2000 |
2 | 2015-03-13 | 13:24:52 | 10000027 | 510050P1506M02250 | PO | 2.2500 | June 24th, 2015 | 0.0450 | 5000 |
3 | 2015-03-13 | 13:24:52 | 10000047 | 510050C1509M02450 | CO | 2.4500 | September 23rd, 2015 | 0.1889 | 3000 |
4.1 使用Black插值模型计算组合风险
optBook.riskReport(volInterpolatorVariance)
optionId | vol | price | delta | gamma | rho | theta | vega | |
---|---|---|---|---|---|---|---|---|
0 | 10000004 | 0.2060 | -860.3000 | -6370.8417 | -12316.8687 | -488.8540 | 1592.3418 | -508.3851 |
1 | 10000011 | 0.2634 | 555.6000 | 1828.2807 | 1456.7054 | 433.8000 | -307.9681 | 256.2961 |
2 | 10000027 | 0.2484 | 220.5000 | -1103.5286 | 4552.0335 | -831.0864 | -856.2742 | 1945.3136 |
3 | 10000047 | 0.2509 | 566.7000 | 1659.5347 | 2626.2983 | 1876.5865 | -503.9843 | 2135.1356 |
portfolio | NaN | nan | 482.5000 | -3986.5549 | -3681.8315 | 990.4461 | -75.8848 | 3828.3602 |
4.2 使用SABR模型组合风险
optBook.riskReport(volInterpolatorSABR)
optionId | vol | price | delta | gamma | rho | theta | vega | |
---|---|---|---|---|---|---|---|---|
0 | 10000004 | 0.2157 | -865.4365 | -6301.5462 | -12703.7735 | -483.0602 | 1800.8937 | -549.0791 |
1 | 10000011 | 0.2523 | 552.8686 | 1845.2432 | 1405.9255 | 438.6890 | -272.7679 | 236.9632 |
2 | 10000027 | 0.2347 | 194.1368 | -1048.6009 | 4677.9921 | -785.3771 | -785.2668 | 1888.5079 |
3 | 10000047 | 0.2511 | 566.9933 | 1659.5667 | 2624.8517 | 1876.4726 | -504.2584 | 2135.1279 |
portfolio | NaN | nan | 448.5622 | -3845.3372 | -3995.0043 | 1046.7243 | 238.6007 | 3711.5199 |
4.3 使用SVI模型组合风险
optBook.riskReport(volInterpolatorSVI)
optionId | vol | price | delta | gamma | rho | theta | vega | |
---|---|---|---|---|---|---|---|---|
0 | 10000004 | 0.2126 | -863.7639 | -6323.4081 | -12591.1718 | -484.8898 | 1734.2876 | -536.4362 |
1 | 10000011 | 0.2634 | 555.6000 | 1828.2807 | 1456.7054 | 433.8000 | -307.9681 | 256.2961 |
2 | 10000027 | 0.2355 | 195.6318 | -1051.9049 | 4670.9045 | -788.1010 | -789.3710 | 1892.0017 |
3 | 10000047 | 0.2495 | 563.6855 | 1659.2077 | 2641.2567 | 1877.7596 | -501.1669 | 2135.2142 |
portfolio | NaN | nan | 451.1534 | -3887.8246 | -3822.3052 | 1038.5689 | 135.7815 | 3747.0758 |
5 比较不同模型的拟合市场数据的能力
这里我们比较不同的模型,对于市场数据的拟合能力。这里我们可以观察到单论你和能力 BlackVarianceSurface > SviCalibratedVolSruface > SABRCalibratedVolSruface
。这里我们并不想下这样的结论:这些模型的优劣也有相同的排序。
另一个我们可以观察到的现象,对于近月合约(流动性最好),波动率微笑是最规则的。在这个期限上,三种模型的拟合都很到位。随着期限的上升,流动性的下降,买卖价差也随之扩大。这时候波动率微笑变得愈发不规则,这个时候一个完美拟合至市场的模型是否必要,是一个很大的问题:如果市场报价并不理性,一个优秀的模型应该可以指出这种不合理点,而不是简单的接受市场的非理性。
from matplotlib import pylab
strikes = sorted(analyticResult['strikePrice'].unique())
expiries = [Date(2015,3,25),Date(2015,4,25),Date(2015,6,25),Date(2015,9,25)]
maturity = [(date - EvaluationDate())/ 365.0 for date in expiries]
volSurfaces = [volInterpolatorSABR, volInterpolatorSVI]
def plotModelFitting(index, volSurfaces, legends = ['Market Quote', 'SABR', 'SVI']):
# Using Black variance surface to extrace the rar wolatility
data = volInterpolatorVariance.volatility(strikes, maturity[index], True)
pylab.plot(strikes, data, 'r+-.', markersize = 8)
for s in volSurfaces:
data = s.volatility(strikes, maturity[index], True)
pylab.plot(strikes, data)
pylab.xlabel('Strike')
pylab.ylabel('Volatility')
pylab.legend(legends, loc = 'best', fontsize = 12)
pylab.title(u'行权结算日: ' + str(expiries[index]), fontproperties = font, fontsize = 20)
pylab.grid(True)
pylab.subplots(2,2, figsize = (16,14))
for i in range(1,5):
pylab.subplot('22' + str(i))
plotModelFitting(i-1, volSurfaces)