BSM模型心得,python实现方案
BSM简介
首先对于BSM模型先简单介绍一下,接触过期权的人应该都不陌生,BSM模型全称Black-Scholes-Merton model,其主要的贡献是提供了一种期权定价模式,并且首次提出了对冲风险的概念,也就是delta hedging,通过delta hedging我们可以完全对冲掉风险,这也为当时的投资界提供了一个崭新的思路。
对于期权的定价我把方法大体分为:
- 离散的时间序列定价方法
- 连续的时间序列定价方法。
Binomial Trees
首先介绍下离散的方法,也就是binomial trees,方法很简单,我们假设资产的价格在T0时为S0,经过一个时间周期T1后,资产的价格可能发生两个方向的变化,升高变为SU,下降变为SD,我们通过把T1时期的每一个可能性的价格乘以概率,然后根据risk-free rate进行折现,就可以得到S0。简单来看不论多少个阶段的binomial trees都可以用同样的方式得出S0的价格。
其中涉及几个重要的问题:
- 如何计算上升的价格和下降的价格SU,SD
- 如何计算上升的概率和下降的概率πU,πD
- 如何计算volatility
具体的计算公式可以参考一本书叫《金融随机分析》,分为上下两册,上册主要讲了离散型的方法,下册主要讲连续型。
上述主要讲的是对于underlying asset的定价方法,那么对于option来说基本原理是一样的,唯一的区别是option只有在in-the-money时才有价值,以call option
为例,在T1时call option的价值应该是:
- CU=MAX(0,SU-exercise price)
- CD=MAX(0,SD-exercise price)
通过对CU,CD进行折现可以很容易的得出call option的价格。
当我们求出同一underlying asset的Call option价格时,想求出Put option的价格有两种方法:
- 通过与Call option 同样的方式再求一遍Put option
- 通过Put-call parity:S0+P0=C0+PV(X) (Note that both options are on the same underlying stock have the same exercise price, and the same maturity.)
需要注意期权分为美式期权和欧式期权,并且以underlying asset的不同也可以划分为很多种类,每个种类个计算可能存在区别,但总体思路相同。
BSM
现实中很少有离散的实际情况,所以对于精确度来说连续的模型会更加的准确也更能反映出市场的信息,但对于binomial tree的理解可以辅助理解BSM的方法,
首先,BSM的模型提出的很对限制条件,也就是假设:
- underlying asset的价格遵循geometric Brownian motion process
- underlying asse的回报率遵循lognormal distribution
- 理想的市场,没有税和交易成本
- 欧式期权(只有到期日可以执行期权)
- volatility是连续的,没有断崖式变化
- 用连续的risk-free rate
在BSM的理论中任何option的价值可以通过underlying asset 和无风险资产进行组合得到,所以option的价值也就与其自身的波动性无关了,唯一的相关因素就是underlying asset的价格,执行价格,波动率,到期时间T,无风险收益率相关。
对于公式的推导可以去看前面推荐的书,文章里不细说了,因为需要大量数学的计算,本人非数学专业,还是看书靠谱。
最后附上用python写出来的BSM公式,并且可视化不同变量对价格的影响。
Python实现方案:
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
import math
from scipy.integrate import quad
def dN(x):
return math.exp(-0.5*x**2)/math.sqrt(2*math.pi)
def N(d):
return quad(lambda x:dN(x),-20,d,limit=50)[0]`
def d1f(St, K, t, T, r, sigma):`
d1 = (math.log(St / K) + (r + 0.5 * sigma ** 2) * (T - t)) / (sigma * math.sqrt(T - t))`
return d1
def BSM_call_value(St, K, t, T, r, sigma):
d1=d1f(St,K,t,T,r,sigma)
d2=d1-sigma*math.sqrt(T-t)
call_value = St * N(d1) - math.exp(-r * (T - t)) * K * N(d2)
return call_value
def BSM_put_value(St, K, t, T, r, sigma):
put_value = BSM_call_value(St,K,t,T,r,sigma)-St + math.exp(-r * (T - t)) * K
return put_value
def plot_values(function):
plt.figure(figsize=(10, 8.3))
points = 100
St = 100.0 # index level
K = 100.0 # option strike
t = 0.0 # valuation date
T = 1.0 # maturity date
r = 0.05 # risk-less short rate
sigma = 0.2 # volatility
# C(K) plot
plt.subplot(221)
klist = np.linspace(80, 120, points)
vlist = [function(St, K, t, T, r, sigma) for K in klist]
plt.plot(klist, vlist)
plt.grid()
plt.xlabel('strike $K$')
plt.ylabel('present value')
# C(T) plot
plt.subplot(222)
tlist = np.linspace(0.0001, 1, points)
vlist = [function(St, K, t, T, r, sigma) for T in tlist]
plt.plot(tlist, vlist)
plt.grid(True)
plt.xlabel('maturity $T$')
# c(r) plot
plt.subplot(223)
rlist = np.linspace(0, 0.1, points)
vlist = [function(St, K, t, T, r, sigma) for r in rlist]
plt.plot(tlist, vlist)
plt.grid(True)
plt.xlabel('short rate $r$')
plt.ylabel('present value')
plt.axis('tight')
# C(sigma) plot
plt.subplot(224)
slist = np.linspace(0.01, 0.5, points)
vlist = [function(St, K, t, T, r, sigma) for sigma in slist]
plt.plot(slist, vlist)
plt.grid(True)
plt.xlabel('volatility $\sigma$')
plt.tight_layout()
接下来准备写一下如果运用Greeks来衡量风险,下篇文章继续。