Beispiel #1
0
def compute_pi_ul(settle, ttl, payment_dates, idx1, idx1_cs, a, sigma):

    # deltas
    dayCount_Act365 = 3
    #day count Act/365 since it a time to maturity

    delta_ttl_payments = dm.yearfrac(ttl * len(payment_dates), payment_dates,
                                     dayCount_Act365)  #npArray
    delta_settle_ttl = dm.yearfrac([settle], ttl, dayCount_Act365)  #npArray

    # cumulated volatility
    ZETA = (sigma / a) * (1 - np.exp(-a * delta_ttl_payments))  #npArray
    Sigma_square_tau = (ZETA**
                        2) * (1 - np.exp(-2 * a * delta_settle_ttl)) / (2 * a)

    # for each bond, replicating the sigma_square_tau of the maturity
    Sigma_square_N = np.repeat(Sigma_square_tau[idx1_cs[1::]],
                               idx1[1::])  #npArray

    # pi_u
    from scipy.stats import norm

    pi_u = (4+Sigma_square_tau)/2* norm.cdf(np.sqrt(Sigma_square_tau)/2) \
    + np.sqrt(Sigma_square_tau/(2*np.pi)) * np.exp(-Sigma_square_tau/8)#npArray

    #pi_l

    def f1(eta):
        r=np.exp(-Sigma_square_N/8)/(np.pi*np.sqrt(1-eta)*np.sqrt(eta))*\
        np.exp(-eta/2*np.sqrt(Sigma_square_tau)*(np.sqrt(Sigma_square_tau)\
                                                 -np.sqrt(Sigma_square_N) ))
        return r

    def f2(eta):
        r=1+np.sqrt(np.pi*(1-eta)/2)*np.sqrt(Sigma_square_N)*\
        np.exp((1-eta)/8*Sigma_square_N)*norm.cdf(np.sqrt(1-eta)/2*\
                                                  np.sqrt(Sigma_square_N))
        return r

    def f3(eta):
        r=1+np.sqrt(np.pi*eta/2)*(2*np.sqrt(Sigma_square_tau)\
            -np.sqrt(Sigma_square_N))*np.exp(eta/8*\
            (2*np.sqrt(Sigma_square_tau)-np.sqrt(Sigma_square_N))**2)*\
            norm.cdf(np.sqrt(eta)/2*(2*np.sqrt(Sigma_square_tau)-np.sqrt(Sigma_square_N)))
        return r

    def integrand(eta):
        r = f1(eta) * f2(eta) * f3(eta)
        return r

    import scipy.integrate as integrate

    pi_l = np.zeros(len(integrand(0.5)))
    for k in range(0, len(pi_l)):
        pi_l[k] = integrate.quad(lambda eta: integrand(eta)[k], 0, 1)[0]

    return [list(pi_u), list(pi_l)]
def bootstrap_OIS(dates, rates):
    # Initial settings
    day_count_act360 = 2
    cleaned_dates_OIS = dates['ois']
    rates_OIS = rates['ois']
    discounts = np.zeros(len(cleaned_dates_OIS))  #inizialize np vector

    # Dates and Deltas
    deltas_settlement_to_date = dm.yearfrac(
        dates['settle'] * np.ones(len(cleaned_dates_OIS)), cleaned_dates_OIS,
        day_count_act360)

    # date 1y after settlement date (int)
    date_1y_after_settlement = dm.dateMoveVec_MF([dates['settle']], 'y', 1,
                                                 dm.eurCalendar())

    # index of the first date after 1y from settle
    oneyear = int( sum(( np.ones(len(cleaned_dates_OIS))*\
     [np.array(cleaned_dates_OIS) <= date_1y_after_settlement] ).T) )

    # delta(t_i,t_i+1)
    deltas = dm.yearfrac(cleaned_dates_OIS[0:len(cleaned_dates_OIS) - 1],
                         cleaned_dates_OIS[1::], day_count_act360)

    # delta(settlement, t_i) for t_i>=1y  NON TROPPO SICURO
    delta_k = np.zeros(len(cleaned_dates_OIS))
    delta_k[oneyear - 1] = dm.yearfrac([dates['settle']],
                                       [cleaned_dates_OIS[oneyear - 1]],
                                       day_count_act360)
    delta_k[oneyear::] = deltas[oneyear - 1::]

    # dates in output
    dates_EONIA = np.zeros(len(cleaned_dates_OIS) + 1)
    dates_EONIA[0] = dates['settle']
    dates_EONIA[1::] = cleaned_dates_OIS

    # Discounts
    # discounts from OIS up to 1y
    discounts[0:oneyear] = 1 / (
        1 + deltas_settlement_to_date[0:oneyear] * rates_OIS[0:oneyear])
    # bootstrap other discounts
    for i in range(oneyear - 1, len(cleaned_dates_OIS)):
        discounts[i] = ( 1 - rates_OIS[i] * delta_k[oneyear-1:i].dot(discounts[oneyear-1:i]) ) / \
        ( 1+delta_k[i]*rates_OIS[i] )

    # discounts in output
    discounts_EONIA = np.zeros(len(cleaned_dates_OIS) + 1)
    discounts_EONIA[0] = 1
    discounts_EONIA[1::] = discounts

    return [dates_EONIA, discounts_EONIA]
