Exemplo n.º 1
0
    def __init__(self, start, underlyings):

        myScheduler = Scheduler()
        myDelays = []
        freqs = ['3M', '6M', '1Y', '3Y']
        for i in range(0, len(freqs)):
            myDelays.append(myScheduler.extractDelay(freqs[i]))
        AAA = {}
        for i in range(0, len(freqs)):
            vas = MC_Vasicek_Sim(x=AAAx[freqs[i]],
                                 datelist=[start, myDelays[i] + start],
                                 t_step=1 / 365.,
                                 simNumber=500)
            AAA[freqs[i]] = vas.getLibor()[0].loc[myDelays[i] + start]

        BBB = {
            '3M':
            MC_Vasicek_Sim(x=BBBx[freqs[0]],
                           datelist=[start, myDelays[0] + start],
                           t_step=1 / 365.,
                           simNumber=500).getLibor()[0].loc[myDelays[0] +
                                                            start]
        }
        self.probs = {'AAA': AAA, 'BBB': BBB}
        self.underlyings = underlyings
class CorporateRates(object):
    def __init__(self):
        self.OIS = []
        self.filename = WORKING_DIR + '/CorpData.dat'
        self.corporates = []
        self.ratings = {
            'AAA': "BAMLC0A1CAAA",
            'AA': "BAMLC0A2CAA",
            'A': "BAMLC0A3CA",
            'BBB': "BAMLC0A4CBBB",
            'BB': "BAMLH0A1HYBB",
            'B': "BAMLH0A2HYB",
            'CCC': "BAMLH0A3HYC"
        }
        self.corpSpreads = {}
        self.corporates = pd.DataFrame()
        self.Qcorporates = pd.DataFrame()  # survival function for corporates
        self.tenors = []
        self.unPickleMe(file=self.filename)
        self.myScheduler = Scheduler()
        self.myVasicek = MC_Vasicek_Sim()
        self.R = 0.4

    def getCorporatesFred(self, trim_start, trim_end):
        fred = Fred(api_key=FRED_API_KEY)
        curr_trim_end = trim_start
        if (self.corporates.size != 0):
            self.trim_start = self.corporates['OIS'].index.min().date()
            curr_trim_end = self.corporates['OIS'].index.max().date()
        if trim_end <= curr_trim_end:
            self.trim_end = curr_trim_end
            return self.corporates
        self.trim_start = trim_start
        self.trim_end = trim_end
        self.OIS = OIS(trim_start=trim_start, trim_end=trim_end)
        self.datesAll = self.OIS.datesAll
        self.datesAll.columns = [x.upper() for x in self.datesAll.columns]
        self.datesAll.index = self.datesAll.DATE
        self.OISData = self.OIS.getOIS()
        for i in np.arange(len(self.OISData.columns)):
            freq = self.OISData.columns[i]
            self.tenors.append(self.myScheduler.extractDelay(freq=freq))
        for rating in self.ratings.keys():
            index = self.ratings[rating]
            try:
                corpSpreads = 1e-2 * (fred.get_series(
                    index,
                    observation_start=trim_start,
                    observation_end=trim_end).to_frame())
                corpSpreads.index = [x.date() for x in corpSpreads.index[:]]
                corpSpreads = pd.merge(left=self.datesAll,
                                       right=corpSpreads,
                                       left_index=True,
                                       right_index=True,
                                       how="left")
                corpSpreads = corpSpreads.fillna(method='ffill').fillna(
                    method='bfill')
                corpSpreads = corpSpreads.drop("DATE", axis=1)
                self.corpSpreads[rating] = corpSpreads.T.fillna(
                    method='ffill').fillna(method='bfill').T
            except Exception as e:
                print(e)
                print(index, " not found")
        self.corpSpreads = pd.Panel.from_dict(self.corpSpreads)
        self.corporates = {}
        self.OISData.drop('DATE', axis=1, inplace=True)
        ntenors = np.shape(self.OISData)[1]
        for rating in self.ratings:
            try:
                tiledCorps = np.tile(self.corpSpreads[rating][0],
                                     ntenors).reshape(np.shape(self.OISData))
                self.corporates[rating] = pd.DataFrame(
                    data=(tiledCorps + self.OISData.values),
                    index=self.OISData.index,
                    columns=self.OISData.columns)
            except:
                print("Error in addition of Corp Spreads")
        self.corporates['OIS'] = self.OISData
        self.corporates = pd.Panel(self.corporates)
        return self.corporates

    def getCorporateData(self, rating, datelist=None):
        # This method gets a curve for a given date or date list for a given rating (normally this will be just a date).
        # It returns a dict of curves read directly from the corporate rates created by getCorporatesFred.
        # Derive delays from self.corporates[rating].columns
        myDelays = self.myScheduler.extractDelay(
            freq=list(self.corporates[rating].columns))
        if datelist is None:
            return
        outCurve = {}
        for day in datelist:
            # Create curves
            # ..............
            # ..............
            # add curve to outcurve dict
            outCurve[day] = myCurve
        return outCurve

    def getCorporateQData(self, rating, datelist=None, R=0.4):
        self.R = R
        if datelist is None:
            return
        outCurve = {}
        for day in datelist:
            # Create Q curves using q-tilde equation
            # ..............
            # ..............
            outCurve[day] = myCurve
        return outCurve

    def pickleMe(self):
        data = [self.corporates, self.corpSpreads]
        with open(self.filename, "wb") as f:
            pickle.dump(len(data), f)
            for value in data:
                pickle.dump(value, f)

    def unPickleMe(self, file):
        data = []
        if (os.path.exists(file)):
            with open(file, "rb") as f:
                for _ in range(pickle.load(f)):
                    data.append(pickle.load(f))
            self.corporates = data[0]
            self.corpSpreads = data[1]

    def saveMeExcel(self, whichdata, fileName):
        try:
            df = pd.DataFrame(whichdata)
        except:
            df = whichdata
        df.to_excel(fileName)
Exemplo n.º 3
0
class CouponBond(object):
    def __init__(self, fee, start,coupon,  maturity, freq, referencedate, observationdate,notional):
        self.fee = fee
        self.coupon=coupon
        self.start = start
        self.maturity = maturity
        self.freq= freq
        self.referencedate = referencedate
        self.observationdate = observationdate
        self.myScheduler = Scheduler()
        self.delay = self.myScheduler.extractDelay(freq=freq)
        self.getScheduleComplete()
        self.ntimes=len(self.datelist)
        self.referencedate = referencedate
        self.pvAvg=0.0
        self.cashFlows = DataFrame()
        self.cashFlowsAvg = []
        self.yieldIn = 0.0
        self.notional=notional

    def getScheduleComplete(self):
        self.datelist = self.myScheduler.getSchedule(start=self.start,end=self.maturity,freq=self.freq,referencedate=self.referencedate)
        fullset = list(sorted(list(set(self.datelist)
                                   .union([self.referencedate])
                                   .union([self.start])
                                   .union([self.maturity])
                                   .union([self.observationdate])
                                   )))
        return fullset,self.datelist

    def setLibor(self,libor):
        self.libor = libor/libor.loc[self.referencedate]
        self.ntimes = np.shape(self.datelist)[0]
        self.ntrajectories = np.shape(self.libor)[1]
        self.ones = np.ones(shape=[self.ntrajectories])

    def getExposure(self, referencedate):
        if self.referencedate!=referencedate:
            self.referencedate=referencedate
            self.getScheduleComplete()
        deltaT= np.zeros(self.ntrajectories)
        if self.ntimes==0:
            pdzeros= pd.DataFrame(data=np.zeros([1,self.ntrajectories]), index=[referencedate])
            self.pv=pdzeros
            self.pvAvg=0.0
            self.cashFlows=pdzeros
            self.cashFlowsAvg=0.0
            return self.pv
        for i in range(1,self.ntimes):
            deltaTrow = ((self.datelist[i]-self.datelist[i-1]).days/365)*self.ones
            deltaT = np.vstack ((deltaT,deltaTrow) )
        self.cashFlows= self.coupon*deltaT
        principal = self.ones
        if self.ntimes>1:
            self.cashFlows[-1:]+= principal
        else:
            self.cashFlows = self.cashFlows + principal
        if(self.datelist[0]<= self.start):
            self.cashFlows[0]=-self.fee*self.ones
    
        if self.ntimes>1:
            self.cashFlowsAvg = self.cashFlows.mean(axis=1)*self.notional
        else:
            self.cashFlowsAvg = self.cashFlows.mean() * self.notional
        pv = self.cashFlows*self.libor.loc[self.datelist]
        self.pv = pv.sum(axis=0)*self.notional
        self.pvAvg = np.average(self.pv)*self.notional
        return self.pv

    def getPV(self,referencedate):
        self.getExposure(referencedate=referencedate)
        return self.pv/self.libor.loc[self.observationdate]

    def getLiborAvg(self, yieldIn, datelist):
        self.yieldIn = yieldIn
        time0 = datelist[0]
        # this function is used to calculate exponential single parameter (r or lambda) Survival or Libor Functions
        Z = np.exp(-self.yieldIn * pd.DataFrame(np.tile([(x - time0).days / 365.0 for x in self.datelist], reps=[self.ntrajectories,1]).T,index=self.datelist))
        return Z

    def getYield(self,price):
        # Fit model to curve data
        yield0 = 0.05 * self.ones
        self.price = price
        self.yieldIn = self.fitModel2Curve(x=yield0)
        return self.yieldIn


    def fitModel2Curve(self, x ):
        # Minimization procedure to fit curve to model
        results = minimize(fun=self.fCurve, x0=x)
        return results.x

    def fCurve(self, x):
        # raw data error function
        calcCurve = self.getLiborAvg(x, self.datelist)
        thisPV = np.multiply(self.cashFlows,calcCurve).mean(axis=1).sum(axis=0)
        error = 1e4 * (self.price - thisPV) ** 2
        return error
