diff options
Diffstat (limited to 'python/analytics')
| -rw-r--r-- | python/analytics/tranche_basket.py | 54 |
1 files changed, 45 insertions, 9 deletions
diff --git a/python/analytics/tranche_basket.py b/python/analytics/tranche_basket.py index 5ef0503b..fbef179c 100644 --- a/python/analytics/tranche_basket.py +++ b/python/analytics/tranche_basket.py @@ -4,6 +4,7 @@ from .tranche_functions import ( credit_schedule, adjust_attachments, cds_accrued, GHquad, BCloss_recov_dist, tranche_cl, tranche_pl) from .index_data import get_singlenames_curves, get_tranche_quotes +from copy import deepcopy from pyisda.cdsone import upfront_charge from pandas.tseries.offsets import BDay from scipy.optimize import brentq @@ -28,9 +29,8 @@ class TrancheBasket(BasketIndex): if index_type == "XO": coupon = 500 * 1e-4 - self.tranche_quotes.quotes.iat[3] = self._snacpv(self.tranche_quotes.running.iat[3], - coupon, - 0.4) + self.tranche_quotes.quotes.iat[3] = self._snacpv( + self.tranche_quotes.running.iat[3], coupon, 0.4) self.tranche_quotes.running = coupon if index_type == "EU": @@ -57,6 +57,7 @@ class TrancheBasket(BasketIndex): self._Ngh = 250 self._Ngrid = 201 self._Z, self._w = GHquad(self._Ngh) + self.rho = np.full(self.K.size, np.nan) def _get_quotes(self): refprice = self.tranche_quotes.indexrefprice.iat[0] @@ -93,6 +94,25 @@ class TrancheBasket(BasketIndex): else: return tranche_cl(L, R, self.cs, 0., K), tranche_pl(L, self.cs, 0., K) + def tranche_pvs(self, protection=False, complement=False): + cl = np.zeros(self.rho.size) + pl = np.zeros(self.rho.size) + i = 0 + for rho, k in zip(self.rho, self.K): + cl[i], pl[i] = self.tranche_legs(k, rho, complement) + i += 1 + dK = np.diff(self.K) + pl = np.diff(pl) / dK + cl = np.diff(cl) / dK * self.tranche_quotes.running + if complement: + pl *= -1 + cl *= -1 + if protection: + bp = -pl -cl + else: + bp = 1 + pl + cl + return cl, pl, bp + def index_pv(self, discounted=True): ELvec = (self.weights * (1 - self.recovery_rates) @ \ self.default_prob) @@ -111,9 +131,26 @@ class TrancheBasket(BasketIndex): def recovery_rates(self): return np.array([c.recovery_rates[0] for c in self.curves]) + def tranche_deltas(self, complement=False): + eps = 1e-4 + self._N = 301 + index_list = [self] + for tweak in eps, -eps, 2*eps: + tb = deepcopy(self) + tb.tweak_portfolio(tweak, self.maturity) + index_list.append(tb) + bp = np.zeros((len(index_list), self.K.size - 1)) + indexbp = np.zeros(len(index_list)) + for i, index in enumerate(index_list): + indexbp[i] = index.index_pv()[2] + bp[i] = index.tranche_pvs(complement)[2] + deltas = (bp[1] - bp[2]) / (indexbp[1]-indexbp[2]) + deltasplus = (bp[3] - bp[0]) / (indexbp[3]-indexbp[0]) + gammas = (deltasplus - deltas) / (indexbp[1] - indexbp[0]) / 100 + return deltas, gammas + def build_skew(self, skew_type="bottomup"): assert(skew_type == "bottomup" or skew_type == "topdown") - rhovec = np.full(self.K.size, np.nan) dK = np.diff(self.K) def aux(rho, obj, K, quote, spread, complement): @@ -122,28 +159,27 @@ class TrancheBasket(BasketIndex): if skew_type == "bottomup": for j in range(len(dK) - 1): - cl, pl = self.tranche_legs(self.K[j], rhovec[j]) + cl, pl = self.tranche_legs(self.K[j], self.rho[j]) q = self.tranche_quotes.quotes.iat[j] * dK[j] - \ pl - cl * self.tranche_quotes.running.iat[j] x0, r = brentq(aux, 0., 1., args=(self, self.K[j+1], q, self.tranche_quotes.running.iat[j], False), full_output=True) if r.converged: - rhovec[j+1] = x0 + self.rho[j+1] = x0 else: print(r.flag) break elif skew_type == "topdown": for j in range(len(dK) - 1, 0, -1): - cl, pl = self.tranche_legs(self.K[j+1], rhovec[j+1]) + cl, pl = self.tranche_legs(self.K[j+1], self.rho[j+1]) q = self.tranche_quotes.quotes.iat[j] * dK[j] - \ pl - cl * self.tranche_quotes.running.iat[j] x0, r = brentq(aux, 0., 1., args=(self, self.K[j], q, self.tranche_quotes.running.iat[j], False), full_output=True) if r.converged: - rhovec[j+1] = x0 + self.rho[j+1] = x0 else: print(res.flag) break - return rhovec |