Beispiel #3
0
def normal_vols_swaption_MHJM(dates_semiannual, deltas_fixed_leg,
                              discount_factors_semiannual,
                              forward_beta_semiannual, settlement_swaption,
                              nv_values, tenor):
    dayCount_maturity = 3  #for the maturity of the swaption
    num_swaptions = len(nv_values)  #for a smarter notation

    BPV = np.zeros(num_swaptions)
    #inizialization
    N_alpha_omega_in_t0 = np.zeros(num_swaptions)
    C_alpha_omega = np.zeros(num_swaptions)

    count_set = range(0, num_swaptions)
    for i in count_set:
        BPV[i] = deltas_fixed_leg[i::] .dot( (discount_factors_semiannual[2*i+2::2] / \
         discount_factors_semiannual[2*i]) )

        N_alpha_omega_in_t0[i] = 1 - discount_factors_semiannual[len(discount_factors_semiannual)-1] / \
        discount_factors_semiannual[2*i] + \
        (discount_factors_semiannual[2*i:len(discount_factors_semiannual-1)-1] / \
        discount_factors_semiannual[2*i]) .dot ( forward_beta_semiannual[2*i::]-1 )

    fwd_swap_rate = N_alpha_omega_in_t0 / BPV
    dates_semi_aux = dates_semiannual[0:len(dates_semiannual) - 2:2]

    dt_t0_alpha = dm.yearfrac([settlement_swaption] * len(dates_semi_aux),
                              dates_semi_aux, 3)
    C_alpha_omega = (1 - 1 /
                     (np.power(1 + fwd_swap_rate, tenor))) / fwd_swap_rate

    prices = discount_factors_semiannual[0:len(discount_factors_semiannual)-2:2] * C_alpha_omega * nv_values * \
    np.sqrt( dt_t0_alpha/(2*np.pi) )

    return [prices, fwd_swap_rate]
    def equations_1(p):
        yf_t0_ti = dm.yearfrac([dates['settle']], [floating_dates[2 * k + 1]],
                               day_count_act_365)
        yf_t0_timinus1 = dm.yearfrac([dates['settle']],
                                     [floating_dates[2 * k]],
                                     day_count_act_365)
        yf_t0_timinus2 = dm.yearfrac([dates['settle']],
                                     [floating_dates[2 * k - 1]],
                                     day_count_act_365)
        yf_timinus2_timinus1 = dm.yearfrac([floating_dates[2 * k - 1]],
                                           [floating_dates[2 * k]],
                                           day_count_act_365)
        yf_timinus1_ti = dm.yearfrac([floating_dates[2 * k]],
                                     [floating_dates[2 * k + 1]],
                                     day_count_act_365)
        yf_timinus2_ti = dm.yearfrac([floating_dates[2 * k - 1]],
                                     [floating_dates[2 * k + 1]],
                                     day_count_act_365)
        z_timinus2 = -np.log(
            pseudo_discounts_semiannual[2 * k - 1]) / yf_t0_timinus2

        return ( discounts_EONIA_semiannual[2*k] * (pseudo_discounts_semiannual[2*k-1]/p[0]-1) +\
                    discounts_EONIA_semiannual [2*k+1] *(p[0]/p[1]-1) + known_term - I, \
                    (-np.log(p[0])/yf_t0_timinus1 - z_timinus2)/yf_timinus2_timinus1 -\
                    (-np.log(p[1])/yf_t0_ti - z_timinus2)/yf_timinus2_ti)
