IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 人工智能 -> Github代码复现-IVIX中国波指计算 -> 正文阅读

[人工智能]Github代码复现-IVIX中国波指计算

目录

参考资料

VIX介绍

总公式

T的计算:

σ计算:

代码复现


参考资料

数据、代码:GitHub - Alexdachen/ivix: 中国波指的计算

阅读文章:小C:VIX指数的来龙去脉和iVIX的计算方法 - 知乎

数据的介绍:vixDate是计算当日的日期

VIX介绍

VIX计算的是未来30天的加权波动率

总公式

总公式如上图所示,可以看出有2个未知变量T、σ:

T1:VixDate到近月合约到期日之间的时间间隔

T2:VixDate到次近月合约到期日之间的时间间隔

σ1:近月合约贡献的波动率

σ2:次近月合约贡献的波动率

时间间隔T

  • 使用EXE_ENDDATE筛选找到近月和次近月合约
  • 计算VixDate与合约到期日之间的时间间隔T

波动率σ

?未知变量:远期价格F、

:筛选出近月合约和次近月合约后,分别使用这2个月份的数据,计算每个月份下每个执行价格下的看涨期权的价格和看跌期权之间的价格差,选择价格差最小的那个期权的执行价格和看涨期权价格和看跌期权价格来计算远期价格,计算公式如下所示:

:选择离F最近且小于F的期权执行价,找到K0后再进行一次数据筛选,选择执行价格小于K0的看跌期权,选择执行价格大于K0的看涨期权

:区分好近月和次近月合约后,筛选好用于计算的期权数据后,数据按照看涨或者看跌类型排序,这个指标表示执行价格为Ki的期权的上一个期权执行价格与下一个期权执行价格之间的间隔的二分之一,如果这个价格是最高的执行价格或者最低的执行价格,这个指标取执行价Ki和临近执行价的均值。

表示执行价格为Ki的期权价格

R:无风险利率,使用插值法获得。

代码复现

导入库

from datetime import datetime
import numpy as np
import pandas as pd
from scipy.interpolate import make_interp_spline #原代码中的spline已经不兼容了,代码会报错

读取数据

#读取利率数据
shibor_rate = pd.read_csv("shibor.csv",index_col=0,encoding='GBK') #index_col参数注明index列
#读取期权交易数据options_data
options_data = pd.read_csv("options.csv",index_col=0,encoding='GBK')
#读取交易日数据,画图时作为横坐标,一共829天
tradeday = pd.read_csv('tradeday.csv',encoding='GBK')
#读取真实披露的ivix
true_ivix = pd.read_csv("ivixx.csv",encoding='GBK')

筛选当天交易的期权数据

def getHistDayOptions(vixDate,options_data):
    #提取交易日为VixDate的期权数据
    options_data = options_data.loc[vixDate,:] #loc是index索引,提取所有index为vixDate的行
    return options_data

计算近月合约和次近月合约

def getNearNextOptExpDate(options,vixDate):
    #输入:期权交易数据、vixDate
    #找到options中的当月和次月期权到期日
    #如果options中近月合约期权离到期日仅剩7天以内,则选择次近月期权为近月期权
    #返回:近月合约和次近月合约的到期日
    vixDate = datetime.strptime(vixDate,'%Y/%m/%d') #strptime是将字符串格式的日期转换为datetime格式
    #ravel:将到期日期数组去重后放入列表中 
    optionsExpDate = list(pd.Series(options.EXE_ENDDATE.values.ravel()).unique())
    optionsExpDate = [datetime.strptime(i,'%Y/%m/%d %H:%M')for i in optionsExpDate]
    near = min(optionsExpDate)
    optionsExpDate.remove(near) #remove方法是删除元素
    #如果近月合约到期时间小于7天,将选择次近月合约当做近月合约
    if near.day-vixDate.day < 7:
        near = min(optionsExpDate)
        optionsExpDate.remove(near)
    nt = min(optionsExpDate)
    #筛选options中属于近月和次近月合约之间数据
    #near、nt是datetime格式
    return near,nt

无风险利率计算

