最近在学习delta对冲的相关内容,找到一篇财通证券在19年发布的《金融工程:场外期权专题之三——期权对冲方案设计》研报,里面有提到波动率恒定情况下的对冲模拟实验。
研报链接如下:
2019-04-21_财通证券_场外期权专题之三:期权对冲方案设计 - 道客巴巴 (doc88.com)http://www.doc88.com/p-1901752947005.html
原文提到期权的对冲成本主要分为 3 部分:
第一部分来自于动态持有 delta 份股指期货带来的资金损益。delta 对冲在具体的操作中就是 delta 升高的时候买入股指期货,delta 降低的时候卖出股指期货,那么,在这一过程中由于高买低卖产生的损失以及到期日的支付 K*(sign(s-k))就近似于期权费。
第二部分来自于调整股指期货持仓产生的交易费用。由于期权 delta 在股价出现变动时会动态调整,那么,由于每天股指期货的持仓 都会出现变化,期权复制会带来一笔交易费用。
对于这 1000 条路径,我们分别计算了每条路径相应的期权对冲组合的对冲损益,交易成本,资金占用成本以及无法被对冲的期权 Gamma 与 Theta 损益。
原文对冲结果如下:
因此 我希望也进行一个对冲模拟实验,其中gamma损益和theta损益部分我参照了两篇知乎文章,基本公式为
期权价格变动之Greek字母归因分析 - 知乎 (zhihu.com)https://zhuanlan.zhihu.com/p/125100275话不多说,直接上代码,,,
首先是关于BSM的模型,之前的文章提到了delta和看涨期权价值的BSM模型代码,下面是关于gamma和theta_call的代码
from math import log, sqrt, exp
from scipy import stats
import numpy as np
class BSMOptionValuation:
def __init__(self, S0, K, T, r, sigma, div=0.0)
self.S0 = float(S0)
self.K = float(K)
self.T = float(T)
self.r = float(r)
self.sigma = float(sigma)
self.div = float(div)
self.d1 = ((log(self.S0 / self.K) + (self.r - self.div + 0.5 * self.sigma ** 2) * self.T) / (self.sigma * sqrt(self.T)))
self.d2 = self.d1 - self.sigma * sqrt(self.T)
def gamma(self):
gamma = exp(-self.div * self.T) * stats.norm.pdf(self.d1) / (self.S0 * self.sigma * sqrt(self.T))
return gamma
def theta(self):
self.theta_part1 = self.div * self.S0 * exp(-self.div * self.T) * stats.norm.cdf(self.d1)
self.theta_part2 = self.r * self.K * stats.norm.cdf(self.d2)*exp(-self.r * self.T)
self.theta_part3 = (self.S0 * exp(-self.div * self.T) * stats.norm.pdf(self.d1) * self.sigma) / (2 * sqrt(self.T))
theta_call = self.theta_part1 - self.theta_part2 - self.theta_part3
theta_put = theta_call + self.r * self.K * exp(-self.r * self.T) - self.div * self.S0 * exp(-self.div * self.T)
return theta_call,theta_put
然后开始蒙特卡洛模拟实验,代码如下:
import math
import datetime
import numpy as np
import pandas as pd
from scipy.stats import norm
from bsm import *
import matplotlib.pyplot as plt
if __name__ == '__main__':
# 图像绘制基本设置
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
plt.rcParams['xtick.direction'] = 'in'
plt.rcParams['ytick.direction'] = 'in'
# 1.波动率恒定模型下对冲模拟
# 给定期权参数
S0 = 1 # 标的初始价格
K = 1 # 标的行权价
T = 0.25 # 期权有效期
r = 0.05 # 无风险利率
sigma = 0.2 # 波动率
feerate = 6/10000 # 交易费率
option = BSMOptionValuation(S0, K, T, r, sigma) # 构造BSM模型下的初始期权
times = 1000 # 模拟路径数
simulation_steps = 63 # 单条路径步数,等于252/4=63
dt = T / simulation_steps
random_seed = np.random.standard_normal((simulation_steps, times))
# 蒙特卡洛模拟股票价格,并进行绘制
montecarlo_path = S0 * np.exp(np.cumsum((r - 0.5 * sigma ** 2) * dt + sigma * sqrt(dt) * random_seed, axis=0))
initial_row = np.ones((1, times))
stock_price_paths = np.insert(montecarlo_path, 0, values=initial_row, axis=0)
df = pd.DataFrame(stock_price_paths)
df.plot()
plt.legend().remove()
plt.show()
蒙特卡洛模拟结果如图:
接着进行对冲,计算各项成本:
# 初始值和结构设定
initial_delta = option.delta()[0]
initial_gamma = option.gamma()
initial_theta = option.theta()[0]
expire_time= np.append((np.ones((simulation_steps , 1)) * dt).cumsum()[::-1],0)
hedge_account = np.zeros((simulation_steps + 1, times)) # 对冲账户
feerate_account = np.zeros((simulation_steps , times)) # 交易费账户
interest = np.zeros((simulation_steps, times)) # 保证金利息
gamma_account = np.zeros((simulation_steps, times)) # Gamma损益
theta_account = np.zeros((simulation_steps + 1, times)) # Theta损益
delta = np.zeros((simulation_steps + 1, times))
gamma = np.zeros((simulation_steps + 1, times))
theta = np.zeros((simulation_steps + 1, times))
# 模拟1000次
for simulation in range(times):
stock_price = stock_price_paths[:, simulation].reshape((simulation_steps + 1, 1))
for step in range(simulation_steps + 1):
# 开仓
delta[0, simulation] = initial_delta
gamma[0, simulation] = initial_gamma
theta[0, simulation] = initial_theta
hedge_account[0, simulation] = 0
feerate_account[0, simulation] = 0
interest[0, simulation] = delta[0, simulation] * stock_price_paths[0, simulation] * r * dt
gamma_account[0, simulation] = 0
theta_account[0, simulation] = 0
# 对冲
if step in range(1, simulation_steps):
delta[step, simulation] = \
BSMOptionValuation(stock_price_paths[step, simulation], K, expire_time[step], r, sigma).delta()[0]
gamma[step, simulation] = \
BSMOptionValuation(stock_price_paths[step, simulation], K, expire_time[step], r, sigma).gamma()
theta[step, simulation] = \
BSMOptionValuation(stock_price_paths[step, simulation], K, expire_time[step], r, sigma).theta()[0]
hedge_account[step, simulation] = hedge_account[step-1, simulation] - \
delta[step - 1, simulation] * (stock_price_paths[step, simulation] - stock_price_paths[step - 1,simulation])
interest[step, simulation] = interest[step - 1, simulation] + \
delta[step, simulation] * stock_price_paths[step, simulation] * r * dt
feerate_account[step, simulation] = feerate_account[step - 1, simulation] + feerate * \
abs((delta[step, simulation] - delta[step - 1, simulation]) * stock_price_paths[step, simulation])
gamma_account[step, simulation] = gamma_account[step - 1, simulation] + \
0.5 * gamma[step, simulation] * (stock_price_paths[step, simulation] - stock_price_paths[step - 1, simulation]) ** 2
theta_account[step, simulation] = theta_account[step - 1,simulation] + theta[step - 1, simulation] * dt
# 结算
if step == simulation_steps:
if stock_price_paths[step, simulation] > K:
hedge_account[step, simulation] = hedge_account[step - 1, simulation] - delta[step - 1, simulation] * \
(stock_price_paths[step, simulation] - stock_price_paths[step - 1, simulation]) + (stock_price_paths[step, simulation] - K)
elif stock_price_paths[step, simulation] <= K:
hedge_account[step, simulation] = hedge_account[step - 1, simulation] - delta[step - 1, simulation] * \
(stock_price_paths[step, simulation] - stock_price_paths[step - 1, simulation])
theta_account[step, simulation] = theta_account[step - 1,simulation] + theta[step - 1, simulation] * dt
# 对冲后得到的各项结果
hedge_cost = sum(hedge_account[-1,:]) / times
feerate_cost = sum(feerate_account[-1, :]) / times
interest_cost = sum(interest[-1, :]) / times
gamma_cost = sum(gamma_account[-1, :]) / times
theta_cost = sum(theta_account[-1, :]) / times
print(hedge_cost,feerate_cost,interest_cost,gamma_cost,theta_cost)
最终结果如下:
C:\Users\ys2005\PycharmProjects\pythonProject1\venv\Scripts\python.exe C:/Users/ys2005/PycharmProjects/pythonProject1/hedge_constant_vol.py
0.03973394785925671 0.0014791526966309774 0.007138575105098588 0.019029334338750092 -0.026088057013953066
我模拟出的结果分别为对冲头寸损益0.0397;交易费0.0015;资金占用费0.0071;Gamma损失为0.0190;Theta损失为-0.0261
正如原文解释,对冲头寸损益为0.0397,低于通过波动率估计得到的期权价格0.0461,其中的差异可以用卖出期权带来的theta安全垫收益超出gamma带来的损失进行解释。
PS:我的theta损益和原文一样,都采用了252个交易日的假设,所以每日的theta损益时长用dt来表示,但是参考知乎大佬的文章解释,其实应该用365个自然日来进行假设,因为期权无时无刻不在decay,因为即便周末也会有信息会被price in,并且资金成本是每天都算的,因此周末虽然market 不开市,但是到了周一,期权的time decay是按照三天算的。