def bond_yield(ttl, dates_bonds_maturity, settle, dirty_prices,
               liquidity_spread, coupons):
    # Creating the vector of coupon payment dates

    n_bonds = len(dates_bonds_maturity)  #number of bonds
    [coupon_payment_dates, idx1, idx1_cs,
     idx2] = aux.create_vector_payment_dates(dates_bonds_maturity, settle, ttl)

    # we consider all the coupons (and no longer the ones after ttl)
    coupon_on_dates = np.repeat(np.array(coupons), np.array(idx1[1::]))
    coupon_on_dates[idx1_cs[1::]] = coupon_on_dates[idx1_cs[1::]] + 1

    # Coupons of interest and deltas
    dayCount_Act365 = 3
    deltas = dm.yearfrac([settle] * len(coupon_on_dates), coupon_payment_dates,
                         dayCount_Act365)

    # Computing P_2bar
    P_2bar = np.array(dirty_prices) - np.array(liquidity_spread)

    # Yield of the liquid bond
    y_T = np.zeros(len(dates_bonds_maturity))  # inizialization
    M = np.zeros(len(dates_bonds_maturity))  # inizialization

    from scipy.optimize import fmin

    for k in range(0, n_bonds):
        f = lambda y: abs(dirty_prices[k] - np.array(coupon_on_dates[idx1_cs[k]+1:idx1_cs[k+1]+1]).dot(\
                    np.exp(-y*deltas[idx1_cs[k]+1:idx1_cs[k+1]+1])))
        y_T[k] = fmin(f,
                      0.5,
                      xtol=1e-15,
                      ftol=1e-15,
                      maxiter=100000,
                      maxfun=1e8,
                      disp=False)
        # we define M to avoid numerical issues
        g=lambda v: abs(P_2bar[k] - np.array(coupon_on_dates[idx1_cs[k]+1:idx1_cs[k+1]+1]).dot(\
                        np.exp(-v*deltas[idx1_cs[k]+1:idx1_cs[k+1]+1])))
        M[k] = fmin(g,
                    0.5,
                    xtol=1e-15,
                    ftol=1e-15,
                    maxiter=100000,
                    maxfun=1e8,
                    disp=False)

    liquidity_yield = M - y_T
    #computing liquidity yield

    return [liquidity_yield, y_T]
