前言

这其实是我们一次课程作业,以上证50ETF期权为例说明波动率微笑现象。按习惯我先上网搜了一下看有没有前辈写过这样的代码,毕竟重复造轮子不好嘛。没想到真的有,原文链接:使用plotly作图,生成可交互式图像。

利用tushare自动拉取数据,计算某日所有50ETF期权的隐含波动率,同时可以生成标准的DataFrame数据。

借鉴

可生成波动率微笑图和波动率曲面图。

本文同步发布在个人博客,见:使用python计算期权隐含波动率并作图 - Shu's Garden​www.sitstars.com

理论

从期权定价模型本身来说,公式中的波动率指的是未来的波动率数据,这使历史波动率始终存在着较大的缺陷。为了回避这一缺陷,一些学者将目光转向隐含波动率。隐含波动率具体计算思路是:不论用何种理论的理论模型对市场上交易的期权用模型确定其合理的期权价值,一般需要用到6个标准参数:执行价格(K)、到期时间(t)、标的资产价格(S)、利率(rf)、标的资产息票率(q)和波动率。前五个参数可以从市场中和期权合约中获取,只有波动率是未知的参数。因此,将期权市场价格以及除波动率之外的5个参数代入期权定价公式后推导出波动率,由此计算出的波动率称为隐含波动率。因此,隐含波动率是根据期权的市场价格反推出来的波动率,也是市场自身对未来波动率的预期值,是市场参与者通过期权交易的买卖报价对未来波动率达成的共识。上述说明来自蒋祥林《金融衍生工具》

分红率用看涨看跌期权平价关系求出:

将上述参数代入Black-Scholes定价公式,即可求出相应隐含波动率

看涨期权:

看跌期权:

代码实现

导入库

import pandas as pd

import datetime

import tushare as ts

import numpy as np

from math import log,sqrt,exp

from scipy import stats

import plotly.graph_objects as go

import plotly

import plotly.express as px

pro = ts.pro_api()

plotly.offline.init_notebook_mode(connected=True)

提取数据并清洗

def extra_data(date): # 提取数据

# 提取50ETF合约基础信息

df_basic = pro.opt_basic(exchange='SSE', fields='ts_code,name,call_put,exercise_price,list_date,delist_date')

df_basic = df_basic.loc[df_basic['name'].str.contains('50ETF')]

df_basic = df_basic[(df_basic.list_date<=date)&(df_basic.delist_date>date)] # 提取当天市场上交易的期权合约

df_basic = df_basic.drop(['name','list_date'],axis=1)

df_basic['date'] = date

# 提取日线行情数据

df_cal = pro.trade_cal(exchange='SSE', cal_date=date, fields = 'cal_date,is_open,pretrade_date')

if df_cal.iloc[0, 1] == 0:

date = df_cal.iloc[0, 2] # 判断当天是否为交易日,若否则选择前一个交易日

opt_list = df_basic['ts_code'].tolist() # 获取50ETF期权合约列表

df_daily = pro.opt_daily(trade_date=date,exchange = 'SSE',fields='ts_code,trade_date,settle')

df_daily = df_daily[df_daily['ts_code'].isin(opt_list)]

# 提取50etf指数数据

df_50etf = pro.fund_daily(ts_code='510050.SH', trade_date = date,fields = 'close')

s = df_50etf.iloc[0, 0]

# 提取无风险利率数据(用一周shibor利率表示)

df_shibor = pro.shibor(date = date,fields = '1w')

rf = df_shibor.iloc[0,0]/100

# 数据合并

df = pd.merge(df_basic,df_daily,how='left',on=['ts_code'])

df['s'] = s

df['r'] = rf

df = df.rename(columns={'exercise_price':'k', 'settle':'c'})

#print(df)

return df

def data_clear(df): # 数据清洗

def days(df): # 计算期权到期时间

start_date = datetime.datetime.strptime(df.date,"%Y%m%d")

end_date = datetime.datetime.strptime(df.delist_date,"%Y%m%d")

delta = end_date - start_date

return int(delta.days)/365

