def F_plus_capital(): indicator = np.where(x_space <= 0, 1, 0) trimmed_x_space = indicator * x_space # чтобы при "сильно положительных" x не росла экспонента integral = ffts.make_rad_ifft(integrand_plus(u_space, gamma, sigma), dx) exponent = exp(-trimmed_x_space * omega_minus) return indicator * exponent * integral
def F_minus_capital(): indicator = np.where(x_space >= 0, 1, 0) trimmed_x_space = indicator * x_space # чтобы при "сильно отрицательных" x не росла экспонента integral = ffts.make_rad_ifft( integrand_minus(u_space, gamma, sigma, pois_lambda, pois_delta, pois_mu), dx) exponent = exp(-trimmed_x_space * omega_plus) return indicator * exponent * integral
def evaluate_option_by_wh(T, H_original, K_original, r_premia, V0, kappa, theta, sigma, rho, N, M): if 2 * kappa * theta < sigma**2: print( "Warning, Novikov condition is not satisfied, the volatility values could be negative" ) r = log(r_premia / 100 + 1) omega = sigma # time-space domain construction x_space = ffts.make_fft_spaces(M, dx)[0] # prices array first_step_of_return = [elem + V0 * rho / sigma for elem in x_space] original_prices_array = H_original * exp(first_step_of_return) # array_to_csv_file(original_prices_array, "../output/routine/price_line_original.csv") # time discretization delta_t = T / N # making volatilily tree markov_chain = build_volatility_tree(T, V0, kappa, theta, omega, N) V = markov_chain[0] pu_f = markov_chain[1] pd_f = markov_chain[2] f_up = markov_chain[3] f_down = markov_chain[4] rho_hat = sqrt(1 - rho**2) q = 1.0 / delta_t + r factor = (q * delta_t)**(-1) F_n_plus_1 = zeros((len(x_space), len(V[N])), dtype=complex) F_n = zeros((len(x_space), len(V[N])), dtype=complex) for j in range(len(x_space)): for k in range(len(V[N])): F_n_plus_1[j, k] = array(G(H_original * exp(x_space[j]), K_original)) # the global cycle starts here. It iterates over the volatility tree we just constructed, and goes backwards in time # starting from n-1 position # print("Main cycle entered") # when the variance is less than that, is is reasonable to assume it to be zero, which leads to simpler calculations treshold = 1e-6 discount_factor = exp(r * delta_t) for n in range(len(V[N]) - 2, -1, -1): print(str(n) + " of " + str(len(V[N]) - 2)) with profiler(): for k in range(n + 1): # to calculate the binomial expectation one should use Antonino's matrices f_up and f_down # the meaning of the containing integers are as follows - after (n,k) you will be in # either (n+1, k + f_up) or (n+1, k - f_down). We use k_u and k_d shorthands, respectively k_u = k + int(f_up[n][k]) k_d = k + int(f_down[n][k]) # initial condition of a step f_n_plus_1_k_u = array( [F_n_plus_1[j][k_u] for j in range(len(x_space))]) f_n_plus_1_k_d = array( [F_n_plus_1[j][k_d] for j in range(len(x_space))]) H_N_k = -(rho / sigma) * V[n, k] # modified barrier local_domain = array( [x_space[j] + H_N_k for j in range(len(x_space))]) if V[n, k] >= treshold: # set up variance-dependent parameters for a given step sigma_local = rho_hat * sqrt(V[n, k]) gamma = r - 0.5 * V[n, k] - rho / sigma * kappa * ( theta - V[n, k]) # also local # beta_plus and beta_minus # beta_minus = - (gamma + sqrt(gamma**2 + 2*sigma_local**2 * q))/sigma_local**2 # beta_plus = - (gamma - sqrt(gamma**2 + 2*sigma_local**2 * q))/sigma_local**2 # factor functions # phi_plus_array = array([beta_plus/(beta_plus - i*2*pi*xi) for xi in xi_space]) # phi_minus_array = array([-beta_minus/(-beta_minus + i*2*pi*xi) for xi in xi_space]) phi_plus_array = mex.make_phi_minus( M, dx, omega_plus, gamma, sigma_local, q) phi_minus_array = mex.make_phi_plus( M, dx, omega_minus, gamma, sigma_local, q) # factorization calculation f_n_k_u = factor * \ ffts.make_rad_ifft(phi_minus_array * ffts.make_rad_fft( indicator( ffts.make_rad_ifft(phi_plus_array * ffts.make_rad_fft(f_n_plus_1_k_u, dx), dx), local_domain, H_N_k), dx), dx) f_n_k_d = factor * \ ffts.make_rad_ifft(phi_minus_array * ffts.make_rad_fft( indicator( ffts.make_rad_ifft(phi_plus_array * ffts.make_rad_fft(f_n_plus_1_k_d, dx), dx), local_domain, H_N_k), dx), dx) elif V[n, k] < treshold: f_n_plus_1_k_u = [ F_n_plus_1[j][k_u] for j in range(len(x_space)) ] f_n_k_u = discount_factor * f_n_plus_1_k_u f_n_plus_1_k_d = [ F_n_plus_1[j][k_d] for j in range(len(x_space)) ] f_n_k_d = discount_factor * f_n_plus_1_k_d f_n_k = f_n_k_u * pu_f[n, k] + f_n_k_d * pd_f[n, k] for j in range(len(f_n_k)): # here we try some cutdown magic. The procedure without it returns great bubbles to the right # from the strike. And the more L the greater this bubble grows. # what we are going to do there is to try to cut off all the values on prices greater than, say, # 4 times bigger then the strike # we use S>4K and, therefore, y > ln(4K/H) + (pho/sigma)*V inequality to do this if local_domain[j] < log(3.5 * K_original / H_original + (rho / sigma) * V[n][k]): F_n[j][k] = f_n_k[j] else: F_n[j][k] = complex(0) # plt.plot(original_prices_array, f_n_plus_1_k_u) # plt.show() # for j in range(len(y)): # tree_to_csv_file(y[j], "../output/routine/price_slices/Y" + str(original_prices_array[j]) + ".csv") # for j in range(len(F)): # tree_to_csv_file(F[j], "../output/routine/answers/F" + str(original_prices_array[j]) + ".csv") answer_total = open("../output/routine/answer_cumul.csv", "w") answers_list = array([F_n[j][0] for j in range(len(x_space))]) for elem in list(zip(original_prices_array, answers_list)): answer_total.write(str(elem[0]) + ',') answer_total.write(str(elem[1].real) + ',') # answer_total.write(str(elem[1].imag) + ',') answer_total.write('\n') # for j in range(len(F)): # tree_to_csv_file(F[j], "../output/routine/answers/F" + str(original_prices_array[j]) + ".csv") plt.plot( original_prices_array[(original_prices_array > 75) & (original_prices_array < 200)], answers_list[(original_prices_array > 75) & (original_prices_array < 200)]) plt.savefig("../output/figure.png") plt.show() plt.close()