diff options
Diffstat (limited to 'python')
| -rw-r--r-- | python/analytics/tranche_basket.py | 60 |
1 files changed, 48 insertions, 12 deletions
diff --git a/python/analytics/tranche_basket.py b/python/analytics/tranche_basket.py index 1d58219c..ff46c74e 100644 --- a/python/analytics/tranche_basket.py +++ b/python/analytics/tranche_basket.py @@ -3,7 +3,7 @@ from .tranche_functions import ( credit_schedule, adjust_attachments, GHquad, BCloss_recov_dist, BCloss_recov_trunc, tranche_cl, tranche_pl) from .index_data import get_tranche_quotes -from .utils import memoize +from .utils import memoize, build_table from collections import namedtuple from db import dbconn from copy import deepcopy @@ -27,13 +27,18 @@ class DualCorrTranche(): value_date: pd.Timestamp=pd.Timestamp.today().normalize()): self._index = BasketIndex(index_type, series, [tenor], value_date=value_date) - def get_quotes(self, spread): - maturity = self.maturities[0] - return {maturity: - self._snacpv(spread * 1e-4, self.coupon(maturity), self.recovery, - maturity)} - # monkey patch _get_quotes (don't try it at home) - BasketIndex._get_quotes = get_quotes + # def get_quotes(self, spread): + # index = self. + + # maturity = self._index.maturities[0] + # return {maturity: + # self._snacpv(spread * 1e-4, self.coupon(maturity), self.recovery, + # maturity)} + # # monkey patch _get_quotes (don't try it at home) + # BasketIndex._get_quotes = get_quotes + self.maturity = self._index.maturities[0] + self.index_type = index_type + self.series = series self.tenor = tenor self.K_orig = np.array([attach, detach]) / 100 self.attach, self.detach = attach, detach @@ -163,19 +168,50 @@ class DualCorrTranche(): def reset_pv(self): self._original_pv = self.pv - self._trade_date = self._value_date + self._trade_date = self.value_date + @property def pnl(self): if self._original_pv is None: raise ValueError("original pv not set") else: # TODO: handle factor change days_accrued = (self.value_date - self._trade_date).days / 360 - return self.notional * self._direction * (self.pv.bond_price - self._original_pv + + return self.notional * self._direction * -(self.pv - self._original_pv + self.tranche_running * days_accrued) - def shock(self, params=['pnl'], *, corr_shock, kwargs): - pass + def __repr__(self): + s = ["{}{} {} Tranche".format(self.index_type, self.series, self.tenor), + "", + "{:<20}\t{:>15}".format("Value Date", ('{:%m/%d/%y}'. + format(self.value_date)))] + rows = [["Notional", self.notional * self._direction, "PV", self.pv *100], + ["Attach", self.attach, "Detach", self.detach], + ["Attach Corr", self.rho[0] * 100, "Detach Corr", self.rho[1] * 100]] + format_strings = [[None, '{:,.0f}', None, '{:,.4f}%'], + [None, '{:.2f}', None, '{:,.2f}'], + [None, '{:.3f}%', None, '{:.3f}%']] + s += build_table(rows, format_strings, "{:<20}{:>19}\t\t{:<19}{:>16}") + return "\n".join(s) + + def shock(self, params=['pnl'], *, spread_shock, corr_shock, **kwargs): + orig_spread, orig_rho = self._index.spread()[0], self.rho + r = [] + actual_params = [p for p in params if hasattr(self, p)] + for ss in spread_shock: + orig_curves = deepcopy(self._index.curves) + self._index.tweak_portfolio(ss, self.maturity) + for corrs in corr_shock: + #also need to map skew + self.rho = np.fmin(1, orig_rho * (1 + corrs)) + r.append([getattr(self, p) for p in actual_params]) + self._index.curves = orig_curves + self.rho = orig_rho + return pd.DataFrame.from_records( + r, + columns=actual_params, + index=pd.MultiIndex.from_product([spread_shock, corr_shock], + names=['spread_shock', 'corr_shock'])) class TrancheBasket(BasketIndex): |
