aboutsummaryrefslogtreecommitdiffstats
path: root/python/analytics/tranche_basket.py
blob: ad96cb59ccb1cbbab004bad45f5295e0e2d9b5c6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
from .basket_index import BasketIndex
from .db import _engine
from .tranche_functions import credit_schedule, adjust_attachments, cds_accrued
from index_data import get_singlenames_curves, get_tranche_quotes
from pyisda.cdsone import upfront_charge
from pandas.tseries.offsets import BDay

import pandas as pd
import numpy as np

class TrancheBasket(BasketIndex):
    def __init__(self, index_type: str, series: int, tenor: str, *,
                 trade_date: pd.Timestamp=pd.Timestamp.today().normalize()):
        print(trade_date)
        super().__init__(index_type, series, [tenor], trade_date=trade_date)
        self.tranche_quotes = get_tranche_quotes(index_type, series, tenor, trade_date.date())
        index_desc = self.index_desc.reset_index('maturity').set_index('tenor')
        self.maturity = index_desc.loc[tenor].maturity
        self.start_date, self.cs = credit_schedule(trade_date, tenor[:-1], 1, self.yc)
        self.K_orig = np.hstack([0, self.tranche_quotes.detach])
        self.K = adjust_attachments(self.K_orig, self.cumloss, self.factor)
        if index_type == "HY":
            self.tranche_quotes['quotes'] = 1 - self.tranche_quotes.trancheupfrontmid / 100
        else:
            self.tranche_quotes['quotes'] = self.tranche_quotes.trancheupfrontmid / 100
        self.tranche_quotes['running'] = self.tranche_quotes.trancherunningmid * 1e-4

        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.running = coupon

        if index_type == "EU":
            if series >= 21:
                coupon = 100 * 1e-4
                for i in [2, 3]:
                    self.tranche_quotes.quotes.iat[i] = self._snacpv(
                        self.tranche_quotes.running.iat[i],
                        coupon,
                        0. if i == 2 else 0.4)
                    self.tranche_quotes.running.iat[i] = coupon
            elif series == 9:
                for i in [3, 4, 5]:
                    coupon = 25 * 1e-4 if i == 5 else 100 * 1e-4
                    recov = 0.4 if i == 5 else 0
                    self.tranche_quotes.quotes.iat[i] = self._snacpv(
                        self.tranche_quotes.running.iat[i],
                        coupon,
                        recov)
                    self.tranche_quotes.running.iat[i] = coupon
        accrued = cds_accrued(self.trade_date, self.tranche_quotes.running)
        self.tranche_quotes.quotes -= accrued

        self._Ngh = 250
        self._Ngrid = 201
        self._Z, self._w = GHquad(self._Ngh)

    def _get_quotes(self):
        refprice = self.tranche_quotes[0]['indexrefprice']
        refspread = self.tranche_quotes[0]['indexrefspread']
        if refprice is not None:
            return {self.maturity: 1 - refprice / 100}
        if refspread is not None:
            return {self.maturity:
                    _scnacpv(refspread * 1e-4, self.coupon(maturity), self.recovery)}
            raise ValueError("ref is missing")

    def _snacpv(self, spread, coupon, recov):
        return  upfront_charge(self.trade_date, self.value_date, self.start_date,
                               self.step_in_date, self.start_date, self.maturity,
                               coupon, self.yc, spread, recov)

    @property
    def default_prob(self):
        return 1 - super().survival_matrix(self.cs.index.values.astype('M8[D]').view('int') + 134774)

    def tranche_legs(self, K, rho, complement=False):
        if ((K == 0 and not complement) or (K == 1 and complement)):
            return {'cl': 0., 'pl': 0.}
        elif ((K == 1 and not complement) or (K == 0 and complement)):
            return BCindexpv(index)
        else:
            L, R = BCloss_recov_dist(self.default_prob,
                                     self.weights,
                                     self.recovery,
                                     rho,
                                     self._Z, self._w, self._Ngrid)
            if complement:
                return {'cl': tranche_cl(L, R, self.cs, K, 1),
                        'pl': tranche_pl(L, self.cs, K, 1)}
            else:
                return {'cl': tranche_cl(L, R, self.cs, 0, K),
                        'pl': tranche_pl(L, self.cs, 0, K)}