aboutsummaryrefslogtreecommitdiffstats
path: root/python/analytics
diff options
context:
space:
mode:
Diffstat (limited to 'python/analytics')
-rw-r--r--python/analytics/tranche_basket.py54
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