def periodsSplineRiskFreeInterestRate(options,date):
    #options是date日交易的期权数据
    #返回date到每个到期日exoDate间的无风险利率
    date = datetime.strptime(date,'%Y/%m/%d')
    
    #这个地方的options是vixDate日交易的期权数据
    exp_dates = np.sort(options.EXE_ENDDATE.unique()) #使用sort方法对所有的到期日期进行排序
   
    #periods键是到期日期、值是到期日期与vixDate之间的时间间隔
    periods = {}
    for epd in exp_dates:
        epd = pd.to_datetime(epd)
        periods[epd] = (epd - date).days*1.0/365.0 #datetime格式的数据是一个三元组,时间元组之间求时间间隔
    shibor_date = datetime.strptime(shibor_rate.index[0],"%Y-%m-%d") #shibor_rate.index[0]是指的是第1和索引“2018-07-13 ”
    
    #插值之前先进行判断:
    #shibor是按照时间降序排序,shibor_date是可获取到的最大日期
    #VixDate日期大于shibor_date,使用shibor_date来插值,即“2018-07-13那日的shibor数据
    if date>=shibor_date:
        date_str = shibor_rate.index[0]
        shibor_values = shibor_rate.ix[0].values
    else:#vixDate日期小于shibor_date时,使用VixDate日披露的shibor数据进行插值
        date_str = date.strftime("%Y-%m-%d")
        shibor_values = shibor_rate.loc[date_str].values 
        
    shibor = {}
    period = np.array([1.0,7.0,14.0,30.0,90.0,180.0,270.0,360.0])/360.0
    for p in periods.keys():#之前写成了key报错了
        tmp = periods[p]
        #使用shibor插值
        #使用spline方法会报错:module 'scipy.interpolate' has no attribute 'spline'
        sh = make_interp_spline(period,shibor_values)(tmp)
        #sh = interpolate.spline(period,shibor_values,tmp,order=3)
        shibor[p] = sh/100.0
    return shibor  
#shibor是一个字典,键是时间间隔,值是插值得到的无风险利率

计算价格差距

def getStrikeMinCallMinusPutClosePrice(options):
    #返回同一期权行权价对应的call和put期权价格差
    call = options[options.EXE_MODE==u"认购"].set_index(u"EXE_PRICE").sort_index() #sort_index默认按照行标签升序排列
    put = options[options.EXE_MODE==u"认沽"].set_index(u"EXE_PRICE").sort_index()
    callMinusPut = call.CLOSE-put.CLOSE
    strike = abs(callMinusPut).idxmin() #idxmin()计算能够获得获取到的最小值的索引位置(整数)
    priceDiff = callMinusPut[strike].min()
    return strike,priceDiff

波动率

