Ejemplo n.º 1
0
def make_phi_minus(M, dx, omega_plus, gamma, sigma, q, pois_lambda, pois_delta,
                   pois_mu):
    x_space = ffts.make_fft_spaces(M, dx)[0]
    u_space = ffts.make_fft_spaces(M, dx)[1]

    def integrand_minus_bates(upsilon_array, gamma, sigma, pois_lambda,
                              pois_delta, pois_mu):
        """
        принимает и возвращает массив длиной в степень двойки, исходя из логики дальнейшего использования
        """
        return np.array([log(1 + psi_merton(upsilon + 1j * omega_plus, gamma, sigma, pois_lambda, pois_delta, pois_mu) \
                             / q) / (upsilon + 1j * omega_plus) ** 2 for upsilon in upsilon_array])

    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

    fm = F_minus_capital()
    F_m_hat = ffts.make_rad_fft(fm, dx)

    def make_phi_minus_array(xi_array):
        first_term = -1j * xi_array * (fm[M // 2])
        second_term = -xi_array * xi_array * F_m_hat
        return exp(first_term + second_term)

    mex_symbol_minus = make_phi_minus_array(u_space)
    return mex_symbol_minus
Ejemplo n.º 2
0
def make_phi_plus(M, dx, omega_minus, gamma, sigma, q, pois_lambda, pois_delta,
                  pois_mu):
    x_space = ffts.make_fft_spaces(M, dx)[0]
    u_space = ffts.make_fft_spaces(M, dx)[1]

    def integrand_plus(upsilon_array, gamma, sigma, pois_lambda, pois_delta,
                       pois_mu):
        return np.array([log(1 + psi_merton(upsilon + 1j * omega_minus, gamma, sigma, pois_lambda, pois_delta, pois_mu)\
                             / q) / (upsilon + 1j * omega_minus) ** 2 for upsilon in upsilon_array])

    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, pois_lambda, pois_delta,
                           pois_mu), dx)
        exponent = exp(-trimmed_x_space * omega_minus)
        return indicator * exponent * integral

    fp = F_plus_capital()

    F_p_hat = ffts.make_rad_fft(fp, dx)

    def make_phi_plus_array(xi_array):
        first_term = 1j * xi_array * fp[M // 2]
        second_term = -xi_array * xi_array * F_p_hat
        return exp(first_term + second_term)

    mex_symbol_plus = make_phi_plus_array(u_space)
    return mex_symbol_plus
Ejemplo n.º 3
0
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()