예제 #1
0
trim_start = date(2000, 1, 1)
trim_end = date(2000, 12, 31)
trim_endMC = date(2001, 12, 31)
effDay = date(2000, 4, 1)
referenceDate = date(2000, 1, 1)
testSched = pd.date_range(trim_start, trim_start)
scheduleComplete = pd.date_range(start=trim_start, end=trim_end)
xR = [3.0, 0.05, 0.04, 0.03]
datelist = myScheduler.getSchedule(start=trim_start,
                                   end=trim_end,
                                   freq=freq,
                                   referencedate=referenceDate)
myMC = MC_Vasicek_Sim()
myMC.setVasicek(x=xR,
                minDay=trim_start,
                maxDay=trim_endMC,
                simNumber=simNumber,
                t_step=t_step)
myMC.getLibor()
myCorp = CorporateRates()
myCorp.getCorporatesFred(trim_start, trim_end)
testRatings = myCorp.getCorporateData("AAA", testSched)
testSurvival = myCorp.getCorporateQData("AAA", scheduleComplete, 0.4)

mySwap = IRSwap(zCurve=myMC.getLibor(),
                startDate=trim_start,
                endDate=trim_end,
                referenceDate=referenceDate,
                effectiveDate=effDay,
                rating="AAA",
                freq=freq,
예제 #2
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
예제 #3
0
class CDS(object):
    def __init__(self,
                 start,
                 end,
                 reference,
                 recovery,
                 rating,
                 notional,
                 freq="1M"):
        self.numSim = 10
        self.t_step = 1.0 / 365
        #z curve is for discounting
        self.zCurve = []
        #q curve is for survival prob of the reference entity
        self.qCurve = []
        self.start = start
        self.end = end
        self.reference = reference
        self.freq = freq
        self.rating = rating
        self.notional = notional
        # mcSim used for simulating default prob, interest rate
        # xR should already be calibrated
        self.xR = []
        # xQ we need to calibrate inside CDS
        self.xQ = []
        self.mcSim = MC_Vasicek_Sim()
        self.mcSimSurvival = MC_Vasicek_Sim()

        #self.mcSim.setVasicek(minDay=startDate, maxDay=endDate, x=xR, t_step=1.0 / 365, simNumber=self.simNum)
        #self.mcSimSurvival.setVasicek(minDay=startDate, maxDay=endDate, x=xR, t_step=1.0 / 365, simNumber=self.simNum)

        self.dateList = pd.date_range(start=start, end=end, freq=freq)
        self.recovery = recovery

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

    def setLibor(self, libor):
        self.zCurve = libor / libor.loc[self.reference]

    def setxR(self, xR):
        self.xR = xR
        self.mcSim.setVasicek(minDay=self.start,
                              maxDay=self.end,
                              x=self.xR,
                              simNumber=self.numSim,
                              t_step=self.t_step)

    def setxQ(self, xQ):
        res = optimize.fmin(func=self.mcSimSurvival.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.mcSimSurvival.setVasicek(minDay=self.start,
                                      maxDay=self.end,
                                      x=self.xQ,
                                      simNumber=self.numSim,
                                      t_step=self.t_step)

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

    def getDefaultLegPV(self):
        interimSum = 0
        for payDates in self.dateList[1:]:
            interimSum += self.zCurve.loc[payDates.date(), 0] * (
                self.qCurve.loc[(payDates - 1).date()] -
                self.qCurve.loc[payDates.date()])
        defaultLeg = (1 - self.recovery) * interimSum
        return defaultLeg

    def getFeeLegPV(self):
        delta = (self.dateList[1] - self.dateList[0]).days / 365
        interimSum = 0
        for payDate in self.dateList[1:]:
            interimSum += self.zCurve.loc[payDate.date(), 0] * delta * (
                self.qCurve.loc[(payDate - 1).date()] +
                self.qCurve.loc[payDate.date()])
        feeLeg = 0.5 * interimSum
        return feeLeg

    def getSpread(self):
        spread = self.getDefaultLegPV() / self.getFeeLegPV()
        self.spread = spread
        return spread

    def setCF(self):
        feeLegCF = np.ones(len(self.dateList)) * self.spread
        defaultLegCF = np.ones(len(self.dateList)) * (
            1 - self.recovery) * self.qCurve.loc[self.dateList].values
        self.feeLeg = pd.DataFrame(data=feeLegCF, index=self.dateList)
        self.defaultLeg = pd.DataFrame(data=defaultLegCF, index=self.dateList)
        return

    def getExposure(self):
        #PV of protection leg - fee leg
        #use survivalCurve passed in as the survival prob of the reference entitity
        #simulate the default probability of the counterparty - newQcurve
        fullDate = pd.date_range(start=self.start,
                                 end=self.end,
                                 freq=self.freq)
        EE = np.zeros((len(self.dateList), self.numSim))
        for i in range(0, self.numSim):
            row = 0
            newZCurve = self.mcSim.getLibor()
            newQCurve = self.mcSimSurvival.getLibor()
            survivalCurve = self.qCurve
            for day in fullDate:
                if day == fullDate[0]:
                    #feePV - pay fee as long as counter and reference do not default
                    feePV = np.transpose(
                        self.feeLeg.values).ravel() * newZCurve.loc[
                            self.dateList, 0].values * survivalCurve.loc[
                                self.dateList].values * newQCurve.loc[
                                    self.dateList, 0].values
                    #defaultPV - recover a portion of the notional given the refernce defaults and the counterparty does NOT
                    defaultPV = (1 - self.recovery) * np.transpose(
                        self.defaultLeg.values).ravel() * self.zCurve.loc[
                            self.dateList, 0].values * (
                                np.ones(len(self.dateList)) -
                                survivalCurve.loc[self.dateList].values
                            ) * newQCurve.loc[self.dateList, 0].values

                elif day > fullDate[0] and day < fullDate[-1]:
                    partialFee = self.feeLeg.loc[day.date():]
                    partialDefault = self.defaultLeg.loc[day.date():]
                    feePV = np.transpose(
                        partialFee.values).ravel() * newZCurve.loc[
                            partialFee.index, 0].values * survivalCurve.loc[
                                partialFee.index].values * newQCurve.loc[
                                    partialFee.index, 0].values
                    defaultPV = (1 - self.recovery) * np.transpose(
                        partialDefault.values).ravel() * self.zCurve.loc[
                            partialFee.index, 0].values * (
                                np.ones(len(partialFee.index)) -
                                survivalCurve.loc[partialFee.index].values
                            ) * newQCurve.loc[partialFee.index, 0].values
                else:
                    feePV = 0
                    defaultPV = 0
                npv = np.sum(defaultPV - feePV)
                if npv < 0:
                    npv = 0
                EE[row, i] = npv
                row += 1
        EE = pd.DataFrame(data=EE, index=fullDate)
        self.fullDate = fullDate
        self.fullExposure = EE
        self.avgExposure = EE.mean(axis=1)

    def getCVA(self):
        self.CVA = self.notional * (
            1 - self.recovery) * self.avgExposure.values * self.zCurve.loc[
                self.fullDate,
                0].values * self.qCurve.loc[self.fullDate].values
        return
예제 #4
0
class IRSwap(object):
    def __init__(self,
                 startDate,
                 endDate,
                 referenceDate,
                 effectiveDate,
                 freq,
                 notional,
                 recovery=0.4):
        """
            effective date is the start of the payments, startDate is when the contract is entered, endDate is maturity
            referenceDate is the date when the PV is taken
            We are paying a fixed rate to receive a floating rate
        """
        self.recovery = recovery
        self.simNum = 10
        self.xR = []
        self.xQ = []
        # use MC to generate scenarios for exposure
        self.mcSim = MC_Vasicek_Sim()
        #self.mcSim.setVasicek(minDay=startDate,maxDay=endDate,x=xR,t_step=1.0/365, simNumber=self.simNum)
        # z is discount curve
        self.zCurve = []
        self.swapRate = []
        self.freq = freq
        self.notional = notional
        self.fixedLeg = []
        self.floatingLeg = []
        self.startDate = startDate
        self.endDate = endDate
        self.referenceDate = referenceDate
        self.effctiveDate = effectiveDate
        self.initialSpread = []
        self.myScheduler = Scheduler()
        self.datelist = pd.date_range(start=effectiveDate,
                                      end=endDate,
                                      freq=freq)

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

    def setLibor(self, libor):
        self.zCurve = libor / libor.loc[self.referenceDate]

    def setxR(self, xR):
        self.xR = xR
        self.mcSim.setVasicek(minDay=self.startDate,
                              maxDay=self.endDate,
                              x=xR,
                              t_step=1.0 / 365,
                              simNumber=self.simNum)

    def setSwapRate(self):
        # getting initial spread at time zero
        floatLegPV = (self.zCurve.loc[self.effctiveDate,
                                      0]) - (self.zCurve.loc[self.endDate, 0])
        fixedLegPV = 0
        delta = (self.datelist[1] - self.datelist[0]).days / 365
        for payDate in self.datelist:
            fixedLegPV += delta * self.zCurve.loc[payDate.date(), 0]
        swapRate = floatLegPV / fixedLegPV
        self.swapRate = swapRate
        return

    def setCashFlows(self):
        fixedLegCF = np.ones(len(self.datelist)) * self.swapRate
        floatLegCF = []
        delta = (self.datelist[1] - self.datelist[0]).days / 365
        for payDate in self.datelist:
            if payDate.date() == self.endDate:
                floatLegCF.append(
                    ((self.zCurve.loc[payDate.date(), 0] / self.zCurve.loc[
                        payDate.date() + timedelta(delta * 365), 0]) - 1) /
                    delta)
            else:
                floatLegCF.append(
                    (self.zCurve.loc[payDate.date(), 0] / self.zCurve.loc[
                        (payDate + 1).date(), 0] - 1) / delta)
        fixedLegCF = pd.DataFrame(data=fixedLegCF, index=self.datelist)
        floatLegCF = pd.DataFrame(data=floatLegCF, index=self.datelist)
        self.fixedLeg = fixedLegCF
        self.floatingLeg = floatLegCF
        return

    def getExposure(self):
        fullDate = pd.date_range(start=self.startDate,
                                 end=self.endDate,
                                 freq=self.freq)
        EE = np.zeros((len(fullDate), self.simNum))
        for i in range(0, self.simNum):
            zCurveNew = self.mcSim.getLibor()
            row = 0
            for day in fullDate:
                if day < self.datelist[0]:
                    npv = (np.sum(
                        (self.floatingLeg - self.fixedLeg).values.ravel() *
                        zCurveNew.loc[self.datelist, 0].values))
                elif day >= self.datelist[0] and day < self.datelist[-1]:
                    fixedPartial = self.fixedLeg.loc[day.date():]
                    floatPartial = self.floatingLeg.loc[day.date():]
                    npv = (np.sum(
                        (floatPartial - fixedPartial).values.ravel() *
                        zCurveNew.loc[fixedPartial.index, 0].values))
                else:
                    npv = 0
                #if npv < 0:
                #    npv = 0
                EE[row, i] = npv
                row += 1
        EE = pd.DataFrame(data=EE, index=fullDate)
        self.fullDate = fullDate
        self.fullExposure = EE
        self.avgExposure = EE.mean(axis=1)
        return

    def getCVA(self, survCurve):
        # CVA = LGD * EE * PD * Discount, LGD =1-R
        CVA = self.notional * (
            1 - self.recovery) * self.avgExposure.values * survCurve.loc[
                self.fullDate].values * self.zCurve.loc[self.fullDate,
                                                        0].values
        CVA = pd.DataFrame(data=CVA, index=self.fullDate)
        self.CVA = CVA
        return
예제 #5
0
trim_start = date(2005, 3, 10)
trim_end = date(2010, 12, 31)  # Last Date of the Portfolio
start = date(2005, 3, 10)
referenceDate = date(2005, 3, 10)

myScheduler = Scheduler()
ReferenceDateList = myScheduler.getSchedule(start=referenceDate,
                                            end=trim_end,
                                            freq="1M",
                                            referencedate=referenceDate)
# Create Simulator
myVasicek = MC_Vasicek_Sim()
xOIS = [3.0, 0.07536509, -0.208477, 0.07536509]
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,
예제 #6
0
coupon = 0.08
fee = 1.0
xR = [3.0, 0.05, 0.04, 0.03]

myBond = CouponBond(fee=fee,
                    start=start,
                    maturity=maturity,
                    coupon=coupon,
                    freq="3M",
                    referencedate=referenceDate,
                    observationdate=observationdate)
fulllist, datelist = myBond.getScheduleComplete()
myMC = MC_Vasicek_Sim()
myMC.setVasicek(x=xR,
                minDay=minDay,
                maxDay=maxDay,
                simNumber=simNumber,
                t_step=t_step)
myMC.getLibor()
libor = myMC.getSmallLibor(datelist=fulllist)
myBond.setLibor(libor)


class TestBond(TestCase):
    def test01_PV(self):
        myPV = myBond.getPV(referencedate=referenceDate)
        print(myPV)
        print(myBond.pv)

    def test00_getLiborAvg(self):
        print(myBond.getLiborAvg(yieldIn=0.05, datelist=datelist))