失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > 美式期权定价python_蒙特卡洛模拟和美式期权定价

美式期权定价python_蒙特卡洛模拟和美式期权定价

时间:2024-06-26 00:08:30

相关推荐

美式期权定价python_蒙特卡洛模拟和美式期权定价

最近面试的时候,面试官问我怎么用蒙卡模拟无股息的美式期权定价。我瞬间石化。。。不怕死地申请了期权建模的实习。。。主要参考课件

主要内容二叉树定价推导+Python

Longstaff-Schwartz定价推导+Python

一、引言

本讲的大前提:股票无股息。

1、美式期权主要问题是:在

之间找到合适的停止点

,从而美式期在t时刻价值

其中,

是收益,又称为内在价值。等式不难理解:给定t时刻的期权价格为

,找到未来合适的停止点

,然后把那一刻的期权价值折现到t时刻。

注意:

是随机值(random variable)。对于股票过程(例如GBM)的每个不同路径,

可以不同。解决之道:每时每刻基于标的股票的当前价值、评估此刻执行期权是不是最优的。

可以证明,V(t,s)是下面方程的弱解(weak solution) :

又是解PDE。。。我之前写过欧式期权的PDE,可参考丹尼尔:Code and Finance 4 期权定价之有限差分法​

美式期权实际上有3中解法,①PDE(以后有空再整理);②二叉树(Binomial tree);③Longstaff-Schwarts(※※※)。本文主要讲解后两种~

二、二叉树求解美式期权定价

1、基本逻辑前提假设风险中性的世界中,衍生品的现值=未来预期收益的折现值,折现率为无风险收益率

股价在

的时间内,上升概率为

,下降概率为

即为无风险概率。

上升幅度为

,下降幅度为

当前时间是t=0,当前标的资产股价为

,当前衍生品价格为

时间后,股价要么上升到

,对应的衍生品价值为

;要么下降到

,对应的衍生品价值为

如何求解p? ,那么

如何求解u和d?前提条件:

Grisanov's theoremu和d选择的必要条件:股价收益率的波动率在现实世界和风险中性世界一致(股价收益率在两个世界可以不同)。

综上:

2、实例+代码例子:当前股价为100,put行权价为100,时间为1年,无风险利率为0.1,年化波动率为0.2。求出当前时间的美式看跌期权价格。

假设我把1年的时间切分成100份,那么在最后一次,一共有101个分支价格,这就是S_T是101个数据点;然后分别和K进行比较,得到每个点的call/put价格。接着,将第100个时间点向第99个时间点折现,注意:

的期权折现值

接着,比较

提前行权的期权价值

和折现值的大小;哪个大那么就选择哪个。代码

import numpy as np

S0 = 100

K = 100

T = 1

r = 0.1

sig = 0.2

payoff = "put"

def getAmeOption(S0, K, T, r, sig, N, payoff):

# 将时间T拆分为N份,每份是dT。

dT = float(T) / N

#计算u,d,p,q。

u = np.exp(sig * np.sqrt(dT))

d = 1.0 / u

a = np.exp(r * dT)

p = (a - d)/(u - d)

q = 1.0 - p

# V承接N+1个价格

V = np.zeros(N+1)

# 注意S_T的生成顺序,是从u=0,d=N开始.

S_T = np.array( [(S0 * u**j * d**(N - j)) for j in range(N + 1)] ) # price S_T at time T

if payoff =="call":

V[:] = np.maximum(S_T-K, 0.0)

elif payoff =="put":

V[:] = np.maximum(K-S_T, 0.0)

for i in range(N-1, -1, -1):

# 这一步至关重要:V在第k轮迭代中,只关注0~N-k的位置,

# 每个位置=(下一个位置上升的期权*p+下一个位置下降的期权*q)*折现因子

V[:-1] = np.exp(-r*dT) * (p * V[1:] + q * V[:-1])

# 股价也进行新一轮的迭代,同样只有0~N-k是需要关注的,剩下的位置无关紧要。

S_T = S_T * u

# 比较此刻行权和下一轮预期收益的折现

if payoff=="call":

V = np.maximum( V, S_T-K )

elif payoff=="put":

V = np.maximum( V, K-S_T )

return V[0]

结果

getAmeOption(S0, K, T, r, sig, 10000, 'put')

getAmeOption(S0, K, T, r, sig, 10000, 'call')

put价格为4.81661591469,call价格为13.269467766434364。

三、Longstaff-Schwartz这个方法又称为是最小二乘法。

1、步骤详解——通过例子详细解答假设:我模拟了10条(paths=10)路径,以及将时间分成了4段(N=4,0-1-2-3),

,每段时间的折现因子

。求出0时刻的call&put价格。

第一步:求出10条路径的股价发展过程首先,第0个时间点的10条路径是[100, ... 100](10个100);

第1个时间点的10条路径计算方式是把第0条的10个100作为输入值,

=[95.84, ..., 121.39](10个随机数);

第2个时间点的10条路径是把第1个时间点的10条路径的股价作为S0输入,结果为[93.16, ... , 135.93];