Exemplo n.º 4
0
class CouponBond(object):
    def __init__(self,
                 fee,
                 coupon,
                 start,
                 maturity,
                 freq,
                 referencedate,
                 observationdate,
                 rating,
                 notional=1,
                 recovery=0.4):
        self.numSim = 10
        self.t_step = 1.0 / 365
        self.fee = fee
        self.coupon = coupon
        self.start = start
        self.maturity = maturity
        self.freq = freq
        self.recovery = recovery
        self.rating = rating
        self.referencedate = referencedate
        self.observationdate = observationdate
        self.myScheduler = Scheduler()
        self.delay = self.myScheduler.extractDelay(freq=freq)
        self.referencedate = referencedate
        self.getScheduleComplete()
        self.fullDateList = self.datelist
        self.ntimes = len(self.datelist)
        self.pvAvg = 0.0
        self.cashFlows = DataFrame()
        self.cashFlowsAvg = []
        self.yieldIn = 0.0
        self.notional = notional
        self.errorCurve = []
        self.mcSim = MC_Vasicek_Sim()

    def getScheduleComplete(self):
        self.datelist = self.myScheduler.getSchedule(
            start=self.start,
            end=self.maturity,
            freq=self.freq,
            referencedate=self.referencedate)
        self.ntimes = len(self.datelist)
        fullset = sorted(
            set(self.datelist).union([self.referencedate]).union([
                self.start
            ]).union([self.maturity]).union([self.observationdate]))
        a = 1
        return fullset, self.datelist

    def setLibor(self, libor):
        self.libor = libor / libor.loc[self.referencedate]
        #self.ntimes = np.shape(self.datelist)[0]
        self.ntrajectories = np.shape(self.libor)[1]
        self.ones = np.ones(shape=[self.ntrajectories])

    def getExposure(self, referencedate):
        if self.referencedate != referencedate:
            self.referencedate = referencedate
            self.getScheduleComplete()
        deltaT = np.zeros(self.ntrajectories)
        if self.ntimes == 0:
            pdzeros = pd.DataFrame(data=np.zeros([1, self.ntrajectories]),
                                   index=[referencedate])
            self.pv = pdzeros
            self.pvAvg = 0.0
            self.cashFlows = pdzeros
            self.cashFlowsAvg = 0.0
            return self.pv
        for i in range(1, self.ntimes):
            deltaTrow = ((self.datelist[i] - self.datelist[i - 1]).days /
                         365) * self.ones
            deltaT = np.vstack((deltaT, deltaTrow))
        self.cashFlows = self.coupon * deltaT
        principal = self.ones
        if self.ntimes > 1:
            self.cashFlows[-1:] += principal
        else:
            self.cashFlows = self.cashFlows + principal
        if (self.datelist[0] <= self.start):
            self.cashFlows[0] = -self.fee * self.ones

        if self.ntimes > 1:
            self.cashFlowsAvg = self.cashFlows.mean(axis=1) * self.notional
        else:
            self.cashFlowsAvg = self.cashFlows.mean() * self.notional
        pv = self.cashFlows * self.libor.loc[self.datelist]
        self.pv = pv.sum(axis=0) * self.notional
        self.pvAvg = np.average(self.pv) * self.notional
        return self.pv

    def getPV(self, referencedate):
        self.getExposure(referencedate=referencedate)
        return self.pv / self.libor.loc[self.referencedate]

    def getFullExposure(self):
        fullExposure = pd.DataFrame(data=np.zeros(len(self.fullDateList)),
                                    index=self.fullDateList)
        for days in self.fullDateList:
            fullExposure.loc[days] = self.getExposure(days)
        self.fullExposure = fullExposure

    def setCorpData(self, corpData):
        self.corpData = corpData.loc[self.rating, :, "1 MO"]

    def setxQ(self, xQ):
        res = optimize.fmin(func=self.mcSim.errorFunction,
                            x0=np.array([xQ[0], xQ[1]]),
                            args=(self.corpData.values[:-1],
                                  self.corpData.values[1:], self.t_step))
        xQSigma = np.std(self.corpData.values[:-1] - self.corpData.values[1:])
        self.xQ = np.append(res, np.array([xQSigma, xQ[3]]))
        self.mcSim.setVasicek(minDay=self.start,
                              maxDay=self.maturity,
                              x=self.xQ,
                              simNumber=self.numSim,
                              t_step=self.t_step)

    def setQCurve(self):
        self.qCurve = self.mcSim.getLibor().loc[:, 0]
        return

    def getCVA(self):
        self.CVA = (1 - self.recovery) * self.fullExposure.loc[
            self.fullDateList, 0].values * self.qCurve.loc[
                self.fullDateList] * self.libor.loc[self.fullDateList, 0]

    def getLiborAvg(self, yieldIn, datelist):
        self.yieldIn = yieldIn
        time0 = datelist[0]
        # this function is used to calculate exponential single parameter (r or lambda) Survival or Libor Functions
        Z = np.exp(-self.yieldIn *
                   pd.DataFrame(np.tile([(x - time0).days / 365.0
                                         for x in self.datelist],
                                        reps=[self.ntrajectories, 1]).T,
                                index=self.datelist))
        return Z

    def getYield(self, price):
        # Fit model to curve data
        yield0 = 0.05 * self.ones
        self.price = price
        self.yieldIn = self.fitModel2Curve(x=yield0)
        return self.yieldIn

    def fitModel2Curve(self, x):
        # Minimization procedure to fit curve to model
        results = optimize.minimize(fun=self.fCurve, x0=x)
        a = 1
        return results.x

    def fCurve(self, x):
        # raw data error function
        calcCurve = self.getLiborAvg(x, self.datelist)
        thisPV = np.multiply(self.cashFlows,
                             calcCurve).mean(axis=1).sum(axis=0)
        error = 1e4 * (self.price - thisPV)**2
        self.errorCurve = error
        return error
