Exemple #1
0
def test_FinCapVolCurve():

    # Reproduces example in Table 32.1 of Hull Book
    valuation_date = Date(1, 1, 2020)

    capVolDates = []
    capletVolTenor = "1Y"
    num_periods = 10
    capletDt = valuation_date

    capVolDates.append(valuation_date)

    for i in range(0, num_periods):
        capletDt = capletDt.add_tenor(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

    day_count_type = DayCountTypes.ACT_ACT_ISDA
    volCurve = IborCapVolCurve(valuation_date, capVolDates, capVolatilities,
                               day_count_type)

    testCases.header("DATE", "CAPVOL", "CAPLETVOL")
    for dt in capVolDates:
        capFloorVol = volCurve.cap_vol(dt)
        capFloorLetVol = volCurve.caplet_vol(dt)
        testCases.print("%s" % dt, "%7.3f" % (capFloorVol * 100.0),
                        "%7.2f" % (capFloorLetVol * 100.0))
    def simulate_nf(self,
                    discount_curve,
                    volCurve: IborCapVolCurve,
                    correlationMatrix: np.ndarray,
                    modelType: ModelLMMModelTypes,
                    num_paths: int = 1000,
                    numeraireIndex: int = 0,
                    useSobol: bool = True,
                    seed: int = 42):
        """ Run the simulation to generate and store all of the Ibor forward
        rate paths using a full factor reduction of the fwd-fwd correlation
        matrix using Cholesky decomposition."""

        check_argument_types(self.__init__, locals())

        if num_paths < 2 or num_paths > 1000000:
            raise FinError("NumPaths must be between 2 and 1 million")

        if isinstance(modelType, ModelLMMModelTypes) is False:
            raise FinError("Model type must be type FinRateModelLMMModelTypes")

        if discount_curve.curve_date != self._start_date:
            raise FinError("Curve anchor date not the same as LMM start date.")

        self._num_paths = num_paths
        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):
            start_date = self._gridDates[i-1]
            end_date = self._gridDates[i]
            fwd_rate = discount_curve.forward_rate(start_date,
                                                end_date,
                                                self._float_day_count_type)
            self._forwardCurve.append(fwd_rate)

        self._forwardCurve = np.array(self._forwardCurve)

        zetas = np.zeros(numGridPoints)
        for ix in range(1, numGridPoints):
            dt = self._gridDates[ix]
            zetas[ix] = volCurve.caplet_vol(dt)

        # This function does not use Sobol - TODO
        self._fwds = lmm_simulate_fwds_nf(self._numForwards,
                                          num_paths,
                                          self._forwardCurve,
                                          zetas,
                                          correlationMatrix,
                                          self._accrual_factors,
                                          seed)
    def simulate_1f(self,
                    discount_curve,
                    volCurve: IborCapVolCurve,
                    num_paths: int = 1000,
                    numeraireIndex: int = 0,
                    useSobol: bool = True,
                    seed: int = 42):
        """ Run the one-factor simulation of the evolution of the forward
        Ibors to generate and store all of the Ibor forward rate paths. """

        if num_paths < 2 or num_paths > 1000000:
            raise FinError("NumPaths must be between 2 and 1 million")

        if discount_curve._valuation_date != self._start_date:
            raise FinError("Curve anchor date not the same as LMM start date.")

        self._num_paths = num_paths
        self._numeraireIndex = numeraireIndex
        self._useSobol = useSobol

        numGridPoints = len(self._gridDates)

        self._numForwards = numGridPoints
        self._forwardCurve = []

        for i in range(1, numGridPoints):
            start_date = self._gridDates[i-1]
            end_date = self._gridDates[i]
            fwd_rate = discount_curve.fwd_rate(start_date,
                                            end_date,
                                            self._float_day_count_type)
            self._forwardCurve.append(fwd_rate)

        self._forwardCurve = np.array(self._forwardCurve)

        gammas = np.zeros(numGridPoints)
        for ix in range(1, numGridPoints):
            dt = self._gridDates[ix]
            gammas[ix] = volCurve.caplet_vol(dt)

        self._fwds = lmm_simulate_fwds_1f(self._numForwards,
                                          num_paths,
                                          numeraireIndex,
                                          self._forwardCurve,
                                          gammas,
                                          self._accrual_factors,
                                          useSobol,
                                          seed)