def bootstrap_pseudo(dates, rates, dates_EONIA, discounts_EONIA):
    # Initial settings
    day_count_act360 = 2
    day_count_30_360 = 6
    day_count_act_365 = 3

    # Deltas and dates
    # delta(settle,6m)
    settle_to_6m_date = dm.yearfrac([dates['settle']], dates['euribor'],
                                    day_count_act360)

    # delta(6m,1y)
    delta_6m_to_1y = dm.yearfrac(dates['euribor'], [dates['fra_end'][5]],
                                 day_count_act360)

    # delta(fra_start, fra_end) for every fra
    delta_fra = dm.yearfrac(dates['fra_start'][0:5], dates['fra_end'][0:5],
                            day_count_act360)

    # floating dates
    floating_dates = dm.tenordates_MF([dates['settle']],
                                      2 * len(dates['swaps']), 'm', 6,
                                      dm.eurCalendar())

    # delta(t_i,t_i+1) on fixed dates
    dt_fixed_dates = dm.yearfrac( [dates['settle']] + floating_dates[1:len(floating_dates)-1:2] ,\
                                floating_dates[1:len(floating_dates)+1:2],day_count_30_360 )

    # Discounts up to 1y
    # pseudo-discount at 6m
    discount_pseudo_6m = 1 / (1 + settle_to_6m_date * rates['euribor6m'])

    # pseudo-discount at 1y
    discount_pseudo_1y = discount_pseudo_6m / (
        1 + delta_6m_to_1y * rates['fra'][5])

    # pseudo-discount 7m to 11m
    discount_7m_to_11m = ut.interp_discount(
        ut.removenest([dates['settle'], dates['euribor'],
                       dates['fra_end'][5]]),
        [1, discount_pseudo_6m, discount_pseudo_1y], dates['fra_end'][0:5])
    # pseudo-discount 1m to 5m
    discount_1m_to_5m = (1 +
                         delta_fra * rates['fra'][0:5]) * discount_7m_to_11m

    # discount EONIA every semester
    discounts_EONIA_semiannual = ut.interp_discount(dates_EONIA,
                                                    discounts_EONIA,
                                                    floating_dates)

    pseudo_discounts_semiannual = np.zeros(len(discounts_EONIA_semiannual))
    pseudo_discounts_semiannual[0] = discount_pseudo_6m
    pseudo_discounts_semiannual[1] = discount_pseudo_1y

    # Define system equation for root_finder
    def equations_1(p):
        yf_t0_ti = dm.yearfrac([dates['settle']], [floating_dates[2 * k + 1]],
                               day_count_act_365)
        yf_t0_timinus1 = dm.yearfrac([dates['settle']],
                                     [floating_dates[2 * k]],
                                     day_count_act_365)
        yf_t0_timinus2 = dm.yearfrac([dates['settle']],
                                     [floating_dates[2 * k - 1]],
                                     day_count_act_365)
        yf_timinus2_timinus1 = dm.yearfrac([floating_dates[2 * k - 1]],
                                           [floating_dates[2 * k]],
                                           day_count_act_365)
        yf_timinus1_ti = dm.yearfrac([floating_dates[2 * k]],
                                     [floating_dates[2 * k + 1]],
                                     day_count_act_365)
        yf_timinus2_ti = dm.yearfrac([floating_dates[2 * k - 1]],
                                     [floating_dates[2 * k + 1]],
                                     day_count_act_365)
        z_timinus2 = -np.log(
            pseudo_discounts_semiannual[2 * k - 1]) / yf_t0_timinus2

        return ( discounts_EONIA_semiannual[2*k] * (pseudo_discounts_semiannual[2*k-1]/p[0]-1) +\
                    discounts_EONIA_semiannual [2*k+1] *(p[0]/p[1]-1) + known_term - I, \
                    (-np.log(p[0])/yf_t0_timinus1 - z_timinus2)/yf_timinus2_timinus1 -\
                    (-np.log(p[1])/yf_t0_ti - z_timinus2)/yf_timinus2_ti)

    # import fsolve in order to solve the system
    from scipy.optimize import fsolve

    for k in range(1, len(dates['swaps'])):
        BPV = discounts_EONIA_semiannual[1:2 * k + 2:2].dot(
            dt_fixed_dates[0:k + 1])
        I = BPV * rates['swaps'][k]

        forward_euribor6m_semiannual = np.array(  ut.removenest([1, pseudo_discounts_semiannual[0:2*k-1].tolist()])  ) / \
            np.array( pseudo_discounts_semiannual[0:2*k].tolist() ) -1

        known_term = discounts_EONIA_semiannual[0:2 * k].dot(
            forward_euribor6m_semiannual)

        x, y = fsolve(equations_1, (0.5, 0.5))
        pseudo_discounts_semiannual[2 * k] = x
        pseudo_discounts_semiannual[2 * k + 1] = y

    dates_pseudo = ut.removenest( [ dates['settle'], dates['fra_start'][0:5], dates['euribor'], dates['fra_end'][0:5],\
                   dates['fra_end'][5], floating_dates[2::] ] )
    discount_pseudo = [1] + discount_1m_to_5m.tolist() + discount_pseudo_6m.tolist() + discount_7m_to_11m.tolist() + \
                   discount_pseudo_1y.tolist() + pseudo_discounts_semiannual[2::].tolist()
    return [dates_pseudo, discount_pseudo]
    def model_prices_swapt(p):
        #convention: p=[a;sigma;gamma];
        dayCount_maturity = 3  #Act/365
        numswapt = len(tenor)  #number of swaptions

        swaption_prices_model = np.zeros(numswapt)  #initialization

        delta_t0_talpha = dm.yearfrac([settlement] * numswapt,
                                      dates_semiannual[0:(2 * numswapt - 1):2],
                                      dayCount_maturity)
        zeta_alpha_square_vec = p[1]**2 * (
            1 - np.exp(-2 * p[0] * delta_t0_talpha)) / (2 * p[0])

        count_set = range(0, numswapt)
        i = 8
        ld = len(dates_semiannual)

        for i in count_set:
            delta_alphaprime_iota = dm.yearfrac(
                [dates_semiannual[2 * i]] * (ld - 2 * i),
                dates_semiannual[2 * i::], dayCount_maturity)
            v_alphaprime_iota = np.sqrt(zeta_alpha_square_vec[i]) / p[0] * (
                1 - np.exp(-p[0] * delta_alphaprime_iota))

            delta_alpha_i = dm.yearfrac(
                [dates_semiannual[2 * i]] * int((ld + 1) / 2 - i),
                dates_semiannual[2 * i::2], dayCount_maturity)
            v_alpha_i = np.sqrt(zeta_alpha_square_vec[i]) / p[0] * (
                1 - np.exp(-p[0] * delta_alpha_i))
            nu_alphaprime_iota = v_alphaprime_iota[
                0:len(v_alphaprime_iota) - 1] - p[2] * v_alphaprime_iota[1::]

            varsigma_alphaprime_iota = (1 - p[2]) * v_alphaprime_iota
            varsigma_alpha_i = (1 - p[2]) * v_alpha_i

            B_alpha_j_fwd = discount_factors_semiannual[
                2 * i + 2::2] / discount_factors_semiannual[2 * i]
            B_alphaprime_iota_fwd = discount_factors_semiannual[
                2 * i::] / discount_factors_semiannual[2 * i]

            from scipy.optimize import fsolve

            x_star = fsolve(aux.f_jam,
                            0,
                            args=(deltas_fixed_leg, B_alpha_j_fwd,
                                  varsigma_alpha_i, B_alphaprime_iota_fwd,
                                  varsigma_alphaprime_iota,
                                  forward_beta_semiannual, nu_alphaprime_iota,
                                  i, strike[i]))
            x_star = -0.017451279157548
            from scipy.integrate import quad

            (x,
             y) = quad(aux.jam_integrand,
                       -10,
                       x_star,
                       args=(deltas_fixed_leg, B_alpha_j_fwd, varsigma_alpha_i,
                             B_alphaprime_iota_fwd, varsigma_alphaprime_iota,
                             forward_beta_semiannual, nu_alphaprime_iota, i,
                             tenor[i], strike[i]))
            swaption_prices_model[i] = x * discount_factors_semiannual[2 * i]

        return swaption_prices_model