class CorporateRates(object):
    def __init__(self):
        self.OIS = []
        self.filename = WORKING_DIR + '/CorpData.dat'
        self.corporates = []
        self.ratings = {
            'AAA': "BAMLC0A1CAAA",
            'AA': "BAMLC0A2CAA",
            'A': "BAMLC0A3CA",
            'BBB': "BAMLC0A4CBBB",
            'BB': "BAMLH0A1HYBB",
            'B': "BAMLH0A2HYB",
            'CCC': "BAMLH0A3HYC"
        }
        self.corpSpreads = {}
        self.corporates = pd.DataFrame()
        self.Qcorporates = pd.DataFrame()  # survival function for corporates
        self.tenors = []
        self.unPickleMe(file=self.filename)
        self.myScheduler = Scheduler()
        #self.myVasicek = MC_Vasicek_Sim()
        self.R = 0.4

    def getCorporatesFred(self, trim_start, trim_end):
        self.corpSpreads = {}
        self.corpSpreads = {}

        fred = Fred(api_key=FRED_API_KEY)
        curr_trim_end = trim_start
        if (self.corporates.size != 0):
            self.trim_start = self.corporates['OIS'].index.min().date()
            curr_trim_end = self.corporates['OIS'].index.max().date()

        self.trim_start = trim_start
        self.trim_end = trim_end
        self.OIS = OIS(trim_start=trim_start, trim_end=trim_end)
        self.datesAll = self.OIS.datesAll
        #print(self.datesAll)
        self.datesAll.columns = [x.upper() for x in self.datesAll.columns]
        #print(self.datesAll)
        self.datesAll.index = self.datesAll.DATE
        self.OISData = self.OIS.getOIS()
        #print(self.OISData)
        for i in np.arange(len(self.OISData.columns)):
            freq = self.OISData.columns[i]
            self.tenors.append(self.myScheduler.extractDelay(freq=freq))
            #print(self.tenors)
        for rating in self.ratings.keys():
            index = self.ratings[rating]
            try:
                corpSpreads = 1e-2 * (fred.get_series(
                    index,
                    observation_start=trim_start,
                    observation_end=trim_end).to_frame())
                corpSpreads.index = [x.date() for x in corpSpreads.index[:]]
                corpSpreads = pd.merge(left=self.datesAll,
                                       right=corpSpreads,
                                       left_index=True,
                                       right_index=True,
                                       how="left")
                corpSpreads = corpSpreads.fillna(method='ffill').fillna(
                    method='bfill')
                corpSpreads = corpSpreads.drop("DATE", axis=1)
                self.corpSpreads[rating] = corpSpreads.T.fillna(
                    method='ffill').fillna(method='bfill').T
            except Exception as e:
                print(e)
                print(index, " not found")
        self.corpSpreads = pd.Panel.from_dict(self.corpSpreads)
        #print(self.corpSpreads)
        self.corporates = {}
        self.OISData.drop('DATE', axis=1, inplace=True)
        ntenors = np.shape(self.OISData)[1]
        for rating in self.ratings:
            try:
                tiledCorps = np.tile(self.corpSpreads[rating][0],
                                     ntenors).reshape(np.shape(self.OISData))
                self.corporates[rating] = pd.DataFrame(
                    data=(tiledCorps + self.OISData.values),
                    index=self.OISData.index,
                    columns=self.OISData.columns)
            except:
                print(rating)
                print("Error in addition of Corp Spreads")
        self.corporates['OIS'] = self.OISData
        self.corporates = pd.Panel(self.corporates)
        return self.corporates

    def convertCols(self, list):
        out = []
        for i in range(0, len(list)):
            out.append(list[i].split(' ', 1)[0] + list[i].split(' ', 1)[1][0])
        return out

    def getCorporateData(self, rating, datelist=None):
        # This method gets a curve for a given date or date list for a given rating (normally this will be just a date).
        # It returns a dict of curves read directly from the corporate rates created by getCorporatesFred.
        # Derive delays from self.corporates[rating].columns
        #print("GEt corporate data ")
        if datelist is None:
            return
        outCurve = {}
        datelist.sort()
        #need an iteratble object
        cols = self.convertCols(list(self.corporates[rating].columns))
        myDelays = []
        myDelays.append(relativedelta.relativedelta(days=0))
        #just putting an iterable object together
        for i in range(0, len(cols)):
            myDelays.append(self.myScheduler.extractDelay(freq=cols[i]))
        myCurve = self.corporates[rating]
        cols = ['0D'] + cols
        #print("My curve")
        #print(myCurve)
        #print(myDelays)
        #grabbing only the info with the rating I want and making a datelist to calulate time differences
        dates = []
        for day in range(0, len(datelist)):
            #print(day)
            dates.append([(myDelays[x] + datelist[day])
                          for x in range(0, len(myDelays))])
            #print(dates)
        #my array of interest rates
        r = np.zeros((len(datelist), len(dates[0])))
        #print(r)
        nrows = len(dates)
        #multiplying the rate by the delta t in days and saving it to a spot in the array
        for j in range(0, len(datelist)):
            #print(datelist[j])
            day_tenors = myCurve.loc[datelist[j]]
            for i in range(1, len(day_tenors) + 1):
                r[j, i] = r[j, i - 1] + day_tenors[i - 1] * (
                    (dates[j][i] - datelist[j]).days / 365)
        # Create curves
        # ..............
        # ..............
        # add curve to outcurve dict
        #integrating and taking e^-
        intR = r.cumsum(axis=1)
        outCurve = np.exp(-intR)
        out = pd.DataFrame(outCurve)
        out.columns = cols
        return out

    def getSpreads(self, rating, datelist=None):
        if datelist is None:
            return
        outCurve = {}
        #need an iteratble object
        #just putting an iterable object together
        myCurve = self.corpSpreads[rating]
        #grabbing only the info with the rating I want and making a datelist to calulate time differences
        #my array of interest rates
        r = np.zeros(len(datelist))
        #multiplying the rate by the delta t in days and saving it to a spot in the array
        for j in range(1, len(datelist)):
            r[j] = r[j - 1] + myCurve['VALUE'].loc[j - 1] * (
                datelist[j] - datelist[j - 1]).days / 365
        # Create curves
        # ..............
        # ..............
        # add curve to outcurve dict
        #integrating and taking e^-
        intR = r.cumsum(axis=0)
        outCurve = np.exp(-intR)
        out = pd.DataFrame(outCurve, index=datelist)
        return out

    def getCorporateQData(self, rating, datelist, R=0.4):
        #print("Get gorporate Q data")
        self.R = R
        if datelist is None:
            return

        trim_start = datelist[0]
        trim_end = datelist[-1]
        # Create Q curves using q-tilde equation

        outCurve = (
            (1 - (1 / (1 - R)) *
             (1 - (self.getCorporateData(rating=rating, datelist=datelist) /
                   self.getCorporateData(rating='OIS', datelist=datelist)))
             ).values).tolist()
        out = pd.DataFrame(outCurve, index=datelist)
        out[out < 0] = 0
        cols = self.convertCols(list(self.corporates[rating].columns))
        cols = ['0D'] + cols

        ## Get OIS ###
        #getOIS = OIS(trim_start = trim_start,trim_end=trim_end)
        #print(getOIS.getOIS(datelist = datelist))

        #outCurve = ((1 - (1 / (1 - R)) * (1 - (self.getCorporatesFred(trim_start) / self.getCorporateData(rating='OIS', datelist=datelist)))).values).tolist()

        out.columns = cols
        return out

    def pickleMe(self):
        data = [self.corporates, self.corpSpreads]
        with open(self.filename, "wb") as f:
            pickle.dump(len(data), f)
            for value in data:
                pickle.dump(value, f)

    def unPickleMe(self, file):
        data = []
        if (os.path.exists(file)):
            with open(file, "rb") as f:
                for _ in range(pickle.load(f)):
                    data.append(pickle.load(f))
            self.corporates = data[0]
            self.corpSpreads = data[1]

    def saveMeExcel(self, whichdata, fileName):
        try:
            df = pd.DataFrame(whichdata)
        except:
            df = whichdata
        df.to_excel(fileName)
