def SABR_beta_d(f, t, k, CallPut, alpha, beta, rho, volvol):
    vol_1 = lognormal_vol(k, f, t, alpha, beta, rho, volvol) * 100
    vol_2 = lognormal_vol(k, f, t, alpha, beta + 0.01, rho, volvol) * 100
    b_s = BlackScholes(f, 0, 0, t)
    if CallPut == 'C':
        vanna = (b_s.BS_call(k, vol_2) - b_s.BS_call(k, vol_1)) / (0.01 * rho)
    else:
        vanna = (b_s.BS_put(k, vol_2) - b_s.BS_put(k, vol_1)) / (0.01 * rho)
    return vanna
def SABR_alpha_deri(f, t, k, CallPut, alpha, beta, rho, volvol):
    vol_1 = lognormal_vol(k, f, t, alpha * 0.99, beta, rho, volvol) * 100
    vol_2 = lognormal_vol(k, f, t, alpha * 1.01, beta, rho, volvol) * 100
    b_s = BlackScholes(f, 0, 0, t)
    if CallPut == 'C':
        volga = (b_s.BS_call(k, vol_2) - b_s.BS_call(k, vol_1)) / (0.02 *
                                                                   alpha)
    else:
        volga = (b_s.BS_put(k, vol_2) - b_s.BS_put(k, vol_1)) / (0.02 * alpha)
    return volga
def SABR_theta(f, t, k, CallPut, alpha, beta, rho, volvol):
    t2 = t * 1.01
    b_s = BlackScholes(f, 0, 0, t)
    b_s_2 = BlackScholes(f, 0, 0, t2)
    if CallPut == 'C':
        theta = -(b_s.BS_call(
            k, 100 * lognormal_vol(k, f, t, alpha, beta, rho, volvol)
        ) - b_s_2.BS_call(
            k, 100 * lognormal_vol(k, f, t2, alpha, beta, rho, volvol))) / (t -
                                                                            t2)
    else:
        theta = -(b_s.BS_put(
            k, 100 * lognormal_vol(k, f, t, alpha, beta, rho, volvol)
        ) - b_s_2.BS_put(
            k, 100 * lognormal_vol(k, f, t2, alpha, beta, rho, volvol))) / (t -
                                                                            t2)
    return theta
def SABR_delta(f, t, k, CallPut, alpha, beta, rho, volvol):
    f2 = f * 1.01
    b_s = BlackScholes(f * 1.01, 0, 0, t)
    b_s_2 = BlackScholes(f * 0.99, 0, 0, t)
    if CallPut == 'C':
        delta_i = (b_s.BS_call(
            k, 100 * lognormal_vol(k, f * 1.01, t, alpha, beta, rho, volvol)) -
                   b_s_2.BS_call(
                       k, 100 * lognormal_vol(k, f * 0.99, t, alpha, beta, rho,
                                              volvol))) / (0.02 * f)
    else:
        delta_i = (b_s.BS_put(
            k, 100 * lognormal_vol(k, f * 1.01, t, alpha, beta, rho, volvol)) -
                   b_s_2.BS_put(
                       k, 100 * lognormal_vol(k, f * 0.99, t, alpha, beta, rho,
                                              volvol))) / (0.02 * f)
    return delta_i
def fit_beta(f, f_new, t, t2, k, v_sln_t1, C_t1, C_t2, C_P_list, v_sln_atm_t1,
             v_sln_atm_t2):
    beta_list = np.arange(0, 11, 1) / 10
    f_diff = f_new - f
    C_diff = C_t2 - C_t1
    min_hedge_error = 1e10
    best_beta = beta_list[0]
    hedge_error_list = []
    for beta in beta_list:
        hedge_error = 0
        param = fit(f, t, beta, k, v_sln_t1)
        alpha_t1 = alpha(v_sln_atm_t1 / 100, f, t, beta, param[1], param[2])
        alpha_t2 = alpha(v_sln_atm_t2 / 100, f_new, t2, beta, param[1],
                         param[2])

        f2 = f * 1.01
        b_s = BlackScholes(f, 0, 0, t)
        b_s_2 = BlackScholes(f2, 0, 0, t)
        delta_list = []
        vega_list = []
        for num in range(len(k)):
            s_k = k[num]
            c_p = C_P_list[num]
            if c_p == 'C':
                delta_i = (b_s.BS_call(
                    s_k, 100 * lognormal_vol(s_k, f, t, param[0], beta,
                                             param[1], param[2])) -
                           b_s_2.BS_call(
                               s_k, 100 *
                               lognormal_vol(s_k, f2, t, param[0], beta,
                                             param[1], param[2]))) / (f - f2)
                vega_i = (b_s.BS_call(s_k, 100*lognormal_vol(s_k, f, t, alpha_t1, beta, param[1], param[2])) -
                          b_s.BS_call(s_k, 100*lognormal_vol(s_k, f, t, alpha_t1 *1.01, beta, param[1], param[2]))) /\
                         (alpha_t1 - 1.01 * alpha_t1)
            else:
                delta_i = (b_s.BS_put(
                    s_k, 100 * lognormal_vol(s_k, f, t, param[0], beta,
                                             param[1], param[2])) -
                           b_s_2.BS_put(
                               s_k, 100 *
                               lognormal_vol(s_k, f2, t, param[0], beta,
                                             param[1], param[2]))) / (f - f2)
                vega_i = (b_s.BS_put(
                    s_k, 100 * lognormal_vol(s_k, f, t, alpha_t1, beta,
                                             param[1], param[2])) -
                          b_s.BS_put(
                              s_k, 100 * lognormal_vol(
                                  s_k, f, t, alpha_t1 * 1.01, beta, param[1],
                                  param[2]))) / (alpha_t1 - 1.01 * alpha_t1)
            delta_list.append(delta_i)
            vega_list.append(vega_i)
        for i in range(len(C_diff)):
            #sig = (C_diff[i] - delta_list[i] * f_diff ) / C_t2[i]
            sig = (C_diff[i] - delta_list[i] * f_diff - vega_list[i] *
                   (alpha_t2 - alpha_t1)) / C_t2[i]
            hedge_error += sig**2
        hedge_error_list.append(hedge_error)
        if hedge_error < min_hedge_error:
            min_hedge_error = hedge_error
            best_beta = beta
    return best_beta