期权专题10:雪球期权(二)(定价应用+主要参数分析)

   

目录

1. 定价应用

1.1 定价比对

1.2 模拟估值

2. 主要参数分析

2.1 模拟次数

2.2 剩余期限

2.3 波动率


    免责声明:本文由作者参考相关资料,并结合自身实践和思考独立完成,对全文内容的准确性、完整性或可靠性不作任何保证。同时,文中提及的数据仅作为举例使用,不构成推荐;文中所有观点均不构成任何投资建议。请读者仔细阅读本声明,若读者阅读此文章,默认知晓此声明。

    在期权专题9中,分享了雪球期权的定价思路及相应的代码实现。本期主要分享一下定价的应用以及主要参数对雪球期权的影响。

1. 定价应用

1.1 定价比对

    在期权专题9中,介绍了雪球存在两种状态下的定价模式:过去发生过敲入和过未发生过敲入。现在对这两种模式就行探讨。假设雪球已经运行了4个月(84天),分别作出标的在不同价格下(价格区间设置为0.73到1.05),两种估值模式对应的估值。为了便捷,将期权专题9的代码打包放在Pricing_model的py中(对应文件夹名为snow_ball)。

from snow_ball.Pricing_model import *
import matplotlib.pyplot as plt

# 雪球要素
r = 0.025
vol = 0.22
residual_day = 168
knock_out = 1.03  # 敲出价格
knock_in = 0.75  # 敲入价格
coupon = 0.2  # 年化票息
lock_time = 3  # 锁定期,单位为月
T = 1  # 期限,折算为年
times = 5000

# 获取两种估值模式下,标的不同价格对应估值
St_list = [0.73 + 0.01 * x for x in range(33)]
in_nav_list = []
out_nav_list = []
for St in St_list:
    print(St)
    price_path = get_s_path(St, r, vol, residual_day, times)
    in_nav = get_snowball_nav('in', coupon, T, r,residual_day, knock_in, knock_out, lock_time, price_path)
    out_nav = get_snowball_nav('out', coupon, T, r,residual_day, knock_in, knock_out, lock_time, price_path)
    in_nav_list.append(in_nav)
    out_nav_list.append(out_nav)
# 作图

plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']
plt.rcParams['axes.unicode_minus'] = False
plt.plot(St_list, in_nav_list, label='发生过敲入')
plt.plot(St_list, out_nav_list, label='未发生过敲入')
plt.title('雪球估值模式比对(变量为标的价格)')
plt.legend()
plt.show()

  对应的结果为:

     由上图可以看出:在敲入线(75%)到敲出线(103%)之间,发生敲入情况下的定价估值会远低于未发生敲入情况下的估值。对于发生过敲入的雪球,只有当标的价格临近敲出线时,才存在获利的可能,因此其估值基本是是趋近于标的的价格。对于未发生过敲入的雪球,随着标的价格的上涨,其发生敲入的概率会越来低,因此估值呈现非线性的增长,在临近敲出线附近时,因为触发敲出的概率加大,获取全额票息的概率降低,因此其估值增速会放慢,但整体的预期收益会高于敲出对应的票息(依然存在获取全额票息的可能)。

   接下来,假设标的价格为0.9,雪球运行了200天,以剩余期限作为自变量,比较两种估值的差异。

     由上图可以看出:随着剩余期限接近于0,发生敲入情况下的定价估值会远低于未发生敲入情况下的估值。对于发生过敲入的雪球,假设标的价格一直在0.9,随着到期日的临近,其发生敲出的概率会越来越低,因此其估值接近于0.9;对于未发生过敲入的雪球,假设标的价格一直在0.9,随着到期日的临近,其大概率可以获得全额的票息,因此估值接近于1.2。

    综上,未发生过敲入的定价整体会高于发生过敲入的定价,原因主要有两个:1. 发生敲入后,不具备获取全额票息(未敲入敲出)的可能;2. 发生敲入后,意味指数已经下跌25%,未来发生敲出的概率很低。在应用过程中,首先要判断雪球当前的状态,然后使用不同的估值模式。

