def test_FinCapVolCurve(): # Reproduces example in Table 32.1 of Hull Book valuationDate = FinDate(1, 1, 2020) capVolDates = [] capletVolTenor = "1Y" numPeriods = 10 capletDt = valuationDate capVolDates.append(valuationDate) for i in range(0, numPeriods): capletDt = capletDt.addTenor(capletVolTenor) capVolDates.append(capletDt) capVolatilities = [ 0.0, 15.50, 18.25, 17.91, 17.74, 17.27, 16.79, 16.30, 16.01, 15.76, 15.54 ] capVolatilities = np.array(capVolatilities) / 100.0 dayCountType = FinDayCountTypes.ACT_ACT_ISDA volCurve = FinLiborCapVolCurve(valuationDate, capVolDates, capVolatilities, dayCountType) testCases.header("DATE", "CAPVOL", "CAPLETVOL") for dt in capVolDates: capFloorVol = volCurve.capVol(dt) capFloorLetVol = volCurve.capletVol(dt) testCases.print("%s" % dt, "%7.3f" % (capFloorVol * 100.0), "%7.2f" % (capFloorLetVol * 100.0))
def simulateNF(self, discountCurve, volCurve: FinLiborCapVolCurve, correlationMatrix: np.ndarray, modelType: FinRateModelLMMModelTypes, numPaths: int = 1000, numeraireIndex: int = 0, useSobol: bool = True, seed: int = 42): ''' Run the simulation to generate and store all of the Libor forward rate paths using a full factor reduction of the fwd-fwd correlation matrix using Cholesky decomposition.''' checkArgumentTypes(self.__init__, locals()) if numPaths < 2 or numPaths > 1000000: raise FinError("NumPaths must be between 2 and 1 million") if isinstance(modelType, FinRateModelLMMModelTypes) is False: raise FinError("Model type must be type FinRateModelLMMModelTypes") if discountCurve.curveDate != self._startDate: raise FinError("Curve anchor date not the same as LMM start date.") self._numPaths = numPaths self._volCurves = volCurve self._correlationMatrix = correlationMatrix self._modelType = modelType self._numeraireIndex = numeraireIndex self._useSobol = useSobol numGridPoints = len(self._gridTimes) self._numForwards = numGridPoints - 1 self._forwardCurve = [] for i in range(1, numGridPoints): startDate = self._gridDates[i-1] endDate = self._gridDates[i] fwdRate = discountCurve.forwardRate(startDate, endDate, self._floatDayCountType) self._forwardCurve.append(fwdRate) self._forwardCurve = np.array(self._forwardCurve) zetas = np.zeros(numGridPoints) for ix in range(1, numGridPoints): dt = self._gridDates[ix] zetas[ix] = volCurve.capletVol(dt) # This function does not use Sobol - TODO self._fwds = LMMSimulateFwdsNF(self._numForwards, numPaths, self._forwardCurve, zetas, correlationMatrix, self._accrualFactors, seed)
def simulate1F(self, discountCurve, volCurve: FinLiborCapVolCurve, numPaths: int = 1000, numeraireIndex: int = 0, useSobol: bool = True, seed: int = 42): ''' Run the one-factor simulation of the evolution of the forward Libors to generate and store all of the Libor forward rate paths. ''' if numPaths < 2 or numPaths > 1000000: raise FinError("NumPaths must be between 2 and 1 million") if discountCurve._valuationDate != self._startDate: raise FinError("Curve anchor date not the same as LMM start date.") self._numPaths = numPaths self._numeraireIndex = numeraireIndex self._useSobol = useSobol numGridPoints = len(self._gridDates) self._numForwards = numGridPoints self._forwardCurve = [] for i in range(1, numGridPoints): startDate = self._gridDates[i-1] endDate = self._gridDates[i] fwdRate = discountCurve.fwdRate(startDate, endDate, self._floatDayCountType) self._forwardCurve.append(fwdRate) self._forwardCurve = np.array(self._forwardCurve) gammas = np.zeros(numGridPoints) for ix in range(1, numGridPoints): dt = self._gridDates[ix] gammas[ix] = volCurve.capletVol(dt) self._fwds = LMMSimulateFwds1F(self._numForwards, numPaths, numeraireIndex, self._forwardCurve, gammas, self._accrualFactors, useSobol, seed)
def test_FinLiborCapFloorVolCurve(): ''' Aim here is to price cap and caplets using cap and caplet vols and to demonstrate they are the same - NOT SURE THAT HULLS BOOKS FORMULA WORKS FOR OPTIONS. ''' todayDate = FinDate(20, 6, 2019) valuationDate = todayDate maturityDate = valuationDate.addTenor("3Y") dayCountType = FinDayCountTypes.THIRTY_E_360 frequency = FinFrequencyTypes.ANNUAL k = 0.04 capFloorType = FinLiborCapFloorTypes.CAP capFloor = FinLiborCapFloor(valuationDate, maturityDate, capFloorType, k, None, frequency, dayCountType) capVolDates = FinSchedule(valuationDate, valuationDate.addTenor("10Y"), frequency)._generate() flatRate = 0.04 liborCurve = FinDiscountCurveFlat(valuationDate, flatRate, frequency, dayCountType) flat = False if flat is True: capVolatilities = [20.0] * 11 capVolatilities[0] = 0.0 else: capVolatilities = [ 0.00, 15.50, 18.25, 17.91, 17.74, 17.27, 16.79, 16.30, 16.01, 15.76, 15.54 ] capVolatilities = np.array(capVolatilities) / 100.0 capVolatilities[0] = 0.0 volCurve = FinLiborCapVolCurve(valuationDate, capVolDates, capVolatilities, dayCountType) print(volCurve._capletGammas) # Value cap using a single flat cap volatility tcap = (maturityDate - valuationDate) / gDaysInYear vol = volCurve.capVol(maturityDate) model = FinModelBlack(vol) valueCap = capFloor.value(valuationDate, liborCurve, model) print("CAP T", tcap, "VOL:", vol, "VALUE OF CAP:", valueCap) # Value cap by breaking it down into caplets using caplet vols vCaplets = 0.0 capletStartDate = capFloor._capFloorLetDates[1] testCases.header("START", "END", "VOL", "VALUE") for capletEndDate in capFloor._capFloorLetDates[2:]: vol = volCurve.capletVol(capletEndDate) modelCaplet = FinModelBlack(vol) vCaplet = capFloor.valueCapletFloorLet(valuationDate, capletStartDate, capletEndDate, liborCurve, modelCaplet) vCaplets += vCaplet testCases.print("%12s" % capletStartDate, "%s" % capletEndDate, "%9.5f" % (vol * 100.0), "%9.5f" % vCaplet) capletStartDate = capletEndDate testCases.header("LABEL", "VALUE") testCases.print("CAPLETS->CAP: ", vCaplets)