def iq(df): # 计算隐含分红率

#q = -log((df.settle+df.exercise_price*exp(-df.interest*df.delta)-df.settle_p)/(df.s0))/df.delta

q = -log((df.c+df.k*exp(-df.r*df.t)-df.c_p)/(df.s))/df.t

return q

df['t'] = df.apply(days,axis = 1)

df = df.drop(['delist_date','date'],axis = 1)

# 计算隐含分红率

df_c = df[df['call_put']=='C']

df_p = df[df['call_put']=='P']

df_p = df_p.rename(columns={'c':'c_p','ts_code':'ts_code_p',

'call_put':'call_put_p'})

df = pd.merge(df_c,df_p,how='left',on=['trade_date','k','t','r','s'])

df['q'] = df.apply(iq,axis = 1)

c_list = [x for x in range(8)]+[11]

df_c = df.iloc[:,c_list]

df_p = df[['ts_code_p','trade_date','c_p','call_put_p','k','t','r','s','q']]

df_p = df_p.rename(columns={'c_p':'c','ts_code_p':'ts_code',

'call_put_p':'call_put'})

df_c = df_c.append(df_p)

#print(df_c)

return df_c

计算隐含波动率

因为公式中有正态分布存在,所以我们没办法直接求出解,只能用二分法求出数值解。

#根据BS公式计算期权价值

def bsm_value(s,k,t,r,sigma,q,option_type):

d1 = ( log( s/k ) + ( r -q + 0.5*sigma**2 )*t )/( sigma*sqrt(t) )

d2 = ( log( s/k ) + ( r -q - 0.5*sigma**2 )*t )/( sigma*sqrt(t) )

if option_type.lower() == 'c':

value = (s*exp(-q*t)*stats.norm.cdf( d1) - k*exp( -r*t )*stats.norm.cdf( d2))

else:

value = k * exp(-r * t) * stats.norm.cdf(-d2) - s*exp(-q*t) * stats.norm.cdf(-d1)

return value

#二分法求隐含波动率

def bsm_imp_vol(s,k,t,r,c,q,option_type):

c_est = 0 # 期权价格估计值

top = 1 #波动率上限

floor = 0 #波动率下限

sigma = ( floor + top )/2 #波动率初始值

count = 0 # 计数器

while abs( c - c_est ) > 0.000001:

c_est = bsm_value(s,k,t,r,sigma,q,option_type)

#根据价格判断波动率是被低估还是高估,并对波动率做修正

count += 1

if count > 100: # 时间价值为0的期权是算不出隐含波动率的,因此迭代到一定次数就不再迭代了

sigma = 0

break

if c - c_est > 0: #f(x)>0

floor = sigma

sigma = ( sigma + top )/2

else:

top = sigma

sigma = ( sigma + floor )/2

return sigma

def cal_iv(df): # 计算主程序

option_list = df.ts_code.tolist()

df = df.set_index('ts_code')

alist = []

for option in option_list:

s = df.loc[option,'s']

k = df.loc[option,'k']

t = df.loc[option,'t']

r = df.loc[option,'r']

c = df.loc[option,'c']

q = df.loc[option,'q']

option_type = df.loc[option,'call_put']

sigma = bsm_imp_vol(s,k,t,r,c,q,option_type)

alist.append(sigma)

df['iv'] = alist

return df

多项式拟合填充缺失值

由于部分期限的50etf期权品种较少,所以使用多项式拟合的方法补全这部分数据,由波动率微笑可知,这是一个二次函数,因此令degree = 2

此外,用plotly做3D曲面图时,需要数据格式如下:

因此,用pandas的pivot_table函数进行整理。但是这样生成的数据仍然不符合我们要求,所以先把数据保存到本地,然后再读取作进一步整理。

def data_pivot(df): # 数据透视

df = df.reset_index()

option_type = 'C' # 具有相同执行价格、相同剩余到期时间的看涨看跌期权隐含波动率相等,因此算一个就够了

df = df[df['call_put']==option_type]

df = df.drop(['ts_code','trade_date','c','s','r','call_put','q'],axis=1)