def calSigmaSquare( options, FF, R, T):
    # 计算某个到期日期权对于VIX的贡献sigma;
    # 输入为期权数据options,FF为forward index price,
    # R为无风险利率, T为期权剩余到期时间
    #输出:近期合约或者远期合约的sigma
    """
    params: options:近月合约和次近月合约的交易数据
            FF: 根据上一步计算得来的strike,然后再计算得到的forward index price, 根据它对所需要的看涨看跌合约进行划分。
                取小于FF的第一个行权价为中间行权价K0, 然后选取大于等于K0的所有看涨合约, 选取小于等于K0的所有看跌合约。
                对行权价为K0的看涨看跌合约,删除看涨合约,不过看跌合约的价格为两者的均值。
            R: 这部分期权合约到期日对应的无风险利率 shibor
            T: 还有多久到期(年化)
    return:Sigma:得到的结果是传入该到期日数据的Sigma
    """
    callAll = options[options.EXE_MODE==u"认购"].set_index(u"EXE_PRICE").sort_index()
    putAll  = options[options.EXE_MODE==u"认沽"].set_index(u"EXE_PRICE").sort_index()
    callAll['deltaK'] = 0.05
    putAll['deltaK']  = 0.05
    
    # 按照看涨、看跌期权排序时,计算执行价格间隔
    index = callAll.index
    if len(index) < 3:#只有2个看涨期权或者1个看涨期权
        callAll['deltaK'] = index[-1] - index[0]
    else:
        for i in range(1,len(index)-1):
            callAll['deltaK'].loc[index[i]] = (index[i+1]-index[i-1])/2.0 #执行价格间隔等于前后两个执行价格之差的一半
        callAll['deltaK'].loc[index[0]] = index[1]-index[0] #第一个和最后一个执行价格使用它们与邻近的执行价格之间的差
        callAll['deltaK'].loc[index[-1]] = index[-1] - index[-2]
       #原代码中的ix需要替换为loc,因为会报 'Series' object has no attribute 'ix' ix替换为loc
    index = putAll.index
    if len(index) < 3:
        putAll['deltaK'] = index[-1] - index[0]
    else:
        for i in range(1,len(index)-1):
            putAll['deltaK'].loc[index[i]] = (index[i+1]-index[i-1])/2.0
        putAll['deltaK'].loc[index[0]] = index[1]-index[0]
        putAll['deltaK'].loc[index[-1]] = index[-1] - index[-2]
    
    call = callAll[callAll.index > FF]
    put  = putAll[putAll.index < FF]
    FF_idx = FF #FF是计算出来的远期价格 FF_idx是K0
    
    if put.empty:#如果用于计算的看跌期权的数据为
        FF_idx = call.index[0]
        callComponent = call.CLOSE*call.deltaK/call.index/call.index
        sigma = (sum(callComponent))*np.exp(T*R)*2/T
        sigma = sigma - (FF/FF_idx - 1)**2/T
    elif call.empty: #如果用于计算的看涨期权数据为空
        FF_idx = put.index[-1]
        putComponent = put.CLOSE*put.deltaK/put.index/put.index
        sigma = (sum(putComponent))*np.exp(T*R)*2/T
        sigma = sigma - (FF/FF_idx - 1)**2/T
    else:
        FF_idx = put.index[-1]
        #当看涨期权和看跌期权都拥有的时候,平值期权被划分为了看跌期权,此时这个期权的价格应该去看涨期权和看跌期权价格的一半
        #我把try-except去掉后,出现setting an array element with a sequence问题
        #去原始数据查看了一下,有这样一种情况:执行价格相同,但是有两个看涨期权收盘价和两个看跌期权,这是因为这是两个不同的合约
        #因为一开始筛选数据是通过日期和执行价格筛选的,不能区分出来,只能通过合约名字看得出来
        #put['CLOSE'].iloc[-1] = (putAll.loc[FF_idx].CLOSE + callAll.loc[FF_idx].CLOSE)/2.0 
        try:
            if len(putAll.loc[FF_idx].CLOSE.values) > 1:
                put['CLOSE'].iloc[-1] = (putAll.loc[FF_idx].CLOSE.values[1] + callAll.loc[FF_idx].CLOSE.values[0])/2.0
        except:
            put['CLOSE'].iloc[-1] = (putAll.loc[FF_idx].CLOSE + callAll.loc[FF_idx].CLOSE)/2.0
        callComponent = call.CLOSE*call.deltaK/call.index/call.index
        putComponent  = put.CLOSE*put.deltaK/put.index/put.index
        sigma = (sum(callComponent)+sum(putComponent))*np.exp(T*R)*2/T
        sigma = sigma - (FF/FF_idx - 1)**2/T
    return sigma

时间转换函数

唯一有点迷糊的是这里为什么要分类讨论,但是不区分又会报错

def changeste(t):
    if t.month>=10:
        str_t = t.strftime('%Y/%m/%d ')+'0:00'
    else:
        str_t = t.strftime('%Y/%m/%d ')
        str_t = str_t[:5]+str_t[6:]+'0:00'
    return str_t
    

计算每日的Vix