1.2 模拟估值

    此处以中证500为标的,选取2018年1月18日到2019年1月18日的数据,进行模拟估值的演示。需要注意,由于本文采取的是相对简单的估值处理(尤其是对于日期的处理),因此估值会存在一定的误差,此方法更适合理解估值逻辑以及做回测。

   首先,使用akshare获取中证500的收盘价数据,并对其进行归一处理,同时生成相应的剩余日期序列。

import akshare as ak
import pandas as pd

# 获取数据,进行净值归一
code = 'sh000905'
st, et = '2018-01-18', '2019-01-18'
data = ak.stock_zh_index_daily_em(symbol=code).sort_values(by=['date'], ascending=True)
index_df = data.loc[(data['date'] >= st) & (data['date'] <= et)]
gy_nav = round(index_df['close'] / index_df['close'].values[0], 3)
new_index = pd.DataFrame({'日期': index_df['date'], '净值': gy_nav})
# 增加剩余期限
new_index['剩余期限'] = [len(new_index) - x for x in range(len(new_index))]

     对应得到的结果为:

   接下来,判断估值节点的对应的状态,即是否发生敲入,需要注意的是一但某个节点发生敲入,则后续的状态均是敲入;同时还需要判断整个过程是否有发生敲出(从实际数据来看,无敲出情况,可以使用实际的日期来作为判断,这里可以使用相应的程序来细化实现,此处不再做进一步的复现)。

# 判断估值节点的状态
def get_status_list(status_list):
    # 一旦发生敲入,将后续的状态全部填充为敲入
    new_list = status_list.copy()
    end = len(status_list)
    for x in range(0, end):
        num = status_list[x]
        if num == 'out':
            pass
        else:
            a = x
            break
    start = a
    new_list[start:end] = ['in' for y in range(0, end - start)]
    return new_list


# 生成状态序列
status_list = ['out' if x >= 0.75 else 'in' for x in new_index['净值']]
# 对状态序列进行判断,并加入净值表格中
new_index['状态'] = get_status_list(status_list)

  对应得到结果为:

   考虑到当前估值的时间区间只有244个交易日,因此get_one_nav函数的参数进行调整。主要是将252参数调整为244,同时每月21天调整为20。此处的主要调整如下:

