如何获取期权市场数据快照

来源:https://uqer.io/community/share/550274e4f9f06c7a9ae9a535

在本文中,我们将通过实际的市场的例子,展示如何在量化实验室中计算和展示期权的隐含波动率微笑。

  1. import pandas as pd
  2. from matplotlib import pylab
  3. pd.options.display.float_format = '{:,>.4f}'.format

1. 获取市场数据

在本节中,我们使用数据API获取数据,并进行一些必要的数据转换。这里我们获取的是实时报价,是本 notebook 运行时的市场快照。

  • dataDate 交易日
  • dataTime 快照时间戳
  • optionId 期权代码
  • instrumentID 期权交易代码
  • contractType 期权类型,CO为看着,PO为看跌
  • strikePrice 行权价
  • expDate 到期日
  • lastPrice 最新价
  1. optionSnapShot = OptionsDataSnapShot()
  2. optionSnapShot[optionSnapShot.expDate == Date(2015,9,23)]
dataDatedataTimeoptionIdinstrumentIDcontractTypestrikePriceexpDatelastPrice
302015-03-1313:24:1210000031510050C1509M02200CO2.2000September 23rd, 20150.3388
312015-03-1313:24:1710000032510050C1509M02250CO2.2500September 23rd, 20150.3019
322015-03-1313:24:2210000033510050C1509M02300CO2.3000September 23rd, 20150.2816
332015-03-1313:24:2710000034510050C1509M02350CO2.3500September 23rd, 20150.2484
342015-03-1313:24:3210000035510050C1509M02400CO2.4000September 23rd, 20150.2070
352015-03-1313:24:3610000036510050P1509M02200PO2.2000September 23rd, 20150.0690
362015-03-1313:24:4110000037510050P1509M02250PO2.2500September 23rd, 20150.0804
372015-03-1313:24:4710000038510050P1509M02300PO2.3000September 23rd, 20150.0955
382015-03-1313:24:5210000039510050P1509M02350PO2.3500September 23rd, 20150.1194
392015-03-1313:24:5810000040510050P1509M02400PO2.4000September 23rd, 20150.1322
462015-03-1313:24:5210000047510050C1509M02450CO2.4500September 23rd, 20150.1889
472015-03-1313:24:5810000048510050P1509M02450PO2.4500September 23rd, 20150.1555
542015-03-1313:24:3210000055510050C1509M02500CO2.5000September 23rd, 20150.1629
552015-03-1313:24:3610000056510050P1509M02500PO2.5000September 23rd, 20150.1900
622015-03-1313:24:3210000063510050C1509M02550CO2.5500September 23rd, 20150.1443
632015-03-1313:24:3610000064510050P1509M02550PO2.5500September 23rd, 20150.2169

2. 计算隐含波动率以及相关Greeks

接着我们可以方便的使用内置函数 BSMImpliedVolatity 计算期权的隐含波动率。

  • price 市场报价或者模型价格
  • delta 期权价格关于标的价格的一阶导数
  • gamma 期权价格关于标的价格的二阶导数
  • rho 期权价格关于无风险利率的一阶导数
  • theta 期权价格关于到期时间的一阶导数(每日)
  • vega 期权价格关于波动率的一阶导数
  1. analyticResult = OptionsAnalyticResult()
  2. analyticResult.loc[:10, ['optionId', 'contractType', 'strikePrice', 'expDate', 'lastPrice', 'vol', 'delta', 'gamma', 'rho', 'theta', 'vega']]
optionIdcontractTypestrikePriceexpDatelastPricevoldeltagammarhothetavega
110000002CO2.2500March 25th, 20150.21840.22590.98860.29470.0730-0.04580.0133
210000003CO2.3000March 25th, 20150.17300.28670.91651.19650.0687-0.29960.0687
310000004CO2.3500March 25th, 20150.12290.21770.89631.84950.0687-0.26700.0806
410000005CO2.4000March 25th, 20150.08140.21660.76763.15040.0596-0.45030.1367
810000009PO2.3500March 25th, 20150.00760.2482-0.13321.9373-0.0111-0.36330.0963
910000010PO2.4000March 25th, 20150.01590.2346-0.24883.0197-0.0207-0.50610.1419
1010000011CO2.2000April 22nd, 20150.27780.27030.90810.74660.2152-0.16610.1347