def calibrate_model(normal_vols, dates_EONIA, discounts_EONIA, dates_pseudo,
                    discount_pseudo):
    # Initial settings
    tenor = normal_vols['tenor']  # tenors of swaptions
    expiry = normal_vols['expiry']  # swaptions' expiry
    nv_values = normal_vols['values']
    settlement = int(dates_EONIA[0])  # settlement date (int)
    dayCount_fixed = 6

    # Deltas and dates
    # date 1y after the settlement (int)
    date_1y_after_settlement = dm.dateMoveVec_MF([settlement], 'y', 1,
                                                 dm.eurCalendar())
    # list of semiannual dates
    dates_semiannual = date_1y_after_settlement + dm.tenordates_MF(
        date_1y_after_settlement, 2 * len(expiry), 'm', 6, dm.eurCalendar())

    # delta(ti,t_i+1) on fixed dates
    deltas_fixed_leg = dm.yearfrac(dates_semiannual[0:len(dates_semiannual):2],
                                   dates_semiannual[2::2], dayCount_fixed)

    # Discounts
    # semiannual discount factors (EONIA and pseudo-discounts)
    discount_factors_semiannual = ut.interp_discount(dates_EONIA,
                                                     discounts_EONIA,
                                                     dates_semiannual)
    pseudo_discount_factors_semiannual = ut.interp_discount(
        dates_pseudo, discount_pseudo, dates_semiannual)

    # semiannual forward dicount factors (EONIA and pseudo-discounts) from t_i to t_i+1
    discount_factors_semiannual_fwd = discount_factors_semiannual[1::] / \
       discount_factors_semiannual[0:len(discount_factors_semiannual)-1]
    pseudo_discount_factors_semiannual_fwd = pseudo_discount_factors_semiannual[1::] / \
       pseudo_discount_factors_semiannual[0:len(discount_factors_semiannual)-1]

    # forward beta from t_i to t_i+1
    forward_beta_semiannual = discount_factors_semiannual_fwd / pseudo_discount_factors_semiannual_fwd

    # Compute market prices using Bachelier formula (the function is in auxiliars library)
    [RS_mkt_prices, strike]=aux.normal_vols_swaption_MHJM(dates_semiannual, deltas_fixed_leg,\
     discount_factors_semiannual, forward_beta_semiannual, settlement, nv_values, tenor)

    #	Define the model-price for reciver cash-settlement swaptions
    def model_prices_swapt(p):
        #convention: p=[a;sigma;gamma];
        dayCount_maturity = 3  #Act/365
        numswapt = len(tenor)  #number of swaptions

        swaption_prices_model = np.zeros(numswapt)  #initialization

        delta_t0_talpha = dm.yearfrac([settlement] * numswapt,
                                      dates_semiannual[0:(2 * numswapt - 1):2],
                                      dayCount_maturity)
        zeta_alpha_square_vec = p[1]**2 * (
            1 - np.exp(-2 * p[0] * delta_t0_talpha)) / (2 * p[0])

        count_set = range(0, numswapt)
        i = 8
        ld = len(dates_semiannual)

        for i in count_set:
            delta_alphaprime_iota = dm.yearfrac(
                [dates_semiannual[2 * i]] * (ld - 2 * i),
                dates_semiannual[2 * i::], dayCount_maturity)
            v_alphaprime_iota = np.sqrt(zeta_alpha_square_vec[i]) / p[0] * (
                1 - np.exp(-p[0] * delta_alphaprime_iota))

            delta_alpha_i = dm.yearfrac(
                [dates_semiannual[2 * i]] * int((ld + 1) / 2 - i),
                dates_semiannual[2 * i::2], dayCount_maturity)
            v_alpha_i = np.sqrt(zeta_alpha_square_vec[i]) / p[0] * (
                1 - np.exp(-p[0] * delta_alpha_i))
            nu_alphaprime_iota = v_alphaprime_iota[
                0:len(v_alphaprime_iota) - 1] - p[2] * v_alphaprime_iota[1::]

            varsigma_alphaprime_iota = (1 - p[2]) * v_alphaprime_iota
            varsigma_alpha_i = (1 - p[2]) * v_alpha_i

            B_alpha_j_fwd = discount_factors_semiannual[
                2 * i + 2::2] / discount_factors_semiannual[2 * i]
            B_alphaprime_iota_fwd = discount_factors_semiannual[
                2 * i::] / discount_factors_semiannual[2 * i]

            from scipy.optimize import fsolve

            x_star = fsolve(aux.f_jam,
                            0,
                            args=(deltas_fixed_leg, B_alpha_j_fwd,
                                  varsigma_alpha_i, B_alphaprime_iota_fwd,
                                  varsigma_alphaprime_iota,
                                  forward_beta_semiannual, nu_alphaprime_iota,
                                  i, strike[i]))
            x_star = -0.017451279157548
            from scipy.integrate import quad

            (x,
             y) = quad(aux.jam_integrand,
                       -10,
                       x_star,
                       args=(deltas_fixed_leg, B_alpha_j_fwd, varsigma_alpha_i,
                             B_alphaprime_iota_fwd, varsigma_alphaprime_iota,
                             forward_beta_semiannual, nu_alphaprime_iota, i,
                             tenor[i], strike[i]))
            swaption_prices_model[i] = x * discount_factors_semiannual[2 * i]

        return swaption_prices_model