df['t'] = df['t']*365

df['t'] = df['t'].astype(int)

df = df.pivot_table(index=["k"],columns=["t"],values=["iv"])

df = df.reset_index()

df.to_excel(r'iv.xlsx')

print('数据保存成功,请进行修改')

def fitting(df): # 多项式拟合

col_list = df.columns

for i in range(df.shape[1]-1):

x_col = col_list[0]

y_col = col_list[i+1]

df1 = df.dropna(subset=[y_col])

x = df1.iloc[:,0]

y = df1.iloc[:,i+1]

degree = 2

weights = np.polyfit(x, y, degree)

model = np.poly1d(weights)

predict = np.poly1d(model)

x_given_list = df[pd.isnull(df[y_col]) == True][x_col].tolist()

# 所有空值对应的k组成列表

for x_given in x_given_list:

y_predict = predict(x_given)

df.loc[df[x_col]==x_given, y_col] = y_predict

return df

def plot_df(): # 作图时进行的数据清洗

df = pd.read_excel('iv.xlsx',skiprows= 1)

df = df.dropna(subset=['t'])

df = df.drop(['t'],axis = 1)

df = df.rename(columns={'Unnamed: 1':'k'})

return df

作图

def im_surface(): # 波动率曲面作图

df = plot_df()

df = fitting(df)

#df.to_excel('iv_fitting.xlsx')

df = df.set_index('k')

y = np.array(df.index)

x = np.array(df.columns)

fig = go.Figure(data=[go.Surface(z=df.values, x=x, y=y)])

fig.update_layout(scene = dict(

xaxis_title='剩余期限',

yaxis_title='执行价格',

zaxis_title='隐含波动率'),

width=1400,

margin=dict(r=20, b=10, l=10, t=10))

#fig.write_image("fig1.jpg")

plotly.offline.plot(fig)

def smile_plot(): # 波动率微笑作图

df = plot_df()

df = df.set_index('k')

df = df.stack().reset_index()

df.columns = ['k', 'days', 'iv']

fig = px.line(df, x="k", y="iv", color="days",line_shape="spline")

plotly.offline.plot(fig)

综合

def main():

date = '20200515' # 可任意更改日期

df = extra_data(date) # 提取数据

df = data_clear(df) # 数据清洗

df = cal_iv(df) # 计算隐含波动率

data_pivot(df) # 数据透视表

smile_plot() # 波动率微笑

im_surface() # 波动率曲面

if __name__ == '__main__':

main()

效果