def get_one_nav(status, coupon, T, r, residual_day, one_path, knock_in, knock_out, lock_time):
    '''
    获取雪球单次的模拟路径下,对应的净值
    :param status: str,雪球过去的状态,'out'表示过去未发生过敲入,'in'表示过去发生过敲入
    :param coupon: int,雪球对应的年化票息,例如0.2
    :param T: int,雪球对应的期限(折算成年),例如1
    :param r: int,无风险利率,例如0.025
    :param residual_day: int,剩余天数,例如252
    :param one_path: 矩阵,单次对应的模拟路径
    :param knock_in: int,雪球对应的敲出价格
    :param knock_out: int,需求对应的敲入价格
    :return: int,预估的雪球净值
    '''
    year_day = 244 # 一年的交易日天数
    month_day = round(year_day/12,0) # 一个月的交易日天数
    
    all_time = T * year_day  # 期限,折算为天

    survival_day = all_time - residual_day  # 已存续期限
    # 价格低于敲入价格的交易日对应的序号
    knock_in_day = np.where(one_path <= knock_in)
    # 价格高于敲出价格的交易日对应的序号
    knock_out_day = np.where(one_path >= knock_out)
    # 上述每个交易日的序号需要加上雪球已存续期限
    new_out_day = knock_out_day[0] + survival_day
    # 判断上述日期是否是观察日,1年252个交易日,因此一个月设定为12
    obs_may_day = new_out_day[new_out_day % month_day == 0]
    # 由于有锁定期,需要剔除前三个月的观察日
    obs_day = obs_may_day[obs_may_day /month_day > lock_time]

    # 过去未发生敲入
    if status == 'out':
        # 情况1:未来发生过敲出
        if len(obs_day) > 0:
            t = obs_day[0]
            re = coupon * (t / year_day) * np.exp(-r * t / year_day)
            nav = 1 * (1 + re)  # 1表示期初的净值
        else:
            # 情况2:未来未发生敲入和敲出
            if len(knock_in_day[0]) == 0:
                re = coupon * np.exp(-r * T)
                nav = 1 + re
            # 情况3:未来未发敲出,但发生敲入
            else:
                # 期末净值大于等于1
                if one_path[-1] >= 1:
                    re = 0
                    nav = 1 * (1 + re)
                # 期末净值小于1
                elif one_path[-1] < 1:
                    re = (one_path[-1] - 1) * np.exp(-r * T)
                    nav = 1 * (1 + re)

    elif status == 'in':
        # 情况1:未来发生过敲出
        if len(obs_day) > 0:
            t = obs_day[0]
            re = coupon * (t / year_day) * np.exp(-r * t /year_day)
            nav = 1 * (1 + re)  # 1表示期初的净值
        else:
            # 情况2:未来未发生过敲出
            # 期末净值大于等于1
            if one_path[-1] >= 1:
                re = 0
                nav = 1 * (1 + re)
            # 期末净值小于1
            elif one_path[-1] < 1:
                re = (one_path[-1] - 1) * np.exp(-r * T)
                nav = 1 * (1 + re)
    else:
        nav = 0
    new_value = nav
    return new_value

   然后,引入雪球估值(一)中介绍的估值函数(调整过交易日参数后的),通过循环得到对应的模拟估值结果。此处,对应的变量主要是标的价格,剩余天数,以及当前对应的状态。

# 计算模拟估值
from snow_ball.Pricing_model import *


def get_one_day_nav(status, residual_day, St):
    # 根据参数,计算雪球对应的模拟估值
    r = 0.025
    vol = 0.22
    times = 5000
    price_path = get_s_path(St, r, vol, residual_day, times)
    # 雪球要素
    knock_out = 1.03  # 敲出价格
    knock_in = 0.75  # 敲入价格
    coupon = 0.2  # 年化票息
    lock_time = 3  # 锁定期,单位为月
    T = 1  # 期限,折算为年
    nav = get_snowball_nav(status, coupon, T, r, residual_day,
                           knock_in, knock_out, lock_time, price_path)
    return nav


nav_list = []
for num in range(0, len(new_index)):
    st = new_index['净值'].values[num]
    residual_day = new_index['剩余期限'].values[num]
    print(residual_day)
    status = new_index['状态'].values[num]
    one_nav = get_one_day_nav(status, residual_day, st)
    nav_list.append(one_nav)

new_index['模拟估值'] = nav_list

  对应得到的结果为:

   对结果进行可视化操作,得到的结果为:

import matplotlib.pyplot as plt
date = pd.to_datetime(new_index['日期'])
plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']
plt.rcParams['axes.unicode_minus'] = False
plt.plot(date, new_index['净值'], label='标的净值走势')
plt.plot(date, new_index['模拟估值'], label='模拟估值')
plt.title('模拟估值案例')
plt.legend()
plt.show()

    由上图可以发现,当雪球未发生敲入时,其估值是远高于标的的净值,这是因为此种情况下未敲入敲出发生的可能较大,因此预期收益会高于标的本身;当发生敲入后,二者估值基本趋于一致 ,这是因为未来再发生敲出的概率极低,等到雪球到期时,二者收敛为一致。

2. 主要参数分析

   影响估值的参数有很多,此处主要用例举三个主要的参数。同时,为了更好的说明参数的敏感性,后文均使用未敲入状态下的雪球估值(敲入状态下的雪球估值对各参数的敏感性较弱)。同时,由于不同标的价格位置受参数的影响也不同,因此设置标的价格为1和0.8,作为对照组。