def calDayVix(vixDate):
    #提取在vixDate日交易的期权数据
    options = getHistDayOptions(vixDate,options_data)
    #获取近月合约和次近月合约的到期日期,格式为datetime格式
    near,nexts = getNearNextOptExpDate(options,vixDate)
    #提取近期合约期权数据和次近月合约期权数据
    str_near = changeste(near)
    str_next = changeste(nexts)
    optionsNearTerm = options[options.EXE_ENDDATE==str_near]
    optionsNextTerm = options[options.EXE_ENDDATE==str_next]
    #获取vixDate到近月合约和次近月合约之间的无风险利率
    shibor_near = periodsSplineRiskFreeInterestRate(optionsNearTerm,vixDate)
    shibor_next = periodsSplineRiskFreeInterestRate(optionsNextTerm,vixDate)
    R_near = shibor_near[datetime(near.year,near.month,near.day)]
    R_next = shibor_next[datetime(nexts.year,nexts.month,nexts.day)]
    

    #计算剩余到期时间
    vixDate = datetime.strptime(vixDate,'%Y/%m/%d')
    T_near = (near-vixDate).days/365.0
    T_next = (nexts-vixDate).days/365.0
    
    #计算远期价格
    nearPriceDiff = getStrikeMinCallMinusPutClosePrice(optionsNearTerm)
    nextPriceDiff = getStrikeMinCallMinusPutClosePrice(optionsNextTerm)
    near_F = nearPriceDiff[0] + np.exp(T_near*R_near)*nearPriceDiff[1]
    next_F = nextPriceDiff[0] + np.exp(T_next*R_next)*nextPriceDiff[1]
    
    #计算不同到期日期权对于VIX的贡献
    near_sigma = calSigmaSquare(optionsNearTerm,near_F,R_near,T_near)
    next_sigma = calSigmaSquare(optionsNextTerm,next_F,R_next,T_next)
    
    w = (T_next - 30.0/365.0)/(T_next - T_near)
    vix = T_near*w*near_sigma + T_next*(1-w)*next_sigma
    return 100*np.sqrt(abs(vix)*365.0/30.0)

主函数

因为一开始程序有错误,只能计算400多个指数,于是我把日期和指数对应起来放到了一个字典中,下面作图的时候需要列表格式,我重新写了一个格式转换函数

ivix = {}
for day in tradeday['DateTime']:
    #ivix.append(calDayVix(day))
    ivix[day] = calDayVix(day)

绘图

def change2f(old_list):
    #保留2位小数,是因为画图的时候发现显示数据很乱
    #主函数中计算出来的数据的指数是series格式,不是list格式,需要转换一下
    mid_np = np.array(old_list)                    #列表转数组
    mid_np_2f = np.round(mid_np,2)                 #对数组中的元素保留两位小数
    new_list = list(mid_np_2f)                     #数组转列表
    return new_list

#画图
#pyecharts因为原代码使用的版本不兼容,需要用以下方式导入,是去看pyecharts的官方文档的例子写的
from pyecharts.charts import Line
from pyecharts import options as opts
datetime = list(tradeday['DateTime'])
data1 = true_ivix[u"收盘价(元)"]
data1 = change2f(data1)
data2 = list(ivix.values())
data2 = change2f(data2)
line1 = Line()
line1.add_xaxis(datetime)
line1.add_yaxis(series_name='中证指数发布',
               y_axis=data1,
               label_opts=opts.LabelOpts(is_show=False),
               markpoint_opts=opts.MarkPointOpts(
            data=[opts.MarkPointItem(type_="max", name="最大值"),opts.MarkPointItem(type_="min", name="最小值"),]),
                markline_opts=opts.MarkLineOpts(
            data=[opts.MarkLineItem(type_="average", name="平均值")]
        ))
line1.add_yaxis(series_name='手动计算', 
                y_axis=data2,
                label_opts=opts.LabelOpts(is_show=False),
               markpoint_opts=opts.MarkPointOpts(
            data=[opts.MarkPointItem(type_="max", name="最大值"),opts.MarkPointItem(type_="min", name="最小值"),]),
                markline_opts=opts.MarkLineOpts(
            data=[opts.MarkLineItem(type_="average", name="平均值")]
        ))

放一个自己画的图:

  人工智能 最新文章
2022吴恩达机器学习课程——第二课(神经网
第十五章 规则学习
FixMatch: Simplifying Semi-Supervised Le
数据挖掘Java——Kmeans算法的实现
大脑皮层的分割方法
【翻译】GPT-3是如何工作的
论文笔记:TEACHTEXT: CrossModal Generaliz
python从零学(六)
详解Python 3.x 导入(import)
【答读者问27】backtrader不支持最新版本的
上一篇文章      下一篇文章      查看所有文章
加:2022-02-04 11:02:36  更:2022-02-04 11:02:58 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 20:28:12-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码