# Define the distance function that we have to minimize in order to calibrate the model

    def model_market_distance(p):
        #convention: p=[a;sigma;gamma];
        prices_model = model_prices_swapt(p)
        return ((RS_mkt_prices - prices_model).dot(RS_mkt_prices -
                                                   prices_model))

# Perform the optimization of model-market distance
# and finding the minimum

    bnds = ((0, 1), (0, 1), (0, 1))  # defining bounds for parameters

    # The optimal starting point has been found performing a stochastic approach
    x0 = [0.108767495200880, 0.018587703751741, 0.000559789728685]
    import warnings
    warnings.filterwarnings('ignore',
                            'The iteration is not making good progress')
    p_opt = sci.optimize.minimize(model_market_distance, x0, bounds=bnds)

    # Calibrated model prices
    RS_calibrated_prices = model_prices_swapt(p_opt.x)

    return [RS_calibrated_prices, RS_mkt_prices, p_opt.x]
Beispiel #9
0
def bootstrap_Z_curve(coupon_payment_dates, idx1, idx1_cs, coupon_on_dates,
                      maturities, discounts_EONIA, dates_EONIA, dirtyPrices):

    settle = dates_EONIA[0]
    dayCount_act365 = 3

    deltas = dm.yearfrac([settle] * len(coupon_payment_dates),
                         coupon_payment_dates, dayCount_act365)

    B_bar = np.zeros(idx1_cs[len(idx1_cs) - 1] + 1)  #initialization
    Z_spread = np.zeros(idx1_cs[len(idx1_cs) - 1] + 1)

    B_interp = ut.interp_discount(dates_EONIA, discounts_EONIA,
                                  coupon_payment_dates)

    def eq_z_cnst(z_cnst):
        return (-dirtyPrices[0] + np.array(coupon_on_dates[0:idx1[1]]).dot(
            B_interp[0:idx1[1]] * np.exp(-z_cnst * deltas[0:idx1[1]])))

    from scipy.optimize import fsolve
    Z_spread[0:idx1[1]] = fsolve(eq_z_cnst, 0.005)

    B_bar[0:idx1[1]] = B_interp[0:idx1[1]] * np.exp(
        -deltas[0:idx1[1]] * Z_spread[0:idx1[1]])

    count_set = range(1, len(maturities))
    for i in count_set:
        fd = idx1_cs[i] + 1
        #first date (even if before ttl)
        ld = idx1_cs[i + 1]
        #last date (maturity)
        flag = sum(
            np.array(coupon_payment_dates[fd:ld + 1]) >
            maturities[i - 1])  #number of unknowns

        idx_sorting = np.argsort(np.insert(deltas[0:fd], 0, 0))
        deltas_sorted = np.insert(deltas[0:fd], 0, 0)
        deltas_sorted = deltas_sorted[idx_sorting]
        zeta_sorted = np.insert(Z_spread[0:fd], 0, Z_spread[0])
        zeta_sorted = zeta_sorted[idx_sorting]

        Z_spread[fd:ld - flag + 1] = np.interp(deltas[fd:ld - flag + 1],
                                               deltas_sorted, zeta_sorted)
        B_bar[fd:ld - flag + 1] = B_interp[fd:ld - flag + 1] * (np.exp(
            -deltas[fd:ld - flag + 1] * Z_spread[fd:ld - flag + 1]))

        if flag == 1:
            B_bar[ld] = (dirtyPrices[i] -
                         np.array(coupon_on_dates[fd:ld - flag + 1]).dot(
                             B_bar[fd:ld - flag + 1])) / coupon_on_dates[ld]
            Z_spread[ld] = -1 / deltas[ld] * np.log(B_bar[ld] / B_interp[ld])

        else:
            z0 = 1e-2 * np.ones(flag)
            Z_spread[ld - flag + 1:ld + 1] = fsolve(
                build_system_of_eqn,
                z0,
                args=(flag, coupon_on_dates[fd:ld + 1],
                      deltas[ld - flag + 1:ld + 1], B_bar[fd:ld - flag + 1],
                      B_interp[ld - flag + 1:ld + 1], dirtyPrices[i],
                      Z_spread[idx1_cs[i]], deltas[idx1_cs[i]]))

            B_bar[ld - flag + 1:ld +
                  1] = B_interp[ld - flag + 1:ld + 1] * np.exp(
                      -deltas[ld - flag + 1:ld + 1] *
                      Z_spread[ld - flag + 1:ld + 1])

    return B_bar