3. 构造波动率曲面

但是对于市场参与者而言,像刚才这样仅仅观察的线的结构不够。他们需要看到整个市场以到期时间,行权价为轴的波动率曲面(Volatility Surface)。除此之外,他们更想知道,波动率曲面上,那些并不是市场报价点的值,至少是个估计。这样的波动率曲面构造,往往需要依赖某种模型,或者某种插值方法。在这一节中,我们将介绍使用 CAL 中的波动率曲面构造函数。

以下的例子基于 CAL 函数: VolatilitySurfaceSnapShot

3.1 基于SABR模型的波动率曲面

  1. volInterpolatorSABR = VolatilitySurfaceSnapShot(optionType = 'CALL', interpType = 'SABR')
  2. volInterpolatorSABR.plotSurface(startStrike = 2.2,endStrike = 2.6)
  3. volInterpolatorSABR.volalitltyProfileFromPeriods([2.2, 2.3, 2.4, 2.5, 2.6], ['1M', '2M', '3M', '6M', '9M'])
1M2M3M6M9M
2.20000.27200.24060.23270.25310.2545
2.30000.20480.22070.23450.25460.2557
2.40000.22450.23410.23890.25250.2533
2.50000.22410.23280.23810.24790.2484
2.60000.23110.23560.23620.24250.2429

如何获取期权市场数据快照 - 图1

3.2 基于SVI模型的波动率曲面

  1. volInterpolatorSVI = VolatilitySurfaceSnapShot(optionType = 'CALL', interpType = 'SVI')
  2. volInterpolatorSVI.plotSurface(startStrike = 2.2,endStrike = 2.6)
  3. volInterpolatorSVI.volalitltyProfileFromPeriods([2.2, 2.3, 2.4, 2.5, 2.6], ['1M', '2M', '3M', '6M', '9M'])
1M2M3M6M9M
2.20000.27690.24760.23690.25660.2580
2.30000.21210.22230.23400.25350.2545
2.40000.21700.22920.23650.25040.2512
2.50000.22900.23570.23890.24740.2479
2.60000.24010.24170.24130.25080.2514

如何获取期权市场数据快照 - 图2

3.3 基于Balck波动率插值的波动率曲面

  1. volInterpolatorVariance = VolatilitySurfaceSnapShot(optionType = 'CALL', interpType = 'BlackVariance')
  2. volInterpolatorVariance.plotSurface(startStrike = 2.2,endStrike = 2.6)
  3. volInterpolatorVariance.volalitltyProfileFromPeriods([2.2, 2.3, 2.4, 2.5, 2.6], ['1M', '2M', '3M', '6M', '9M'])
1M2M3M6M9M
2.20000.26760.23800.22020.25160.2537
2.30000.20820.22700.24410.26600.2672
2.40000.22770.23250.23410.24040.2408
2.50000.22780.23630.24080.24630.2466
2.60000.22520.23240.23650.25170.2526

如何获取期权市场数据快照 - 图3

4. 组合计算

在本节中,我们假设客户已经拥有了自己的期权头寸,希望利用量化实验室的功能进行风险监控。我们假设有以下的期权头寸:

期权代码数量行权价(¥)到期时间
10000004-70002.352015-03-25
1000001120002.202015-04-22
1000002750002.252015-06-24
1000004730002.452015-09-23

然后我们构造 OptionBook:

  1. optionIDs = ['10000011', '10000027', '10000004', '10000047']
  2. amounts = [2000, 5000, -7000, 3000]
  3. optBook = OptionBook(optionIDs, amounts)
  4. print u'期权头寸:'
  5. optBook.description()
  6. 期权头寸:
dataDatedataTimeoptionIdinstrumentIDcontractTypestrikePriceexpDatelastPriceamount
02015-03-1313:24:5810000004510050C1503M02350CO2.3500March 25th, 20150.1229-7000
12015-03-1313:24:3210000011510050C1504M02200CO2.2000April 22nd, 20150.27782000
22015-03-1313:24:5210000027510050P1506M02250PO2.2500June 24th, 20150.04505000
32015-03-1313:24:5210000047510050C1509M02450CO2.4500September 23rd, 20150.18893000

