aboutsummaryrefslogtreecommitdiffstats
path: root/python
diff options
context:
space:
mode:
Diffstat (limited to 'python')
-rw-r--r--python/analytics/tranche_basket.py60
1 files changed, 26 insertions, 34 deletions
diff --git a/python/analytics/tranche_basket.py b/python/analytics/tranche_basket.py
index 034ca416..5cd152f3 100644
--- a/python/analytics/tranche_basket.py
+++ b/python/analytics/tranche_basket.py
@@ -3,11 +3,10 @@ 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 cityhash import CityHash64
+from .utils import memoize
from collections import namedtuple
from db import dbconn
from copy import deepcopy
-from functools import partial
from lru import LRU
from pyisda.date import cds_accrued
from scipy.optimize import brentq
@@ -18,27 +17,6 @@ import pandas as pd
import numpy as np
-_cache = LRU(64)
-
-
-def BCloss_recov_dist_cached(default_prob,
- weights,
- recovery_rates,
- rho,
- Z, w, Ngrid):
- h = CityHash64(default_prob.T) ^ CityHash64(weights) ^ \
- CityHash64(recovery_rates) ^ hash(rho)
- if h in _cache:
- return _cache[h]
- else:
- _cache[h] = BCloss_recov_dist(default_prob,
- weights,
- recovery_rates,
- rho,
- Z, w, Ngrid)
- return _cache[h]
-
-
class DualCorrTranche():
def __init__(self, index_type: str, series: int, tenor: str, *,
attach: float, detach: float, corr_attach: float,
@@ -47,13 +25,13 @@ class DualCorrTranche():
value_date: pd.Timestamp=pd.Timestamp.today().normalize()):
self._index = BasketIndex(index_type, series, [tenor], value_date=value_date)
- def get_quotes(index, spread):
- maturity = index.maturities[0]
+ def get_quotes(self, spread):
+ maturity = self.maturities[0]
return {maturity:
- index._snacpv(spread * 1e-4, index.coupon(maturity), index.recovery,
- maturity)}
-
- self._index._get_quotes = partial(get_quotes, self._index)
+ 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.tenor = tenor
self.K_orig = np.array([attach, detach]) / 100
self.attach, self.detach = attach, detach
@@ -68,12 +46,25 @@ class DualCorrTranche():
self.cs = credit_schedule(value_date, None,
1., self._index.yc, self._index.maturities[0])
self._accrued = cds_accrued(value_date, tranche_running * 1e-4)
+ self._cache = LRU(64)
+ self._ignore_hash = set(['_Z', '_w', 'cs', '_cache', '_ignore_hash'])
def _default_prob(self):
return 1 - self._index.survival_matrix(
self.cs.index.values.astype('M8[D]').
view('int') + 134774)[0]
+ def __hash__(self):
+ def aux(v):
+ if isinstance(v, list):
+ return hash(tuple(v))
+ elif type(v) is np.ndarray:
+ return hash(v.tobytes())
+ else:
+ return hash(v)
+ return hash(tuple(aux(v) for k, v in vars(self).items()
+ if k not in self._ignore_hash))
+
@classmethod
def from_tradeid(cls, trade_id):
with dbconn('dawndb') as conn:
@@ -106,6 +97,7 @@ class DualCorrTranche():
self.cs = credit_schedule(d, None, 1., self._index.yc, self._index.maturities[0])
self._accrued = cds_accrued(d, self.tranche_running * 1e-4)
+ @memoize
def tranche_legs(self, K, rho):
if K == 0.:
return 0., 0.
@@ -114,11 +106,11 @@ class DualCorrTranche():
elif np.isnan(rho):
raise ValueError("rho needs to be a real number between 0. and 1.")
else:
- L, R = BCloss_recov_dist_cached(self._default_prob(),
- self._index.weights,
- self._index.recovery_rates,
- rho,
- self._Z, self._w, self._Ngrid)
+ L, R = BCloss_recov_dist(self._default_prob(),
+ self._index.weights,
+ self._index.recovery_rates,
+ rho,
+ self._Z, self._w, self._Ngrid)
Legs = namedtuple('TrancheLegs', 'coupon_leg, protection_leg')
return Legs(tranche_cl(L, R, self.cs, 0., K), tranche_pl(L, self.cs, 0., K))