class PortfolioLossCalculation(object):
    def __init__(self, K1, K2, Fs, Rs, betas, start_dates, end_dates, freqs,
                 coupons, referenceDates, ratings, bootstrap):
        self.bootstrap = bootstrap
        self.K1 = K1
        self.K2 = K2
        self.Fs = Fs
        self.Rs = Rs
        self.betas = betas
        self.referenceDates = referenceDates
        self.freqs = freqs
        self.coupons = coupons
        self.start_dates = start_dates
        self.end_dates = end_dates
        self.ratings = ratings

        self.R = Rs[0]
        self.beta = betas[0]
        self.referenceDate = referenceDates[0]
        self.freq = freqs[0]
        self.coupon = coupons[0]
        self.start_date = start_dates[0]
        self.end_date = end_dates[0]
        self.rating = ratings[0]
        self.maturity = end_dates[0]

        self.myScheduler = Scheduler()

    def setParameters(self, R, rating, coupon, beta, start_date, referenceDate,
                      end_date, freq):
        self.R = R
        self.beta = beta
        self.referenceDate = referenceDate
        self.freq = freq
        self.coupon = coupon
        self.start_date = start_date
        self.end_date = end_date
        self.rating = rating
        self.maturity = end_date

    def getQ(self, start_date, referenceDate, end_date, freq, coupon, rating,
             R):
        ## Use CorporateDaily to get Q for referencedates ##
        # print("GET Q")
        # print(self.portfolioScheduleOfCF)

        if self.bootstrap:
            print("Q bootstrap")
            CDSClass = CDS(start_date=start_date,
                           end_date=end_date,
                           freq=freq,
                           coupon=coupon,
                           referenceDate=referenceDate,
                           rating=rating,
                           R=R)
            myLad = BootstrapperCDSLadder(start=self.start_date,
                                          freq=[freq],
                                          CDSList=[CDSClass],
                                          R=CDSClass.R).getXList(x0Vas)[freq]
            self.Q1M = MC_Vasicek_Sim(
                x=myLad,
                t_step=1 / 365,
                datelist=[CDSClass.referenceDate, CDSClass.end_date],
                simNumber=simNumber).getLibor()[0]
            print(self.Q1M)
        else:
            myQ = CorporateRates()
            myQ.getCorporatesFred(trim_start=referenceDate, trim_end=end_date)
            ## Return the calculated Q(t,t_i) for bonds ranging over maturities for a given rating
            daterange = pd.date_range(start=referenceDate, end=end_date).date
            myQ = myQ.getCorporateQData(rating=rating, datelist=daterange, R=R)
            Q1M = myQ[freq]
            print(Q1M)

        return (Q1M)

    def Q_lhp(self, t, K1, K2, R, beta, Q):
        """Calculates the Tranche survival curve for the LHP model.

        Args:
            T (datetime.date): Should be given in "days" (no hours, minutes, etc.)
            K1 (float): The starting value of the tranche. Its value should be
                between 0 & 1.
            K2 (float): The final value of the tranche.
            beta (float): Correlation perameter. Its value should be between 0 and 1.
            R (float): Recovery rate. Usually between 0 and 1.
            Q (callable function): A function Q that takes in a dateime.date and
                outputs a float from 0 to 1. It is assumed that Q(0) = 1 and Q is
                decreasing. Represents survival curve of each credit.
        """
        if Q(t) == 1:
            return 1  # prevents infinity

        def emin(K):
            # Calculates E[min(L(T), K)] in LHP model
            C = norm.ppf(1 - Q(t))
            A = (1 / beta) * (C - sqrt(1 - beta * beta) * norm.ppf(K /
                                                                   (1 - R)))
            return (1 - R) * mvn.mvndst(
                upper=[C, -1 * A],
                lower=[0, 0],
                infin=[0, 0],  # set lower bounds = -infty
                correl=-1 * beta)[1] + K * norm.cdf(A)

        return 1 - (emin(K2) - emin(K1)) / (K2 - K1)

    def Q_gauss(self, t, K1, K2, Fs, Rs, betas, Qs):
        """ Calculate the tranche survival probability in the Gaussian heterogenous model.

        Arguments:
            t (float): Time. Positive.
            K1 (float): Starting tranche value. Between 0 and 1.
            K2 (float): Ending tranche value. Between 0 and 1.
            Fs (list): List of fractional face values for each credit. Each entry must be
                between 0 and 1.
            Rs (list): List of recovery rates for each credit. Each entry must be between
                0 and 1.
            betas (list): Correlation perameters for each credit. Each entry must be between
                0 and 1.
            Qs (list): Survival curves for each credit. Each entry must be a callable function
                that takes in a datetime.date argument and returns a number from 0 to 1.
        """
        Cs = [norm.ppf(1 - q(t)) for q in Qs]
        N = len(Fs)

        def f(K, z):
            ps = [
                norm.cdf((C - beta * z) / sqrt(1 - beta**2))
                for C, beta in zip(Cs, betas)
            ]
            mu = 1 / N * sum([p * F * (1 - R) for p, F, R in zip(ps, Fs, Rs)])
            sigma_squared = 1 / N / N * sum([
                p * (1 - p) * F**2 * (1 - R)**2 for p, F, R in zip(ps, Fs, Rs)
            ])
            sigma = sqrt(sigma_squared)
            return -1 * sigma * norm.pdf(
                (mu - K) / sigma) - (mu - K) * norm.cdf((mu - K) / sigma)

        emin = lambda K: quad(lambda z: norm.pdf(z) * f(K, z), -10, 10)[0]
        return 1 - (emin(K2) - emin(K1)) / (K2 - K1)

    def Q_adjbinom(self, t, K1, K2, Fs, Rs, betas, Qs):
        """ Calculates the tranche survival probability under the adjusted
            binomial model.

            Arguments:
                t (datetime.date): Time.
                K1 (float): Starting tranche value (0 to 1).
                K2 (float): Final tranche value (0 to 1).
                Fs (list): List of fractional face values (floats) for each credit.
                Rs (list): List of recovery rates (floats) for each credit.
                betas (list): List of correlation perameters
                Qs (list): List of survival probabilities. These are callable functions that
                    takes in a single datetime.date argument and returns a float.
            Returns:
                float: The value of the tranche survival curve.
        """
        if Qs[0](t) == 1:
            return 1.0  # initial value -- avoids weird nan return
        N = len(Fs)
        Cs = [norm.ppf(1 - Q(t)) for Q in Qs]
        L = sum([(1 - R) * F for R, F in zip(Rs, Fs)]) / N

        def choose(n, k):  # Calculates binomial coeffecient: n choose k.
            if k == 0 or k == n:
                return 1
            return choose(n - 1, k - 1) + choose(n - 1, k)

        def g(k, z):
            ps = [
                norm.cdf((C - beta * z) / sqrt(1 - beta * beta))
                for C, beta in zip(Cs, betas)
            ]
            p_avg = sum([(1 - R) * F / L * p
                         for R, F, p in zip(Rs, Fs, ps)]) / N
            f = lambda k: choose(N, k) * p_avg**k * (1 - p_avg)**(N - k)
            vA = p_avg * (1 - p_avg) / N
            vE = 1 / N / N * sum([((1 - R) * F / L)**2 * p * (1 - p)
                                  for R, F, p in zip(Rs, Fs, ps)])
            m = p_avg * N
            l = int(m)
            u = l + 1
            o = (u - m)**2 + ((l - m)**2 - (u - m)**2) * (u - m)
            alpha = (vE * N + o) / (vA * N + o)
            if k == l:
                return f(l) + (1 - alpha) * (u - m)
            if k == u:
                return f(u) - (1 - alpha) * (l - m)
            return alpha * f(k)

        I = lambda k: quad(lambda z: norm.pdf(z) * g(k, z), -10, 10)[0]
        emin = lambda K: sum([I(k) * min(L * k, K) for k in range(0, N + 1)])
        return 1 - (emin(K2) - emin(K1)) / (K2 - K1)

    def gcd(self, a, b):
        if a * b == 0:
            return max(a, b)
        if a < b:
            return self.gcd(a, b % a)
        return self.gcd(a % b, b)

    def Q_exact(self, t, K1, K2, Fs, Rs, betas, Qs):
        Cs = [norm.ppf(1 - Q(t)) for Q in Qs]
        N = len(Fs)
        g = round(3600 * Fs[0] * (1 - Rs[0]))
        for j in range(1, N):
            g = self.gcd(g, round(3600 * Fs[j] * (1 - Rs[j])))
        g = g / 3600
        ns = [round(F * (1 - R) / g) for F, R in zip(Fs, Rs)]

        def f(j, k, z):
            if (j, k) == (0, 0):
                return 1.0
            if j == 0:
                return 0.0
            ps = [
                norm.cdf((C - beta * z) / sqrt(1 - beta**2))
                for C, beta in zip(Cs, betas)
            ]
            if k < ns[j - 1]:
                return f(j - 1, k, z) * (1 - ps[j - 1])
            return f(j - 1, k, z) * (1 - ps[j - 1]) + f(
                j - 1, k - ns[j - 1], z) * ps[j - 1]

        I = [
            quad(lambda z: norm.pdf(z) * f(N, k, z), -12, 12)[0]
            for k in range(sum(ns))
        ]
        emin = lambda K: sum([I[k] * min(k * g, K) for k in range(sum(ns))])
        return 1 - (emin(K2) - emin(K1)) / (K2 - K1)

    def getZ_Vasicek(self):
        ### Get Z(t,t_i) for t_i in datelist #####

        ## Simulate Vasicek model with paramters given in workspace.parameters
        # xR = [5.0, 0.05, 0.01, 0.05]
        # kappa = x[0]
        # theta = x[1]
        # sigma = x[2]
        # r0 = x[3]
        vasicekMC = MC_Vasicek_Sim(
            datelist=[self.referenceDate, self.end_date],
            x=xR,
            simNumber=10,
            t_step=t_step)
        self.myZ = vasicekMC.getLibor()
        self.myZ = self.myZ.loc[:, 0]

    def getScheduleComplete(self):
        datelist = self.myScheduler.getSchedule(
            start=self.start_date,
            end=self.maturity,
            freq=self.freq,
            referencedate=self.referenceDate)
        ntimes = len(datelist)
        fullset = list(
            sorted(
                list(
                    set(datelist).union([self.referenceDate]).union([
                        self.start_date
                    ]).union([self.maturity]).union([self.referenceDate]))))
        return fullset, datelist

    def getPremiumLegZ(self, myQ):
        Q1M = myQ
        # Q1M = self.myQ["QTranche"]
        fulllist, datelist = self.getScheduleComplete()
        portfolioScheduleOfCF = fulllist
        timed = portfolioScheduleOfCF[portfolioScheduleOfCF.
                                      index(self.referenceDate):]

        Q1M = Q1M.loc[timed]

        zbarPremLeg = self.myZ / self.myZ.loc[self.referenceDate]
        zbarPremLeg = zbarPremLeg.loc[timed]
        ## Calculate Q(t_i) + Q(t_(i-1))
        Qplus = []
        out = 0
        for i in range(1, len(Q1M)):
            out = out + (Q1M[(i - 1)] + Q1M[i]) * float(
                (timed[i] - timed[i - 1]).days / 365) * zbarPremLeg[i]

        zbarPremLeg = pd.DataFrame(zbarPremLeg, index=timed)
        # print("Premium LEg")
        PVpremiumLeg = out * (1 / 2)
        # print(PVpremiumLeg)
        ## Get coupon bond ###
        print(PVpremiumLeg)
        return PVpremiumLeg

        # //////////////// Get Protection leg Z(t_i)( Q(t_(i-1)) - Q(t_i) )

    def getProtectionLeg(self, myQ):
        print("Protection Leg ")
        Q1M = myQ
        #Qminus = np.gradient(Q1M)
        zbarProtectionLeg = self.myZ

        out = 0
        for i in range(1, zbarProtectionLeg.shape[0]):
            #out = -Qminus[i] * zbarProtectionLeg.iloc[i]*float(1/365)
            out = out - (Q1M.iloc[i] -
                         Q1M.iloc[i - 1]) * zbarProtectionLeg.iloc[i]

        ## Calculate the PV of the premium leg using the bond class
        print(out)
        return out

    def CDOPortfolio(self):
        self.setParameters(R=self.Rs[0],
                           rating=self.ratings[0],
                           coupon=self.coupons[0],
                           beta=self.betas[0],
                           start_date=start_dates[0],
                           referenceDate=referenceDates[0],
                           end_date=end_dates[0],
                           freq=self.freqs[0])
        ## price CDOs using LHP
        Q_now1 = self.getQ(start_date=self.start_dates[0],
                           referenceDate=self.referenceDates[0],
                           end_date=self.end_dates[0],
                           freq=self.freqs[0],
                           coupon=self.coupons[0],
                           rating=self.ratings[0],
                           R=self.Rs[0])

        ## Estimate default probabilites from Qtranche list ###
        ## Assume that lambda is constant over a small period of time
        def getApproxDefaultProbs(Qvals, freq, tvalues):
            t_start = tvalues[0]
            delay = self.myScheduler.extractDelay(freq)
            delay_days = ((t_start + delay) - t_start).days
            ## Estimate constant lambda
            lam = -(1 / delay_days) * np.log(Qvals[t_start])
            Qvals = [
                ((Qvals[t_start] * exp(-lam * (t - t_start).days)) / Qvals[t])
                for t in tvalues
            ]
            return (Qvals)

        ########################################################

        print(Q_now1)
        ### Create Q dataframe
        tvalues = Q_now1.index.tolist()
        Cs = pd.Series(Q_now1, index=tvalues)
        for cds_num in range(1, len(Fs)):
            Q_add = self.getQ(start_date=self.start_dates[cds_num],
                              referenceDate=self.referenceDates[cds_num],
                              end_date=self.end_dates[cds_num],
                              freq=self.freqs[cds_num],
                              coupon=self.coupons[cds_num],
                              rating=self.ratings[cds_num],
                              R=self.Rs[cds_num])
            Q_add = pd.Series(Q_add, index=tvalues)
            Cs = pd.concat([Cs, Q_add], axis=1)

        def expdecay(n):
            return lambda t: Cs.ix[t, n]

        ##
        #Qs = [expdecay(0),expdecay(1)]
        Qs = [expdecay(n) for n in range(0, Cs.shape[1])]

        self.getZ_Vasicek()

        ###### LHP Method #####################################################################
        Rs_mean = np.mean(self.Rs)
        betas_mean = np.mean(betas)

        lhpcurve = [
            self.Q_lhp(t, self.K1, self.K2, R=Rs[0], beta=betas[0], Q=Qs[0])
            for t in tvalues
        ]

        lhpcurve = pd.Series(lhpcurve, index=tvalues)
        lhpcurve = getApproxDefaultProbs(lhpcurve,
                                         freq=self.freq,
                                         tvalues=tvalues)
        lhpcurve = pd.Series(lhpcurve, index=tvalues)

        ProtectionLeg = self.getProtectionLeg(myQ=lhpcurve)
        PremiumLeg = self.getPremiumLegZ(myQ=lhpcurve)
        spreads = ProtectionLeg / PremiumLeg
        print("The spread for LHP is: ", 10000 * spreads, ".")
        ########################################################################################

        ###### Gaussian Method #####################################################################
        print('Gaussian progression: ', end="")
        gaussiancurve = [
            self.Q_gauss(t,
                         self.K1,
                         self.K2,
                         Fs=self.Fs,
                         Rs=self.Rs,
                         betas=self.betas,
                         Qs=Qs) for t in tvalues
        ]
        gaussiancurve = pd.Series(gaussiancurve, index=tvalues)
        gaussiancurve = getApproxDefaultProbs(gaussiancurve,
                                              freq=self.freq,
                                              tvalues=tvalues)
        gaussiancurve = pd.Series(gaussiancurve, index=tvalues)

        ProtectionLeg = self.getProtectionLeg(myQ=gaussiancurve)
        PremiumLeg = self.getPremiumLegZ(myQ=gaussiancurve)
        spreads = ProtectionLeg / PremiumLeg
        print("The spread for Gaussian is: ", 10000 * spreads, ".")
        ########################################################################################

        ###### Adjusted Binomial Method #####################################################################
        adjustedbinomialcurve = [
            self.Q_adjbinom(t,
                            self.K1,
                            self.K2,
                            Fs=self.Fs,
                            Rs=self.Rs,
                            betas=self.betas,
                            Qs=Qs) for t in tvalues
        ]
        adjustedbinomialcurve = pd.Series(adjustedbinomialcurve, index=tvalues)
        adjustedbinomialcurve = getApproxDefaultProbs(adjustedbinomialcurve,
                                                      freq=self.freq,
                                                      tvalues=tvalues)
        adjustedbinomialcurve = pd.Series(adjustedbinomialcurve, index=tvalues)
        #adjustedbinomialcurve = adjustedbinomialcurve.to_frame(self.freqs[0])

        ProtectionLeg = self.getProtectionLeg(myQ=adjustedbinomialcurve)
        PremiumLeg = self.getPremiumLegZ(myQ=adjustedbinomialcurve)
        spreads = ProtectionLeg / PremiumLeg
        print("The spread for Ajusted Binomial is: ", 10000 * spreads, ".")
        ########################################################################################

        ###### Exact Method #####################################################################
        exactcurve = [
            self.Q_exact(t,
                         self.K1,
                         self.K2,
                         Fs=self.Fs,
                         Rs=self.Rs,
                         betas=self.betas,
                         Qs=Qs) for t in tvalues
        ]
        exactcurve = pd.Series(exactcurve, index=tvalues)
        exactcurve = getApproxDefaultProbs(exactcurve,
                                           freq=self.freq,
                                           tvalues=tvalues)
        exactcurve = pd.Series(exactcurve, index=tvalues)
        #exactcurve = exactcurve.to_frame(self.freqs[0])

        ProtectionLeg = self.getProtectionLeg(myQ=exactcurve)
        PremiumLeg = self.getPremiumLegZ(myQ=exactcurve)
        spreads = ProtectionLeg / PremiumLeg
        print("The spread for Exact is: ", 10000 * spreads, ".")
