第2节 二叉树计算欧式和美式期权价格
1.1 简介
考虑期权为股票期权,二叉树是指股票价格在期限内可能的变化路径的图形。
考虑时间段为0至T,对于步数为N的二叉树,在 t = 0 , Δ t , . . . , ( N − 1 ) Δ t t=0,\; \Delta t, ...,(N-1)\Delta t t=0,Δt,...,(N−1)Δt 的时间节点上股票价格有概率 p p p由当前价格 S t S_t St变为 u S t uS_t uSt,有概率 ( 1 − p ) (1-p) (1−p)变为 d S t dS_t dSt。其中 Δ t = T N \Delta t = \frac{T}{N} Δt=NT, u和d分别为上升和下降幅度。当二叉树的步数足够多时,股票价格的最后分布将为对数正态分布。
John Hull的《期权、期货及其他衍生产品》中说明了当我们要求没有无风险套利空间,选取
p
=
e
r
Δ
t
−
d
u
−
d
p=\frac{e^{r\Delta t}-d}{u-d}
p=u−derΔt−d时,期权在当前节点的价格为期权在分叉后价格期望的贴现后价格。此外我们需要选取的
u
u
u和
d
d
d会让股票价格的波动率与几何布朗运动:
d
S
S
=
r
d
t
+
σ
d
z
\frac{dS}{S} = r dt + \sigma dz
SdS=rdt+σdz
相符合。即考虑下列等式,
p
u
+
(
1
−
p
)
d
=
e
r
Δ
t
,
p
(
u
−
1
)
2
+
(
1
−
p
)
(
d
−
1
)
2
−
[
p
(
u
−
1
)
+
(
1
−
p
)
(
d
−
1
)
]
2
=
σ
2
Δ
t
.
pu+(1-p)d = e^{r\Delta t}, \;\; p(u-1)^2+(1-p)(d-1)^2-[p(u-1)+(1-p)(d-1)]^2 = \sigma^2\Delta t .
pu+(1−p)d=erΔt,p(u−1)2+(1−p)(d−1)2−[p(u−1)+(1−p)(d−1)]2=σ2Δt.
让
d
=
1
/
u
d=1/u
d=1/u,我们会得到一个重合的树形。这时忽略
Δ
t
\Delta t
Δt的
3
2
\frac{3}{2}
23阶小量后会有
u
=
e
σ
Δ
t
,
d
=
e
−
σ
Δ
t
.
u=e^{\sigma\sqrt{\Delta t}}, \;\; d = e^{-\sigma\sqrt{\Delta t}}.
u=eσΔt,d=e−σΔt.
下面左图和右图分别为一步和多步二叉树分叉过程,多步二叉树中每一个节点的分叉过程都是相同的。
2.2 二叉树计算期权价格算法
欧式期权价格
- 根据给定的股票价格的波动率 σ \sigma σ和无风险利率 r r r,按照上图中公式计算出 u , d , u,\;d, u,d,和 p p p,其中 Δ t \Delta t Δt为每一步步长 T / N T/N T/N。
- 计算出股票价格在树形末端每个节点的价格,如上右图右侧。
- 根据期权类型(看涨或看跌),以及期权的执行价格 K K K计算出期权在树形末端的价格分布。
- 用期权价格的递推关系计算出前一层节点上期权价格的期望值。期权价格的递推关系为
f i , j = e − r Δ t ( p f i + 1 , j + 1 + ( 1 − p ) f i + 1 , j ) . f_{i,j} = e^{-r\Delta t}(pf_{i+1,j+1}+(1-p)f_{i+1,j})\;. fi,j=e−rΔt(pfi+1,j+1+(1−p)fi+1,j).
其中 f i , j f_{i, j} fi,j为期权在 i Δ t i\Delta t iΔt时刻,第 j j j层(由下往上数,从0开始)的价格。 - 重复过程4,直到计算出根节点处期权的价格 f 0 , 0 f_{0,0} f0,0。
美式期权的价格
重复欧式期权价格的计算过程1~3,然后在递推上一层期权价格时考虑可以在该节点执行的情况,具体为:
- 根据给定的股票价格的波动率 σ \sigma σ和无风险利率 r r r,按照上图中公式计算出 u , d u,\;d u,d和 p p p。
- 计算出股票价格在树形末端每个节点的价格。
- 根据期权类型(看涨或看跌),以及期权的执行价格 K K K计算出期权在树形末端的价格分布。
- 计算出前一层节点上期权价格的期望值。此时需要考虑可以在该节点执行期权,假设期权为看涨期权,则其价格的递推关系为
f i , j = max [ S i , j − K , e − r Δ t ( p f i + 1 , j + 1 + ( 1 − p ) f i + 1 , j ) ] . f_{i,j} = \max{\left[S_{i, j}-K,\;e^{-r\Delta t}(pf_{i+1,j+1}+(1-p)f_{i+1,j})\right]}\;. fi,j=max[Si,j−K,e−rΔt(pfi+1,j+1+(1−p)fi+1,j)].
其中 f i , j f_{i, j} fi,j为期权在 i Δ t i\Delta t iΔt时刻,第 j j j层的价格, S i , j \;S_{i,j} Si,j为该处的股票价格。 - 重复过程4,计算出根节点处期权的价格 f 0 , 0 f_{0,0} f0,0。
2.3 计算过程 Python 代码实现
import numpy as np
import math
E = math.e
class Binomial_tree_sim:
def __init__(self, r, sigma, S_0, K, T, steps, option_type="european", call_or_put="call"):
""" 用输入参数初始化树。
"""
self.r = r
self.sigma = sigma
self.S_0 = S_0
self.K = K
self.T = T
self.steps = steps
self.option_type = option_type
self.call_or_put = call_or_put
# 计算出树形分叉参数
self.dt = self.T/self.steps
self.u = E**(self.sigma*self.dt**0.5)
self.d = 1/self.u
self.p = (E**(self.r*self.dt)-self.d)/(self.u-self.d)
# 将会得到的结果
self.tree = None
self.option_price = None
# 计算出一个树形
self.build_tree()
def build_tree(self):
""" 计算出股票价格在树形上每个节点的价格。
"""
self.tree = list()
for lvl in range(self.steps+1):
row = list()
for j in range(lvl+1):
node = dict()
node["stock_price"] = self.S_0*self.u**(j)*self.d**(lvl-j)
node["option_price"] = None
row.append(node)
self.tree.append(row)
return
def calculate_option_price(self):
""" 计算给定类型期权的价格。
"""
# 简化参数名称。
r, K, steps = self.r, self.K, self.steps
dt, p = self.dt, self.p
# 计算出期权在树形末端的价格。
for node in self.tree[-1]:
# 如果是看涨期权。
if self.call_or_put == "call":
node["option_price"] = max(node["stock_price"]-K, 0)
# 如果是看跌期权。
else:
node["option_price"] = max(K-node["stock_price"], 0)
# 如果是欧式期权。
if self.option_type == "european":
# 递推出树形根节点期权的价格。
for lvl in range(steps-1, -1, -1):
for j in range(len(self.tree[lvl])):
self.tree[lvl][j]["option_price"] = E**(-r*dt)*(p*self.tree[lvl+1][j+1]["option_price"]+\
(1-p)*self.tree[lvl+1][j]["option_price"])
# 如果是美式期权,过程同欧式期权,计算节点价格时考虑需不需要在该节点执行。
else:
for lvl in range(self.steps-1, -1, -1):
for j in range(len(self.tree[lvl])):
self.tree[lvl][j]["option_price"] = E**(-r*dt)*(p*self.tree[lvl+1][j+1]["option_price"]+\
(1-p)*self.tree[lvl+1][j]["option_price"])
# 考虑要不要这时执行。
if self.call_or_put == "call":
self.tree[lvl][j]["option_price"] = max(self.tree[lvl][j]["option_price"], \
self.tree[lvl][j]["stock_price"]-K)
else:
self.tree[lvl][j]["option_price"] = max(self.tree[lvl][j]["option_price"], \
K-self.tree[lvl][j]["stock_price"])
self.option_price = self.tree[0][0]["option_price"]
return
2.4 相关说明
2.4.1 计算例子
考虑一个期限在3年后,执行价格为10的期权。当前股票价格为10,无风险利率为10,股票价格波动率为0.2 。使用10步二叉树,可以如下计算出各种期权价格。
tree_obj = Binomial_tree_sim(0.05, 0.2, 10, 10, 3, 10, option_type="european", call_or_put="call")
tree_obj.calculate_option_price()
print("欧式看涨期权价格为: {:0.4f}".format(tree_obj.option_price))
tree_obj = Binomial_tree_sim(0.05, 0.2, 10, 10, 3, 10, option_type="european", call_or_put="put")
tree_obj.calculate_option_price()
print("欧式看跌期权价格为:{:0.4f}".format(tree_obj.option_price))
tree_obj = Binomial_tree_sim(0.05, 0.2, 10, 10, 3, 10, option_type="american", call_or_put="call")
tree_obj.calculate_option_price()
print("美式看涨期权价格为:{:0.4f}".format(tree_obj.option_price))
tree_obj = Binomial_tree_sim(0.05, 0.2, 10, 10, 3, 10, option_type="american", call_or_put="put")
tree_obj.calculate_option_price()
print("美式看跌期权价格为:{:0.4f}".format(tree_obj.option_price))
输出结果为:
欧式看涨期权价格为: 2.0585
欧式看跌期权价格为:0.6656
美式看涨期权价格为:2.0585
美式看跌期权价格为:0.8563
2.4.2 树形定价收敛情况
依旧考虑上面参数的欧式看涨期权,我们可以用解析公式计算出期权价格应该为2.0924。然后我们可以调整树形定价步数,将得到的期权价格和解析解数值进行比较。
X = np.arange(10, 210, 10)
Y = np.array([])
for steps in X:
tree_obj = Binomial_tree_sim(0.05, 0.2, 10, 10, 3, steps, option_type="european", call_or_put="call")
tree_obj.calculate_option_price()
Y = np.append(Y, [tree_obj.option_price])
figure = plt.figure()
ax1 = figure.add_subplot(1, 1, 1)
line1, = ax1.plot(X, Y, '-s', color="blue", linewidth=1.5)
line2, = ax1.plot(X, len(X)*[2.0924], '-', color="red", linewidth=1)
ax1.set_xlabel("steps")
ax1.set_ylabel("price")
ax1.set_title("option price vs tree depth")
ax1.axis((10, 200, 2.04, 2.1))
得:
参考资料:
- 《期权、期货及其他衍生产品》,John C. Hull 著,王勇、索吾林译 。