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]
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]
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
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]