基于BSM定价模型与蒙特卡罗模拟的上证50ETF期权定价研究

期权
蒙特卡洛模拟
期权定价
bsm模型
标签: #<Tag:0x00007f4ce9ba03a0> #<Tag:0x00007f4ce9ba01c0> #<Tag:0x00007f4ce9baff58> #<Tag:0x00007f4ce9bafc38>

(xysgs) #1

在开发期权交易策略时,对期权的定价是至关重要的一步,本文基于鼎鼎大名的Black-Schole-Merton期权定价模型,与蒙特卡洛模拟方法对上证50ETF期权进行定价,以便于后续期权策略的开发。

关于BSM模型的详细推导以及蒙特卡洛模拟这里不做详细介绍,有兴趣的可以参阅BSM model以及Monte Carlo method

一般的,期权定价的蒙特卡罗方法包括以下步骤(以欧式看涨期权为例):

  1. 将时间区间$[0,T]$分成$n$个子区间$0=t_0<t_1<t_2<\dots<t_n=T$根据BSM微分方程得到标的资产价格过程的离散形式为:
    $$S^j(t_{i+1})=S^j(t_i)e^{(r-\frac{1}{2}\sigma^2)(t_{i+1}-t_i)+\sigma(t_{i+1}-t_i)z_i}, z_i\sim N(0,1)$$$S_j$为标的资产价格;$r$为无风险利率;$\sigma$为波动率;$z_i$为服从标准正态分布的随机变量。
    此处使用的波动率为对数历史波动率,即$$\sigma=252^{0.5}\times D[ln(return_i)]$$$return_i$为第$i$期的收益
    由于中国市场上的隐含收益率无法计算,因此仅通过历史收益率来对期权进行定价是不能保证准确的。

  2. 计算该条路径下的期权到期回报:$$C^j=max(0,S^j-K)$$$K$为期权行权价;$C^j$为期权到期回报

  3. 重复前两步得到大量期权回报值的抽样样本

  4. 求得样本均值,得到期权贴现值的蒙特卡洛模拟结果$$C^j=\frac{e^{-rT}\displaystyle\sum_{j=1}^{n} max(0,S^j-K)}{n}$$

以下为基于BSM模型的蒙特卡洛模拟方法程序运行结果,可以看出,由于模拟次数有限和BSM模型的诸多假设以及波动率计算等问题,导致预测值与实际收盘价有较大的偏差,读者可以在该方法基础上通过对波动率计算方法进行优化从而确定期权价格。

克隆策略
In [15]:
import math
import numpy as np
import time
import pandas as pd

# np.random.seed(20000) 
t_0 = time.time()
# 参数
def data_fetcher():
    data_info = DataSource('basic_info_CN_OPTION').read(start_date='2019-01-01')
    df_hq = DataSource('bar1d_CN_OPTION').read(start_date='2019-01-01')
    df_merge = data_info.merge(df_hq,on=['instrument'])
    df_merge['days_todelist'] = ((df_merge['delist_date'] - df_merge['date'])/np.timedelta64(1, 'D')).astype(int)
    df_option = df_merge[['date','instrument','settle', 'strike_direction','strike_price','days_todelist']]
    df_option['settle'] = df_merge[['close']]
    return df_option
In [16]:
def volatility():
    df_option = data_fetcher()
    df_index = DataSource('bar1d_CN_FUND').read(instruments=['510050.HOF'],start_date='2019-02-27', end_date='2019-09-26')[['date', 'close']]
    df_index['std_year'] = 252**0.5*np.std(np.log(df_index['close']/df_index['close'].shift(1)))
    df_index['std_daily'] = np.std(np.log(df_index['close']/df_index['close'].shift(1)))
    df_final = df_index.merge(df_option,on='date')
    return df_final
In [17]:
def call_option_price():
    option_data = volatility()
    option_data = option_data[option_data['instrument'] == '10001749.SHAO']
    sigma = option_data['std_year'].mean()#波动率
    risk_free_rate = 0.03#无风险利率
    time_to_maturity = np.array(option_data['days_todelist'])#计算出的到期天数
    divide = 50 #到期天数对应的时间区间数
    time_interval = time_to_maturity/divide#每个区间长度
    N = 50000#随机变量模拟数量
    exercise_prise = np.array(option_data['strike_price'])#行权价
    gauss = np.random.standard_normal((len(time_to_maturity), divide + 1, N))#生成三维高斯随机变量
    time_interval = time_to_maturity/divide#每个区间长度
    fund_prise_0 = option_data.settle.values[0]
    fund_prise_log = np.log(fund_prise_0) + np.array([np.cumsum((risk_free_rate - 0.5 * sigma ** 2) * time_interval[i] + sigma * np.sqrt(time_interval[i]) * gauss[i], axis=0) for i in range(0, len(time_to_maturity))])
    fund_prise = np.exp(fund_prise_log)
    fund_prise[:,0:1,:] = fund_prise_0
    call_option_prise = [np.exp(-risk_free_rate * time_to_maturity[i]) * np.sum(np.maximum(fund_prise[i][-1] - exercise_prise[i], 0)) / N for i in range(0, len(time_to_maturity))]
    errors = call_option_prise - np.array(option_data['settle'])
    errors = pd.Series(errors, index=option_data['date'])
    call_option_prise = pd.Series(call_option_prise, index=option_data['date'])
    return '看涨期权定价为:', call_option_prise, '绝对误差为:', errors, '程序运行时间为:', np.round(time.time() - t_0, 1), 's.'
