波动率模型是学界搞期权的重点,BS模型中,使用的是固定的波动率。现在提的较多的是局部波动率模型和随机波动率模型。局部波动率模型是随机波动率模型的一种简化,将波动率定义为标的价格S和时间t的函数sigma(S,t),随机波动率模型中,对波动率描述存在随机项(独立于价格中的随机项)。
局部波动率模型中,常用的是SVI模型(stochastic volatility inspired),SVI模型本质上是描述了波动率微笑曲线,并且增加了一些期权性质上的约束。
我前面研究过一次SVI模型,但由于对python里面最优化函数理解的不透,对外层使用了是穷举法,这个方法显然是不好的,只是让我初次了解这个模型的性质。最近部门一个实习生用matlab实现了一下这个模型,虽然拟合的结果并不是很好,但让我发现原来matlab里面的几个函数,如lsqlin就是二次非线性最优化,而fminsearch的函数,使用的就是Nelder-Mead Simplex方法。
实际上我以前虽然也用matlab做最优化,但是对里面的求解算法实在是没研究,反正直接用就好了。但前面自己用python摸索求解函数的时候,突然觉得自己根本不知道在python里面用什么函数去求解自己要解的最优化方程。
最初以为scipy里面应该有对应的最优化函数,后来发现matlab里面基本的lsqlin在scipy里面就没有实现,scipy最接近的是lsq_liner,但这个函数只能接受上下限,无法接受不等式方程约束,后来发现用凸优化报cvxopt才有希望。但是这个包里面也没有lsqlin函数,不过知识点到这里,搜索一下lsqlin+python关键词就能找到一个俄罗斯人贡献的用python实现的lsqlin代码了。
在这些知识点的基础上,我重新将自己的svi模型实现了一下。
首先是数据源格式
- 合约编码 行权日 行权日 剩余到期时间(日历日) 期权类型 标的收盘价 期权行权价 收盘中间价
- 10000887 20171227 2017-12-27 0.052082192 C 2.865 2.209 0.6624
- 10000888 20171227 2017-12-27 0.052082192 C 2.865 2.258 0.6135
- 10000889 20171227 2017-12-27 0.052082192 C 2.865 2.307 0.56465
- 10000890 20171227 2017-12-27 0.052082192 C 2.865 2.356 0.5158
- 10000891 20171227 2017-12-27 0.052082192 C 2.865 2.405 0.46705
- 10000892 20171227 2017-12-27 0.052082192 P 2.865 2.209 0.00015
- 10000893 20171227 2017-12-27 0.052082192 P 2.865 2.258 0.00015
- 10000894 20171227 2017-12-27 0.052082192 P 2.865 2.307 0.00015
- 10000895 20171227 2017-12-27 0.052082192 P 2.865 2.356 0.0002
- 10000896 20171227 2017-12-27 0.052082192 P 2.865 2.405 0.0003
- 10000897 20171227 2017-12-27 0.052082192 C 2.865 2.16 0.7117
其次是拟合代码
- #!/usr/bin/env python
- # encoding: utf-8
- """
- @version: ??
- @author: laofish
- @contact: laofish@outlook.com
- @site: http://www.laofish.com
- @file: fitSVI.py
- @time: 2018-09-07 23:48
- 拟合SVI曲线
- """
- import traceback
- from scipy.optimize import lsq_linear
- from scipy.optimize import fmin
- from lsqlin import *
- from derivaties_fun2 import *
- from scipy.optimize import least_squares
- # 中文和负号的正常显示
- import socket
- hostName = socket.gethostname()
- if hostName == 'laofish-home-PC':
- plt.rcParams['font.sans-serif'] = ['Yahei Mono'] # mat 2.1
- else:
- plt.rcParams['font.sans-serif'] = ['Microsoft Yahei Mono']
- plt.rcParams['axes.unicode_minus'] = False
- # 设置图形的显示风格
- plt.style.use('ggplot')
- def neicengOptimization(guess, myargs):
- '''内侧优化使用'''
- # SVI模型内层优化
- # m,sigma 为给定值,直接从参数里面得到
- # x 为自变量,即最优化问题里面的x
- # a d c 为系数,即最优化问题里面的c
- m, sigma = guess
- x = myargs[0]
- omg_i = myargs[1]
- # x = lsqlin(C,d,A,b) solves the linear system C*x = d
- # in the least-squares sense subject to A*x ≤ b, where C is m-by-n.
- yx = (x - m) / sigma
- zx = np.sqrt(yx ** 2 + 1)
- omega = max(omg_i)
- # xz = np.array([np.ones([len(x), 1]).T, yx, zx])
- xz = np.array([np.array(np.ones([len(x), 1]).T.tolist()[0]), yx, zx])
- # 实际上可能可以用cvxpy这个凸优化包的使用更为简单
- A = [[0, 0, -1], [0, 0, 1], [0, -1, -1], [0, 1, -1], [0, 1, 1], [0, -1, 1], [-1, 0, 0], [1, 0, 0]]
- # 约束边界b
- b = [0, 4 * sigma, 0, 0, 4 * sigma, 4 * sigma, 0, omega]
- # lsqlin(C, d, reg=0, A=None)
- xmatric = lsqlin(xz.T, omg_i, 0, np.array(A), np.array(b))
- acap = np.array(xmatric['x'])[0][0]
- d = np.array(xmatric['x'])[1][0]
- c = np.array(xmatric['x'])[2][0]
- # [acap, d, c]=lsqlin(xz.T, omg_i, 0, np.array(A), np.array(b))
- # [acap,d,c] = lsqlin(xz, omg_i,A,b)
- a = acap
- b = c / sigma
- rho = d / c
- # 目标函数
- sigma2 = np.sum(np.array(acap + d * yx + c * zx - omg_i) ** 2)
- # return [a,b,rho,sigma2]
- return sigma2
- def neicengOptimization2(guess, myargs):
- '''返回a d c '''
- m, sigma = guess
- x = myargs[0]
- omg_i = myargs[1]
- yx = (x - m) / sigma
- zx = np.sqrt(yx ** 2 + 1)
- omega = max(omg_i)
- # xz = np.array([np.ones([len(x), 1]).T, yx, zx])
- xz = np.array([np.array(np.ones([len(x), 1]).T.tolist()[0]), yx, zx])
- A = [[0, 0, -1], [0, 0, 1], [0, -1, -1], [0, 1, -1], [0, 1, 1], [0, -1, 1], [-1, 0, 0], [1, 0, 0]]
- # 约束边界b
- b = [0, 4 * sigma, 0, 0, 4 * sigma, 4 * sigma, 0, omega]
- # lsqlin(C, d, reg=0, A=None)
- xmatric = lsqlin(xz.T, omg_i, 0, np.array(A), np.array(b))
- acap = np.array(xmatric['x'])[0][0]
- d = np.array(xmatric['x'])[1][0]
- c = np.array(xmatric['x'])[2][0]
- # [acap, d, c]=lsqlin(xz.T, omg_i, 0, np.array(A), np.array(b))
- # [acap,d,c] = lsqlin(xz, omg_i,A,b)
- a = acap
- b = c / sigma
- rho = d / c
- # 目标函数
- # sigma2 = np.sum(np.array(acap + d * yx + c * zx - omg_i) ** 2)
- return [a, b, rho]
- def getfitsiv(x, t2M, a_star, b_star, rho_star, m_star, sigma_star):
- '''生成拟合后的SVI波动率'''
- # 计算拟合值
- fit_omg = a_star + b_star * (rho_star * (x - m_star) + np.sqrt((x - m_star) ** 2 + sigma_star ** 2))
- fsigma = np.sqrt(fit_omg / t2M)
- return fsigma
- if __name__ == '__main__':
- optionData = pd.read_excel('rawOptionData.xlsx')
- strikeArr = pd.unique(optionData['期权行权价'])
- time2Mature = pd.unique(optionData['剩余到期时间(日历日)'])
- ulprice = pd.unique(optionData['标的收盘价'])
- r = 0.04
- S = ulprice[0]
- q = 0
- # 鉴于国内特色,只计算call
- oD = optionData
- vArr = []
- strikeArrE = []
- time2MatureE = []
- cData = pd.DataFrame()
- try:
- # 处理错误
- # step 1
- # 计算期权市场的隐含波动率
- for strike in strikeArr:
- for t2M in time2Mature:
- oprice = oD[(oD['期权行权价'] == strike) & (oD['期权类型'] == 'C')
- & (oD['剩余到期时间(日历日)'] == t2M)]['收盘中间价']
- if oprice.empty == False:
- cimpv = bsmImpVol(S, strike, t2M, r, q, oprice.tolist()[0], 'C')
- else:
- cimpv = 0
- # 这个就是隐含方差
- # total implied variance
- v = cimpv ** 2 * t2M
- vArr.append(v)
- strikeArrE.append(strike)
- time2MatureE.append(t2M)
- cData['K'] = strikeArrE
- cData['t2M'] = time2MatureE
- cData['v'] = vArr
- # 去掉v等于0的元素
- cData2 = cData[cData['v'] != 0]
- # 论文中没提到的是,这里应该一个到期时间一个到期时间的循环
- for t2M in cData2['t2M'].unique():
- # 扣除所需数据
- thisData = cData2[cData2['t2M'] == t2M]
- x = np.log(thisData['K'] / (S * np.exp(r * t2M)))
- omg_i = thisData['v'].values
- # %para为m和sigma的初值
- m = 0.1
- sigma = 0.2
- myargs = np.array([x, omg_i]) # 需要传进去的参数
- # arg_out= fmin(neicengOptimization, para)
- # neicengOptimization(m, sigma, myargs)
- # arg_out = fmin(neicengOptimization, x0=[m, sigma],args=(myargs,))
- guess = [m, sigma]
- arg_out = fmin(neicengOptimization, guess, args=(myargs,))
- # m sigma
- m_star, sigma_star = arg_out
- # 获取a,b,rho
- a_star, b_star, rho_star = neicengOptimization2(arg_out.tolist(), myargs)
- # ===================================
- # 绘制拟合和真是曲线
- k1 = thisData['K'].tolist()
- # 换成隐含波动率比较
- tsigma = np.sqrt(omg_i / t2M)
- fig = plt.figure()
- ax1 = fig.add_subplot(111) # 在图表1中创建子图1
- ax1.scatter(k1, tsigma, color='.25', label='Value')
- # 生成拟合后的曲线
- # xaxis = np.linspace(min(k1), max(k1), 100)
- xaxis = np.linspace(min(k1), max(k1), 100)
- # np.log(thisData['K'] / (S * np.exp(r * t2M)))
- # 行权价转化为实际计算用x
- xbx=[np.log(x / (S * np.exp(r * t2M))) for x in xaxis]
- yaxis = [getfitsiv(xk, t2M, a_star, b_star, rho_star, m_star, sigma_star) for xk in xbx]
- # ax1.plot(xaxis.tolist(), yaxis, color='r--',label='fitValue')
- ax1.plot(xaxis.tolist(), yaxis, 'r--', label='fitValue')
- # 去除图形顶部边界和右边界的刻度
- # ax1.tick_params(top='off', right='off') mat 2.1
- ax1.tick_params(top=False, right=False)
- ax1.set_title('svi模型拟合对比')
- ax1.legend()
- plt.savefig('fitsvi_t2m=' + str(round(t2M, 3)) + '.png')
- plt.close()
- # plt.show()
- # 检测是否在要求阈值内
- print(cData)
- except: # 处理异常
- traceback.print_exc()
- pass
- print(optionData)
最后展示一下拟合的结果

