# LSM Algorithm for American Put in BCC97
# Delta Hedging an American Put Option in BCC97
# via Least Squares Monte Carlo (Multiple Replications)
#
import sys
sys.path.extend(['09_gmm', '11_cal', '12_val'])
import math
import numpy as np
import warnings
warnings.simplefilter('ignore')
import matplotlib as mpl
mpl.rcParams['font.family'] = 'serif'
import matplotlib.pyplot as plt
from H93_calibration import S0, kappa_r, theta_r, sigma_r, r0
from BCC97_simulation import *
from BSM_lsm_hedging_algorithm import plot_hedge_path
#
# Model Parameters
#
opt = np.load('11_cal/opt_full.npy')
kappa_v, theta_v, sigma_v, rho, v0, lamb, mu, delta = opt
#
# Simulation
#
K = S0
T = 1.0
M = 50
I = 50000
a = 1.0 # a from the interval [0.0, 2.0]
dis = 0.01 # change of S[t] in percent to estimate derivative
dt = T / M
moment_matching = True
def BCC97_lsm_put_value(S0, K, T, M, I):
''' Function to value American put options by LSM algorithm.
Parameters
==========
S0: float
intial index level
K: float
strike of the put option
T: float
final date/time horizon
M: int
number of time steps
I: int
number of paths
Returns
=======
V0: float
LSM Monte Carlo estimator of American put option value
S: NumPy array
simulated index level paths
r: NumPy array
simulated short rate paths
v: NumPy array
simulated variance paths
ex: NumPy array
exercise matrix
rg: NumPy array
regression coefficients
h: NumPy array
inner value matrix
dt: float
length of time interval
'''
dt = T / M
# Cholesky Matrix
cho_matrix = generate_cholesky(rho)
# Random Numbers
rand = random_number_generator(M, I, anti_paths, moment_matching)
# Short Rate Process Simulation
r = SRD_generate_paths(r0, kappa_r, theta_r, sigma_r, T, M, I,
rand, 0, cho_matrix)
# Variance Process Simulation
v = SRD_generate_paths(v0, kappa_v, theta_v, sigma_v, T, M, I,
rand, 2, cho_matrix)
# Index Level Process Simulation
S = B96_generate_paths(S0, r, v, lamb, mu, delta, rand, 1, 3,
cho_matrix, T, M, I, moment_matching)
h = np.maximum(K - S, 0) # inner value matrix
V = np.maximum(K - S, 0) # value/cash flow matrix
ex = np.zeros_like(V) # exercise matrix
D = 10 # number of regression functions
rg = np.zeros((M + 1, D + 1), dtype=np.float)
# matrix for regression parameters
for t in xrange(M - 1, 0, -1):
df = np.exp(-(r[t] + r[t + 1]) / 2 * dt)
# select only ITM paths
itm = np.greater(h[t], 0)
relevant = np.nonzero(itm)
rel_S = np.compress(itm, S[t])
no_itm = len(rel_S)
if no_itm == 0:
cv = np.zeros((I), dtype=np.float)
else:
rel_v = np.compress(itm, v[t])
rel_r = np.compress(itm, r[t])
rel_V = (np.compress(itm, V[t + 1])
* np.compress(itm, df))
matrix = np.zeros((D + 1, no_itm), dtype=np.float)
matrix[10] = rel_S * rel_v * rel_r
matrix[9] = rel_S * rel_v
matrix[8] = rel_S * rel_r
matrix[7] = rel_v * rel_r
matrix[6] = rel_S ** 2
matrix[5] = rel_v ** 2
matrix[4] = rel_r ** 2
matrix[3] = rel_S
matrix[2] = rel_v
matrix[1] = rel_r
matrix[0] = 1
rg[t] = np.linalg.lstsq(matrix.transpose(), rel_V)[0]
cv = np.dot(rg[t], matrix)
erg = np.zeros((I), dtype=np.float)
np.put(erg, relevant, cv)
V[t] = np.where(h[t] > erg, h[t], V[t + 1] * df)
# value array
ex[t] = np.where(h[t] > erg, 1, 0)
# exercise decision
df = np.exp(-((r[0] + r[1]) / 2) * dt)
V0 = max(np.sum(V[1, :] * df) / I, h[0, 0]) # LSM estimator
return V0, S, r, v, ex, rg, h, dt
def BCC97_hedge_run(p):
''' Implements delta hedging for a single path. '''
#
# Initializations
#
np.random.seed(50000)
po = np.zeros(M + 1, dtype=np.float) # vector for portfolio values
vt = np.zeros(M + 1, dtype=np.float) # vector for option values
delt = np.zeros(M + 1, dtype=np.float) # vector for deltas
# random path selection ('real path')
print
print "DYNAMIC HEDGING OF AMERICAN PUT (BCC97)"
print "---------------------------------------"
ds = dis * S0
V_1, S, r, v, ex, rg, h, dt = BCC97_lsm_put_value(S0 + (2 - a) * ds,
K, T, M, I)
# 'data basis' for delta hedging
V_2 = BCC97_lsm_put_value(S0 - a * ds, K, T, M, I)[0]
delt[0] = (V_1 - V_2) / (2 * ds)
V0LSM = BCC97_lsm_put_value(S0, K, T, M, I)[0]
# initial option value for S0
vt[0] = V0LSM # initial option values
po[0] = V0LSM # initial portfolio values
bo = V0LSM - delt[0] * S0 # initial bond position value
print "Initial Hedge"
print "Stocks %8.3f" % delt[0]
print "Bonds %8.3f" % bo
print "Cost %8.3f" % (delt[0] * S0 + bo)
print
print "Regular Rehedges "
print 82 * "-"
print "step|" + 7 * " %9s|" % ('S_t', 'Port', 'Put',
'Diff', 'Stock', 'Bond', 'Cost')
for t in range(1, M + 1, 1):
if ex[t, p] == 0:
df = math.exp((r[t, p] + r[t - 1, p]) / 2 * dt)
if t != M:
po[t] = delt[t - 1] * S[t, p] + bo * df
vt[t] = BCC97_lsm_put_value(S[t, p], K, T - t * dt,
M - t, I)[0]
ds = dis * S[t, p]
sd = S[t, p] + (2 - a) * ds # disturbed index level
stateV_A = [sd * v[t, p] * r[t, p],
sd * v[t, p],
sd * r[t, p],
v[t, p] * r[t, p],
sd ** 2,
v[t, p] ** 2,
r[t, p] ** 2,
sd,
v[t, p],
r[t, p],
1]
# state vector for S[t, p] + (2.0 - a) * dis
stateV_A.reverse()
V0A = max(0, np.dot(rg[t], stateV_A))
# print V0A
# revaluation via regression
sd = S[t, p] - a * ds # disturbed index level
stateV_B = [sd * v[t, p] * r[t, p],
sd * v[t, p],
sd * r[t, p],
v[t, p] * r[t, p],
sd ** 2,
v[t, p] ** 2,
r[t, p] ** 2,
sd,
v[t, p],
r[t, p],
1]
# state vector for S[t, p] - a * dis
stateV_B.reverse()
V0B = max(0, np.dot(rg[t], stateV_B))
# print V0B
# revaluation via regression
delt[t] = (V0A - V0B) / (2 * ds)
bo = po[t] - delt[t] * S[t, p] # bond position value
else:
po[t] = delt[t - 1] * S[t, p] + bo * df
vt[t] = h[t, p]
# inner value at final date
delt[t] = 0.0
print "%4d|" % t + 7 * " %9.3f|" % (S[t, p], po[t], vt[t],
(po[t] - vt[t]), delt[t], bo, delt[t] * S[t, p] + bo)
else:
po[t] = delt[t - 1] * S[t, p] + bo * df
vt[t] = h[t, p]
break
errs = po - vt # hedge errors
print "MSE %7.3f" % (np.sum(errs ** 2) / len(errs))
print "Average Error %7.3f" % (np.sum(errs) / len(errs))
print "Total P&L %7.3f" % np.sum(errs)
return S[:, p], po, vt, errs, t