Exemplo n.º 7
0
myScheduler = Scheduler()
ReferenceDateList = myScheduler.getSchedule(start=referenceDate,
                                            end=trim_end,
                                            freq="1M",
                                            referencedate=referenceDate)
# Create Simulator
xOIS = [3.0, 0.07536509, -0.208477, 0.07536509]
myVasicek = MC_Vasicek_Sim(datelist=[trim_start, trim_end],
                           x=xOIS,
                           simNumber=simNumber,
                           t_step=1 / 365.0)
#myVasicek.setVasicek(x=xOIS,minDay=trim_start,maxDay=trim_end,simNumber=simNumber,t_step=1/365.0)
myVasicek.getLibor()

# Create Coupon Bond with several startDates.
SixMonthDelay = myScheduler.extractDelay("6M")
TwoYearsDelay = myScheduler.extractDelay("2Y")
startDates = [
    referenceDate + nprnd.randint(0, 3) * SixMonthDelay for r in range(10)
]

# For debugging uncomment this to choose a single date for the forward bond
# print(startDates)
startDates = [
    date(2005, 3, 10) + SixMonthDelay,
    date(2005, 3, 10) + TwoYearsDelay
]
maturities = [(x + TwoYearsDelay) for x in startDates]

myPortfolio = {}
coupon = 0.07536509
Exemplo n.º 8
0
class CDS(object):
    def __init__(self,
                 start_date,
                 end_date,
                 freq,
                 coupon,
                 referenceDate,
                 rating,
                 R=.4):
        ### Parameters passed to external functions
        self.start_date = start_date
        self.end_date = end_date
        self.freq = freq
        self.R = R
        self.notional = 1
        self.fee = fee
        self.rating = rating
        self.coupon = coupon
        self.referenceDate = referenceDate
        self.observationDate = referenceDate

        ## Get datelist ##
        self.myScheduler = Scheduler()
        # ReferenceDateList = self.myScheduler.getSchedule(start=referenceDate,end=end_date,freq=freq, referencedate=referenceDate)

        ## Delay start and maturity
        delay = self.myScheduler.extractDelay(self.freq)
        cashFlowDays = self.myScheduler.extractDelay("3M")
        ## Delay maturity and start date
        # self.start_date = self.start_date +SixMonthDelay
        # self.maturity =self.start_date + delay
        self.maturity = self.start_date + delay

        fulllist, datelist = self.getScheduleComplete()
        self.datelist = datelist
        self.portfolioScheduleOfCF = fulllist

        self.myZ = None
        self.myQ = None

    # ////////////////////////////////////////////////////////////////////////////////////////////#
    # ////////////////////////////////////////////////////////////////////////////////////////////#
    # ////////////////////////////// SET FUNCTIONS ///////////////////////////////////////////////#
    # ////////////////////////////////////////////////////////////////////////////////////////////#
    # ////////////////////////////////////////////////////////////////////////////////////////////#

    def setZ(self, Zin):
        ## Zin needs to be a pandas dataframe
        self.myZ = Zin

    def setQ(self, Qin):
        self.myQ = Qin

    # ////////////////////////////////////////////////////////////////////////////////////////////#
    # ////////////////////////////////////////////////////////////////////////////////////////////#
    # ////////////////////////////// GET FUNCTIONS ///////////////////////////////////////////////#
    # ////////////////////////////////////////////////////////////////////////////////////////////#
    # ////////////////////////////////////////////////////////////////////////////////////////////#

    # //////////////// Get Vasicek simulated Z(t,t_j)
    def getZ_Vasicek(self):
        ### Get Z(t,t_i) for t_i in datelist #####

        ## Simulate Vasicek model with paramters given in workspace.parameters
        # xR = [5.0, 0.05, 0.01, 0.05]
        # kappa = x[0]
        # theta = x[1]
        # sigma = x[2]
        # r0 = x[3]
        vasicekMC = MC_Vasicek_Sim(
            datelist=[self.referenceDate, self.maturity],
            x=xR,
            simNumber=100,
            t_step=t_step)
        self.myZ = vasicekMC.getLibor()

        self.myLibor = self.myZ
        self.myZ = self.myZ.loc[:, 0]

        ## get Libor Z for reference dates ##
        # self.myZ = vasicekMC.getSmallLibor(datelist= self.portfolioScheduleOfCF).loc[:,0]

    # //////////////// Get Corporates simulated Q(t,t_j)
    def getQ_Corporate(self):
        ## Use CorporateDaily to get Q for referencedates ##
        # print("GET Q")
        # print(self.portfolioScheduleOfCF)
        myQ = CorporateRates()
        myQ.getCorporatesFred(trim_start=self.referenceDate,
                              trim_end=self.end_date)
        ## Return the calculated Q(t,t_i) for bonds ranging over maturities for a given rating
        daterange = pd.date_range(start=self.referenceDate,
                                  end=self.maturity).date
        self.myQ = myQ.getCorporateQData(rating=self.rating,
                                         datelist=daterange,
                                         R=self.R)

        return (self.myQ)

    # //////////////// Get Premium leg Z(t_i)( Q(t_(i-1)) + Q(t_i) )
    def getPremiumLegZ(self):
        ## Check if Z and Q exists
        if self.myZ is None:
            self.getZ_Vasicek()

        if self.myQ is None:
            self.getQ_Corporate()

        ## Choose 1month Q
        '''
        Q1M = self.myQ[self.freq]
        # Q1M = self.myQ["QTranche"]
        timed = self.portfolioScheduleOfCF[self.portfolioScheduleOfCF.index(self.referenceDate):]
        Q1M = Q1M.loc[timed]
        Q1M = Q1M.cumprod(axis=0)
        zbarPremLeg = self.myZ / self.myZ.loc[self.referenceDate]
        zbarPremLeg = zbarPremLeg.loc[timed]
        ## Calculate Q(t_i) + Q(t_(i-1))
        out = 0
        for i in range(1, len(Q1M)):
            out = out + (Q1M[(i - 1)] + Q1M[i]) * float((timed[i] - timed[i - 1]).days / 365) * zbarPremLeg[i]

        ## Calculate the PV of the premium leg using the bond class

        # zbarPremLeg = zbarPremLeg.cumsum(axis=0)
        zbarPremLeg = pd.DataFrame(zbarPremLeg, index=timed)
        # print("Premium LEg")
        PVpremiumLeg = out * (1 / 2)
        # print(PVpremiumLeg)
        ## Get coupon bond ###
        return PVpremiumLeg
        '''
        Q1M = self.myQ[self.freq]
        # Q1M = self.myQ["QTranche"]
        timed = self.portfolioScheduleOfCF[self.portfolioScheduleOfCF.
                                           index(self.referenceDate):]
        Q1M = Q1M.loc[timed]
        Q1M = Q1M.cumprod()
        zbarPremLeg = self.myZ / self.myZ.loc[self.referenceDate]
        zbarPremLeg = zbarPremLeg.loc[timed]
        ## Calculate Q(t_i) + Q(t_(i-1))
        Qplus = []
        out = 0
        for i in range(1, len(Q1M)):
            out = out + (Q1M[(i - 1)] + Q1M[i]) * float(
                (timed[i] - timed[i - 1]).days / 365) * zbarPremLeg[i]
        ## Calculate the PV of the premium leg using the bond class
        # zbarPremLeg = zbarPremLeg.cumsum(axis=0)
        zbarPremLeg = pd.DataFrame(zbarPremLeg, index=timed)
        # print("Premium LEg")
        PVpremiumLeg = out * (1 / 2)
        # print(PVpremiumLeg)
        ## Get coupon bond ###
        return PVpremiumLeg

    # //////////////// Get Protection leg Z(t_i)( Q(t_(i-1)) - Q(t_i) )
    def getProtectionLeg(self):
        if self.myZ is None:
            self.getZ_Vasicek()

        if self.myQ is None:
            self.getQ_Corporate()

        # Q1M = self.myQ["QTranche"]

        ## Calculate Q(t_i) + Q(t_(i-1))
        # Qminus = np.gradient(np.array(Q1M))
        # print(Qminus)
        # QArray = np.array(Q1M)
        # QArray = np.insert(QArray, obj = 0, values = 1)
        # print(QArray)

        # Q1M = self.myQ["QTranche"]
        '''
        Q1M = self.myQ[self.freq]
        Q1M = Q1M.cumprod()
        timed = Q1M.index.tolist()
        timed = self.portfolioScheduleOfCF[self.portfolioScheduleOfCF.index(self.referenceDate):]
        Q1M = Q1M.loc[timed]
        zbarPremLeg = self.myZ / self.myZ.loc[self.referenceDate]
        zbarPremLeg = zbarPremLeg.loc[timed]

        ## Calculate Q(t_i) + Q(t_(i-1))
        Qplus = []
        out = 0
        for i in range(1, len(Q1M)):
            out = out + (Q1M[(i-1)] - Q1M[(i)]) * float((timed[i] - timed[i - 1]).days / 365) * zbarPremLeg[i]

        return(out)
        ## Calculate Z Bar ##
        
        Qminus = np.gradient(Q1M)

        zbarProtectionLeg = self.myZ / self.myZ.loc[self.referenceDate]
        for i in range(1,zbarProtectionLeg.shape[0]):
            zbarProtectionLeg.iloc[i] = -Qminus[i] * zbarProtectionLeg.iloc[i] * (1/365)

        ## Calculate the PV of the premium leg using the bond class

        zbarProtectionLeg = zbarProtectionLeg.cumsum(axis=0)
        zbarProtectionLeg = pd.DataFrame(zbarProtectionLeg, index=Q1M.index)
        PVprotectionLeg = (1 - self.R) * zbarProtectionLeg
        ## Get coupon bond ###
        return PVprotectionLeg.loc[self.maturity]
        '''
        Q1M = self.myQ[self.freq]
        Q1M = Q1M.cumprod()
        Qminus = np.gradient(Q1M)
        zbarProtectionLeg = self.myZ / self.myZ.loc[self.referenceDate]
        for i in range(zbarProtectionLeg.shape[0]):
            zbarProtectionLeg.iloc[
                i] = -Qminus[i] * zbarProtectionLeg.iloc[i] * (1 / 365)
        ## Calculate the PV of the premium leg using the bond class
        zbarProtectionLeg = zbarProtectionLeg.cumsum(axis=0)
        zbarProtectionLeg = pd.DataFrame(zbarProtectionLeg, index=Q1M.index)
        PVprotectionLeg = (1 - self.R) * zbarProtectionLeg
        ## Get coupon bond ###
        return PVprotectionLeg.loc[self.maturity]

    # /////////////////////// Functions to get the exposure sum [delta Z(t,t_j)( Q(t,t_(j-1)) +/- Q(t,t_j) )
    # ////// These are copied from Coupon bond
    def getScheduleComplete(self):
        self.datelist = self.myScheduler.getSchedule(
            start=self.start_date,
            end=self.maturity,
            freq='3M',
            referencedate=self.referenceDate)
        self.ntimes = len(self.datelist)
        fullset = list(
            sorted(
                list(
                    set(self.datelist).union([self.referenceDate]).union([
                        self.start_date
                    ]).union([self.maturity]).union([self.observationDate]))))
        return fullset, self.datelist

    # /////// Get exposure
    def getExposure(self, referencedate, libor):
        self.ntrajectories = np.shape(libor)[1]
        self.ones = np.ones(shape=[self.ntrajectories])
        deltaT = np.zeros(self.ntrajectories)
        if self.ntimes == 0:
            pdzeros = pd.DataFrame(data=np.zeros([1, self.ntrajectories]),
                                   index=[referencedate])
            self.pv = pdzeros
            self.pvAvg = 0.0
            self.cashFlows = pdzeros
            self.cashFlowsAvg = 0.0
            return self.pv
        for i in range(1, self.ntimes):
            deltaTrow = ((self.datelist[i] - self.datelist[i - 1]).days /
                         365) * self.ones
            deltaT = np.vstack((deltaT, deltaTrow))
        self.cashFlows = self.coupon * deltaT
        principal = self.ones
        if self.ntimes > 1:
            self.cashFlows[-1:] += principal
        else:
            self.cashFlows = self.cashFlows + principal
        if (self.datelist[0] <= self.start_date):
            self.cashFlows[0] = -self.fee * self.ones

        if self.ntimes > 1:
            self.cashFlowsAvg = self.cashFlows.mean(axis=1) * self.notional
        else:
            self.cashFlowsAvg = self.cashFlows.mean() * self.notional
        pv = self.cashFlows * libor.loc[self.datelist]
        self.pv = pv.sum(axis=0) * self.notional
        self.pvAvg = np.average(self.pv) * self.notional
        return self.pv

    # ///// Get the calculated Market to Market based on spread
    def getValue(self, spread=1, R=0, buyer=True):
        ## Assume V(t) = S/2 sum Z(t_i) (Q(t_i) + Q(t_{i-1})) - (1-R)sum Z(t_i) (Q(t_{i-1}) - Q(t_{i}))
        ## Premium leg = S/2 sum Z(t_i) (Q(t_i) + Q(t_{i-1}))
        ## Protection leg =sum Z(t_i) (Q(t_i) + Q(t_{i-1}))
        premiumLeg = self.getPremiumLegZ()
        protectionLeg = self.getProtectionLeg()

        mtm = (spread / 2) * premiumLeg - (1 - R) * protectionLeg
        if buyer is True:
            return mtm
        else:
            return -mtm

    def getSpread(self):

        out = self.getProtectionLeg() / self.getPremiumLegZ()

        return out.values[0]

    def changeGuessForSpread(self, x):
        '''
        inputs a x list of guesses for the Vasicek simulator than changes the myQ
        '''
        vasicekMC = MC_Vasicek_Sim(
            datelist=[self.referenceDate, self.maturity],
            x=x,
            simNumber=20,
            t_step=t_step)
        self.myQ = vasicekMC.getLibor()[0]
        self.myQ = pd.DataFrame(self.myQ, index=self.myQ.index)
        self.myQ.columns = [self.freq]
        spread = self.bootProtec() / self.bootPrem()
        return spread.values[0]

    def bootProtec(self):
        Q1M = self.myQ[self.freq]
        Q1M = Q1M.cumprod()
        Qminus = np.gradient(Q1M)
        zbarProtectionLeg = self.myZ / self.myZ.loc[self.referenceDate]
        for i in range(zbarProtectionLeg.shape[0]):
            zbarProtectionLeg.iloc[
                i] = -Qminus[i] * zbarProtectionLeg.iloc[i] * (1 / 365)
        ## Calculate the PV of the premium leg using the bond class
        zbarProtectionLeg = zbarProtectionLeg.cumsum(axis=0)
        zbarProtectionLeg = pd.DataFrame(zbarProtectionLeg, index=Q1M.index)
        PVprotectionLeg = (1 - self.R) * zbarProtectionLeg
        ## Get coupon bond ###
        return PVprotectionLeg.loc[self.maturity]

    def bootPrem(self):
        Q1M = self.myQ[self.freq]
        # Q1M = self.myQ["QTranche"]
        timed = self.portfolioScheduleOfCF[self.portfolioScheduleOfCF.
                                           index(self.referenceDate):]
        Q1M = Q1M.loc[timed]
        Q1M = Q1M.cumprod()
        zbarPremLeg = self.myZ / self.myZ.loc[self.referenceDate]
        zbarPremLeg = zbarPremLeg.loc[timed]
        ## Calculate Q(t_i) + Q(t_(i-1))
        Qplus = []
        out = 0
        for i in range(1, len(Q1M)):
            out = out + (Q1M[(i - 1)] + Q1M[i]) * float(
                (timed[i] - timed[i - 1]).days / 365) * zbarPremLeg[i]
        ## Calculate the PV of the premium leg using the bond class
        # zbarPremLeg = zbarPremLeg.cumsum(axis=0)
        zbarPremLeg = pd.DataFrame(zbarPremLeg, index=timed)
        # print("Premium LEg")
        PVpremiumLeg = out * (1 / 2)
        # print(PVpremiumLeg)
        ## Get coupon bond ###
        return PVpremiumLeg
