文章目录
期权Delta对冲:模拟实验
1. 模拟参数设定
假定买入一个欧式平值认购期权,一年后到期,行权价为100,隐含波动率为20%,实际波动率为30%,无风险利率为5%。本文将对冲1000次,根据不同的价格路径模拟标准delta对冲过程十次。本实验基于BS公式与其假设条件(波动率是固定不变的)。
2. Monte Carlo模拟标的价格路径
假设标的资产价格服从几何布朗运动:
d
S
=
μ
S
d
t
+
σ
S
d
z
,
d
z
=
ϵ
d
t
dS = \mu S dt +\sigma S dz, dz = \epsilon \sqrt{dt}
dS=μSdt+σSdz,dz=ϵdt
由于风险中性的假设存在,其中
μ
=
r
\mu = r
μ=r,
μ
\mu
μ是标的资产价格收益的均值,
σ
\sigma
σ是标的资产价格收益的年化标准差,
ϵ
\epsilon
ϵ服从
N
(
0
,
1
)
N(0,1)
N(0,1)的正态分布。
根据伊藤引理:
有伊藤过程
d
x
=
a
(
t
,
x
)
d
t
+
b
(
t
,
x
)
d
z
dx = a(t,x)dt+b(t,x)dz
dx=a(t,x)dt+b(t,x)dz,其中dz服从维纳过程
G(x,t)服从以下过程 :
d
G
=
(
∂
G
∂
x
a
+
∂
G
∂
t
+
1
2
∂
2
G
∂
x
2
b
2
)
d
t
+
∂
G
∂
z
b
d
z
dG = (\frac{\partial G}{\partial x}a +\frac{\partial G}{\partial t} +\frac{1}{2} \frac{\partial^2 G}{\partial x^2}b^2)dt+\frac{\partial G}{\partial z}bdz
dG=(∂x∂Ga+∂t∂G+21∂x2∂2Gb2)dt+∂z∂Gbdz
若
G
=
ln
S
G=\ln S
G=lnS,则
∂
G
∂
x
=
1
S
,
∂
2
G
∂
x
2
=
−
1
S
2
,
∂
G
∂
t
=
0
\frac{\partial G}{\partial x} =\frac{1}{S}, \frac{\partial^2 G}{\partial x^2}=-\frac{1}{S^2}, \frac{\partial G}{\partial t}=0
∂x∂G=S1,∂x2∂2G=−S21,∂t∂G=0,可以推出:
d
G
=
d
(
ln
S
)
=
(
μ
−
σ
2
2
)
d
t
+
σ
d
z
S
T
=
S
0
e
x
p
(
(
μ
−
σ
2
2
)
T
+
σ
ϵ
T
)
dG =d(\ln S)=(\mu - \frac{\sigma^2}{2})dt + \sigma dz \\ S_T = S_0 exp((\mu - \frac{\sigma^2}{2})T + \sigma \epsilon \sqrt{T})
dG=d(lnS)=(μ−2σ2)dt+σdzST=S0exp((μ−2σ2)T+σϵT)
模拟标的价格的代码如下:
stock_price_paths = init_stock_price * np.exp(
np.cumsum((risk_free_rate - 0.5 * actual_volatility ** 2) * dt + actual_volatility * sqrt(dt) * random_seed,axis=0))
3. 利用BS计算delta和期权理论价值
Black-sholes公式如下所示:
def get_delta(S, T, K, sigma, rf, option_type):
if option_type == "Call":
n = 1
else:
n = -1
d1 = (np.log(S / K) + (rf + 0.5 * sigma ** 2) * T) / (
sigma * np.sqrt(T))
delta = n * si.norm.cdf(n * d1)
return delta
def get_option_price(S, T, K, sigma, rf, option_type):
d1 = (np.log(S / K) + (rf + 0.5 * sigma ** 2) * T) / (
sigma * np.sqrt(T))
d2 = d1 - sigma * np.sqrt(T)
if option_type == "Call":
option_price = S * norm.cdf(d1) - K * np.exp(-rf * T) * norm.cdf(d2)
else:
option_price = K * np.exp(-rf * T) * norm.cdf(-d2) - S * norm.cdf(-d1)
return option_price
4. 结果呈现
4.1 使用实际波动率进行对冲
使用实际波动率进行对冲,最终的收益是确定的,即 V ( S , t , σ ) − V ( S , t , σ ~ ) V(S,t,\sigma) - V(S,t,\tilde{\sigma}) V(S,t,σ)−V(S,t,σ~),其中S代表标的资产的价格,t代表剩余到期时间, σ \sigma σ代表实际波动率, σ ~ \tilde{\sigma} σ~代表隐含波动率。对冲收益取决于隐含波动率和实际波动率的差。
此外,可以看出每次对冲的收益是不确定的,具有较大的波动性。
4.2 使用隐含波动率进行对冲
使用隐含波动率进行对冲,最终的收益是不确定的,总收益为 1 2 ( σ 2 − σ ~ 2 ) ∫ t 0 T e − r ( t − t 0 ) S 2 Γ i d t \frac{1}{2}(\sigma^2 - \tilde{\sigma}^2) \int_{t_0}^{T} e^{-r(t-t_0)} S^2 \Gamma^i dt 21(σ2−σ~2)∫t0Te−r(t−t0)S2Γidt, 在本次实验中的实际波动率为30%,高于隐含波动率20%,且期权的Gamma值一定为正,对冲的收益一定为正,但收益的值是不确定的。
但是每次对冲的收益是确定的,没有较大的波动。每次对冲的收益为 1 2 ( σ 2 − σ ~ 2 ) S 2 Γ i d t \frac{1}{2}(\sigma^2 - \tilde{\sigma}^2) S^2 \Gamma^i dt 21(σ2−σ~2)S2Γidt
5. 完整代码
# -*- coding: utf-8 -*-
"""
@time:2021/6/24 9:58
@author: Hu Yue
@email: hhhuyue@gmail.com
@file: hedge.py
Note:
"""
from math import sqrt
import scipy.stats as si
import numpy as np
from matplotlib import pyplot as plt
from scipy.stats import norm
# 1.对冲场景设定(无分红)
risk_free_rate = 0.05
implied_volatility = 0.2
actual_volatility = 0.3
init_stock_price = 100
strike_price = 100
strike_style = "European"
option_type = "Call"
T = 1
simulation_steps = 1000 # 每次模拟有1000步
simulation_times = 10 # 模拟10次
dt = 1 / 1000
random_seed = np.random.standard_normal((simulation_steps, simulation_times))
# 2.Monte Carlo模拟标的价格路径 S_t = S_0 * exp((u-0.5*sigma**2)dt+sigma*dz)
stock_price_paths = init_stock_price * np.exp(
np.cumsum((risk_free_rate - 0.5 * actual_volatility ** 2) * dt + actual_volatility * sqrt(dt) * random_seed,axis=0))
# 制作模拟价格走势图表
# plt.plot(stock_price_paths[:, :], lw=1.5)
# plt.rcParams['font.sans-serif'] = ['SimHei']
# plt.xlabel('时间')
# plt.ylabel('价格')
# plt.title('模拟价格走势')
# plt.show()
# 3.delta对冲
def get_delta(S, T, K, sigma, rf, option_type):
if option_type == "Call":
n = 1
else:
n = -1
d1 = (np.log(S / K) + (rf + 0.5 * sigma ** 2) * T) / (
sigma * np.sqrt(T))
delta = n * si.norm.cdf(n * d1)
return delta
def get_option_price(S, T, K, sigma, rf, option_type):
d1 = (np.log(S / K) + (rf + 0.5 * sigma ** 2) * T) / (
sigma * np.sqrt(T))
d2 = d1 - sigma * np.sqrt(T)
if option_type == "Call":
option_price = S * norm.cdf(d1) - K * np.exp(-rf * T) * norm.cdf(d2)
else:
option_price = K * np.exp(-rf * T) * norm.cdf(-d2) - S * norm.cdf(-d1)
return option_price
# 计算每次对冲的delta值
expire_time = (np.ones((simulation_steps, 1)) * dt).cumsum()[::-1] # 倒序
pnl = np.zeros((simulation_steps - 1, simulation_times))
for simulation in range(simulation_times):
# 股票价格
stock_price = stock_price_paths[:, simulation].reshape((simulation_steps, 1))
delta = np.zeros((simulation_steps, 1))
option_price = np.zeros((simulation_steps, 1))
for step in range(simulation_steps):
# 基于实际波动率计算的delta值
delta[step] = get_delta(stock_price[step], expire_time[step], strike_price, actual_volatility, risk_free_rate,option_type)
# 基于隐含波动率计算的delta值
# delta[step] = get_delta(stock_price[step], expire_time[step], strike_price, implied_volatility, risk_free_rate,option_type)
# 基于implied volatility计算出的期权理论价值,也就是市场上期权的价值。
option_price[step] = get_option_price(stock_price[step], expire_time[step], strike_price, implied_volatility,
risk_free_rate,
option_type)
pnl_path = np.diff(option_price, axis=0) - delta[:-1] * np.diff(stock_price, axis=0) - \
risk_free_rate * dt * (option_price[:-1] - delta[:-1] * stock_price[:-1])
pnl[:, simulation] = pnl_path.reshape(simulation_steps - 1)
cum_pnl = pnl.cumsum(axis=0)
# 4.不同价格路径下期权对冲累积收益图
plt.plot(cum_pnl[:, :], lw=1.5)
plt.rcParams['font.sans-serif'] = ['KaiTi', 'SimHei', 'FangSong'] # 汉字字体,优先使用楷体,如果找不到楷体,则使用黑体
plt.rcParams['font.size'] = 12 # 字体大小
plt.rcParams['axes.unicode_minus'] = False # 正常显示负号
plt.xlabel('时间')
plt.ylabel('收益')
plt.title('期权对冲累积收益图')
plt.show()