def implicit(self, N, M): S = self.S K = self.K r = self.r q = self.q T = self.T sigma = self.sigma # Step 1: t_delta = T / N S_max = 2 * K S_delta = S_max / M # Step 2: Fc_hat = [[0 for _ in range(N + 1)] for _ in range(M + 1)] Fp_hat = [[0 for _ in range(N + 1)] for _ in range(M + 1)] Fc = [[0 for _ in range(N + 1)] for _ in range(M + 1)] Fp = [[0 for _ in range(N + 1)] for _ in range(M + 1)] for j in range(M + 1): Fc[j][N] = max(j * S_delta - K, 0) Fp[j][N] = max(K - j * S_delta, 0) # Step 3: for i in range(N - 1, -1, -1): # Step 3.1: for j in range(1, M): Fc_hat[j][i + 1] = Fc[j][i + 1] Fp_hat[j][i + 1] = Fp[j][i + 1] Fc_hat[0][i + 1] = 0 Fc_hat[M][i + 1] = S_max - K * math.exp(-r * (N - i) * t_delta) Fp_hat[0][i + 1] = K * math.exp(-r * (N - i) * t_delta) Fp_hat[M][i + 1] = 0 # Step 3.2: A = [[0 for _ in range(M + 1)] for _ in range(M + 1)] A[0][0] = 1 for j in range(1, M): A[j][j - 1] = 0.5 * t_delta * ((r - q) * j - sigma * sigma * j * j) A[j][j] = 1 + t_delta * (sigma * sigma * j * j + r) A[j][j + 1] = -0.5 * t_delta * (sigma * sigma * j * j + (r - q) * j) A[M][M] = 1 A_inv = matrixOperations.inverse(A) Fc_hat_col = [[Fc_hat[j][i + 1]] for j in range(M + 1)] Fp_hat_col = [[Fp_hat[j][i + 1]] for j in range(M + 1)] Fc_col = matrixOperations.multiply(A_inv, Fc_hat_col) Fp_col = matrixOperations.multiply(A_inv, Fp_hat_col) for j in range(M + 1): Fc[j][i] = Fc_col[j][0] Fp[j][i] = Fp_col[j][0] # Step 4: k = int(math.floor(S / S_delta)) # Step 5: Vc = Fc[k][0] + (Fc[k + 1][0] - Fc[k][0]) / S_delta * (S - k * S_delta) Vp = Fp[k][0] + (Fp[k + 1][0] - Fp[k][0]) / S_delta * (S - k * S_delta) return {"call": Vc, "put": Vp}
def crankNicolson(S, K, r, q, T, sigma, N, M): # Step 1: t_delta = T / N S_max = 2 * K S_delta = S_max / M # Step 2: Fc = [[0 for _ in range(N + 1)] for _ in range(M + 1)] Fp = [[0 for _ in range(N + 1)] for _ in range(M + 1)] for j in range(M + 1): Fc[j][N] = max(j * S_delta - K, 0) Fp[j][N] = max(K - j * S_delta, 0) # Step 3: for i in range(N - 1, -1, -1): # Step 3.1, 3.2: bc = [[0] for _ in range(M + 1)] bp = [[0] for _ in range(M + 1)] for j in range(1, M): alpha = 0.25 * t_delta * (sigma * sigma * j * j - (r - q) * j) beta = -0.5 * t_delta * (sigma * sigma + r) gamma = 0.25 * t_delta * (sigma * sigma * j * j + (r - q) * j) bc[j][0] = alpha * Fc[j - 1][i + 1] + beta * Fc[j][i + 1] + gamma * Fc[j + 1][i + 1] bp[j][0] = alpha * Fp[j - 1][i + 1] + beta * Fp[j][i + 1] + gamma * Fp[j + 1][i + 1] bc[0][0] = 0 bc[M][0] = S_max - K * math.exp(-r * (N - i) * t_delta) bp[0][0] = K * math.exp(-r * (N - i) * t_delta) bp[M][0] = 0 # Step 3.3: M1 = [[0 for _ in range(M + 1)] for _ in range(M + 1)] M1[0][0] = 1 M1[M][M] = 1 for j in range(1, M): M1[j][j - 1] = 0.25 * t_delta * (sigma * sigma * j * j - (r - q) * j) M1[j][j] = -0.5 * t_delta * (sigma * sigma + r) M1[j][j + 1] = 0.25 * t_delta * (sigma * sigma * j * j + (r - q) * j) M1_inv = matrixOperations.inverse(M1) Fc_col = matrixOperations.multiply(M1_inv, bc) Fp_col = matrixOperations.multiply(M1_inv, bp) for j in range(M + 1): Fc[j][i] = Fc_col[j][0] Fp[j][i] = Fp_col[j][0] # Step 4: k = int(math.floor(S / S_delta)) # Step 5: Vc = Fc[k][0] + (Fc[k + 1][0] - Fc[k][0]) / S_delta * (S - k * S_delta) Vp = Fp[k][0] + (Fp[k + 1][0] - Fp[k][0]) / S_delta * (S - k * S_delta) return {"call": Vc, "put": Vp}
def ImplicitFDM(self, M, N): # 1 t_delta = self.T / N S_max = 2 * self.K S_delta = S_max / M # 2 Fc_hat = [[0 for _ in range(N + 1)] for _ in range(M + 1)] Fp_hat = [[0 for _ in range(N + 1)] for _ in range(M + 1)] Fc = [[0 for _ in range(N + 1)] for _ in range(M + 1)] Fp = [[0 for _ in range(N + 1)] for _ in range(M + 1)] for j in range(M + 1): Fc[j][N] = max(j * S_delta - self.K, 0) Fp[j][N] = max(self.K - j * S_delta, 0) # 3 A = [[0 for _ in range(M + 1)] for _ in range(M + 1)] A[0][0] = 1 for j in range(1, M): A[j][j - 1] = 0.5 * t_delta * ( (self.r - self.q) * j - self.sigma * self.sigma * j * j) A[j][j] = 1 + t_delta * (self.sigma * self.sigma * j * j + self.r) A[j][j + 1] = -0.5 * t_delta * (self.sigma * self.sigma * j * j + (self.r - self.q) * j) A[M][M] = 1 A_inv = matrixOperations.inverse(A) for i in range(N - 1, -1, -1): # 3.1 for j in range(1, M): Fc_hat[j][i + 1] = Fc[j][i + 1] Fp_hat[j][i + 1] = Fp[j][i + 1] Fc_hat[0][i + 1] = 0 Fc_hat[M][i + 1] = S_max - self.K * exp(-self.r * (N - i) * t_delta) Fp_hat[0][i + 1] = self.K * exp(-self.r * (N - i) * t_delta) Fp_hat[M][i + 1] = 0 # 3.2 Fc_hat_col = [[Fc_hat[j][i + 1]] for j in range(M + 1)] Fp_hat_col = [[Fp_hat[j][i + 1]] for j in range(M + 1)] Fc_col = matrixOperations.multiply(A_inv, Fc_hat_col) Fp_col = matrixOperations.multiply(A_inv, Fp_hat_col) for j in range(M + 1): Fc[j][i] = Fc_col[j][0] Fp[j][i] = Fp_col[j][0] # 4 k = int(floor(self.S / S_delta)) # 5 Vc = (Fc[k][0] + (Fc[k + 1][0] - Fc[k][0]) / S_delta * (self.S - k * S_delta)) Vp = (Fp[k][0] + (Fp[k + 1][0] - Fp[k][0]) / S_delta * (self.S - k * S_delta)) return {"call": Vc, "put": Vp}
def fit(self, x, y): x = buildX(x) y = buildY(y) # xT * x result = multiply(transposed(x), x) # inverse(xT * x) result = inverse(result) # inverse(xT * x) * xT result = multiply(result, transposed(x)) # inverse(xT * x) * xT * y result = multiply(result, y) self.intercept_ = result[0][0] # w0 self.coef_[0] = result[1][0] # w1 self.coef_[1] = result[2][0] # w2
def rootMeanSquareError(answers, coefficients, x_bar): error_vector = matrixOperations.subtract( answers, matrixOperations.multiply(coefficients, x_bar)) s = 0 for i in error_vector: s = s + i[0]**2 return (s / len(error_vector))**0.5
def jacobi(D, L, U, solution_vector): vector_x_0 = [[0] for i in range(len(solution_vector))] tol = 10**-6 D_inverse = [[0 for i in range(len(D))] for j in range(len(D))] for i in range(len(D)): D_inverse[i][i] = 1 / D[i][i] for i in range(10**6): vector_x_1 = matrixOperations.multiply( D_inverse, matrixOperations.subtract( solution_vector, matrixOperations.multiply(matrixOperations.add(L, U), vector_x_0))) if (matrixOperations.isEqual(vector_x_1, vector_x_0, tol)): vector_x_0 = [i[:] for i in vector_x_1] print("Required", i, "steps") break vector_x_0 = [i[:] for i in vector_x_1] matrixOperations.printMatrix(vector_x_0)
def CrankNicolsonM(self, M, N): # 1 t_delta = self.T / N S_max = 2 * self.K S_delta = S_max / M # 2 Fc = [[0 for _ in range(N + 1)] for _ in range(M + 1)] Fp = [[0 for _ in range(N + 1)] for _ in range(M + 1)] for j in range(M + 1): Fc[j][N] = max(j * S_delta - self.K, 0) Fp[j][N] = max(self.K - j * S_delta, 0) # 3 M1 = [[0 for _ in range(M + 1)] for _ in range(M + 1)] M1[0][0] = 1 M1[M][M] = 1 for j in range(1, M): M1[j][j - 1] = -0.25 * t_delta * (self.sigma * self.sigma * j * j - (self.r - self.q) * j) M1[j][j] = 1 + 0.5 * t_delta * (self.sigma * self.sigma * j * j + self.r) M1[j][j + 1] = -0.25 * t_delta * (self.sigma * self.sigma * j * j + (self.r - self.q) * j) M1_inv = matrixOperations.inverse(M1) for i in range(N - 1, -1, -1): # 3.1 and 3.2: bc = [[0] for _ in range(M + 1)] bp = [[0] for _ in range(M + 1)] for j in range(1, M): alpha = 0.25 * t_delta * (self.sigma * self.sigma * j * j - (self.r - self.q) * j) beta = -0.5 * t_delta * (self.sigma * self.sigma * j * j + self.r) gamma = 0.25 * t_delta * (self.sigma * self.sigma * j * j + (self.r - self.q) * j) bc[j][0] = (alpha * Fc[j - 1][i + 1] + (1 + beta) * Fc[j][i + 1] + gamma * Fc[j + 1][i + 1]) bp[j][0] = (alpha * Fp[j - 1][i + 1] + (1 + beta) * Fp[j][i + 1] + gamma * Fp[j + 1][i + 1]) bc[0][0] = 0 bc[M][0] = S_max - self.K * exp(-self.r * (N - i) * t_delta) bp[0][0] = self.K * exp(-self.r * (N - i) * t_delta) bp[M][0] = 0 # 3.3 Fc_col = matrixOperations.multiply(M1_inv, bc) Fp_col = matrixOperations.multiply(M1_inv, bp) for j in range(M + 1): Fc[j][i] = Fc_col[j][0] Fp[j][i] = Fp_col[j][0] # 4 k = int(floor(self.S / S_delta)) # 5 Vc = (Fc[k][0] + (Fc[k + 1][0] - Fc[k][0]) / S_delta * (self.S - k * S_delta)) Vp = (Fp[k][0] + (Fp[k + 1][0] - Fp[k][0]) / S_delta * (self.S - k * S_delta)) return {"call": Vc, "put": Vp}
def test_multiply(self): A = [[1, 1, 1], [1, 1, 1], [1, 1, 1]] B = [[1, 1, 1], [1, 1, 1], [1, 1, 1]] product = [[3, 3, 3], [3, 3, 3], [3, 3, 3]] self.assertEqual(multiply(A, B), product)
def leastSquares(A, b): A_transpose = matrixOperations.transpose(A) return matrixOperations.multiply( matrixOperations.multiply( matrixOperations.invert(matrixOperations.multiply(A_transpose, A)), A_transpose), b)