2.1 模拟次数

  以模拟次数作为唯一变量,标的价格分别设置为1和0.8;其余参数固定。

from snow_ball.Pricing_model import *
import matplotlib.pyplot as plt

# 雪球要素
r = 0.025
vol = 0.22
residual_day = 252
knock_out = 1.03  # 敲出价格
knock_in = 0.75  # 敲入价格
coupon = 0.2  # 年化票息
lock_time = 3  # 锁定期,单位为月
T = 1  # 期限,折算为年
# times = 5000

time_list = [1000 * x for x in range(20)]
nav_list = []
nav_list1 = []

for times in time_list:
    print(times)
    price_path = get_s_path(0.8, r, vol, residual_day, times)
    one_nav = get_snowball_nav('out', coupon, T, r, residual_day, knock_in, knock_out, lock_time, price_path)
    price_path1 = get_s_path(1, r, vol, residual_day, times)
    one_nav1 = get_snowball_nav('out', coupon, T, r, residual_day, knock_in, knock_out, lock_time, price_path1)
    nav_list.append(one_nav)
    nav_list1.append(one_nav1)
# 作图
plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']
plt.rcParams['axes.unicode_minus'] = False
zt = plt.figure()
p1 = zt.add_subplot(2, 1, 1)
p1.plot(time_list, nav_list, label='标的价格0.8')

plt.legend(loc='best')
plt.title('模拟次数对雪球估值的影响')

p2 = zt.add_subplot(2, 1, 2)
p2.plot(time_list, nav_list1, label='标的价格1.0')

plt.legend(loc='best')
plt.show()

     从上述结果可以看出,当次数到达5000次以后,估值影响基本是在千分位上的差异。若是追求较高的精确度,可以将次数上调至10万次;如果只是做一些理解测算,或者是大量的回测数据,那么5000或者10000次是一个比较好的选择。

2.2 剩余期限

  以剩余期限作为唯一变量,标的价格分别设置为1和0.8;其余参数固定。

from snow_ball.Pricing_model import *
import matplotlib.pyplot as plt

# 雪球要素
r = 0.025
vol = 0.22
knock_out = 1.03  # 敲出价格
knock_in = 0.75  # 敲入价格
coupon = 0.2  # 年化票息
lock_time = 3  # 锁定期,单位为月
T = 1  # 期限,折算为年
times = 5000

day_list = [252 - x for x in range(252)]
nav_list = []
nav_list1 = []


for day in day_list:
    print(day)
    price_path = get_s_path(0.8, r, vol, day, times)
    one_nav = get_snowball_nav('out', coupon, T, r, day, knock_in, knock_out, lock_time, price_path)
    price_path1 = get_s_path(1, r, vol, day, times)
    one_nav1 = get_snowball_nav('out', coupon, T, r, day, knock_in, knock_out, lock_time, price_path1)
    nav_list.append(one_nav)
    nav_list1.append(one_nav1)
# 作图
plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']
plt.rcParams['axes.unicode_minus'] = False
plt.plot(day_list, nav_list, label='标的价格0.8')
plt.plot(day_list, nav_list1, label='标的价格1.0')

plt.title('剩余期限对雪球估值的影响')
plt.legend()
plt.show()

     从上图可以看出,再不发生敲入的情况下,越临近到期,雪球的估值对应会越高,同时在临近到期时估值会有一个加速上涨的过程(普通期权依然存在这一特性),二者最终估值收敛于1.2(均获取到了全额票息)。相比于标的价格为0.8的雪球,标的价格为1的雪球走势会相对更加平滑,这是因为这个位置基本不会存在敲入的情况,同时发生敲出的概率极大,因此随着存续时间的增加,其估值随之增加。位于0.8位置的雪球,随着到期日的临近,其获取全额票息的概率相比前期更高,因此估值存在一个加速上涨的趋势。

2.3 波动率

  以波动率作为唯一变量,标的价格分别设置为1和0.8;其余参数固定。

from snow_ball.Pricing_model import *
import matplotlib.pyplot as plt

