(Python)绘制波动率曲面

1.#tushare导入
2.import pandas as pd
3.import datetime
4.import tushare as ts
5.import numpy as np
6.from math import log,sqrt,exp
7.from scipy import stats
8.import plotly
9.import plotly.graph_objects as go
10.import plotly.express as px
11.pro = ts.pro_api(token = '')#输入自己的tushare token
12.plotly.offline.init_notebook_mode(connected=True)
13.#数据提取
14.def extra_data(date): # 提取数据
15.    # 提取沪深300ETF合约基础信息
16.    df_basic = pro.opt_basic(exchange='SSE', fields='ts_code,name,call_put,exercise_price,list_date,delist_date')
17.    df_basic = df_basic.loc[df_basic['name'].str.contains('300ETF')]
18.    df_basic = df_basic[(df_basic.list_date<=date)&(df_basic.delist_date>date)] #提取当天市场上交易期权合约
19.    df_basic = df_basic.drop(['name','list_date'],axis=1)
20.    df_basic['date'] = date
21.    # 提取日线行情数据
22.    df_cal = pro.trade_cal(exchange='SSE', cal_date=date, fields = 'cal_date,is_open,pretrade_date')
23.    if df_cal.iloc[0, 1] == 0:
24.        date = df_cal.iloc[0, 2] # 判断当天是否为交易日,若否则选择前一个交易日
25.    opt_list = df_basic['ts_code'].tolist() # 获取300ETF期权合约列表
26.    df_daily = pro.opt_daily(trade_date=date,exchange = 'SSE',fields='ts_code,trade_date,close')
27.    df_daily = df_daily[df_daily['ts_code'].isin(opt_list)]
28.    df_300etf = pro.fund_daily(ts_code='510300.SH', trade_date = date,fields = 'close')
29.    s = df_300etf.iloc[0, 0] 
30.    # 提取无风险利率数据(用一周shibor利率表示)
31.    df_shibor = pro.shibor(date = date,fields = '2w')
32.    rf = df_shibor.iloc[0,0]/100
33.
34.    # 数据合并
35.    df = pd.merge(df_basic,df_daily,how='left',on=['ts_code'])
36.    df['s'] = s
37.    df['r'] = rf
38.    df = df.rename(columns={'exercise_price':'k', 'close':'c'})
39.
40.#隐含波动率求解模块:二分法
41.def bsm_value(s,k,t,r,sigma,q,option_type):
42.    d1 = ( log( s/k ) + ( r- q+ 0.5*sigma**2 )*t )/( sigma*sqrt(t) )
43.    d2 = ( log( s/k ) + ( r- q - 0.5*sigma**2 )*t )/( sigma*sqrt(t) )
44.    if option_type.lower() == 'c':
45.        value = s*exp( -q*t )*stats.norm.cdf( d1) - k*exp( -r*t )*stats.norm.cdf( d2)
46.    else:
47.        value = k * exp(-r * t) * stats.norm.cdf(-d2) - s*exp( -q*t )*stats.norm.cdf(-d1)
48.    return value
49.
50.def black_value(F,k,t,r,sigma,option_type):
51.    d1 = ( log( F/k ) + ( 0.5*sigma**2 )*t )/( sigma*sqrt(t) )
52.    d2 = ( log( F/k ) + ( -0.5*sigma**2 )*t )/( sigma*sqrt(t) )
53.    if option_type.lower() == 'c':
54.        value = exp( -r*t )*(F*stats.norm.cdf( d1) - k*stats.norm.cdf( d2))
55.    else:
56.        value = exp(-r * t)*(k*stats.norm.cdf(-d2) - F* stats.norm.cdf(-d1))
57.    return value
58.#二分法求隐含波动率
59.def bsm_imp_vol(s,k,t,r,c,q,option_type):
60.    c_est = 0 # 期权价格估计值
61.    top = 1  #波动率上限
62.    floor = 0  #波动率下限
63.    sigma = ( floor + top )/2 #波动率初始值
64.    count = 0 # 计数器
65.    while abs( c - c_est ) > 0.00000001:
66.        c_est = bsm_value(s,k,t,r,sigma,q,option_type) 
67.        #根据价格判断波动率是被低估还是高估,并对波动率做修正
68.        count += 1           
69.        if count > 1000: # 时间价值为0的期权是算不出隐含波动率的,因此迭代到一定次数就不再迭代了
70.            sigma = 0
71.            break
72.        
73.        if c - c_est > 0: #f(x)>0
74.            floor = sigma
75.            sigma = ( sigma + top )/2
76.        else:
77.            top = sigma
78.            sigma = ( sigma + floor )/2
79.    return sigma  
80.def black_imp_vol(F,k,t,r,c,option_type):
81.    c_est = 0 # 期权价格估计值
82.    top = 1  #波动率上限
83.    floor = 0  #波动率下限
84.    sigma = ( floor + top )/2 #波动率初始值
85.    count = 0 # 计数器
86.    while abs( c - c_est ) > 0.00000001:
87.        c_est = black_value(F,k,t,r,sigma,option_type) 
88.        #根据价格判断波动率是被低估还是高估,并对波动率做修正
89.        count += 1           
90.        if count > 1000: # 时间价值为0的期权是算不出隐含波动率的,因此迭代到一定次数就不再迭代了
91.            sigma = 0
92.            break
93.        if c - c_est > 0: #f(x)>0
94.            floor = sigma
95.            sigma = ( sigma + top )/2
96.        else:
97.            top = sigma
98.            sigma = ( sigma + floor )/2
99.    return sigma  
100.def cal_iv(df): # 计算主程序
101.    option_list = df.ts_code.tolist()
102.    
103.    #df['F']=0
104.    #for i in range(len(df)):
105.        #df['F'].iloc[i]=df['s'].iloc[i]*exp(df['r'].iloc[i]*df['r'].iloc[i])
106.    df = df.set_index('ts_code')
107.    alist = []
108.
109.    for option in option_list:
110.        s = df.loc[option,'s']
111.        #F = df.loc[option,'F']
112.        k = df.loc[option,'k']
113.        t = df.loc[option,'t']
114.        r = df.loc[option,'r']
115.        c = df.loc[option,'c']
116.        q = df.loc[option,'q']
117.        option_type = df.loc[option,'call_put']
118.        sigma = bsm_imp_vol(s,k,t,r,c,q,option_type)
119.        #sigma = black_imp_vol(F,k,t,r,c,option_type)
120.        alist.append(sigma)
121.    df['iv'] = alist
122.    return df  
123.    #print(df)
124.#隐含波动率求解方法:牛顿迭代法
125.def bsm_value(s,k,t,r,sigma,option_type):
126.    d1 = ( log( s/k ) + ( r + 0.5*sigma**2 )*t )/( sigma*sqrt(t) )
127.    d2 = ( log( s/k ) + ( r - 0.5*sigma**2 )*t )/( sigma*sqrt(t) )
128.    if option_type.lower() == 'c':
129.        value = (s*stats.norm.cdf( d1) - k*exp( -r*t )*stats.norm.cdf( d2))
130.    else:
131.        value = k * exp(-r * t) * stats.norm.cdf(-d2) - s* stats.norm.cdf(-d1)
132.    return value
133.
134.def bsm_vega(s,k,t,r,sigma):
135.    d1 = log( s/k ) + ( r + 0.5*sigma**2 )*t/( sigma*sqrt(t) )
136.    vega = s*stats.norm.cdf(d1,0.,1.)*sqrt(t)
137.    #print('vega',vega)
138.    return vega
139.
140.#牛顿迭代法求隐含波动率,迭代次数设为100
141.def bsm_call_imp_vol_newton(s, k, t, r, c, sigma_est,option_type, it = 10000):    
142.    for i in range(it):
143.        sigma_est =sigma_est-((bsm_value(s,k,t,r,sigma_est,option_type) - c)/ 
144.                      bsm_vega(s, k, t, r, sigma_est))
145.    return sigma_est
146.
147.def cal_iv(df): # 计算主程序
148.    option_list = df.ts_code.tolist()
149.    df_shibor6 = pro.shibor(date = date,fields = '6m')
150.    rf6 = df_shibor6.iloc[0,0]/100    
151.    df.loc[df['t']<=(186/365),'r']=rf6
152.    df_shibor5 = pro.shibor(date = date,fields = '3m')
153.    rf5 = df_shibor5.iloc[0,0]/100    
154.    df.loc[df['t']<=(93/365),'r']=rf5
155.    df_shibor4 = pro.shibor(date =date,fields = '1m')
156.    rf4 = df_shibor4.iloc[0,0]/100    
157.    df.loc[df['t']<=(31/365),'r']=rf4
158.    df = df.set_index('ts_code')
159.    alist = []
160.    for option in option_list:
161.        s = df.loc[option,'s']
162.        k = df.loc[option,'k']
163.        t = df.loc[option,'t']
164.        r = df.loc[option,'r']
165.        c = df.loc[option,'c']
166.        sigma_est=0.5
167.        option_type = df.loc[option,'call_put']
168.        sigma = bsm_call_imp_vol_newton(s, k, t, r, c, sigma_est, option_type,it = 1000)
169.        alist.append(sigma)
170.    df['iv'] = alist
171.    return df  
172.def data_pivot(df): # 数据透视
173.    df_c=df[(df['call_put']=='C')&(df['k']>df['s'])]
174.    df_p=df[(df['call_put']=='P')&(df['k']<=df['s'])]
175.    df=df_c.append(df_p,sort=False)
176.    df = df.reset_index()
177.    df = df.drop(['ts_code','trade_date','c','s','r','call_put'],axis=1)
178.    df['t'] = df['t']*240
179.    df['t'] = df['t'].astype(int)
180.    df = df.pivot_table(index=["k"],columns=["t"],values=["iv"])
181.    df.columns = df.columns.droplevel(0)
182.    df.index.name = None
183.    df = df.reset_index()
184.    df = df.rename(columns={'index':'k'})
185.    return df
186.
187.def fitting(df): # 多项式拟合    
188.    col_list = df.columns
189.    for i in range(df.shape[1]-1):
190.        x_col = col_list[0]
191.        y_col = col_list[i+1]
192.        df1 = df.dropna(subset=[y_col])
193.        x = df1.iloc[:,0]
194.        y = df1.iloc[:,i+1]
195.        degree = 2
196.        weights = np.polyfit(x, y, degree)
197.        model = np.poly1d(weights)
198.        predict = np.poly1d(model)
199.        x_given_list = df[pd.isnull(df[y_col]) == True][x_col].tolist()
200.        # 所有空值对应的k组成列表
201.        for x_given in x_given_list:
202.            y_predict = predict(x_given)
203.            df.loc[df[x_col]==x_given, y_col] = y_predict
204.    return df
205.
206.def im_surface(df): # 波动率曲面作图
207.    df = fitting(df)    
208.    df = df.set_index('k')
209.    y = np.array(df.index)
210.    x = np.array(df.columns)
211.    fig = go.Figure(data=[go.Surface(z=df.values, x=x, y=y)])
212.    fig.update_layout(scene = dict(
213.                    xaxis_title='剩余期限',
214.                    yaxis_title='执行价格',
215.                    zaxis_title='隐含波动率'),
216.                    width=1400,
217.                    margin=dict(r=20, b=10, l=10, t=10))
218.    plotly.offline.plot(fig)
219.
220.def smile_plot(df): # 波动率微笑作图
221.    df = df.set_index('k')
222.    df = df.stack().reset_index()
223.    df.columns = ['k', 'days', 'iv']
224.    fig = px.line(df, x="k", y="iv", color="days",line_shape="spline")
225.    plotly.offline.plot(fig)
226.
227.def main():
228.    date = '20210401' # 
229.    df = extra_data(date) # 提取数据
230.    df = data_clear(df,date) # 数据清洗
231.    df = cal_iv(df) # 计算隐含波动率
232.    df = data_pivot(df) # 数据透视表
233.    smile_plot(df) # 波动率微笑
234.    im_surface(df)# 波动率曲面
235.    
236.if __name__ == '__main__':
237.    main()
238.    return df

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Bachelor_Hu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值