Exemplo n.º 9
0
from Scheduler.Scheduler import Scheduler
import matplotlib.pyplot as plt
import pandas as pd
from datetime import date

# dr(t) = k(θ − r(t))dt + σdW(t)
# self.kappa = x[0]
# self.theta = x[1]
# self.sigma = x[2]
# self.r0 = x[3]
myScheduler = Scheduler()

observationdate = minDay = date(2005, 1, 10)  # Observation Date
maxDay = date(2010, 1, 10)  # Last Date of the Portfolio
start = date(2005, 3, 30)
maturity = start + myScheduler.extractDelay("1Y")
referenceDate = date(2005, 5, 3)  # 6 months after trim_start
simNumber = 5
R = 0.4
inArrears = True
freq = '3M'
t_step = 1.0 / 365

simNumber = 5
coupon = 0.08
fee = 1.0
xR = [3.0, 0.05, 0.04, 0.03]

myBond = CouponBond(fee=fee,
                    start=start,
                    maturity=maturity,
Exemplo n.º 10
0
class CorporateRates(object):
    def __init__(self):
        self.OIS = []
        self.filename = WORKING_DIR + '/CorpData.dat'
        self.corporates = []
        self.ratings = ['AAA', 'AA', 'A', 'BBB', 'BB', 'B', 'CCC']
        self.corpSpreads = {}
        self.corporates = pd.DataFrame()
        self.tenors = []
        self.unPickleMe(file=self.filename)
        self.myScheduler=Scheduler()

    def getCorporates(self, trim_start, trim_end):
        curr_trim_end=trim_start
        if(self.corporates.size!=0):
            self.trim_start = self.corporates['OIS'].index.min().date()
            curr_trim_end = self.corporates['OIS'].index.max().date()
        if trim_end<=curr_trim_end:
            self.trim_end = curr_trim_end
            return self.corporates
        self.trim_start = trim_start
        self.trim_end = trim_end
        self.OIS = OIS(trim_start=trim_start, trim_end=trim_end)
        self.datesAll = self.OIS.datesAll
        self.datesAll.columns= [x.upper() for x in self.datesAll.columns]
        self.OISData = self.OIS.getOIS()
        for i in np.arange(len(self.OISData.columns)):
            freq = self.OISData.columns[i]
            self.tenors.append(self.myScheduler.extractDelay(freq=freq))
        for rating in self.ratings:
            index = 'ML/' + rating + 'TRI'
            try:
                corpSpreads = 1e-4 * (
                    quandl.get(index, authtoken="Lqsxas8ieaKqpztgYHxk", trim_start=trim_start, trim_end=trim_end))
                corpSpreads.reset_index(level=0, inplace=True)
                corpSpreads = pd.merge(left=self.datesAll, right=corpSpreads, how='left')
                corpSpreads = corpSpreads.fillna(method='ffill').fillna(method='bfill')
                self.corpSpreads[rating] = corpSpreads.T.fillna(method='ffill').fillna(method='bfill').T
            except:
                print(index, " not found")
        self.corpSpreads = pd.Panel.from_dict(self.corpSpreads)
        self.corporates = {}
        self.OISData.drop('DATE', axis=1, inplace=True)
        ntenors = np.shape(self.OISData)[1]
        for rating in self.ratings:
            try:
                tiledCorps = np.tile(self.corpSpreads[rating]['VALUE'], ntenors).reshape(np.shape(self.OISData))
                self.corporates[rating] = pd.DataFrame(data=(tiledCorps + self.OISData.values),
                                                       index=self.OISData.index, columns=self.OISData.columns)
            except:
                print("Error in addition of Corp Spreads")
        self.corporates['OIS'] = self.OISData
        self.corporates = pd.Panel(self.corporates)
        return self.corporates

    def getOISData(self, datelist=[]):
        if (len(datelist) != 0):
            return self.corporates["OIS"].loc[datelist]
        else:
            return self.self.corporates["OIS"]


    def getCorporateData(self, rating, datelist=[]):
        if (len(datelist) != 0):
            return self.corporates[rating].loc[datelist]
        else:
            return self.corporates[rating]

    def pickleMe(self):
        data = [self.corporates, self.corpSpreads]
        with open(self.filename, "wb") as f:
            pickle.dump(len(data), f)
            for value in data:
                pickle.dump(value, f)

    def unPickleMe(self, file):
        data = []
        if (os.path.exists(file)):
            with open(file, "rb") as f:
                for _ in range(pickle.load(f)):
                    data.append(pickle.load(f))
            self.corporates = data[0]
            self.corpSpreads = data[1]

    def saveMeExcel(self, whichdata, fileName):
        try:
            df = pd.DataFrame(whichdata)
        except:
            df = whichdata
        df.to_excel(fileName)
Exemplo n.º 11
0
class CorporateRates(object):
    def __init__(self):
        self.OIS = []
        self.filename = WORKING_DIR + '/CorpData.dat'
        self.corporates = []
        self.ratings = {
            'AAA': "BAMLC0A1CAAA",
            'AA': "BAMLC0A2CAA",
            'A': "BAMLC0A3CA",
            'BBB': "BAMLC0A4CBBB",
            'BB': "BAMLH0A1HYBB",
            'B': "BAMLH0A2HYB",
            'CCC': "BAMLH0A3HYC"
        }
        self.corpSpreads = {}
        self.corporates = pd.DataFrame()
        self.Qcorporates = pd.DataFrame()  # survival function for corporates
        self.tenors = []
        self.unPickleMe(file=self.filename)
        self.myScheduler = Scheduler()
        self.myVasicek = MC_Vasicek_Sim()
        self.R = 0.4

    def getCorporatesFred(self, trim_start, trim_end):
        fred = Fred(api_key=FRED_API_KEY)
        curr_trim_end = trim_start
        if (self.corporates.size != 0):
            self.trim_start = self.corporates['OIS'].index.min().date()
            curr_trim_end = self.corporates['OIS'].index.max().date()
        if trim_end <= curr_trim_end:
            self.trim_end = curr_trim_end
            return self.corporates
        self.trim_start = trim_start
        self.trim_end = trim_end
        self.OIS = OIS(trim_start=trim_start, trim_end=trim_end)
        self.datesAll = self.OIS.datesAll
        self.datesAll.columns = [x.upper() for x in self.datesAll.columns]
        self.datesAll.index = self.datesAll.DATE
        self.OISData = self.OIS.getOIS()
        for i in np.arange(len(self.OISData.columns)):
            freq = self.OISData.columns[i]
            self.tenors.append(self.myScheduler.extractDelay(freq=freq))
        for rating in self.ratings.keys():
            index = self.ratings[rating]
            try:
                corpSpreads = 1e-2 * (fred.get_series(
                    index,
                    observation_start=trim_start,
                    observation_end=trim_end).to_frame())
                corpSpreads.index = [x.date() for x in corpSpreads.index[:]]
                corpSpreads = pd.merge(left=self.datesAll,
                                       right=corpSpreads,
                                       left_index=True,
                                       right_index=True,
                                       how="left")
                corpSpreads = corpSpreads.fillna(method='ffill').fillna(
                    method='bfill')
                corpSpreads = corpSpreads.drop("DATE", axis=1)
                self.corpSpreads[rating] = corpSpreads.T.fillna(
                    method='ffill').fillna(method='bfill').T
            except Exception as e:
                print(e)
                print(index, " not found")
        self.corpSpreads = pd.Panel.from_dict(self.corpSpreads)
        self.corporates = {}
        self.OISData.drop('DATE', axis=1, inplace=True)
        ntenors = np.shape(self.OISData)[1]
        for rating in self.ratings:
            try:
                tiledCorps = np.tile(self.corpSpreads[rating][0],
                                     ntenors).reshape(np.shape(self.OISData))
                self.corporates[rating] = pd.DataFrame(
                    data=(tiledCorps + self.OISData.values),
                    index=self.OISData.index,
                    columns=self.OISData.columns)
            except:
                print("Error in addition of Corp Spreads")
        self.corporates['OIS'] = self.OISData
        self.corporates = pd.Panel(self.corporates)
        return self.corporates

    def getCorporateData(self, rating, datelist=None):
        # This method gets a curve for a given date or date list for a given rating (normally this will be just a date).
        # It returns a dict of curves read directly from the corporate rates created by getCorporatesFred.
        # Derive delays from self.corporates[rating].columns
        myDelays = self.myScheduler.extractDelay(
            freq=list(self.corporates[rating].columns))
        if datelist is None:
            return
        outCurve = {}
        for day in datelist:
            # add curve to outcurve dict
            myCurve = self.corporates.loc[rating, datelist]
            outCurve[day] = myCurve
        return outCurve

    def getCorporateQData(self, rating, datelist=None, R=0.4):
        self.R = R
        self.OIS = OIS()
        # there is a difference in labels between Fred and Quandl...
        colLabel = [
            "1M", "3M", "6M", "1Y", "2Y", "3Y", "5Y", "7Y", "10Y", "20Y", "30Y"
        ]
        outCurve = {}
        if datelist is None:
            return
        myCurve = np.ones(11)
        tempCurve = np.ones(11)
        outCurve[datelist[0]] = myCurve
        z = self.OIS.getOIS(datelist)
        spread = self.getCorporateData(rating, datelist)
        delta = (datelist[1] - datelist[0]).days / 365
        interimSum = np.zeros(11)
        for day in datelist[1:]:
            # Create Q curves using q-tilde equation
            endDate = datelist.slice_indexer(start=day).start
            for day2 in datelist[endDate - 1:endDate]:
                if day2 == datelist[0]:
                    qPrev = np.ones(11)
                else:
                    qPrev = outCurve[day2 - 1]
                qCurr = outCurve[day2]
                spread = self.getCorporateData(
                    rating, pd.date_range(start=day, end=day))
                interimSum = interimSum + z.loc[day2].values[1:] * (
                    outCurve[day2] * delta * spread[day].values - (1 - R) *
                    (qPrev - qCurr))
            myCurve = (z.loc[day].values[1:] * (1 - R) * outCurve[day - 1] -
                       interimSum) / (z.loc[day].values[1:] *
                                      (delta * spread[day] + 1 - R))
            tempCurve = np.vstack((tempCurve, myCurve.values.ravel()))
            outCurve[day] = myCurve.values.ravel()
        a = 1
        tempCurve = pd.DataFrame(data=tempCurve,
                                 columns=colLabel,
                                 index=datelist.values)
        return tempCurve

    def pickleMe(self):
        data = [self.corporates, self.corpSpreads]
        with open(self.filename, "wb") as f:
            pickle.dump(len(data), f)
            for value in data:
                pickle.dump(value, f)

    def unPickleMe(self, file):
        data = []
        if (os.path.exists(file)):
            with open(file, "rb") as f:
                for _ in range(pickle.load(f)):
                    data.append(pickle.load(f))
            self.corporates = data[0]
            self.corpSpreads = data[1]

    def saveMeExcel(self, whichdata, fileName):
        try:
            df = pd.DataFrame(whichdata)
        except:
            df = whichdata
        df.to_excel(fileName)