python绘制隐含波动率曲面_使用python+tushare计算期权隐含波动率并作图相关推荐

  1. html提交表单使用python计算_使用python+tushare计算期权隐含波动率并作图

    前言 这其实是我们一次课程作业,以上证50ETF期权为例说明波动率微笑现象.按习惯我先上网搜了一下看有没有前辈写过这样的代码,毕竟重复造轮子不好嘛.没想到真的有,原文链接:https://www.ji ...

  2. python绘制樱花洒落_用python绘制樱花树

    黑夜可能漫长,但总会迎来温暖的阳光,三月如期而至,武大的樱花又一次盛开.那么今天就一起来看看怎样在python中画一棵美丽的樱花树- 说到用python画画,那当然就是小乌龟Turtle库了,为啥是t ...

  3. python绘制基因结构图_使用Python绘制GWAS分析中的曼哈顿图和QQ图

    [前言]其实这篇文章是为了简单介绍一下geneview的用法,它是一个Python高级库,建立在matplotlib的基础之上,专门用于基因组数据的可视化,目的是为了使创建高大上(精致)的基因组数据图 ...

  4. python绘制动态图形_让Python绘制一套动态图形给你看看

    选自TowardsDataScience 作者:Costas Andreou 机器之心编译 参与:Jamin.张倩在读技术博客的过程中,我们会发现那些能够把知识.成果讲透的博主很多都会做动态图表.他们 ...

  5. python绘制混淆矩阵_使用python matplotlib绘制混淆矩阵

    使用python matplotlib绘制混淆矩阵 今天使用了python matplotlib包,绘制混淆矩阵.基本代码参考官网教程,在此基础上增加了格网显示. 代码说明: cm - 混淆矩阵的数值 ...

  6. python绘制气象等值线图_利用Python插值绘制等值线图

    最近需要根据有限的站位点绘制插值等值线图,在网上中文搜索一通,只发现了这货Matplot Basemap 画湖北地图.插值.等值线,要么就是对这货的转载,这货不提供数据的形式,但是基本的代码思路还是不 ...

  7. 用python绘制心形_用Python画一颗特别的心送给她

    [前言] 520刚过去了,大家有没有跟自己喜欢的对象在一起呢? 520 当天你还在送 玫瑰花?巧克力?情侣套装?... 小编就想说:你能不能换点新意呢,这些操作已经普通的不能再普通了吧!就像别人来例假 ...

  8. python绘制回形纹_用python画百变风味月饼

    举头望明月,低头思故乡,不知道为什么,现在总是对儿时的事有感而发,回不到的过去,唯有珍惜当下,中秋快乐. 1.首先我们需要导入画图和数据计算的相关库. import numpy as np from ...

  9. python绘制曲线视频_使用Python绘制各种优美简单曲线

    matplotlib是著名的Python绘图库,它提供了一整套绘图API,十分适合交互式绘图.,解决数据分析和可视化问题,其实也是Python的拿手好戏.另外,在数据处理过程中会用到numpy. 例如 ...

  10. python绘制pr曲线图_利用Python中的numpy包实现PR曲线和ROC曲线的计算!

    闲来无事,边理解PR曲线和ROC曲线,边写了一下计算两个指标的代码.在python环境下,sklearn里有现成的函数计算ROC曲线坐标点,这里为了深入理解这两个指标,写代码的时候只用到numpy包. ...

最新文章

  1. ajax长轮询 java web_Ajax长轮询
  2. 整型数据在内存中的存放形式
  3. 实验 4 操作、输出值和数据表实验报告--软件功能测试与性能测试实验
  4. 正则表达式总结之查找
  5. android升级adt和sdk之后无法识别SDK Location的一个解决方式
  6. android耳机孔状态设置,android 耳机系统笔记2 --多媒体设备各种状态
  7. 吴恩达神经网络和深度学习-学习笔记-42-目标检测
  8. AJAX,JSON 夜鹰
  9. 电压放大倍数公式运放_三点出发,学习运算放大器不再“犯难”
  10. Cognos report studio 清单表优化实录
  11. 硬件射频测试和软件的区别,细说拉力试验机软件与硬件之间的区别
  12. matlab 获取axes图片,matlabaxes显示图片
  13. dell网卡linux驱动,[求助]Linux下dell的无线网卡驱动的安装
  14. 一个简单的apk破解
  15. PC端 VUE 官网项目 前端开发 响应式布局(宽+高 等比例缩放)
  16. 使用u盘如何装linux系统教程视频教程,使用U盘安装Linux系统图解一
  17. widows快捷键大全
  18. 宏观调控绝不是微观控制
  19. 国科大学习资料--最优化计算方法(王晓)--第一次作业答案
  20. 线上教学困难多?来试试轻量级互动课堂方案

热门文章

  1. 19、ADS使用记录之窄带F类功放设计
  2. html 输出helloworld,以及基本结构详解
  3. CAD导入图片怎么操作?简单几步就导入
  4. python简单实现爬取小说《天龙八部》,并在页面本地访问
  5. Amazon教程:刚买就降价!避免损失,申请PRICE MATCH(价格保护)的方法
  6. 练习一: 提示:emp员工表(empno员工号/ename员工姓名/job工作/mgr上级编号/hiredate受雇日期/sal薪金/comm佣金/deptno所属部门编号) dept部门
  7. Mac腾讯会议没声音
  8. 力扣36.有效的数独
  9. Linux环境中的网络分段卸载技术 GSO/TSO/UFO/LRO/GRO
  10. xp系统开机自检很久_xp系统电脑开机硬盘自检时间很长如何处理