# 雪球要素
r = 0.025
# vol = 0.22
residual_day = 252
knock_out = 1.03  # 敲出价格
knock_in = 0.75  # 敲入价格
coupon = 0.2  # 年化票息
lock_time = 3  # 锁定期,单位为月
T = 1  # 期限,折算为年
times = 5000

vol_list = [0.1+x*0.01 for x in range(40)]
nav_list = []
nav_list1 = []

for vol in vol_list:
    print(vol)
    price_path = get_s_path(0.8, r, vol, residual_day, times)
    one_nav = get_snowball_nav('out', coupon, T, r, residual_day, knock_in, knock_out, lock_time, price_path)
    price_path1 = get_s_path(1, r, vol, residual_day, times)
    one_nav1 = get_snowball_nav('out', coupon, T, r, residual_day, knock_in, knock_out, lock_time, price_path1)
    nav_list.append(one_nav)
    nav_list1.append(one_nav1)
# 作图
plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']
plt.rcParams['axes.unicode_minus'] = False
zt = plt.figure()
p1 = zt.add_subplot(2, 1, 1)
p1.plot(vol_list, nav_list, label='标的价格0.8')

plt.legend(loc='best')
plt.title('波动率对雪球估值的影响')

p2 = zt.add_subplot(2, 1, 2)
p2.plot(vol_list, nav_list1, label='标的价格1.0')

plt.legend(loc='best')
plt.show()

     波动率作为雪球最为核心的要素,同时还会影响票息的水平。由于雪球的投资者更多预期未来标的小幅震荡,即波动率处于小幅区间内;因此,当波动率水平越高,对应雪球的整体估值会越低,因为这种状态下获取全额票息的可能性非常低,对应的票息就会较高(可以视为补偿)。波动率水平的预测方式主要有GARCH类模型以及随机波动模型,但是整体预测难度比较大。笔者也做了下关于波动率取值方式的一些探讨,但最终发现多重模式下波动率的差异不大,同期基本位于一个正负2%的区间内。所以,对于波动率的取值,笔者倾向于选择一些较为简单的方式,移动平滑或者均值基本上就可以了。

  本期内容到此结束,有问题欢迎交流。

免责声明:本文由作者参考相关资料,并结合自身实践和思考独立完成,对全文内容的准确性、完整性或可靠性不作任何保证。同时,文中提及的数据仅作为举例使用,不构成推荐;文中所有观点均不构成任何投资建议。请读者仔细阅读本声明,若读者阅读此文章,默认知晓此声明。

内容概要:本文档详细描述了一种雪球期权的产品设计,其中包括采用蒙特卡洛(Monte Carlo)模拟和拟蒙特卡洛(QMC)方法来对期权进行定价的技术细节。文档涵盖了产品的基本要素,如挂钩标的是中证1000指数,期限为24个月,并定义了敲入、敲出的具体机制及其相应的票息政策。此外,提供了详细的数学模型用于计算不同情境下投资者所获的投资收益,以及利用Sobol序列的QMC模拟方法确定各观测点的敲入和敲出概率。文中还包括了针对敲出水平、波动率等因素变动情况下期权价值影响的敏感性分析,有助于更好地理解和管理该金融工具的风险。 适合人群:适合于对金融衍生品有一定了解的金融机构分析师、风控管理人员以及高级研究人员。 使用场景及目标:旨在通过对具体金融产品的案例分析,加深对复杂期权产品内部运作机制的理解,并提高在实际操作中应用数学建模解决问题的能力。特别适用于希望优化风险管理策略的企业和个人投资者。 阅读建议:建议读者首先掌握基本的期权理论知识,同时具备一定的统计学背景,在深入研读文档之前最好先复习一下Monte Carlo和Quasi-Monte Carlo仿真算法的基本概念,这样更容易把握文档中关于模型构造和技术细节的内容。此外,为了验证和测试文档提供的算法效果,动手实现相关的程序代码也将是非常有益的学习过程。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值