4.1 使用Black插值模型计算组合风险

  1. optBook.riskReport(volInterpolatorVariance)
optionIdvolpricedeltagammarhothetavega
0100000040.2060-860.3000-6370.8417-12316.8687-488.85401592.3418-508.3851
1100000110.2634555.60001828.28071456.7054433.8000-307.9681256.2961
2100000270.2484220.5000-1103.52864552.0335-831.0864-856.27421945.3136
3100000470.2509566.70001659.53472626.29831876.5865-503.98432135.1356
portfolioNaNnan482.5000-3986.5549-3681.8315990.4461-75.88483828.3602

4.2 使用SABR模型组合风险

  1. optBook.riskReport(volInterpolatorSABR)
optionIdvolpricedeltagammarhothetavega
0100000040.2157-865.4365-6301.5462-12703.7735-483.06021800.8937-549.0791
1100000110.2523552.86861845.24321405.9255438.6890-272.7679236.9632
2100000270.2347194.1368-1048.60094677.9921-785.3771-785.26681888.5079
3100000470.2511566.99331659.56672624.85171876.4726-504.25842135.1279
portfolioNaNnan448.5622-3845.3372-3995.00431046.7243238.60073711.5199

4.3 使用SVI模型组合风险

  1. optBook.riskReport(volInterpolatorSVI)
optionIdvolpricedeltagammarhothetavega
0100000040.2126-863.7639-6323.4081-12591.1718-484.88981734.2876-536.4362
1100000110.2634555.60001828.28071456.7054433.8000-307.9681256.2961
2100000270.2355195.6318-1051.90494670.9045-788.1010-789.37101892.0017
3100000470.2495563.68551659.20772641.25671877.7596-501.16692135.2142
portfolioNaNnan451.1534-3887.8246-3822.30521038.5689135.78153747.0758

5 比较不同模型的拟合市场数据的能力

这里我们比较不同的模型,对于市场数据的拟合能力。这里我们可以观察到单论你和能力 BlackVarianceSurface > SviCalibratedVolSruface > SABRCalibratedVolSruface。这里我们并不想下这样的结论:这些模型的优劣也有相同的排序。

另一个我们可以观察到的现象,对于近月合约(流动性最好),波动率微笑是最规则的。在这个期限上,三种模型的拟合都很到位。随着期限的上升,流动性的下降,买卖价差也随之扩大。这时候波动率微笑变得愈发不规则,这个时候一个完美拟合至市场的模型是否必要,是一个很大的问题:如果市场报价并不理性,一个优秀的模型应该可以指出这种不合理点,而不是简单的接受市场的非理性。

  1. from matplotlib import pylab
  2. strikes = sorted(analyticResult['strikePrice'].unique())
  3. expiries = [Date(2015,3,25),Date(2015,4,25),Date(2015,6,25),Date(2015,9,25)]
  4. maturity = [(date - EvaluationDate())/ 365.0 for date in expiries]
  5. volSurfaces = [volInterpolatorSABR, volInterpolatorSVI]
  6. def plotModelFitting(index, volSurfaces, legends = ['Market Quote', 'SABR', 'SVI']):
  7. # Using Black variance surface to extrace the rar wolatility
  8. data = volInterpolatorVariance.volatility(strikes, maturity[index], True)
  9. pylab.plot(strikes, data, 'r+-.', markersize = 8)
  10. for s in volSurfaces:
  11. data = s.volatility(strikes, maturity[index], True)
  12. pylab.plot(strikes, data)
  13. pylab.xlabel('Strike')
  14. pylab.ylabel('Volatility')
  15. pylab.legend(legends, loc = 'best', fontsize = 12)
  16. pylab.title(u'行权结算日: ' + str(expiries[index]), fontproperties = font, fontsize = 20)
  17. pylab.grid(True)
  18. pylab.subplots(2,2, figsize = (16,14))
  19. for i in range(1,5):
  20. pylab.subplot('22' + str(i))
  21. plotModelFitting(i-1, volSurfaces)

如何获取期权市场数据快照 - 图4