Beispiel #10
0
def create_vector_payment_dates(dates_bonds_maturity, settle, ttl):
    """Build a unique vector containing all coupon payment dates, and return 
	indexes in order to handle it.
	__________________________________________________________________________
	 INPUT
	 - datesSet:       vector containing all the maturity dates for the bonds;
	 - settle:         settlement date for the basket of bonds;
	 - ttl:            time-to-liquidate.
	--------------------------------------------------------------------------
	 OUTPUT
	 - coupon_payment_dates:  vector that contains all the (unsorted) coupon
	                          payment dates of the bonds (even the ones
	                          between the settlement date and the ttl);
	 - idx1:                  vector that contains the number of coupons 
	                          paid for each bond. 
	                          NB: for practical use, the first element is
	                          set to 0, so the first bond will pay idx(2)
	                          coupons, the second one will pay idx(3) coupons
	                          and so on.
	 - idx1_cs:               cumulative sum of idx_1. This means that
	                          payment dates of the i-th coupon will be
	                          coupon_payment_dates(idx1_cs(i)+1:idx1_cs(i+1))
	                          (indeed if we have N bonds, length(idx1_cs)=N); 
	 - idx2:                  vector that contains the number of coupons paid
	                          between the settlement date and the ttl. The
	                          notation used is the same as idx1 and idx1_cs,
	                          with the first element idx(1) set to 0.
	                          [In our case, since each bond pays annual coupon
	                          and we consider ttl=2weeks or ttl=2monts, idx2
	                          is a binary variable that holds 1 if the coupon 
	                          is paid in between and 0 otherwise].
	--------------------------------------------------------------------------
	 Functions used: dateMoveVec.
	--------------------------------------------------------------------------"""

    # Initial settings
    n_bonds = len(dates_bonds_maturity)  # number of bonds
    num_coupon_payments = list(
        map(
            lambda x: int(x),
            np.floor(
                np.array(
                    dm.yearfrac([settle] * n_bonds, dates_bonds_maturity,
                                0))).tolist()))
    coupon_payment_dates_list = [0] * n_bonds  # initialization
    idx1 = [0] * (n_bonds + 1)
    #+1 for smarter use in the future
    idx2 = [0] * (n_bonds + 1)
    #+1 to use the same notation

    # Create vector and indexes
    for k in range(0, n_bonds):
        # we compute coupon payment dates
        coupon_payment_dates_list[k] = [0] * (num_coupon_payments[k] + 1)

        for j in range(0, num_coupon_payments[k] + 1):
            coupon_payment_dates_list[k][j]= dm.dateMoveVec_MF([dates_bonds_maturity[k]],\
                                                            'y', -num_coupon_payments[k]+j, dm.eurCalendar())[0]

        # we store the number of coupons that will be paid for the i-th bond

        idx1[k + 1] = len(coupon_payment_dates_list[k])

        # we want to know how many of these coupons fall between settlement and
        # ttl (in our model, at most one, in the worst cases)
        idx2[k+1]=len( list(np.extract(np.array(coupon_payment_dates_list[k])<=ttl,\
            np.array(coupon_payment_dates_list[k]))) )
    #doing the cumulative sum, as explained in the header
    idx1_cs = list(np.cumsum(np.array(idx1)) - 1)

    # converting the dynamic array in a static array
    coupon_payment_dates= [item for sublist in coupon_payment_dates_list\
                           for item in sublist]
    return [coupon_payment_dates, idx1, idx1_cs, idx2]