Delta对冲:一般形式及模拟实验

期权Delta对冲

参考文献:Ahmad, R., & Wilmott, P. (2005). Which free lunch would you like today, sir?: Delta hedging, volatility arbitrage and optimal portfolios. Wilmott, 64-79.

1. 对冲收益的一般形式

假定买入认购期权,标的资产价格为S,剩余到期时间为t,调整标的资产仓位进行对冲至到期,隐含波动率为 σ ~ \tilde{\sigma} σ~,实际波动率为 σ ~ \tilde{\sigma} σ~,用于对冲的波动率为 σ h \sigma_h σh
V ( S , t ; σ h ) − V ( S , t ; σ ~ ) + 1 2 ( σ 2 − σ h 2 ) ∫ t 0 T e − r ( t − t 0 ) S 2 Γ h d t (1) V(S,t;\sigma_h)-V(S,t;\tilde{\sigma}) + \frac{1}{2}(\sigma^2 - \sigma^2_h) \int_{t_0}^{T} e^{-r(t-t_0)S^2} \Gamma^hdt \tag{1} V(S,t;σh)V(S,t;σ~)+21(σ2σh2)t0Ter(tt0)S2Γhdt(1)
每次对冲的收益为:
1 2 ( σ 2 − σ ~ 2 ) S 2 Γ i d t + ( Δ i − Δ h ) ( ( μ − r + D ) S d t + σ S d z ) (2) \frac{1}{2}(\sigma^2 - \tilde{\sigma}^2) S^2 \Gamma^i dt +(\Delta^i - \Delta^h)((\mu - r +D)Sdt +\sigma Sdz) \tag{2} 21(σ2σ~2)S2Γidt+(ΔiΔh)((μr+D)Sdt+σSdz)(2)

标的资产价格服从几何布朗运动 d S = μ S d t + σ S d z dS = \mu Sdt + \sigma S dz dS=μSdt+σSdz,dz是维纳过程, μ \mu μ是标的资产期望收益率, σ \sigma σ是收益率的年化标准差。

其中, Γ i \Gamma^i Γi是基于隐含波动率计算出的期权Gamma值, Δ i , D e l t a h \Delta^i,Delta^h Δi,Deltah分别是基于隐含波动率和实际波动率计算出的期权的delta值。D是股票的分红(连续分红),r是无风险利率。

使用实际波动率进行对冲

上式可以简化为:
V ( S , t ; σ h ) − V ( S , t ; σ ~ ) (3) _ V(S,t;\sigma_h)-V(S,t;\tilde{\sigma}) \tag{3} V(S,t;σh)V(S,t;σ~)(3)

使用隐含波动率进行对冲

上式可以简化为:
1 2 ( σ 2 − σ h 2 ) ∫ t 0 T e − r ( t − t 0 ) S 2 Γ h d t (4) \frac{1}{2} (\sigma^2 - \sigma^2_h) \int_{t_0}^{T} e^{-r(t-t_0)S^2} \Gamma^hdt \tag{4} 21(σ2σh2)t0Ter(tt0)S2Γhdt(4)

收益波动与波动率选择

如果说期权是根据模型定价的(Mark to Model),而不是根据市场定价的(Mark to Market),那么自然应该选择使用实际波动率进行对冲。换句话说,就是定价的波动率其实是实际波动率,可参见2.1节的 σ = σ ~ \sigma = \tilde{\sigma} σ=σ~的对冲收益情景,这种情况下使用实际波动率进行对冲,最终的收益波动为0,且收益与最优期望收益相差较小。

