%pylab inline
lecture = 13
import sys
sys.path.append("lib")
import fmt
import sympy as sp
import pandas as pd
from IPython.display import display
assert sp.__version__ == "0.7.5", "Need sympy version 0.7.5 to render properly"
sp.init_printing(use_latex = True)
Populating the interactive namespace from numpy and matplotlib
\begin{aligned} e^{a\triangle t} & = \left\{ \frac{1}{2}\sigma^2 x_j^2 \frac{\triangle t}{\triangle x^2} - r x_j \frac{\triangle t}{2\triangle x} \right\} e^{-il_m\triangle x} \\ & + \left\{ 1 - \sigma^2 x_j^2 \frac{\triangle t}{\triangle x^2} -r \triangle t \right\} \\ & + \left\{ \frac{1}{2}\sigma^2 x_j^2 \frac{\triangle t}{\triangle x^2} + r x_j \frac{\triangle t}{2\triangle x} \right\} e^{il_m\triangle x} \end{aligned}
$$ e^{a\triangle t} = 1 - r\triangle t + \sigma^2 x_j^2 \frac{\triangle t}{\triangle x^2} \cdot 2\sin^2(l_m\triangle x/2) + i\; r x_j \frac{\triangle t}{\triangle x} \sin(l_m\triangle x) $$
\begin{aligned} \renewcommand{PDut}{\frac{\partial u}{\partial t}} \renewcommand{PDux}{\frac{\partial u}{\partial x}} \renewcommand{PDutt}{\frac{\partial ^2u}{\partial t^2}} \renewcommand{PDuxx}{\frac{\partial ^2u}{\partial x^2}} \renewcommand{FDut}{\frac{u_{i,k+1}-u_{i,k}}{\triangle t}} \renewcommand{FDutb}{\frac{u_{i,k}-u_{i,k-1}}{\triangle t}} \renewcommand{FDutc}{\frac{u_{i,k+1}-u_{i,k-1}}{2\triangle t}} \renewcommand{FDutt}{\frac{u_{i,k+1}-2u_{i,k}+u_{i,k-1}}{\triangle t^2}} \renewcommand{FDux}{\frac{u_{i+1,k}-u_{i,k}}{\triangle x}} \renewcommand{FDuxb}{\frac{u_{i,k}-u_{i-1,k}}{\triangle x}} \renewcommand{FDuxc}{\frac{u_{i+1,k}-u_{i-1,k}}{2\triangle x}} \renewcommand{FDuxx}{\frac{u_{i+1,k}-2u_{i,k}+u_{i-1,k}}{\triangle x^2}} & r >0, \\ & \triangle t < \frac{\triangle x^2}{ \sigma^2 x_{max}^2 }, \\ & \triangle t < \frac{ \sigma^2 }{r^2 }. \end{aligned}
The first condition is trivial (until the FED decrees all rates to be negative!)
The last condition does not have much impact in practice unless the volatility is very small.
So the important one is the second condition, which is what we went through last lecture.
\begin{aligned} & dS_t = rS_t dt + \sqrt{\nu_t}S_t dW_t^1 \\ & d\nu_t = \kappa(\theta - \nu_t) + \xi\sqrt{\nu_t} dW_t^2 \\ & \hspace{0.2in} \left< dW_t^1, dW_t^2 \right> = \rho dt \end{aligned}
\begin{aligned} \renewcommand{PDuS}{\frac{\partial u}{\partial S}} \renewcommand{PDuSS}{\frac{\partial ^2u}{\partial S^2}} \PDut &+ rS\PDuS + [\kappa(\theta - \nu)-\lambda \nu]\frac{\partial u}{\partial \nu} \\ &+ \frac{1}{2}\nu S^2\PDuSS + \rho\xi\nu S\frac{\partial^2 u}{\partial S\partial \nu} + \frac{1}{2}\xi^2\nu\frac{\partial^2 u}{\partial \nu^2} - ru = 0 \end{aligned}
\begin{aligned} \renewcommand{fD}{\mathfrak{D}} \FDut = & \frac{1}{4} \sigma^2 x_i^2 \left\{ \FDuxx + \frac{u_{i+1,k+1}-2u_{i,k+1}+u_{i-1,k+1}}{\triangle x^2} \right\} \\ & + \frac{1}{2} r x_i \left\{ \FDuxc + \frac{u_{i+1,k+1}-u_{i-1,k+1}}{2\triangle x} \right\} \\ & - \frac{1}{2} r \left\{ u_{i,k} + u_{i,k+1} \right\} \\ = & \frac{1}{2} \mathfrak{D}\cdot ( u_{i,k} + u_{i,k+1} ) \end{aligned}
where $ \mathfrak{D}\cdot u_{i,k} $ can be considered as the Crank-Nicolson finite difference operator on $u_{i,k}$.
$$ (1 + \frac{1}{2}\triangle t\fD)\cdot u_{i,k+1} = (1-\frac{1}{2}\triangle t\fD)\cdot u_{i,k} $$
This is also applicable when the spatial variable $x_i$ is a vector.
For the one spatial variable case, the operator $\fD$ involves three points in one time slice.
For two dimension case (the Heston model above), the operator will involve five points in one time slice.
So instead of solving a tridiagonal system, now the linear system has five nonzero diagonals, whcih is much more costly to solve.
\begin{aligned} (1 + \frac{1}{2}\triangle t\fD^1)\cdot \tilde{u}^1_{i,k+1} &= (1-\frac{1}{2}\triangle t\fD^1)\cdot u_{i,k} \\ (1 + \frac{1}{2}\triangle t\fD^2)\cdot \tilde{u}^2_{i,k+1} &= (1-\frac{1}{2}\triangle t\fD^2)\cdot \tilde{u}^1_{i,k} \\ \vdots \\ (1 + \frac{1}{2}\triangle t\fD^n)\cdot \tilde{u}^n_{i,k+1} &= (1-\frac{1}{2}\triangle t\fD^n)\cdot \tilde{u}^{n-1}_{i,k} \end{aligned}
and set
$$ u_{i+1,k} = \tilde{u}^n_{i,k} $$
import numpy as np
from scipy.stats import norm
import time
#Black and Scholes
def BlackScholesFormula(type, S0, K, r, sigma, T):
dtmp1 = np.log(S0 / K)
dtmp2 = 1.0/(sigma * np.sqrt(T))
sigsq = 0.5 * sigma * sigma
d1 = dtmp2 * (dtmp1 + T * (r + sigsq))
d2 = dtmp2 * (dtmp1 + T * (r - sigsq))
if type=="C":
return S0 * norm.cdf(d1) - K * np.exp(-r * T) * norm.cdf(d2)
else:
return K * np.exp(-r * T) * stats.cdf(-d2) - S0 * norm.cdf(-d1)
K = 100.0
r = 0.05
sigma = 0.35
T = 1
putCall ='C'
Smin = 0.0
Smax = 200.0
ns = 201
Ss = np.linspace(Smin, Smax, ns, endpoint=True)
Ss = Ss[1:-1]
#print Ss
t=time.time()
px = BlackScholesFormula(putCall, Ss, K, r, sigma, T)
elapsed=time.time()-t
print px
print "Elapsed Time:", elapsed
#idx = 200-1
#print Ss[idx]
#print px[idx]
payoff = clip(Ss-K, 0.0, 1e600)
#print "payoff = ", payoff
figure(figsize=[10, 4])
subplot(1, 2, 1)
plot(Ss, payoff)
xlabel('Stock', fontsize=14);
title('Payoff' , fontsize=16);
subplot(1, 2, 2)
plot(Ss, px)
xlabel('Stock', fontsize=14);
title('Analytical Solution' , fontsize=16);
[ 1.28766561e-39 5.53362091e-29 1.53135787e-23 5.00445199e-20 1.68889238e-17 1.46407871e-15 5.18474263e-14 9.78800798e-13 1.16276880e-11 9.70067620e-11 6.13310850e-10 3.10394648e-09 1.30958867e-08 4.75053666e-08 1.51752856e-07 4.35044961e-07 1.13639156e-06 2.73830396e-06 6.14907826e-06 1.29773535e-05 2.59235792e-05 4.93116756e-05 8.97803630e-05 1.57147519e-04 2.65452935e-04 4.34175578e-04 6.89611730e-04 1.06639082e-03 1.60909722e-03 2.37395905e-03 3.43056014e-03 4.86352770e-03 6.77414796e-03 9.28186285e-03 1.25256040e-02 1.66649252e-02 2.18809002e-02 2.83767600e-02 3.63782504e-02 4.61336992e-02 5.79137892e-02 7.20110398e-02 8.87390076e-02 1.08431222e-01 1.31439872e-01 1.58134278e-01 1.88899163e-01 2.24132765e-01 2.64244808e-01 3.09654380e-01 3.60787729e-01 4.18076027e-01 4.81953109e-01 5.52853236e-01 6.31208890e-01 7.17448635e-01 8.11995048e-01 9.15262759e-01 1.02765660e+00 1.14956987e+00 1.28138275e+00 1.42346084e+00 1.57615385e+00 1.73979446e+00 1.91469728e+00 2.10115801e+00 2.29945271e+00 2.50983725e+00 2.73254683e+00 2.96779573e+00 3.21577708e+00 3.47666283e+00 3.75060382e+00 4.03772986e+00 4.33815003e+00 4.65195304e+00 4.97920754e+00 5.31996271e+00 5.67424873e+00 6.04207739e+00 6.42344276e+00 6.81832181e+00 7.22667519e+00 7.64844792e+00 8.08357019e+00 8.53195807e+00 8.99351435e+00 9.46812932e+00 9.95568151e+00 1.04560385e+01 1.09690578e+01 1.14945874e+01 1.20324666e+01 1.25825269e+01 1.31445924e+01 1.37184810e+01 1.43040045e+01 1.49009696e+01 1.55091783e+01 1.61284289e+01 1.67585161e+01 1.73992318e+01 1.80503657e+01 1.87117056e+01 1.93830378e+01 2.00641481e+01 2.07548214e+01 2.14548427e+01 2.21639973e+01 2.28820712e+01 2.36088511e+01 2.43441252e+01 2.50876830e+01 2.58393160e+01 2.65988176e+01 2.73659834e+01 2.81406114e+01 2.89225024e+01 2.97114597e+01 3.05072897e+01 3.13098016e+01 3.21188080e+01 3.29341245e+01 3.37555702e+01 3.45829676e+01 3.54161424e+01 3.62549242e+01 3.70991457e+01 3.79486436e+01 3.88032578e+01 3.96628321e+01 4.05272138e+01 4.13962537e+01 4.22698063e+01 4.31477298e+01 4.40298856e+01 4.49161390e+01 4.58063586e+01 4.67004164e+01 4.75981879e+01 4.84995522e+01 4.94043912e+01 5.03125907e+01 5.12240391e+01 5.21386286e+01 5.30562539e+01 5.39768133e+01 5.49002078e+01 5.58263413e+01 5.67551209e+01 5.76864561e+01 5.86202595e+01 5.95564461e+01 6.04949339e+01 6.14356432e+01 6.23784968e+01 6.33234201e+01 6.42703407e+01 6.52191888e+01 6.61698966e+01 6.71223986e+01 6.80766314e+01 6.90325338e+01 6.99900465e+01 7.09491123e+01 7.19096758e+01 7.28716834e+01 7.38350835e+01 7.47998261e+01 7.57658631e+01 7.67331477e+01 7.77016349e+01 7.86712814e+01 7.96420452e+01 8.06138857e+01 8.15867639e+01 8.25606420e+01 8.35354837e+01 8.45112537e+01 8.54879183e+01 8.64654447e+01 8.74438014e+01 8.84229580e+01 8.94028851e+01 9.03835545e+01 9.13649388e+01 9.23470118e+01 9.33297481e+01 9.43131232e+01 9.52971137e+01 9.62816968e+01 9.72668506e+01 9.82525541e+01 9.92387868e+01 1.00225529e+02 1.01212762e+02 1.02200468e+02 1.03188629e+02 1.04177229e+02] Elapsed Time: 0.000999927520752
from scipy import sparse
import scipy.sparse.linalg.dsolve as linsolve
class BS_FDM_explicit:
def __init__(self,
r,
sigma,
maturity,
Smin,
Smax,
Fl,
Fu,
payoff,
nt,
ns):
self.r = r
self.sigma = sigma
self.maturity = maturity
self.Smin = Smin
self.Smax = Smax
self.Fl = Fl
self.Fu = Fu
self.nt = nt
self.ns = ns
self.dt = float(maturity)/nt
self.dx = float(Smax-Smin)/(ns+1)
self.xs = Smin/self.dx
self.u = empty((nt + 1, ns))
self.u[0,:] = payoff
## Building Coefficient matrix:
A = sparse.lil_matrix((self.ns, self.ns))
for j in xrange(0, self.ns):
xd = j + 1 + self.xs
sx = self.sigma * xd
sxsq = sx * sx
dtmp1 = self.dt * sxsq
dtmp2 = self.dt * self.r
A[j,j] = 1.0 - dtmp1 - dtmp2
dtmp1 = 0.5 * dtmp1
dtmp2 = 0.5 * dtmp2 * xd
if j > 0:
A[j,j-1] = dtmp1 - dtmp2
if j < self.ns - 1:
A[j,j+1] = dtmp1 + dtmp2
self.A = A.tocsr()
### Building bc_coef:
nxl = 1 + self.xs
sxl = self.sigma * nxl
nxu = self.ns + self.xs
sxu = self.sigma * nxu
self.blcoef = 0.5 * self.dt * (sxl * sxl - self.r * nxl)
self.bucoef = 0.5 * self.dt * (sxu * sxu + self.r * nxu)
def solve(self):
for i in xrange(0, m):
self.u[i+1,:] = self.A * self.u[i,:]
self.u[i+1,0] += self.blcoef * self.Fl[i]
self.u[i+1,self.ns-1] += self.bucoef * self.Fu[i]
return self.u
dx = (Smax - Smin)/(ns-1)
print "ns =", ns
print "dx =", dx
print "sigma =", sigma
dt_max = dx*dx/(sigma*sigma*Smax*Smax)
print "by CFL, dt <", dt_max
mt_min = int(T/dt_max)+1
print "mt_min ~= ", mt_min
ns = 201 dx = 1.0 sigma = 0.35 by CFL, dt < 0.000204081632653 mt_min ~= 4900
n = ns-2
X = linspace(0.0, Smax, n+2)
X = X[1:-1]
payoff = clip(X-K, 0.0, 1e600)
#print "payoff = ", payoff
m = 4555
Fl = zeros((m+1,))
Fu = Smax - K*exp(-r * linspace(0.0, T, m+1))
t = time.time()
bs1 = BS_FDM_explicit(r, sigma, T, Smin, Smax, Fl, Fu, payoff, m, n)
px_fd_mat = bs1.solve()
elapsed=time.time()-t
print "Elapsed Time1:", elapsed
##print px_fd_mat.shape
nrow = len(px_fd_mat[:,1])
print px_fd_mat[nrow-1,:]
figure(figsize=[15, 4]);
subplot(1, 3, 1)
plot(X, px_fd_mat[nrow-1,:])
xlabel('Stock', fontsize=14);
title('nx = %.f'%m, fontsize=16);
m = 4560
Fl = zeros((m+1,))
Fu = Smax - K*exp(-r * linspace(0.0, T, m+1))
t = time.time()
bs2 = BS_FDM_explicit(r, sigma, T, Smin, Smax, Fl, Fu, payoff, m, n)
px_fd_mat = bs2.solve()
elapsed=time.time()-t
print "Elapsed Time2:", elapsed
subplot(1, 3, 2)
nrow = len(px_fd_mat[:,1])
plot(X, px_fd_mat[nrow-1,:])
xlabel('Stock', fontsize=14);
title('nx = %.f'%m, fontsize=16);
m = 4565
Fl = zeros((m+1,))
Fu = Smax - K*exp(-r * linspace(0.0, T, m+1))
t = time.time()
bs3 = BS_FDM_explicit(r, sigma, T, Smin, Smax, Fl, Fu, payoff, m, n)
px_fd_mat = bs3.solve()
elapsed=time.time()-t
print "Elapsed Time3:", elapsed
subplot(1, 3, 3)
nrow = len(px_fd_mat[:,1])
plot(X, px_fd_mat[nrow-1,:])
xlabel('Stock', fontsize=14);
title('nx = %.f' % m, fontsize=16);
Elapsed Time1: 0.0460000038147 [ 4.07772413e-23 1.58474399e-20 1.73965059e-18 8.74535265e-17 2.49568562e-15 4.58093482e-14 5.87935695e-13 5.60665034e-12 4.16258352e-11 2.49732862e-10 1.24803027e-09 5.32745593e-09 1.98368066e-08 6.55753768e-08 1.95342914e-07 5.31044478e-07 1.33172299e-06 3.10914675e-06 6.81146334e-06 1.40982161e-05 2.77310391e-05 5.21031331e-05 9.39269921e-05 1.63093911e-04 2.73710967e-04 4.45312032e-04 7.04229658e-04 1.08510517e-03 1.63250565e-03 2.40260928e-03 3.46491532e-03 4.90393153e-03 6.82079120e-03 9.33475279e-03 1.25845383e-02 1.67294712e-02 2.19503804e-02 2.84502447e-02 3.64545569e-02 4.62113982e-02 5.79912176e-02 7.20863197e-02 8.88100703e-02 1.08495836e-01 1.31495676e-01 1.58178815e-01 1.88929915e-01 2.24147190e-01 2.64240376e-01 3.09628608e-01 3.60738215e-01 4.18000478e-01 4.81849371e-01 5.52719318e-01 6.31042986e-01 7.17249139e-01 8.11760571e-01 9.14992136e-01 1.02734890e+00 1.14922439e+00 1.28099903e+00 1.42303865e+00 1.57569319e+00 1.73929554e+00 1.91416052e+00 2.10058402e+00 2.29884230e+00 2.50919136e+00 2.73186658e+00 2.96708236e+00 3.21503195e+00 3.47588741e+00 3.74979962e+00 4.03689847e+00 4.33729310e+00 4.65107220e+00 4.97830447e+00 5.31903906e+00 5.67330611e+00 6.04111737e+00 6.42246685e+00 6.81733144e+00 7.22567170e+00 7.64743254e+00 8.08254400e+00 8.53092204e+00 8.99246929e+00 9.46707585e+00 9.95462009e+00 1.04549694e+01 1.09679810e+01 1.14935027e+01 1.20313735e+01 1.25814247e+01 1.31434803e+01 1.37173575e+01 1.43028680e+01 1.48998182e+01 1.55080097e+01 1.61272404e+01 1.67573046e+01 1.73979938e+01 1.80490973e+01 1.87104022e+01 1.93816947e+01 2.00627597e+01 2.07533816e+01 2.14533451e+01 2.21624346e+01 2.28804354e+01 2.36071337e+01 2.43423168e+01 2.50857736e+01 2.58372947e+01 2.65966726e+01 2.73637021e+01 2.81381802e+01 2.89199068e+01 2.97086840e+01 3.05043172e+01 3.13066146e+01 3.21153874e+01 3.29304500e+01 3.37516204e+01 3.45787194e+01 3.54115716e+01 3.62500049e+01 3.70938507e+01 3.79429437e+01 3.87971226e+01 3.96562292e+01 4.05201090e+01 4.13886111e+01 4.22615879e+01 4.31388956e+01 4.40203938e+01 4.49059452e+01 4.57954165e+01 4.66886774e+01 4.75856011e+01 4.84860639e+01 4.93899457e+01 5.02971292e+01 5.12075005e+01 5.21209489e+01 5.30373665e+01 5.39566484e+01 5.48786928e+01 5.58034006e+01 5.67306756e+01 5.76604244e+01 5.85925560e+01 5.95269824e+01 6.04636179e+01 6.14023794e+01 6.23431862e+01 6.32859600e+01 6.42306247e+01 6.51771066e+01 6.61253340e+01 6.70752380e+01 6.80267498e+01 6.89798084e+01 6.99343360e+01 7.08903187e+01 7.18475437e+01 7.28064348e+01 7.37654549e+01 7.47290004e+01 7.56839518e+01 7.66677184e+01 7.75754125e+01 7.86933146e+01 7.92584878e+01 8.12530925e+01 7.96565621e+01 8.68588532e+01 7.30811291e+01 1.07990554e+02 3.30302708e+01 1.99034047e+02 -1.48175809e+02 5.65252293e+02 -8.46307420e+02 1.86517555e+03 -3.16154189e+03 5.84112652e+03 -9.68847278e+03 1.60815607e+04 -2.49405793e+04 3.75380247e+04 -5.31645025e+04 7.17829508e+04 -9.05316708e+04 1.06627979e+05 -1.14453853e+05 1.09689360e+05 -8.78344405e+04 4.96751069e+04] Elapsed Time2: 0.0450000762939 Elapsed Time3: 0.0410001277924
Smax = 120
n = ns-2
X = linspace(0.0, Smax, n+2)
X = X[1:-1]
payoff = clip(X-K, 0.0, 1e600)
#print "payoff = ", payoff
m = 4570
Fl = zeros((m+1,))
Fu = zeros((m+1,))
t = time.time()
bs1 = BS_FDM_explicit(r, sigma, T, Smin, Smax, Fl, Fu, payoff, m, n)
px_fd_mat = bs1.solve()
elapsed=time.time()-t
print "Elapsed Time1:", elapsed
##print px_fd_mat.shape
nrow = len(px_fd_mat[:,1])
print px_fd_mat[nrow-1,:]
figure(figsize=[15, 4]);
subplot(1, 3, 1)
plot(X, px_fd_mat[nrow-1,:])
xlabel('Stock', fontsize=14);
title('nx = %.f'%m, fontsize=16);
m = 4573
Fl = zeros((m+1,))
Fu = zeros((m+1,))
t = time.time()
bs2 = BS_FDM_explicit(r, sigma, T, Smin, Smax, Fl, Fu, payoff, m, n)
px_fd_mat = bs2.solve()
elapsed=time.time()-t
print "Elapsed Time2:", elapsed
subplot(1, 3, 2)
nrow = len(px_fd_mat[:,1])
plot(X, px_fd_mat[nrow-1,:])
xlabel('Stock', fontsize=14);
title('nx = %.f'%m, fontsize=16);
m = 4580
Fl = zeros((m+1,))
Fu = zeros((m+1,))
t = time.time()
bs3 = BS_FDM_explicit(r, sigma, T, Smin, Smax, Fl, Fu, payoff, m, n)
px_fd_mat = bs3.solve()
elapsed=time.time()-t
print "Elapsed Time3:", elapsed
subplot(1, 3, 3)
nrow = len(px_fd_mat[:,1])
plot(X, px_fd_mat[nrow-1,:])
xlabel('Stock', fontsize=14);
title('nx = %.f' % m, fontsize=16);
Elapsed Time1: 0.0460000038147 [ 1.01704397e-28 5.07283379e-26 7.18984489e-24 4.68830891e-22 1.74072660e-20 4.16234095e-19 6.95467412e-18 8.61238308e-17 8.26824165e-16 6.37765319e-15 4.06932208e-14 2.20044937e-13 1.02914359e-12 4.23570647e-12 1.55695816e-11 5.17651596e-11 1.57382418e-10 4.41714179e-10 1.15387760e-09 2.82564962e-09 6.52727942e-09 1.43015144e-08 2.98649516e-08 5.96924592e-08 1.14628045e-07 2.12191890e-07 3.79775698e-07 6.58934313e-07 1.11098825e-06 1.82414722e-06 2.92234764e-06 4.57596663e-06 7.01453177e-06 1.05414905e-05 1.55510379e-05 2.25469294e-05 3.21631260e-05 4.51860447e-05 6.25781067e-05 8.55022075e-05 1.15346670e-04 1.53750189e-04 2.02626238e-04 2.64186378e-04 3.40961911e-04 4.35823312e-04 5.51996896e-04 6.93078223e-04 8.63041768e-04 1.06624646e-03 1.30743677e-03 1.59173903e-03 1.92465290e-03 2.31203775e-03 2.76009409e-03 3.27534000e-03 3.86458272e-03 4.53488566e-03 5.29353117e-03 6.14797920e-03 7.10582258e-03 8.17473908e-03 9.36244092e-03 1.06766222e-02 1.21249047e-02 1.37147828e-02 1.54535680e-02 1.73483331e-02 1.94058580e-02 2.16325751e-02 2.40345184e-02 2.66172723e-02 2.93859255e-02 3.23450254e-02 3.54985376e-02 3.88498080e-02 4.24015289e-02 4.61557096e-02 5.01136502e-02 5.42759210e-02 5.86423455e-02 6.32119876e-02 6.79831445e-02 7.29533428e-02 7.81193390e-02 8.34771256e-02 8.90219392e-02 9.47482747e-02 1.00649901e-01 1.06719884e-01 1.12950607e-01 1.19333799e-01 1.25860566e-01 1.32521423e-01 1.39306324e-01 1.46204708e-01 1.53205527e-01 1.60297295e-01 1.67468123e-01 1.74705766e-01 1.81997660e-01 1.89330975e-01 1.96692647e-01 2.04069434e-01 2.11447949e-01 2.18814709e-01 2.26156179e-01 2.33458809e-01 2.40709078e-01 2.47893532e-01 2.54998828e-01 2.62011762e-01 2.68919314e-01 2.75708677e-01 2.82367293e-01 2.88882878e-01 2.95243460e-01 3.01437400e-01 3.07453417e-01 3.13280617e-01 3.18908511e-01 3.24327033e-01 3.29526565e-01 3.34497943e-01 3.39232480e-01 3.43721975e-01 3.47958722e-01 3.51935520e-01 3.55645682e-01 3.59083036e-01 3.62241932e-01 3.65117244e-01 3.67704370e-01 3.69999230e-01 3.71998265e-01 3.73698434e-01 3.75097207e-01 3.76192563e-01 3.76982977e-01 3.77467420e-01 3.77645341e-01 3.77516663e-01 3.77081772e-01 3.76341503e-01 3.75297128e-01 3.73950345e-01 3.72303264e-01 3.70358392e-01 3.68118620e-01 3.65587208e-01 3.62767768e-01 3.59664251e-01 3.56280934e-01 3.52622398e-01 3.48693515e-01 3.44499436e-01 3.40045570e-01 3.35337570e-01 3.30381318e-01 3.25182908e-01 3.19748632e-01 3.14084962e-01 3.08198542e-01 3.02096154e-01 2.95784760e-01 2.89271303e-01 2.82563285e-01 2.75666908e-01 2.68592676e-01 2.61338692e-01 2.53939079e-01 2.46326719e-01 2.38712943e-01 2.30562309e-01 2.23293232e-01 2.13339863e-01 2.09528451e-01 1.90671166e-01 2.06361812e-01 1.43753470e-01 2.52562922e-01 -3.99580310e-03 4.94288821e-01 -5.19976227e-01 1.40031289e+00 -2.18719234e+00 4.21080703e+00 -6.85231546e+00 1.14799447e+01 -1.77278041e+01 2.67320910e+01 -3.78361940e+01 5.10864915e+01 -6.44524111e+01 7.58680118e+01 -8.14990126e+01 7.80272499e+01 -6.25720798e+01 3.52918730e+01] Elapsed Time2: 0.0469999313354 Elapsed Time3: 0.047000169754
from scipy import sparse
import scipy.sparse.linalg.dsolve as linsolve
class BS_FDM_implicit:
def __init__(self,
r,
sigma,
maturity,
Smin,
Smax,
Fl,
Fu,
payoff,
nt,
ns):
self.r = r
self.sigma = sigma
self.maturity = maturity
self.Smin = Smin
self.Smax = Smax
self.Fl = Fl
self.Fu = Fu
self.nt = nt
self.ns = ns
self.dt = float(maturity)/nt
self.dx = float(Smax-Smin)/(ns+1)
self.xs = Smin/self.dx
self.u = empty((nt + 1, ns))
self.u[0,:] = payoff
## Building Coefficient matrix:
A = sparse.lil_matrix((self.ns, self.ns))
for j in xrange(0, self.ns):
xd = j + 1 + self.xs
sx = self.sigma * xd
sxsq = sx * sx
dtmp1 = self.dt * sxsq
dtmp2 = self.dt * self.r
A[j,j] = 1.0 + dtmp1 + dtmp2
dtmp1 = -0.5 * dtmp1
dtmp2 = -0.5 * dtmp2 * xd
if j > 0:
A[j,j-1] = dtmp1 - dtmp2
if j < self.ns - 1:
A[j,j+1] = dtmp1 + dtmp2
self.A = linsolve.splu(A)
self.rhs = empty((self.ns, ))
### Building bc_coef:
nxl = 1 + self.xs
sxl = self.sigma * nxl
nxu = self.ns + self.xs
sxu = self.sigma * nxu
self.blcoef = 0.5 * self.dt * (- sxl * sxl + self.r * nxl)
self.bucoef = 0.5 * self.dt * (- sxu * sxu - self.r * nxu)
def solve(self):
for i in xrange(0, m):
self.rhs[:] = self.u[i,:]
self.rhs[0] -= self.blcoef * self.Fl[i]
self.rhs[self.ns-1] -= self.bucoef * self.Fu[i]
self.u[i+1,:] = self.A.solve(self.rhs)
return self.u
Smax = 200
n = ns-2
X = linspace(0.0, Smax, n+2)
X = X[1:-1]
payoff = clip(X-K, 0.0, 1e600)
m = 4555
Fl = zeros((m+1,))
Fu = Smax - K*exp(-r * linspace(0.0, T, m+1))
t = time.time()
bs1 = BS_FDM_implicit(r, sigma, T, Smin, Smax, Fl, Fu, payoff, m, n)
px_fd_mat = bs1.solve()
elapsed=time.time()-t
print "Elapsed Time1:", elapsed
#print px_fd_mat.shape
figure(figsize=[15, 4]);
subplot(1, 3, 1)
nrow = len(px_fd_mat[:,1])
plot(X, px_fd_mat[nrow-1,:])
xlabel('Stock', fontsize=14);
title('nx = %.f'%m, fontsize=16);
m = 1000
Fl = zeros((m+1,))
Fu = Smax - K*exp(-r * linspace(0.0, T, m+1))
t = time.time()
bs2 = BS_FDM_implicit(r, sigma, T, Smin, Smax, Fl, Fu, payoff, m, n)
px_fd_mat = bs2.solve()
elapsed=time.time()-t
print "Elapsed Time2:", elapsed
subplot(1, 3, 2)
nrow = len(px_fd_mat[:,1])
plot(X, px_fd_mat[nrow-1,:])
xlabel('Stock', fontsize=14);
title('nx = %.f'%m, fontsize=16);
m = 100
Fl = zeros((m+1,))
Fu = Smax - K*exp(-r * linspace(0.0, T, m+1))
t = time.time()
bs3 = BS_FDM_implicit(r, sigma, T, Smin, Smax, Fl, Fu, payoff, m, n)
px_fd_mat = bs3.solve()
elapsed=time.time()-t
print "Elapsed Time3:", elapsed
subplot(1, 3, 3)
nrow = len(px_fd_mat[:,1])
plot(X, px_fd_mat[nrow-1,:])
xlabel('Stock', fontsize=14);
title('nx = %.f'%m, fontsize=16);
print px_fd_mat[nrow-1,:]
Elapsed Time1: 0.0649998188019 Elapsed Time2: 0.0190000534058 Elapsed Time3: 0.00699996948242 [ 2.98641926e-21 7.95294389e-19 6.07132757e-17 2.16141936e-15 4.46125332e-14 6.06271497e-13 5.90512355e-12 4.38258315e-11 2.59592502e-10 1.27238057e-09 5.31142971e-09 1.93277995e-08 6.24868999e-08 1.82323286e-07 4.86411656e-07 1.19954343e-06 2.75978915e-06 5.97002567e-06 1.22239975e-05 2.38272713e-05 4.44331425e-05 7.96114517e-05 1.37564347e-04 2.29997480e-04 3.73148280e-04 5.88965351e-04 9.06425082e-04 1.36296400e-03 2.00599845e-03 2.89449764e-03 4.10057163e-03 5.71103357e-03 7.82889451e-03 1.05747499e-02 1.40880193e-02 1.85280050e-02 2.40747384e-02 3.09295924e-02 3.93156382e-02 4.94777381e-02 6.16823668e-02 7.62171638e-02 9.33902216e-02 1.13529124e-01 1.36979747e-01 1.64104854e-01 1.95282487e-01 2.30904205e-01 2.71373176e-01 3.17102172e-01 3.68511464e-01 4.26026688e-01 4.90076661e-01 5.61091218e-01 6.39499062e-01 7.25725659e-01 8.20191211e-01 9.23308698e-01 1.03548203e+00 1.15710433e+00 1.28855625e+00 1.43020460e+00 1.58240089e+00 1.74548019e+00 1.91976005e+00 2.10553959e+00 2.30309872e+00 2.51269751e+00 2.73457569e+00 2.96895229e+00 3.21602540e+00 3.47597205e+00 3.74894819e+00 4.03508884e+00 4.33450820e+00 4.64730004e+00 4.97353796e+00 5.31327594e+00 5.66654874e+00 6.03337257e+00 6.41374561e+00 6.80764873e+00 7.21504618e+00 7.63588627e+00 8.07010218e+00 8.51761268e+00 8.97832294e+00 9.45212526e+00 9.93889993e+00 1.04385160e+01 1.09508320e+01 1.14756967e+01 1.20129500e+01 1.25624237e+01 1.31239419e+01 1.36973221e+01 1.42823756e+01 1.48789083e+01 1.54867214e+01 1.61056120e+01 1.67353733e+01 1.73757958e+01 1.80266675e+01 1.86877743e+01 1.93589007e+01 2.00398302e+01 2.07303457e+01 2.14302298e+01 2.21392656e+01 2.28572363e+01 2.35839265e+01 2.43191215e+01 2.50626084e+01 2.58141760e+01 2.65736149e+01 2.73407182e+01 2.81152810e+01 2.88971013e+01 2.96859798e+01 3.04817200e+01 3.12841285e+01 3.20930149e+01 3.29081921e+01 3.37294765e+01 3.45566877e+01 3.53896488e+01 3.62281863e+01 3.70721305e+01 3.79213151e+01 3.87755775e+01 3.96347584e+01 4.04987026e+01 4.13672580e+01 4.22402765e+01 4.31176133e+01 4.39991273e+01 4.48846808e+01 4.57741397e+01 4.66673732e+01 4.75642541e+01 4.84646585e+01 4.93684656e+01 5.02755581e+01 5.11858218e+01 5.20991457e+01 5.30154219e+01 5.39345454e+01 5.48564144e+01 5.57809297e+01 5.67079952e+01 5.76375175e+01 5.85694058e+01 5.95035723e+01 6.04399313e+01 6.13784001e+01 6.23188981e+01 6.32613474e+01 6.42056721e+01 6.51517989e+01 6.60996564e+01 6.70491758e+01 6.80002898e+01 6.89529337e+01 6.99070444e+01 7.08625609e+01 7.18194239e+01 7.27775760e+01 7.37369617e+01 7.46975269e+01 7.56592194e+01 7.66219884e+01 7.75857847e+01 7.85505608e+01 7.95162703e+01 8.04828685e+01 8.14503119e+01 8.24185583e+01 8.33875669e+01 8.43572980e+01 8.53277132e+01 8.62987752e+01 8.72704478e+01 8.82426958e+01 8.92154852e+01 9.01887830e+01 9.11625570e+01 9.21367761e+01 9.31114100e+01 9.40864295e+01 9.50618059e+01 9.60375116e+01 9.70135196e+01 9.79898040e+01 9.89663392e+01 9.99431006e+01 1.00920064e+02 1.01897207e+02 1.02874505e+02 1.03851938e+02]
Smax = 120
n = ns-2
X = linspace(0.0, Smax, n+2)
X = X[1:-1]
payoff = clip(X-K, 0.0, 1e600)
m = 4555
Fl = zeros((m+1,))
Fu = zeros((m+1,))
t = time.time()
bs1 = BS_FDM_implicit(r, sigma, T, Smin, Smax, Fl, Fu, payoff, m, n)
px_fd_mat = bs1.solve()
elapsed=time.time()-t
print "Elapsed Time1:", elapsed
#print px_fd_mat.shape
figure(figsize=[15, 4]);
subplot(1, 3, 1)
nrow = len(px_fd_mat[:,1])
plot(X, px_fd_mat[nrow-1,:])
xlabel('Stock', fontsize=14);
title('nx = %.f'%m, fontsize=16);
m = 1000
Fl = zeros((m+1,))
Fu = zeros((m+1,))
t = time.time()
bs2 = BS_FDM_implicit(r, sigma, T, Smin, Smax, Fl, Fu, payoff, m, n)
px_fd_mat = bs2.solve()
elapsed=time.time()-t
print "Elapsed Time2:", elapsed
subplot(1, 3, 2)
nrow = len(px_fd_mat[:,1])
plot(X, px_fd_mat[nrow-1,:])
xlabel('Stock', fontsize=14);
title('nx = %.f'%m, fontsize=16);
m = 100
Fl = zeros((m+1,))
Fu = zeros((m+1,))
t = time.time()
bs3 = BS_FDM_implicit(r, sigma, T, Smin, Smax, Fl, Fu, payoff, m, n)
px_fd_mat = bs3.solve()
elapsed=time.time()-t
print "Elapsed Time3:", elapsed
subplot(1, 3, 3)
nrow = len(px_fd_mat[:,1])
plot(X, px_fd_mat[nrow-1,:])
xlabel('Stock', fontsize=14);
title('nx = %.f'%m, fontsize=16);
print px_fd_mat[nrow-1,:]
Elapsed Time1: 0.0629999637604 Elapsed Time2: 0.0190000534058 Elapsed Time3: 0.00899982452393 [ 7.86391997e-26 2.43630771e-23 2.17528767e-21 9.09456815e-20 2.21047505e-18 3.54181257e-17 4.06680009e-16 3.55313181e-15 2.47154878e-14 1.41799741e-13 6.90208717e-13 2.91621919e-12 1.08981438e-11 3.65882728e-11 1.11800634e-10 3.14357643e-10 8.20959540e-10 2.00717719e-09 4.62568425e-09 1.01075920e-08 2.10483475e-08 4.19585339e-08 8.03800929e-08 1.48488656e-07 2.65321208e-07 4.59783507e-07 7.74601788e-07 1.27138672e-06 2.03697314e-06 3.19118575e-06 4.89615859e-06 7.36730436e-06 1.08859900e-05 1.58139276e-05 2.26092360e-05 3.18440739e-05 4.42236828e-05 6.06066236e-05 8.20259326e-05 1.09710872e-04 1.45108906e-04 1.89907492e-04 2.46055265e-04 3.15782142e-04 4.01617915e-04 5.06408855e-04 6.33331909e-04 7.85906063e-04 9.68000495e-04 1.18383919e-03 1.43800172e-03 1.73541999e-03 2.08137073e-03 2.48146367e-03 2.94162538e-03 3.46807874e-03 4.06731814e-03 4.74608068e-03 5.51131338e-03 6.37013683e-03 7.32980557e-03 8.39766541e-03 9.58110837e-03 1.08875253e-02 1.23242571e-02 1.38985441e-02 1.56174758e-02 1.74879390e-02 1.95165671e-02 2.17096898e-02 2.40732837e-02 2.66129244e-02 2.93337411e-02 3.22403726e-02 3.53369270e-02 3.86269431e-02 4.21133563e-02 4.57984671e-02 4.96839136e-02 5.37706478e-02 5.80589157e-02 6.25482418e-02 6.72374173e-02 7.21244924e-02 7.72067733e-02 8.24808223e-02 8.79424628e-02 9.35867870e-02 9.94081690e-02 1.05400280e-01 1.11556106e-01 1.17867972e-01 1.24327569e-01 1.30925975e-01 1.37653695e-01 1.44500684e-01 1.51456391e-01 1.58509791e-01 1.65649421e-01 1.72863426e-01 1.80139595e-01 1.87465404e-01 1.94828057e-01 2.02214531e-01 2.09611616e-01 2.17005958e-01 2.24384105e-01 2.31732543e-01 2.39037742e-01 2.46286193e-01 2.53464452e-01 2.60559173e-01 2.67557150e-01 2.74445350e-01 2.81210949e-01 2.87841363e-01 2.94324281e-01 3.00647696e-01 3.06799929e-01 3.12769658e-01 3.18545941e-01 3.24118239e-01 3.29476437e-01 3.34610862e-01 3.39512300e-01 3.44172009e-01 3.48581737e-01 3.52733727e-01 3.56620734e-01 3.60236024e-01 3.63573389e-01 3.66627143e-01 3.69392131e-01 3.71863730e-01 3.74037843e-01 3.75910904e-01 3.77479872e-01 3.78742226e-01 3.79695962e-01 3.80339584e-01 3.80672096e-01 3.80692997e-01 3.80402265e-01 3.79800354e-01 3.78888175e-01 3.77667089e-01 3.76138892e-01 3.74305803e-01 3.72170448e-01 3.69735846e-01 3.67005398e-01 3.63982863e-01 3.60672354e-01 3.57078312e-01 3.53205495e-01 3.49058961e-01 3.44644053e-01 3.39966381e-01 3.35031804e-01 3.29846420e-01 3.24416543e-01 3.18748691e-01 3.12849567e-01 3.06726049e-01 3.00385168e-01 2.93834095e-01 2.87080130e-01 2.80130679e-01 2.72993250e-01 2.65675428e-01 2.58184871e-01 2.50529291e-01 2.42716442e-01 2.34754109e-01 2.26650094e-01 2.18412206e-01 2.10048248e-01 2.01566006e-01 1.92973243e-01 1.84277682e-01 1.75487001e-01 1.66608823e-01 1.57650706e-01 1.48620136e-01 1.39524521e-01 1.30371177e-01 1.21167330e-01 1.11920100e-01 1.02636504e-01 9.33234429e-02 8.39876998e-02 7.46359341e-02 6.52746771e-02 5.59103273e-02 4.65491469e-02 3.71972583e-02 2.78606405e-02 1.85451268e-02 9.25640199e-03]