用python计算标普500期权的持有至到期delta对冲收益,参考Bakish(2003)

参考文献:Bakshi, G., and N. Kapadia. “Delta-Hedged Gains and the Negative Market Volatility Risk Premium.” Review of Financial Studies, 16 Bakish (2003), 527–566.

期权持有至到期的delta对冲收益率用途非常多,包括研究波动率风险溢价和衍生品收益率等。我们参考Bakish(2003)计算标普500期权的持有一个月到期收益率,并按照在值程度进行分类分组,然后观察各组的平均收益率。我们使用的数据来自于OptionMetric数据库,包括2021年的标普500期权日度数据,无风险收益率数据。

import Cython
import pandas as pd
import numpy as np

from 数据文件.基本参数 import *


#第一步,读取无风险收益数据并调整格式
risk_less_rate=pd.read_csv(PATH_RISK_LESS_RATE)
#筛选并使用最短天数的无风险收益率,因为每天delta对冲中资金调整频繁,使用短期收益率即可
risk_less_rate.columns=[C.TradingDate,C.RemainingDays,C.RisklessRate]
index=pd.pivot_table(risk_less_rate,index=[C.TradingDate],values=[C.RemainingDays],aggfunc=[np.min])['amin'].reset_index()
risk_less_rate=pd.merge(risk_less_rate,index,on=[C.TradingDate,C.RemainingDays],how='right')
risk_less_rate[C.RisklessRate]/=100


#第二步,读取标的资产数据并调整格式
underlying=pd.read_csv(PATH_UNDERLYING)
# underlying=underlying[underlying['ticker']=='AAPL']
underlying.rename(columns={'close':C.UnderlyingScrtClose},inplace=True)


#第三步,读取期权数据并调整格式
data=pd.read_csv(PATH_SPX_OPTIONS)
#剔除无效列标题
data=data[['secid', 'date', 'symbol', 'symbol_flag', 'exdate', 'last_date',
   'cp_flag', 'strike_price', 'best_bid', 'best_offer', 'volume',
   'open_interest', 'impl_volatility', 'delta', 'gamma', 'vega', 'theta',
   'optionid',
   'ticker']]

#剔除隐含波动率过于离谱的期权数据
data=data.loc[-data[C.ImpliedVolatility].isna(),:]
data=data[(data[C.ImpliedVolatility]>=data[C.ImpliedVolatility].quantile(0.01))
          &(data[C.ImpliedVolatility]<=data[C.ImpliedVolatility].quantile(0.99))]

# 计算期权剩余天数
data[C.RemainingDays] = (pd.to_datetime(data[C.ExerciseDate], format='%Y%m%d')
                         - pd.to_datetime(data[C.TradingDate], format='%Y%m%d')).astype(str).str[
                   :-24].astype(int)

#保留剩余到期时间为30天的期权样本数据
data=data.loc[data[C.RemainingDays]<=30,:]

#将期权数据与无风险利率和标的数据合并
data=pd.merge(data,risk_less_rate[[C.TradingDate,C.RisklessRate]],on=[C.TradingDate])
data=pd.merge(data,underlying[[C.TradingDate,C.UnderlyingScrtClose]],on=[C.TradingDate])

#计算期权收盘价
data[C.ClosePrice]=(data[C.Bid]+data[C.Ask])/2

#计算下一个交易日的收盘价和日期
data=data.sort_values([C.SecurityID,C.TradingDate])
data[C.next_TradingDate]=data[C.TradingDate].shift(-1)
data[C.next_UnderlyingScrtClose]=data[C.UnderlyingScrtClose].shift(-1)
data=data.loc[-data[C.next_UnderlyingScrtClose].isna(),:]

#计算当前交易日与下一个交易日之间的间隔天数
data[C.next_DeltaDays]=(pd.to_datetime(data[C.next_TradingDate], format='%Y%m%d')
                         - pd.to_datetime(data[C.TradingDate], format='%Y%m%d')).astype(str).str[
                   :-24].astype(int)

#剔除有效交易天数低于10的期权样本,比如某些期权样本在经过处理后,一个月只有三四个有效交易日
option_count=pd.pivot_table(data,index=[C.SecurityID],values=[C.ClosePrice],aggfunc=[np.count_nonzero])['count_nonzero'].sort_values(C.ClosePrice)
option_count=pd.DataFrame(option_count).loc[option_count[C.ClosePrice]>=10,:].index
data=data.loc[data[C.SecurityID].apply(lambda x:x in option_count),:]