第3个时间点的10条路径是把第2个时间点的10个路径的股价作为S0输入,结果为[103.58, ... , 145.24]。

因此股价的矩阵为

代码

from random import gauss

from math import exp, sqrt

def calculate_S_T(S, v, r, T):

"""模拟epsilon,计算S_T"""

return S * exp((r - 0.5 * v ** 2) * T + v * sqrt(T) * gauss(0.0, 1.0))

def getRoundStockPrice(S, v, r, N, T, rounds, paths):

firstRound = [S] * paths

nextRound = firstRound.copy()

for i in range(rounds):

nextRound1 = nextRound[-paths:]

for s in nextRound1:

nextS = calculate_S_T(s, v, r, T)

nextRound.append(nextS)

nextRound = np.array(nextRound).reshape((-1, paths)).T

return nextRound

S = 100

v = 0.2

r = 0.1

N = 3

T = 1 / N

paths = 10

S_Matrix = getRoundStockPrice(S, v, r, N, T, N, paths)第二步:求出每个时期行权的收益,称为exercise value(EV)call的EV=max(S-K, 0),put的EV=max(K-S, 0),第三步t=3的时候,必须要行权,exercise value(EV)=holding value(HV)。

t=2的时候,计算第2期的收益现值HV,就是t=3的EV折现(这是因为第三期就到期了,第三期的EV=HV),即为下两张表的第2列2callHV和2putHV。

然后,将t=2的EV>0的部分圈出来(※※※※※),对于call而言,即为2.3.6.7.10,对于put而言,即为1.4.5.8.9;

然后对相应行进行least-squares回归,回归方程

;其中S是第2期的股价,HV是第二期的持有价值HV;即为y是2callHV(2putHV),自变量是S2和S2^2;得到回归系数之后,再代入第二期的股价S,求出E(HV);注意,put和call分开回归,不是一起回归。

然后计算出E(HV),即为2callE(HV)和2putE(HV),比较E(HV)和EV大小;如果E(HV)>EV,那么绝不提前行权;如果E(HV)≤EV,那么第二期立刻行权。最后,得到了第二期的期权情况,即为最后一列。t=1的时候,第2列1callHV和1putHV,分别是上面两张表的最后一列的折现值;第二列来自H矩阵在t=1的值;同样,圈出EV>0的情况,call是2、3、6、7、10行,put是1、4、5、8、9行,分别和S1&S1^2回归,然后计算得到1callE(HV)和1putE(HV);比较E(HV)和EV的大小,if E(HV)>EV,绝不提前行权;else 提前行权;最终得到1call和1put。最后一步,将1call和1put分别计算均值,然后折现到t=0时期,即为

和二叉树差的有点远。。应该是我分的区间太小了。下面拆成10000*10000的网格点的时候,明显结果更加稳健。

2、代码详解

可以看到,上面的计算,程序基本大同小异,那么使用python一次性解决。

import scipy.stats as ss

import numpy as np

def LSM(S0, K, T, r, sig, payoff, N=10000, paths=10000, order=2):

dt = T/(N-1) # time interval

df = np.exp(r * dt) # discount factor per time time interval

X0 = np.zeros((paths,1))

increments = ss.norm.rvs(loc=(r - sig**2/2)*dt, scale=np.sqrt(dt)*sig, size=(paths,N-1))

X = np.concatenate((X0,increments), axis=1).cumsum(1)

S = S0 * np.exp(X)

if payoff == "put":

H = np.maximum(K - S, 0) # intrinsic values for put option

if payoff == "call":

H = np.maximum(S - K, 0) # intrinsic values for call option

V = np.zeros_like(H) # value matrix

V[:,-1] = H[:,-1]

# Valuation by LS Method

for t in range(N-2, 0, -1):

good_paths = H[:,t] > 0

# polynomial regression:将EV>0的部分挑出来回归

rg = np.polyfit( S[good_paths, t], V[good_paths, t+1] * df, 2)

# 估计E(HV)

C = np.polyval( rg, S[good_paths,t] )

# 如果E(HV)

exercise = np.zeros( len(good_paths), dtype=bool)

exercise[good_paths] = H[good_paths,t] > C

V[exercise,t] = H[exercise,t]

V[exercise,t+1:] = 0

discount_path = (V[:,t] == 0)

V[discount_path,t] = V[discount_path,t+1] * df

V0 = np.mean(V[:,1]) * df #

return V0

结果

call = LSM(100, 100, 1, 0.1, 0.2, 'call', N=10000, paths=10000, order=2)

put = LSM(100, 100, 1, 0.1, 0.2, 'put', N=10000, paths=10000, order=2)

得到call=13.297700328385172,put=4.755646113796444。

基本和二叉树的结果一致。

整理了一天,终于完成这篇小作业~对于二叉树定价,我这里也是第一次试验,结果还挺不错;以前以为二叉树是不是太简单的,现在来看,结果和复杂的Longstaff-Schwartz结果一致;而且运行速度也更占优势。

以上是美式无股息期权定价推导+Python代码,希望能够给你带来帮助~

参考

如果觉得《美式期权定价python_蒙特卡洛模拟和美式期权定价》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。