In [18]:
a = call_option_price()
a
Out[18]:
('看涨期权定价为:', date
 2019-02-27    0.287249
 2019-02-28    0.298701
 2019-03-01    0.379017
 2019-03-04    0.295021
 2019-03-05    0.311811
 2019-03-06    0.286657
 2019-03-07    0.347475
 2019-03-08    0.371281
 2019-03-11    0.364393
 2019-03-12    0.309484
 2019-03-13    0.401991
 2019-03-14    0.415961
 2019-03-15    0.291768
 2019-03-18    0.306029
 2019-03-19    0.296864
 2019-03-20    0.326924
 2019-03-21    0.296761
 2019-03-22    0.324629
 2019-03-25    0.309562
 2019-03-26    0.300076
 2019-03-27    0.281743
 2019-03-28    0.322113
 2019-03-29    0.295321
 2019-04-01    0.294642
 2019-04-02    0.297239
 2019-04-03    0.299548
 2019-04-04    0.320931
 2019-04-08    0.273584
 2019-04-09    0.329734
 2019-04-10    0.275416
                 ...   
 2019-08-14    0.069745
 2019-08-15    0.065249
 2019-08-16    0.059192
 2019-08-19    0.049838
 2019-08-20    0.047450
 2019-08-21    0.045544
 2019-08-22    0.042190
 2019-08-23    0.035907
 2019-08-26    0.028849
 2019-08-27    0.028259
 2019-08-28    0.023743
 2019-08-29    0.021800
 2019-08-30    0.016285
 2019-09-02    0.012405
 2019-09-03    0.008620
 2019-09-04    0.007732
 2019-09-05    0.006864
 2019-09-06    0.004627
 2019-09-09    0.002460
 2019-09-10    0.001449
 2019-09-11    0.000964
 2019-09-12    0.000622
 2019-09-16    0.000042
 2019-09-17    0.000054
 2019-09-18    0.000032
 2019-09-19    0.000000
 2019-09-20    0.000000
 2019-09-23    0.000000
 2019-09-24    0.000000
 2019-09-25    0.000000
 Length: 142, dtype: float64, '绝对误差为:', date
 2019-02-27   -0.004151
 2019-02-28    0.019101
 2019-03-01    0.131717
 2019-03-04    0.051621
 2019-03-05    0.057411
 2019-03-06    0.023057
 2019-03-07    0.056075
 2019-03-08    0.028881
 2019-03-11    0.050093
 2019-03-12   -0.011216
 2019-03-13    0.089291
 2019-03-14    0.100761
 2019-03-15    0.000068
 2019-03-18    0.040429
 2019-03-19    0.017564
 2019-03-20    0.048824
 2019-03-21    0.012961
 2019-03-22    0.042529
 2019-03-25   -0.010338
 2019-03-26   -0.023824
 2019-03-27   -0.017457
 2019-03-28    0.020713
 2019-03-29    0.046421
 2019-04-01    0.063842
 2019-04-02    0.071539
 2019-04-03    0.081548
 2019-04-04    0.111631
 2019-04-08    0.069784
 2019-04-09    0.134734
 2019-04-10    0.077516
                 ...   
 2019-08-14   -0.071255
 2019-08-15   -0.067251
 2019-08-16   -0.071108
 2019-08-19   -0.039862
 2019-08-20   -0.041550
 2019-08-21   -0.038856
 2019-08-22   -0.038910
 2019-08-23   -0.024793
 2019-08-26   -0.057451
 2019-08-27   -0.039741
 2019-08-28   -0.055657
 2019-08-29   -0.062100
 2019-08-30   -0.060015
 2019-09-02   -0.047895
 2019-09-03   -0.051580
 2019-09-04   -0.032268
 2019-09-05   -0.019036
 2019-09-06   -0.012173
 2019-09-09   -0.014340
 2019-09-10   -0.016051
 2019-09-11   -0.016236
 2019-09-12   -0.007378
 2019-09-16   -0.006758
 2019-09-17   -0.013646
 2019-09-18   -0.008768
 2019-09-19   -0.005500
 2019-09-20   -0.003500
 2019-09-23   -0.004300
 2019-09-24   -0.001000
 2019-09-25   -0.000100
 Length: 142, dtype: float64, '程序运行时间为:', 62.6, 's.')