Exemple #4
0
def test_FinIborCapFloorVolCurve():
    """ 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 = Date(20, 6, 2019)
    valuation_date = todayDate
    maturity_date = valuation_date.add_tenor("3Y")
    day_count_type = DayCountTypes.THIRTY_E_360
    frequency = FrequencyTypes.ANNUAL

    k = 0.04
    capFloorType = FinCapFloorTypes.CAP
    capFloor = IborCapFloor(valuation_date,
                            maturity_date,
                            capFloorType,
                            k,
                            None,
                            frequency,
                            day_count_type)

    capVolDates = Schedule(valuation_date,
                           valuation_date.add_tenor("10Y"),
                           frequency)._generate()

    flat_rate = 0.04
    libor_curve = DiscountCurveFlat(valuation_date,
                                    flat_rate,
                                    frequency,
                                    day_count_type)

    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 = IborCapVolCurve(valuation_date,
                               capVolDates,
                               capVolatilities,
                               day_count_type)

#    print(volCurve._capletGammas)

    # Value cap using a single flat cap volatility
    tcap = (maturity_date - valuation_date) / gDaysInYear
    vol = volCurve.cap_vol(maturity_date)
    model = Black(vol)
    valueCap = capFloor.value(valuation_date, libor_curve, 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.caplet_vol(capletEndDate)
        modelCaplet = Black(vol)
        vCaplet = capFloor.value_caplet_floor_let(valuation_date,
                                                  capletStartDate,
                                                  capletEndDate,
                                                  libor_curve,
                                                  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)
def test_FinCapVolCurve():
    # Reproduces example in Table 32.1 of Hull Book
    valuation_date = Date(1, 1, 2020)

    capVolDates = []
    capletVolTenor = "1Y"
    num_periods = 10
    capletDt = valuation_date

    capVolDates.append(valuation_date)

    for i in range(0, num_periods):
        capletDt = capletDt.add_tenor(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

    day_count_type = DayCountTypes.ACT_ACT_ISDA
    volCurve = IborCapVolCurve(valuation_date, capVolDates, capVolatilities,
                               day_count_type)

    dt = Date(1, 1, 2020)
    capFloorVol = volCurve.cap_vol(dt)
    capFloorLetVol = volCurve.caplet_vol(dt)
    assert round(capFloorVol * 100.0, 2) == 15.5
    assert round(capFloorLetVol * 100.0, 2) == 15.5

    dt = Date(1, 1, 2022)
    capFloorVol = volCurve.cap_vol(dt)
    capFloorLetVol = volCurve.caplet_vol(dt)
    assert round(capFloorVol * 100.0, 2) == 18.25
    assert round(capFloorLetVol * 100.0, 2) == 20.64

    dt = Date(1, 1, 2024)
    capFloorVol = volCurve.cap_vol(dt)
    capFloorLetVol = volCurve.caplet_vol(dt)
    assert round(capFloorVol * 100.0, 2) == 17.740
    assert round(capFloorLetVol * 100.0, 2) == 17.22

    dt = Date(1, 1, 2026)
    capFloorVol = volCurve.cap_vol(dt)
    capFloorLetVol = volCurve.caplet_vol(dt)
    assert round(capFloorVol * 100.0, 2) == 16.790
    assert round(capFloorLetVol * 100.0, 2) == 14.15

    dt = Date(1, 1, 2028)
    capFloorVol = volCurve.cap_vol(dt)
    capFloorLetVol = volCurve.caplet_vol(dt)
    assert round(capFloorVol * 100.0, 2) == 16.010
    assert round(capFloorLetVol * 100.0, 2) == 13.81