刘主席的三年
突然想写点东西,记录一下刘主席的这三年。
我算是12年开始正式接触证券市场,上交所在12年准备股票期权的仿真,我在迎春路那做虚拟撮合,据说旁边郭树清视察时候关心了股票期权的情况。
郭主席是市场派,是创新派,其在任上,证券公司跟着主席后面推创新业务,每周就有新政策出台,就和刘主席任上,我们每周都能看到抓内幕交易一样。
郭主席对经济金融有研究,对创新业务有激情,每年券商创新大会都搞的很隆重,但治下的指数一直在两千多点晃荡,至其留人,下跌了7%,另外其任上IPO暂停了很长一段时间,市场也不见起色,记得蓝筹具有罕见的投资价值,应该是在其在任上喊出来的。
转眼就迎来了肖主席,肖主席在中行时年轻有为,记得我实习的时候,似乎就看到他对资本市场的一篇点评,主要说的是影子银行的问题,那段时间是国内信托业的第五次高潮,刚兑项目如火如荼。肖主席对创新没有郭主席这么热情,政策上面没觉得出台什么东西,券商创新大会也基本不参加了(当然现在这个会都没什么格局了)。不过其任上出来了50期权,这个是我交易生涯的起步。
肖主席对创新热情不高,但是奈何其任上4万亿的药效过了,后遗症来了。朱镕基总理铺下的新局面,红利终于要被消耗赶紧了,没有那种帕累托式的改进,改革开始要触动利益了。
触动利益的改革总是很困难的,于是刘智囊想到了利用资本市场推进改革这条路,各种资金带着杠杆涌进了中国的股票市场,一时间大爷大妈也跑步入场,中国有十亿人口,中国的公司市值是不是应该比美国的还要大。市梦率在这个时候,似乎并没有多少感情色彩,就是一个技术术语。
终于,指数是不能涨到天上去的,越美好的时光是越短暂的,肖主席看到了指数涨的太快的风险,但是他看到的太晚了,而有人是乐意指数这样涨上去的,“四千点是牛市的新起点”言犹在耳,这个肖主席也难以违背这个上次的喜好的。
当然,从技术上面讲,肖主席有很多工作是可以提前做,是可以好好做的,但又或者是由于我们的资本市场是在太过羸弱,自身的调节能力是在是太差,而上层的意思又是那么的明确,总之,肖主席任上,泡沫被吹大了之后(不一定是他吹大的),但是他戳泡泡的手段太过粗暴,连带整个金融体系都来替他扛雷,譬如小川的央行连续降准降息。
不过既然泡泡不是肖刚吹起来的,吹泡泡的人怪罪戳泡泡的,怎么都有点理不直气不壮,但是后来的熔断,直接就将肖主席赶下了椅子了。
终于等来了刘主席。
刘主席是16年接任肖主席的位子的,当时股灾将尽未尽,又添熔断新片,资本市场刚刚经历了一轮波澜壮阔的大戏,急切的需要休养生息。
刘主席做的第一件事情是注册制暂停,取消了上交所推上去的战略新兴产业版(回头来看主席就是在所谓的战略版上栽了跟头)。
注册制这个事情,实际上也是呼吁了很久了,我印象里面,郭主席任上就喊,IPO不审行不行,肖主席任上,这个事情也一直在推进,写到了人大报告里面。
刘主席对注册制不感冒,实际上我一开始是有反感的,作为在改革开放浪潮中出生长大的人,我们天然的对所有的创新有好感,刚一上任就如此保守,对于我们这种新人来说,没有新业务的驱动,哪里有职业生涯的想象力。
虽然刘主席暂停了注册制,但是刘主席治下,IPO发的比以往都快,能难能可贵的是,由于指数下跌,市场上不断有人呼吁暂停IPO,但是主席顶住了这个压力,对市场的声音有回应,但是还是坚持ipo不暂停,也事实上解决了IPO堰塞湖的问题。虽然股票发的多,但是IPO的审核实际上是更严的,交易所的问询函,都能当财务会计的参考案例。很多公司看看自己的报表觉得过不了,主动撤回了首发申请,这也是IPO排队家数减少的另一个原因。
刘主席做的第二件事情,是老虎妖精害人精,这个词虽然被归为刘主席,但是应该是最高层的意思,这是没得跑了。但是刘主席在拿到这个尚方宝剑之后,各路大鳄的严监管,是切切实实让我看到了一个规范市场的希望。
很多人同情姚员外,同情徐股神,甚至同情那个望北楼的大鳄,对这些人动手,我觉得是鼓掌称道的,但是我觉得无法归功到刘主席身上,他的能量还不够。
我不同情这些人,他们或许真的没有突破既定规则,只是把规则揉捏的出神入化,但是从来没有一个规则是一成不变的,当你的能量到了一定级别,你的政治觉悟务必要跟上。德不配位的话,根基就太不牢靠了。
这些人,跟着杠杆赚钱,在金融里面弄潮,德行上修行太少。反而是互联网里面的两个马,政治觉悟上,马云一直是很高的,15年后,马化腾似乎突然意识到,自己已经不仅仅是一个企业家,这么大一个公司的社会责任也是义不容辞的。
不过也只有他们能这样谈,只有把企业做到对社会影响力无与伦比,这个觉悟才是真领悟吧。携程的梁建章,那只是科班的一种观点,缺乏现实的影响力和行动力。
刘主席的第三件事情,实际上是跟着第二件的,如果说大老虎主席没法大,但是各种狐狸苍蝇,刘主席可没少拍。严管妖股炒作,三涨临停,这个是最为人诟病。但实际上,中国股市里面这些妖股,我是看不惯的,完全是赌博的筹码,没有任何价值,对了,只有流动性价值。在刘主席治下,创业板是跌的稀里糊涂,但是某些被妖精炒作起来的大股票,还是涨了不少。当然18年之后,外界经济环境的变化,这个市场下跌,这又是另一个事情。
刘主席的第四件事情就是对指数的维护,这个被很多机构诟病,实际上,这也能看出屁股做的地方不一样。散户觉得不让他追涨停,就是断了发财的路,但是追涨停板能赚钱,那是头部效应,亏钱的小散不会发帖,只有赵老哥在耀武扬威。机构对打压涨停没什么意见,毕竟党委领导下的机构,可是不能参与这个游戏的。但是维护指数这个情,动不动就不然买,还有净卖出限制。
当18年10月份,证监会出台消息说,要减少对市场干预,刘主席在认错了,实际上大概已经知道自己在证监会待不久了。
其实17年就已经传易主席要接任,但奇怪的是,现在找不到那种新闻了,大概是因为被证实为谣言,各种渠道都自觉的删干净了,但实际上,微博上还是有痕迹的。
17年的风波抗过去了,以为19大后能高升央行行长,或者外放一方诸侯,但不知是运作的问题,还是想继续治理资本市场,但18年的独角兽和CDR,终于让自己摔了跟头,主席终于还是在19年让出来了。