# Binomial Valuation # # Valuation of American Options # with the Cox-Ross-Rubinstein Model # Primal Algorithm # Case 1: American Put Option (APO) # Case 2: Short Condor Spread (SCS) # import math import numpy as np # General Parameters and Option Values def set_parameters(otype, M): ''' Sets parameters depending on valuation case. Parameters ========== otype: int option type 1 = American put option 2 = Short Condor Spread ''' if otype == 1: # Parameters -- American Put Option S0 = 36. # initial stock level T = 1.0 # time-to-maturity r = 0.06 # short rate sigma = 0.2 # volatility elif otype == 2: # Parameters -- Short Condor Spread S0 = 100. # initial stock level T = 1.0 # time-to-maturity r = 0.05 # short rate sigma = 0.5 # volatility else: raise ValueError('Option type not known.') # Numerical Parameters dt = T / M # time interval df = math.exp(-r * dt) # discount factor u = math.exp(sigma * math.sqrt(dt)) # up-movement d = 1 / u # down-movement q = (math.exp(r * dt) - d) / (u - d) # martingale probability return S0, T, r, sigma, M, dt, df, u, d, q def inner_value(S, otype): ''' Inner value functions for American put option and short condor spread option with American exercise. Parameters ========== otype: int option type 1 = American put option 2 = Short Condor Spread ''' if otype == 1: return np.maximum(40. - S, 0) elif otype == 2: return np.minimum(40., np.maximum(90. - S, 0) + np.maximum(S - 110., 0)) else: raise ValueError('Option type not known.') def CRR_option_valuation(otype, M=500): S0, T, r, sigma, M, dt, df, u, d, q = set_parameters(otype, M) # Array Generation for Stock Prices mu = np.arange(M + 1) mu = np.resize(mu, (M + 1, M + 1)) md = np.transpose(mu) mu = u ** (mu - md) md = d ** md S = S0 * mu * md # Valuation by Backwards Induction h = inner_value(S, otype) # innver value matrix V = inner_value(S, otype) # value matrix C = np.zeros((M + 1, M + 1), dtype=np.float) # continuation values ex = np.zeros((M + 1, M + 1), dtype=np.float) # exercise matrix z = 0 for i in range(M - 1, -1, -1): C[0:M - z, i] = (q * V[0:M - z, i + 1] + (1 - q) * V[1:M - z + 1, i + 1]) * df V[0:M - z, i] = np.where(h[0:M - z, i] > C[0:M - z, i], h[0:M - z, i], C[0:M - z, i]) ex[0:M - z, i] = np.where(h[0:M - z, i] > C[0:M - z, i], 1, 0) z += 1 return V[0, 0]