dcomplex G(dcomplex z) { int i; dcomplex e[10]; dcomplex d,sum,dum; e[1].r =-10.0/eV2Hartree; e[1].i = 0.0; e[2].r = -5.0/eV2Hartree; e[2].i = 0.0; e[3].r = -2.0/eV2Hartree; e[3].i = 0.0; e[4].r = 5.0/eV2Hartree; e[4].i = 0.0; sum.r = 0.0; sum.i = 0.0; for (i=1; i<=4; i++) { d = Csub(z,e[i]); dum = RCdiv(1.0,d); sum.r += dum.r; sum.i += dum.i; } return sum; }
static int compute_price(double tt, double H, double K, double r_premia, double v0, double kappa, double theta, double sigma, double rho, double L, int M, int Nt ) { /*Variables*/ int j, n, k; double r; /*continuous rate*/ double min_log_price, max_log_price; double ds, dt; /*price and time discretization steps*/ double rho_hat; /*parameter after substitution*/ double q, factor, discount_factor; /*pde parameters*/ double treshold = 1e-9; /* when we assume probability to be zero and switch to a different equation*/ int k_d, k_u; /*n+1 vertice numbers, depending on [n][k]*/ double sigma_local, gamma; /*wh factors parameters*/ double beta_minus, beta_plus; /*wh-factors coefficients*/ double local_barrier; /*a barrier depending on [n][k], to check crossing on each step*/ //if (2.0 * kappa * theta < pow(sigma, 2)) // return 1; /*Novikov condition not satisfied, probability values could be incorrect*/ /*Body*/ r = log(1 + r_premia / 100); /*building voltree*/ tree_v(tt, v0, kappa, theta, sigma, Nt); /*spacial variable. Price space construction*/ min_log_price = L*log(0.5) - (rho / sigma)* V[Nt][Nt]; max_log_price = L*log(2); ds = (max_log_price - min_log_price) / double(M); for (j = 0; j < M; j++) { ba_log_prices[j] = min_log_price + j*ds; ba_prices[j] = H*exp(ba_log_prices[j] + (rho / sigma)* V[0][0]); } dt = tt / double(Nt); /*fft frequences we'll need in every vertice of a tree*/ fftfreq(M, ds); rho_hat = sqrt(1.0 - pow(rho, 2.0)); q = 1.0 / dt + r; factor = pow(q*dt, -1.0); //discount_factor = exp(r*dt); discount_factor = r - rho / sigma * kappa * theta; /*filling F_next matrice by initial (in time T) conditions*/ for (j = 0; j < M; j++) for (k = 0; k < Nt + 1; k++) { F_next[j][k] = Complex(G(H*exp(ba_log_prices[j] + (rho / sigma)* V[Nt][k]), K), 0); } /*here the main cycle starts - the backward induction procedure*/ for (n = Nt - 1; n >= 0; n--) { printf("Processing: %d of %d\n", n, Nt-1); for (k = 0; k <= n; k++) { /*to calculate the binomial expectation we should use matrices from the tree method. After (n,k) vertice one could either get to (n+1,k_u) or (n+1, k_d). The numbers k_u and k_d could be read from f_up and f_down matrices, by the rule of addition, for example: f_down[i][j] = -z; Rd = V[i + 1][j - z] f_up[i][j] = z; Ru = V[i + 1][j + z]; */ k_u = k + f_up[n][k]; k_d = k + f_down[n][k]; local_barrier = - (rho / sigma) * V[n][k]; /*initial conditions of a step*/ for (j = 0; j < M; j++) { //f_n_plus_1_k_u[j] = F[j][n+1][k_u]; //f_n_plus_1_k_d[j] = F[j][n+1][k_d]; f_n_plus_1_k_u[j] = F_next[j][k_u]; f_n_plus_1_k_d[j] = F_next[j][k_d]; } /*applying indicator function*/ for (j = 0; j < M; j++) { if (ba_log_prices[j] < local_barrier) { f_n_plus_1_k_u[j].r = 0.0; f_n_plus_1_k_u[j].i = 0.0; f_n_plus_1_k_d[j].r = 0.0; f_n_plus_1_k_d[j].i = 0.0; } } 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^2 * q)) / sigma^2 beta_plus = -(gamma - sqrt(gamma^2 + 2 * sigma^2 * q)) / sigma^2*/ beta_minus = -(gamma + sqrt(pow(gamma,2) + 2 * pow(sigma_local,2) * q)) / pow(sigma_local,2); beta_plus = -(gamma - sqrt(pow(gamma,2) + 2 * pow(sigma_local,2) * q)) / pow(sigma_local,2); for (j = 0; j < M; j++) { /* factor functions phi_plus_array = ([beta_plus / (beta_plus - i * 2 * pi*xi) for xi in xi_space]) phi_minus_array = ([-beta_minus / (-beta_minus + i * 2 * pi*xi) for xi in xi_space]) */ phi_plus_array[j] = RCdiv(beta_plus, RCsub(beta_plus, RCmul((2.0 * PI * fftfreqs[j]), CI))); phi_minus_array[j] = RCdiv(-beta_minus, RCadd(-beta_minus, RCmul((2.0 * PI * fftfreqs[j]), CI))); } /*factorization calculation*/ /*f_n_k_u = factor * fft.ifft(phi_minus_array * fft.fft( indicator(original_prices_array, 0) * fft.ifft(phi_plus_array * fft.fft(f_n_plus_1_k_u))))*/ for (int j = 0; j < M; j++) { f_n_plus_1_k_u_re[j] = f_n_plus_1_k_u[j].r; f_n_plus_1_k_u_im[j] = f_n_plus_1_k_u[j].i; } pnl_fft2(f_n_plus_1_k_u_re, f_n_plus_1_k_u_im, M); for (j = 0; j < M; j++) { /*putting complex and imaginary part together again*/ f_n_plus_1_k_u_fft_results[j] = Complex(f_n_plus_1_k_u_re[j], f_n_plus_1_k_u_im[j]); /*multiplying by phi_plus*/ f_n_plus_1_k_u_fft_results[j] = Cmul(phi_plus_array[j], f_n_plus_1_k_u_fft_results[j]); /*extracting imaginary and complex parts to use in further fft*/ f_n_plus_1_k_u_fft_results_re[j] = f_n_plus_1_k_u_fft_results[j].r; f_n_plus_1_k_u_fft_results_im[j] = f_n_plus_1_k_u_fft_results[j].i; } pnl_ifft2(f_n_plus_1_k_u_fft_results_re, f_n_plus_1_k_u_fft_results_im, M); /*applying indicator function, after ifft*/ for (j = 0; j < M; j++) { if (ba_log_prices[j] < local_barrier) { f_n_plus_1_k_u_fft_results_re[j] = 0.0; f_n_plus_1_k_u_fft_results_im[j] = 0.0; } } /*performing second fft */ pnl_fft2(f_n_plus_1_k_u_fft_results_re, f_n_plus_1_k_u_fft_results_im, M); for (j = 0; j < M; j++) { /*putting complex and imaginary part together again*/ f_n_plus_1_k_u_fft_results[j] = Complex(f_n_plus_1_k_u_fft_results_re[j], f_n_plus_1_k_u_fft_results_im[j]); /*multiplying by phi_minus*/ f_n_plus_1_k_u_fft_results[j] = Cmul(phi_minus_array[j], f_n_plus_1_k_u_fft_results[j]); /*extracting imaginary and complex parts to use in further fft*/ f_n_plus_1_k_u_fft_results_re[j] = f_n_plus_1_k_u_fft_results[j].r; f_n_plus_1_k_u_fft_results_im[j] = f_n_plus_1_k_u_fft_results[j].i; } /*the very last ifft*/ pnl_ifft2(f_n_plus_1_k_u_fft_results_re, f_n_plus_1_k_u_fft_results_im, M); /*multiplying by factor*/ for (j = 0; j < M; j++) { f_n_k_u[j].r = factor * f_n_plus_1_k_u_fft_results_re[j]; f_n_k_u[j].i = factor * f_n_plus_1_k_u_fft_results_im[j]; } /*f_n_k_d = factor * fft.ifft(phi_minus_array * fft.fft( indicator(original_prices_array, 0) * fft.ifft(phi_plus_array * fft.fft(f_n_plus_1_k_d))))*/ for (int j = 0; j < M; j++) { f_n_plus_1_k_d_re[j] = f_n_plus_1_k_d[j].r; f_n_plus_1_k_d_im[j] = f_n_plus_1_k_d[j].i; } pnl_fft2(f_n_plus_1_k_d_re, f_n_plus_1_k_d_im, M); for (j = 0; j < M; j++) { /*putting complex and imaginary part together again*/ f_n_plus_1_k_d_fft_results[j] = Complex(f_n_plus_1_k_d_re[j], f_n_plus_1_k_d_im[j]); /*multiplying by phi_plus*/ f_n_plus_1_k_d_fft_results[j] = Cmul(phi_plus_array[j], f_n_plus_1_k_d_fft_results[j]); /*extracting imaginary and complex parts to use in further fft*/ f_n_plus_1_k_d_fft_results_re[j] = f_n_plus_1_k_d_fft_results[j].r; f_n_plus_1_k_d_fft_results_im[j] = f_n_plus_1_k_d_fft_results[j].i; } pnl_ifft2(f_n_plus_1_k_d_fft_results_re, f_n_plus_1_k_d_fft_results_im, M); /*applying indicator function, after ifft*/ for (j = 0; j < M; j++) { if (ba_log_prices[j] < local_barrier) { f_n_plus_1_k_d_fft_results_re[j] = 0.0; f_n_plus_1_k_d_fft_results_im[j] = 0.0; } } /*performing second fft */ pnl_fft2(f_n_plus_1_k_d_fft_results_re, f_n_plus_1_k_d_fft_results_im, M); for (j = 0; j < M; j++) { /*putting complex and imaginary part together again*/ f_n_plus_1_k_d_fft_results[j] = Complex(f_n_plus_1_k_d_fft_results_re[j], f_n_plus_1_k_d_fft_results_im[j]); /*multiplying by phi_minus*/ f_n_plus_1_k_d_fft_results[j] = Cmul(phi_minus_array[j], f_n_plus_1_k_d_fft_results[j]); /*extracting imaginary and complex parts to use in further fft*/ f_n_plus_1_k_d_fft_results_re[j] = f_n_plus_1_k_d_fft_results[j].r; f_n_plus_1_k_d_fft_results_im[j] = f_n_plus_1_k_d_fft_results[j].i; } /*the very last ifft*/ pnl_ifft2(f_n_plus_1_k_d_fft_results_re, f_n_plus_1_k_d_fft_results_im, M); /*multiplying by factor*/ for (j = 0; j < M; j++) { f_n_k_d[j].r = factor * f_n_plus_1_k_d_fft_results_re[j]; f_n_k_d[j].i = factor * f_n_plus_1_k_d_fft_results_im[j]; } } else if (V[n][k] < treshold) { /*applying indicator function*/ for (j = 0; j < M; j++) { if (ba_log_prices[j] < local_barrier) { f_n_plus_1_k_u[j].r = 0.0; f_n_plus_1_k_u[j].i = 0.0; f_n_plus_1_k_d[j].r = 0.0; f_n_plus_1_k_d[j].i = 0.0; } } for (j = 0; j < M; j++) { //f_n_plus_1_k_u[j] = F[j][n + 1][k_u]; f_n_plus_1_k_u[j] = F_next[j][k_u]; f_n_k_u[j] = CRsub(f_n_plus_1_k_u[j], discount_factor * dt); f_n_k_d[j] = f_n_k_u[j]; } } /* f_n_k = pd_f[n, k] * f_n_k_d + pu_f[n, k] * f_n_k_u */ for (j = 0; j < M; j++) { f_n_k[j] = Cadd(RCmul(pd_f[n][k], f_n_k_d[j]), RCmul(pu_f[n][k], f_n_k_u[j])); F_prev[j][k] = f_n_k[j]; } } for (j = 0; j < M; j++) { for (int state = 0; state < Nt; state++) { F_next[j][state] = F_prev[j][state]; F_prev[j][state] = Complex(0,0); } } } /*Preprocessing F before showing out*/ for (j = 0; j < M; j++) { if (ba_prices[j] <= H) { F_next[j][0].r = 0; } if (F_next[j][0].r < 0.) { F_next[j][0].r = 0; } } return OK; }