如果期权是根据市场定价的,通常处于风险管理的需要,将基于期权市场价值汇报每天的损益(Profit and Loss),为了避免每天收益的波动率,在这种情况下通常会选择隐含波动率进行对冲。为什么要关心每天的PnL呢?因为如果标准差越大,风险越大,在某一天收益出现较大亏损的可能性就越大,被强行平仓的可能性就会越大,交易员或者投资者需要尽力避免这种极端情况的发生。
如公式(2)所示,每次收益的波动率是由 σ S ∣ Δ i − Δ h ∣ d z \sigma S |\Delta^i - \Delta^h|dz σSΔiΔhdz项引起的,(2)式的标准差可以写为
σ S ∣ Δ i − Δ h ∣ d t (5) \sigma S |\Delta^i - \Delta^h|\sqrt{dt} \tag{5} σSΔiΔhdt (5)
可以看出,每次对冲收益的标准差(风险)与隐含波动率,实际波动率和对冲波动率都有关,如果对冲的波动率越接近实际波动率,风险就会越小。
在这里插入图片描述
对于一个认购欧式期权,还有六个月到期,隐含波动率为20%,对冲波动率为30%,分别计算出的相应Delta值,其与标的资产价格的关系如如上图所示。当价格处于深虚值或者深实值(far in or out of money),两种波动率计算出的Delta值差距不大,而当价格越靠近平值(越靠近行权价时),Delta值的差距较为明显,局部的收益风险较大。
两条曲线相交于:
S = K e x p ( − T − t σ ~ − σ h ( σ ~ ( r − D + σ h 2 / 2 ) − σ h ( r − D + σ 2 / 2 ) ) S = K exp(-\frac{T-t}{\tilde{\sigma}-\sigma^h}(\tilde{\sigma}(r-D+\sigma^{h^2}/2)-\sigma^h(r-D+\sigma^2/2)) S=Kexp(σ~σhTt(σ~(rD+σh2/2)σh(rD+σ2/2))

2. 对冲收益跟对冲波动率的关系

假定买入欧式认购期权,一年到期,行权价 k k k为100,标的资产价格为 100 100 100,无风险利率 r r r=10%,分红D=0, μ \mu μ标的资产的价格期望收益为0。对于每种情况模拟了100次,并求收益的期望值、最大值、最小值和标准差。

2.1 实际波动率= 隐含波动率( σ = σ ~ = 20 % \sigma = \tilde{\sigma} = 20\% σ=σ~=20%

在这里插入图片描述

当实际波动率等于隐含波动率时,无论采用哪个波动率来进行对冲,其期望的收益相对于期权的市场价格(13.3)来说都是比较小的。但是当使用实际波动率0.2进行对冲的时候,收益的标准差最小。最高收益曲线比最低收益曲线更加陡峭。所有的曲线相交于同一点(0.2,0)。

2.2 实际波动率>隐含波动率( σ = 40 % , σ ~ = 20 % \sigma =40\%, \tilde{\sigma} = 20\% σ=40%,σ~=20%

在这里插入图片描述
当实际波动率大于隐含波动率的时候,如果对冲的波动率小于隐含波动率,或高于了0.75左右,很有可能会发生亏损(最低收益低于了0);如果对冲的波动率介于0.2到0.75左右,反而不会亏损。同时可以看出,期望收益对于对冲的波动率是不敏感的。

2.3 实际波动率<隐含波动率( σ = 20 % , σ ~ = 40 % \sigma =20\%, \tilde{\sigma} = 40\% σ=20%,σ~=40%

在这里插入图片描述
当实际波动率小于隐含波动率的时候,如果对冲的波动率小于0.1左右,或高于隐含波动率,很有可能会发生亏损(最低收益低于了0);如果对冲的波动率介于0.1到0.4左右,反而不会亏损。同时可以看出,期望收益对于对冲的波动率是不敏感的。而最低收益曲线比最高收益曲线更加陡峭。

3. 代码实现

主要包括了PriceSimulator和OptionHedge两个类,前者是用来模拟期权的价格路径(基于隐含波动率)和标的资产的价格路径(基于实际波动率),后者则是基于对冲的波动率来计算对冲的delta,并多次进行模拟,得到期权对冲的收益及期望值、标准差、最大值、最小值等。参数设定及调用方式参见main函数。

# -*- coding: utf-8 -*-
"""
@time:2021/6/24 9:58

@author: Hu Yue
@email: hhhuyue@gmail.com
@file: hedge.py
Note:
"""
from math import sqrt
from typing import Type

import scipy.stats as si
import numpy as np
from matplotlib import pyplot as plt
from scipy.stats import norm


class PriceSimulator:

    def __init__(self, S, K, T, rf, cp_type, IV, RV, simulation_steps, expected_return):
        self.simulation_steps = simulation_steps
        self.RV = RV
        self.IV = IV
        self.cp_type = cp_type
        self.rf = rf
        self.T = T
        self.K = K
        self.S = S
        self.mu = expected_return

    def get_option_price(self, S, K, T, 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

    def simulate(self):
        random_seed = np.random.standard_normal((self.simulation_steps, 1))
        dt = self.T / self.simulation_steps

        # Monte carlo模拟 真实的波动率生成标的价格路径
        stock_price = self.S * np.exp(
            np.cumsum((self.mu - 0.5 * self.RV ** 2) * dt + self.RV * sqrt(dt) * random_seed, axis=0))
        option_price = np.zeros((self.simulation_steps, 1))
        expire_time = (np.ones((self.simulation_steps, 1)) * dt).cumsum()[::-1]
        # 期权价格路径基于隐含波动率生成,期权市场价格
        for step in range(self.simulation_steps):
            option_price[step] = self.get_option_price(stock_price[step], self.K, expire_time[step], self.IV,
                                                       self.rf,
                                                       self.cp_type)

        return stock_price, option_price

    def plot(self, price):
        # 制作模拟价格走势图表
        plt.plot(price[:, :], lw=1.5)
        plt.rcParams['font.sans-serif'] = ['SimHei']
        plt.xlabel('时间')
        plt.ylabel('价格')
        plt.title('模拟价格走势')
        plt.show()


class OptionHedge:

    def __init__(self, S, K, T, rf, cp_type, IV, RV, expected_return):
        self.mu = expected_return
        self.RV = RV
        self.IV = IV
        self.cp_type = cp_type
        self.rf = rf
        self.T = T
        self.K = K
        self.S = S
        self.simulation_steps = 1000
        self.dt = 1 / 1000

    def init_price_simulator(self, price_simulator: Type[PriceSimulator], simulation_steps):
        self.simulation_steps = simulation_steps
        self.dt = self.T / simulation_steps
        return price_simulator(self.S, self.K, self.T, self.rf, self.cp_type, self.IV, self.RV, simulation_steps,
                               self.mu)

    def get_delta(self, S, K, T, 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 hedge(self, hedge_volatility, price_simulator: PriceSimulator, simulation_times):
        pnl = np.zeros((self.simulation_steps - 1, simulation_times))
        for simulation in range(simulation_times):
            stock_price, option_price = price_simulator.simulate()

            # 基于对冲波动率计算的delta值
            expire_time = (np.ones((simulation_steps, 1)) * self.dt).cumsum()[::-1]  # 倒序
            delta = np.zeros((simulation_steps, 1))
            for step in range(simulation_steps):
                delta[step] = self.get_delta(stock_price[step], self.K, expire_time[step], hedge_volatility,
                                             self.rf,
                                             self.cp_type)

            pnl_path = np.diff(option_price, axis=0) - delta[:-1] * np.diff(stock_price, axis=0) - \
                       self.rf * self.dt * (option_price[:-1] - delta[:-1] * stock_price[:-1])
            pnl[:, simulation] = pnl_path.reshape(simulation_steps - 1)

        return pnl

    def plot(self, pnl):
        plt.plot(pnl.cumsum(axis=0)[:, :], 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()


if __name__ == '__main__':
    # 参数设定,无分红
    risk_free_rate = 0.1
    expected_return = 0
    implied_volatility = 0.2
    actual_volatility = 0.2

    init_stock_price = 100
    strike_price = 100

    option_type = "Call"

    T = 1
    simulation_steps = 1000  # 每次模拟有1000步
    simulation_times = 100  # 模拟1000次

    # 初始化期权和标的
    option_hedge = OptionHedge(init_stock_price, strike_price, T, risk_free_rate, option_type, implied_volatility,
                               actual_volatility, expected_return)
    # 期权价格和标的资产价格路径模拟器
    price_simulator = option_hedge.init_price_simulator(PriceSimulator, simulation_steps)
    # 多次模拟并进行对冲,对冲的波动率可自行选择
    # pnl = option_hedge.hedge(implied_volatility, price_simulator, simulation_times)
    # option_hedge.plot(pnl)

    # 分析不同波动率对对冲收益的影响
    volatility = np.arange(0, 1, 0.02)
    hedge_pnl = np.ones((len(volatility), 5))
    for i in range(1, len(volatility)):
        pnl = option_hedge.hedge(volatility[i], price_simulator, simulation_times).sum(axis=0)
        expected_profit = np.mean(pnl)
        standard_deviation_profit = np.std(pnl)
        max_profit = np.max(pnl)
        min_profit = np.min(pnl)
        print(volatility[i], expected_profit, standard_deviation_profit, min_profit, max_profit)
        hedge_pnl[i, :] = [volatility[i], expected_profit, standard_deviation_profit, min_profit, max_profit]

    plt.plot(hedge_pnl[1:, 0], hedge_pnl[1:, 1:], lw=1.5)
    plt.rcParams['font.sans-serif'] = ['KaiTi', 'SimHei', 'FangSong']
    plt.rcParams['font.size'] = 12
    plt.rcParams['axes.unicode_minus'] = False
    # plt.xticks(np.arange(0, 1, 0.1))
    plt.xlabel('波动率')
    plt.ylabel('收益')
    plt.title('期权对冲累积收益图')
    plt.legend(["expected profit", "Standard deviation of profit", "Minimum profit", "Maximum profit"], loc=9,
               fontsize=10)

    ax = plt.gca()  # gca:get current axis得到当前轴
    ax.spines['right'].set_color('none')
    ax.spines['top'].set_color('none')
    ax.spines['bottom'].set_position(('data', 0))
    plt.show()

  • 6
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值