#为了迅速计算delta对冲收益,直接将期权样本排序平移和错位相减,但这样会把会把第二个期权的初始价格移动至第一个期权的末尾,需要处理!!
data.reset_index(inplace=True)  # 重置索引,就地重置索引,设置inplace参数为True,否则将创建一个新的 DataFrame
data['index'] = data.index  # 重新分配索引
data_drop = pd.pivot_table(data, index=[C.SecurityID], values=['index'], aggfunc=[np.nanmax])[
    'nanmax'].reset_index()  # 插入数据透视表,以合约编码为索引,index对应每一合约最多持有的天数
data = data.loc[set(data.index) - set(data_drop['index']), :]  # 将每一份合约最后一个交易日的数据替换为Nan


#第四步,计算delta对冲的收益
#计算股价变化带来的收益
data[C.gains_stock]=(data[C.next_UnderlyingScrtClose]-data[C.UnderlyingScrtClose])*data[C.Delta]
#计算资金调整带来的无风险收益
data[C.gains_RiskLess]=data[C.RisklessRate]*(data[C.Delta]*data[C.UnderlyingScrtClose]-data[C.ClosePrice])*data[C.next_DeltaDays]/365
#计算期权价格变化收益
index_end=pd.pivot_table(data,index=[C.SecurityID],values=['index'],aggfunc=[np.nanmax])['nanmax']['index'].tolist()#每个期权首个交易日所在行号
index_start = pd.pivot_table(data, index=[C.SecurityID], values=['index'], aggfunc=[np.nanmin])['nanmin']['index'].tolist()#每个期权末尾交易日所在行号
option_start = data.loc[index_start,[C.SecurityID, C.TradingDate, C.ClosePrice]]
option_end = data.loc[index_end, [C.SecurityID, C.TradingDate, C.ClosePrice]]
option_start[C.gains_option]=option_end[C.ClosePrice].values-option_start[C.ClosePrice].values
option_start['ClosePrice_end']=option_end[C.ClosePrice].values

#合并收益数据
gains=pd.pivot_table(data,index=[C.SecurityID],values=[C.gains_stock,C.gains_RiskLess],aggfunc=[np.sum])['sum'].reset_index()
gains=pd.merge(gains,option_start,on=[C.SecurityID])

#计算每个期权样本的总Delta对冲收益
gains[C.gains_Delta]=gains[C.gains_option]-gains[C.gains_stock]+gains[C.gains_RiskLess]
gains=pd.merge(gains,underlying[[C.TradingDate,C.UnderlyingScrtClose]],on=[C.TradingDate])

#计算收益率
gains[C.gains_Delta_to_Stock]=gains[C.gains_Delta]/gains[C.UnderlyingScrtClose]#delta对冲收益/股票价格
gains[C.gains_Delta_to_Option]=gains[C.gains_Delta]/gains[C.ClosePrice]#delta对冲收益/期权价格


#计算不同在值程度组合中的delta中性平均收益
gains = pd.merge(gains, data[[C.TradingDate,C.SecurityID,C.Delta,C.CallOrPut]], on=[C.TradingDate,C.SecurityID])
gains['Delta_bin']=pd.cut(gains[C.Delta],bins=10)

#观察不同组合的收益
print(pd.pivot_table(gains,index=['Delta_bin'],columns=[C.CallOrPut],values=[C.gains_Delta]))
print(pd.pivot_table(gains,index=['Delta_bin'],columns=[C.CallOrPut],values=[C.gains_Delta_to_Stock]))
print(pd.pivot_table(gains,index=['Delta_bin'],columns=[C.CallOrPut],values=[C.gains_Delta_to_Option]))

可以看出,大部分在值程度组合中的收益率均值均为负值:

在这里插入图片描述

在这里插入图片描述

项目存放百度链接:链接:https://pan.baidu.com/s/1AD7yqUidZNGozX_wnWddyw
提取码:p1qq

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

江姐vior

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

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

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

打赏作者

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

抵扣说明:

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

余额充值