All Downloads are FREE. Search and download functionalities are using the official Maven repository.

.cdm-java.6.0.0-dev.82.source-code.product-asset-floatingrate-func.rosetta Maven / Gradle / Ivy

There is a newer version: 6.0.0-dev.89
Show newest version
namespace cdm.product.asset.floatingrate : <"Product-related, asset class-specific floating-rate index concepts, such as rate definitions .">
version "${project.version}"

import cdm.base.datetime.*
import cdm.base.math.*

import cdm.observable.asset.calculatedrate.*
import cdm.observable.asset.fro.*

import cdm.product.asset.*
import cdm.product.asset.calculation.*
import cdm.product.common.schedule.*

//-------------------------------------------------------
// The following functions determine the type of rate and what to do for each
//-------------------------------------------------------
func DetermineFloatingRateReset: <"Get the value of a floating rate by either observing it directly or performing a rate calculation.  This function works differently depending on the rate category and style, as described in the 2021 ISDA Definitions, Section 6.6.">
    inputs:
        interestRatePayout InterestRatePayout (1..1) <"Floating rate stream definition.">
        calcPeriod CalculationPeriodBase (1..1) <"The calculation period for which you want the rate.">
    output:
        floatingRate FloatingRateSettingDetails (1..1) <"Details of the rate observation/calculation corresonding to the supplied rate definition and calculation period.">

    // figure out the characteristics of the rate
    alias rateDef: interestRatePayout -> rateSpecification -> FloatingRateSpecification
    alias processingType: GetFloatingRateProcessingType(rateDef) // get a processing category that will be used to dermine how to process the rate, based on the rate category, style, and calculation method
    // perform the relevant operation (look up a term rate or do the rate calculation for a calculated rate)
    set floatingRate:
        ProcessFloatingRateReset(interestRatePayout, calcPeriod, processingType)

func GetFloatingRateProcessingType: <"Get a classification of  the floating rate is processed. This is based on FRO category, style, and calculation method, as described in the 2021 ISDA Definitions Section 6.6.  The categorization information is obtained from the FRO metadata. .">
    inputs:
        rateDef FloatingRateSpecification (1..1) <"Specification details of the floating rate.">
    output:
        processingType FloatingRateIndexProcessingTypeEnum (1..1) <"The processing category for the rate .">

    // is it a modular calculated rate?
    alias isCalculatedRate: rateDef -> calculationParameters exists
    // look up the floating rate option definition from the metadata
    alias floatingRateDefinition:
        FloatingRateIndexMetadata(
                rateDef -> rateOption -> InterestRateIndex -> floatingRateIndex
            )
    alias calcDefaults: floatingRateDefinition -> calculationDefaults
    alias category: calcDefaults -> category
    alias idxStyle: calcDefaults -> indexStyle
    alias method: calcDefaults -> method

    // determine the processing category for FROs that have embedded calculations
    alias calcProcessingType:
        if (idxStyle = FloatingRateIndexStyleEnum -> CompoundedFRO and method = FloatingRateIndexCalculationMethodEnum -> OISCompound)
        then FloatingRateIndexProcessingTypeEnum -> OIS
        else if (idxStyle = FloatingRateIndexStyleEnum -> AverageFRO and method = FloatingRateIndexCalculationMethodEnum -> Average)
        then FloatingRateIndexProcessingTypeEnum -> OvernightAvg

    // determine the processing category for FROs for which we have metadata
    alias definitionProcessingType:
        if category = FloatingRateIndexCategoryEnum -> ScreenRate
        then FloatingRateIndexProcessingTypeEnum -> Screen
        else calcProcessingType

    // categorize the rates based on the floating rate specification in the payout and based on the FRO definition from the metadata and output the resulting category
    alias processingCategory:
        if (isCalculatedRate = True)
        then FloatingRateIndexProcessingTypeEnum -> Modular
        else (if floatingRateDefinition -> fro exists
        then definitionProcessingType
        else FloatingRateIndexProcessingTypeEnum -> Screen)

    // return the processing category
    set processingType: processingCategory

func ProcessFloatingRateReset: <"Entry point for the function that performs the floating rate resetting operation.  There are different variations depending on the processing type (e.g. screen rate, OIS, modular calculated rate. .">
    inputs:
        interestRatePayout InterestRatePayout (1..1) <"Floating rate stream definition.">
        calcPeriod CalculationPeriodBase (1..1) <"The calculation period for which you want the rate.">
        processingType FloatingRateIndexProcessingTypeEnum (1..1) <"The rate processing type (e.g. Screen Rate, OIS); this drives how the resetting calculation is done. .">
    output:
        floatingRate FloatingRateSettingDetails (1..1) <"Details of the rate observation/calculation.">

func ProcessFloatingRateReset(processingType: FloatingRateIndexProcessingTypeEnum -> Screen): <"Evaluate the rate for a screen rate - call logic to determine how to observe the screen rate.">
    [calculation]
    // set up convenience aliases
    alias resetDates: interestRatePayout -> resetDates
    alias rateDef: interestRatePayout -> rateSpecification -> FloatingRateSpecification
    set floatingRate: EvaluateScreenRate(rateDef, resetDates, calcPeriod) // Call the screen rate evaluation logic

func ProcessFloatingRateReset(processingType: FloatingRateIndexProcessingTypeEnum -> Modular): <"Evaluate the rate for a modular calculated rate.  Call the calculated rate calculation logic to determine the value of the reset.">
    [calculation]
    // set up convenience aliases
    alias rateDef: interestRatePayout -> rateSpecification -> FloatingRateSpecification
    alias resetDates: interestRatePayout -> resetDates
    alias dayCount: interestRatePayout -> dayCountFraction
    alias fro: rateDef -> rateOption
    alias calcParams: rateDef -> calculationParameters

    // determine the prior calculation period corresponding to this period, in case needed.  (used for set-in-advance calculated rates and some fallback rates.)
    alias priorCalculationPeriod:
        Create_CalculationPeriodBase(
                CalculationPeriod(
                        interestRatePayout -> calculationPeriodDates,
                        calcPeriod -> adjustedStartDate
                    )
            )

    // call the calculated rate evaluation logic
    set floatingRate:
        EvaluateCalculatedRate(
                fro,
                calcParams,
                resetDates,
                calcPeriod,
                priorCalculationPeriod,
                dayCount
            )

func ProcessFloatingRateReset(processingType: FloatingRateIndexProcessingTypeEnum -> OIS): <"Evaluate the rate for an OIS calculated rate. Call the calculated rate calculation logic to determine the value of the reset.  See the 2021 ISDA Definitions Section 6.6.3.">
    [calculation]
    // set up convenience aliases
    alias rateDef: interestRatePayout -> rateSpecification -> FloatingRateSpecification
    alias resetDates: interestRatePayout -> resetDates
    alias dayCount: interestRatePayout -> dayCountFraction
    alias fro: rateDef -> rateOption
    // create a pseudo calculation parameters block to drive the OIS calculation
    alias calcParams:
        GetCalculatedFROCalculationParameters(
                resetDates,
                CalculationMethodEnum -> Compounding
            )

    // call the calculated rate evaluation logic to evaluate the OIS rate
    set floatingRate:
        EvaluateCalculatedRate(
                fro,
                calcParams,
                resetDates,
                calcPeriod,
                calcPeriod,
                dayCount
            )

func ProcessFloatingRateReset(processingType: FloatingRateIndexProcessingTypeEnum -> OvernightAvg): <"Evaluate the rate for a daily average calculated FRO. Call the calculated rate calculation logic to determine the value of the reset. See the 2021 ISDA Definitions Section 6.6.3.">
    [calculation]
    // set up convenience aliases
    alias rateDef: interestRatePayout -> rateSpecification -> FloatingRateSpecification
    alias resetDates: interestRatePayout -> resetDates
    alias dayCount: interestRatePayout -> dayCountFraction
    alias rateOption: rateDef -> rateOption
    // create a pseudo calculation parameters block to drive the averaging calculation
    alias calcParams:
        GetCalculatedFROCalculationParameters(
                resetDates,
                CalculationMethodEnum -> Averaging
            )

    // call the calculated rate evaluation logic to evaluate the daily average rate
    set floatingRate:
        EvaluateCalculatedRate(
                rateOption,
                calcParams,
                resetDates,
                calcPeriod,
                calcPeriod,
                dayCount
            )

func GetCalculatedFROCalculationParameters: <"Initialize a calculation parameters block for an OIS or a daily average rate. Used to support FROs that include an embedded calculation.">
    inputs:
        resetDates ResetDates (1..1) <"The reset dates for the interest rate payout for which the calculated rate is being computed.">
        calcMethod CalculationMethodEnum (1..1) <"Whether the rate is a compound (OIS) or daily average rate.">
    output:
        calcParams FloatingRateCalculationParameters (1..1) <"A calculation parameters block.">

    // generate and output the required type
    set calcParams -> calculationMethod: calcMethod
    set calcParams -> applicableBusinessDays: resetDates -> fixingDates -> businessCenters

func ProcessFloatingRateReset(processingType: FloatingRateIndexProcessingTypeEnum -> CompoundIndex): <"Call the compounded index processing logic to calculate the reset.">

// TODO:  this will depend on exactly how FpML implements this.
//-------------------------------------------------------
// The following functions do rate reset processing for Screen Rates
//-------------------------------------------------------
func EvaluateScreenRate: <"Evaluate/lookup the value of a screen rate.">
    inputs:
        rateDef FloatingRate (1..1) <"Floating rate definition.">
        resetDates ResetDates (1..1) <"Reset dates for observing the rate.">
        calculationPeriod CalculationPeriodBase (1..1) <"Calculation period for which you want the rate.">
    output:
        details FloatingRateSettingDetails (1..1) <"Resulting details of the rate setting .">

    // figure out the date for which the rate is needed
    alias resetDate: DetermineResetDate(resetDates, calculationPeriod)
    alias fixingDate: DetermineFixingDate(resetDates, resetDate)

    // look up the rate on that date
    alias observedRate: IndexValueObservation(fixingDate, rateDef -> rateOption)
    // record relevant dates and observed rate
    set details -> resetDate: resetDate
    set details -> observationDate: fixingDate
    set details -> floatingRate: observedRate

func DetermineResetDate: <"Determine the value of the reset date given a reset dates structure and a calculation paeriod for which it's needed. Reset dates are defined in the 2021 ISDA Definition in Section 6.5.5.">
    inputs:
        resetDates ResetDates (1..1) <"Reset dates for observing the rate.">
        calculationPeriod CalculationPeriodBase (1..1) <"Calculation period for which you want the rate.">
    output:
        resetDate date (1..1) <"The date upon which the rate should be observed. .">

    // figure out the date for which the rate is needed
    alias resetRelativeTo: resetDates -> resetRelativeTo
    alias isStart: resetRelativeTo = ResetRelativeToEnum -> CalculationPeriodStartDate
    alias reset:
        if (isStart)
        then calculationPeriod -> adjustedStartDate
        else calculationPeriod -> adjustedEndDate

    set resetDate: reset

func DetermineFixingDate: <"Determine the observation (fixing) date needed given a reset dates structure and a reset date.">
    inputs:
        resetDates ResetDates (1..1) <"Reset date parameters for observing the rate.">
        resetDate date (1..1) <"The date that the rate is needed for.">
    output:
        fixingDate date (1..1) <"The date upon which the rate should be observed. .">

    alias fixingOffsetDays: resetDates -> fixingDates -> periodMultiplier
    alias businessCenters:
        GetAllBusinessCenters(resetDates -> fixingDates -> businessCenters)
    alias fixDate: AddBusinessDays(resetDate, fixingOffsetDays, businessCenters)

    set fixingDate: fixDate

// =====================================================================
//
// Rate processing and treatment functions
//
// these functions retrieve and apply processing and treatment parameters for a floating rate.
// This includes multipliers, spreads, caps/floors, rate treatment, rounding, and negative treatment.
//
// ======================================================================
//-------------------------------------------------------------
// The following functions look up processing parameters
//-------------------------------------------------------------
func GetFloatingRateProcessingParameters: <"Determine the processing parameters to use from the InterestRatePayout by looking them up if necessary from the corresponding schedules in the interest rate stream.">
    inputs:
        interestRatePayout InterestRatePayout (1..1) <"An interest rate stream.">
        calculationPeriod CalculationPeriodBase (1..1) <"The calculation period for which the calculation is being perfmored (needed to look up paramters).">
    output:
        processingParameters FloatingRateProcessingParameters (1..1) <"The processing parameters.">

    // look up parameters
    alias spreadRate: SpreadAmount(interestRatePayout, calculationPeriod)
    alias multiplier: MultiplierAmount(interestRatePayout, calculationPeriod)
    alias cap: CapRateAmount(interestRatePayout, calculationPeriod)
    alias floor: FloorRateAmount(interestRatePayout, calculationPeriod)

    alias rounding:
        interestRatePayout -> rateSpecification -> FloatingRateSpecification -> finalRateRounding
    alias negativeTreatment:
        interestRatePayout -> rateSpecification -> FloatingRateSpecification -> negativeInterestRateTreatment
    alias treatment:
        interestRatePayout -> rateSpecification -> FloatingRateSpecification -> rateTreatment

    set processingParameters -> initialRate:
        interestRatePayout -> rateSpecification -> FloatingRateSpecification -> initialRate
    set processingParameters -> spread: spreadRate
    set processingParameters -> multiplier: multiplier
    set processingParameters -> treatment: treatment
    set processingParameters -> capRate: cap
    set processingParameters -> floorRate: floor
    set processingParameters -> rounding: rounding
    set processingParameters -> negativeTreatment: negativeTreatment

func SpreadAmount: <"Look up the spread amount for a calculation period.">
    [calculation]
    inputs:
        interestRatePayout InterestRatePayout (1..1) <"An interest rate stream.">
        calculationPeriod CalculationPeriodBase (1..1) <"The calculation period for which you want the spread.">
    output:
        spread number (0..1) <"The spread value for the period.">

    set spread:
        GetRateScheduleAmount(
                interestRatePayout -> rateSpecification -> FloatingRateSpecification -> spreadSchedule,
                calculationPeriod -> adjustedStartDate
            )

func MultiplierAmount: <"Look up the multiplier amount for a calculation period.">
    [calculation]
    inputs:
        interestRatePayout InterestRatePayout (1..1) <"An interest rate stream.">
        calculationPeriod CalculationPeriodBase (1..1) <"The calculation period for which you want the multiplier.">
    output:
        multiplier number (0..1) <"The multiplier in effect from the calculation period start date.">

    set multiplier:
        GetRateScheduleAmount(
                interestRatePayout -> rateSpecification -> FloatingRateSpecification -> floatingRateMultiplierSchedule,
                calculationPeriod -> adjustedStartDate
            )

func CapRateAmount: <"Look up the cap rate amount for a calculation period.">
    [calculation]
    inputs:
        interestRatePayout InterestRatePayout (1..1) <"An interest rate stream.">
        calculationPeriod CalculationPeriodBase (1..1) <"The calculation period for which you want the cap rate.">
    output:
        capRate number (0..1) <"The cap rate in effect from the calculation period start date.">

    set capRate: <"Look up and return the rate for the period start date.">
        GetRateScheduleAmount(
                interestRatePayout -> rateSpecification -> FloatingRateSpecification -> capRateSchedule,
                calculationPeriod -> adjustedStartDate
            )

func FloorRateAmount: <"Look up the floor rate amount for a calculation period.">
    [calculation]
    inputs:
        interestRatePayout InterestRatePayout (1..1) <"An interest rate stream.">
        calculationPeriod CalculationPeriodBase (1..1) <"The calculation period for which you want the floor rate.">
    output:
        floorRate number (0..1) <"The cap rate in effect from the calculation period start date.">

    set floorRate: <"Look up and return the rate for the period start date.">
        GetRateScheduleAmount(
                interestRatePayout -> rateSpecification -> FloatingRateSpecification -> floorRateSchedule,
                calculationPeriod -> adjustedStartDate
            )

func GetRateScheduleAmount: <"Get the rate for the period start date.">
    inputs:
        schedule RateSchedule (1..1) <"The rate schedule.">
        periodStartDate date (1..1) <"The start date for which you want the rate.">
    output:
        amount number (1..1)

    set amount: GetRateScheduleStepValues(schedule, periodStartDate) last

func GetRateScheduleStepValues: <"Get all rate schedule step values whose stepDate is before or equal to the supplied periodStartDate.  Returns a list of step values starting from the initial rate.">
    inputs:
        schedule RateSchedule (1..1) <"The rate schedule.">
        periodStartDate date (1..1) <"The start date for which you want the rate.">
    output:
        stepValues number (0..*)

    add stepValues: <"Add initial step value.">
        schedule -> price -> value
    add stepValues: <"Add all schedule step values whose stepDate is before or equal to the supplied periodStartDate.">
        schedule -> price -> datedValue
            filter date <= periodStartDate
            then extract value

//-------------------------------------------------------------
// The following functions apply processing parameters
//-------------------------------------------------------------
func ApplyFloatingRateProcessing: <"Perform rate treatments on floating rates, such as applying spreads, multipliers, caps and floors, rounding, and negative interest treatment. TODO: initialRate needs to be supported.  Also, to support compounding methods, it may be necessary to split the before spread and after spread values and return both, so that cashflows can be computed both ways. This may require this function to be redesigned or split into pieces (e.g. factor out the post-spread processing).  Rate treatments are described in Section 6 of the 2021 ISDA Definitions.  Negative treatment does not correctly support the case where compounded periods are applicable and will need to be enhanced for that case when compounding calculations are developed.">
    inputs:
        processing FloatingRateProcessingParameters (1..1) <"THe parameters to be used for processing, such as multipliers, spreads, cap rates, etc.">
        rawRate number (1..1) <"The floating rate prior to treatment, either a single term rate, or a calculated rate such as an OIS or lookback compounded rate.">
        calculationPeriod CalculationPeriodBase (1..1) <"The calculation period for with the processing need to be performed.">
        isInitialPeriod boolean (1..1) <"Is this the initial calculation period of the payout?">
    output:
        details FloatingRateProcessingDetails (1..1) <"Results are details of the rate treatment.">

    // evaluate any floating rate multiplier (these are not described in the ISDA Definition but are included in FpML to support Inverse Floaters.  The multiplier typically 1 or -1 and is applied prior to other treatments.
    alias multiplier: processing -> multiplier
    alias multiplied: rawRate * multiplier
    alias multipliedRate:
        if multiplier exists then multiplied else rawRate
    // evaluate US Dollar treatments (described in Section 6.9 of the 2021 ISDA Definitions)
    alias treatedRate:
        ApplyUSRateTreatment(multipliedRate, processing -> treatment, calculationPeriod) * 1.0

    // begin evaluating the floating negative treatment, in section 5.8 of the 2021 ISDA definitions
    alias negativeTreatment: processing -> negativeTreatment
    // the following linne addresses section 6.8.6.  If the rate is negative prior to the spread, set it to 0
    alias negativeTreatedRate:
        if (negativeTreatment = NegativeInterestRateTreatmentEnum -> ZeroInterestRateExcludingSpreadMethod)
        then Max(0.0, treatedRate)
        else treatedRate

    // add spread (covered in section 6.5.4 and other places)
    alias spreadRate: processing -> spread
    alias added: negativeTreatedRate + spreadRate
    alias ratePlusSpread:
        if spreadRate exists then added else negativeTreatedRate
    // the following line addresses section 6.8.4.  If the rate is negative after the spread, set it to 0
    alias negativeTreatedRatePlusSpread:
        if (negativeTreatment = NegativeInterestRateTreatmentEnum -> ZeroInterestRateMethod)
        then Max(0.0, ratePlusSpread)
        else ratePlusSpread

    // initial rate - if the initial rate is specified and it is the initial (first) period, use the initial rate instead.  This sets up aliases to support that
    alias doInitialRate:
        if (isInitialPeriod = True and processing -> initialRate exists)
        then True
        else False
    alias initialRate: processing -> initialRate -> value
    alias initialRatePluSpread: initialRate + spreadRate
    alias initialRatePlusSpread:
        if (spreadRate exists)
        then initialRatePluSpread
        else initialRate

    // return the key inputs
    set details -> processingParameters: processing
    set details -> rawRate: rawRate

    // calculate and return the processes rate, both including and excluding the spread
    set details -> processedRate:
        if (doInitialRate = True)
        then initialRatePluSpread
        else ApplyFloatingRatePostSpreadProcessing(ratePlusSpread, processing)
    set details -> spreadExclusiveRate:
        if (doInitialRate = True)
        then initialRate
        else ApplyFloatingRatePostSpreadProcessing(negativeTreatedRate, processing)

func ApplyFloatingRatePostSpreadProcessing: <"Perform post-spread rate treatments on floating rates, such as applying caps and floors, rounding, and negative interest treatment.  TODOO:  initialRate needs to be supported.  Also, to support compounding methods, it may be necessary to split the before spread and after spread values and return both, so that cashflows can be computed both ways.  This may require this function to be redesigned or split into pieces (e.g. factor out the post-spread processing).">
    inputs:
        inputRate number (1..1) <"The floating rate prior to post-sprad, either a single term rate, or a calculated rate such as an OIS or lookback compounded rate.">
        processing FloatingRateProcessingParameters (1..1)
    output:
        processedRate number (1..1) <"rate after post-spread processing.">

    // apply any caps and floors on the rate
    alias cappedAndFlooredRate: ApplyCapsAndFloors(processing, inputRate)
    // calculate and output the rounded rate
    set processedRate: ApplyFinalRateRounding(cappedAndFlooredRate, processing -> rounding)

func ApplyCapsAndFloors: <"Apply any cap or floor rate as a constraint on a regular swap rate, as discussed in the 2021 ISDA Definitions, section 6.5.8 and 6.5.9.">
    [calculation]
    inputs:
        processing FloatingRateProcessingParameters (1..1)
        inputRate number (1..1) <"The floating rate prior to treatment, either a single term rate, or a calculated rate such as an OIS or lookback compounded rate.">
    output:
        cappedAndFlooredRate number (1..1) <"The rate after application of cap and/or floor.">

    alias cap: processing -> capRate
    alias floor: processing -> floorRate
    alias cappedRate:
        if cap exists and inputRate > cap then cap else inputRate
    alias flooredRate:
        if floor exists and cappedRate < floor
        then floor
        else cappedRate
    set cappedAndFlooredRate: flooredRate

func ApplyUSRateTreatment: <"Apply the US rate treatment logic where applicable (Bond Equivalent Yield, Money Market Yield, as described in the 2021 ISDA Definitions, section 6.9.">
    inputs:
        baseRate number (1..1) <"Rate before treatment.">
        rateTreatment RateTreatmentEnum (1..1) <"type of treatment.">
        calculationPeriod CalculationPeriodBase (1..1) <"The calculation period over which the rate is computed.">
    output:
        treatedRate number (1..1) <"rate after treatment.">

    set treatedRate: baseRate // temporary, stub definition until support is added

func ApplyFinalRateRounding: <"Apply the final rate rounding treatment logic as described in the 2021 ISDA Definitions, section 4.8.1.">
    [calculation]
    inputs:
        baseRate number (1..1) <"Rate before rounding.">
        finalRateRounding Rounding (0..1) <"type of rounding (precision and direction).">
    output:
        roundedRate number (1..1) <"rate after rounding.">

    alias precision:
        if finalRateRounding -> precision exists
        then finalRateRounding -> precision
        else 7
    alias direction:
        if finalRateRounding -> roundingDirection exists
        then finalRateRounding -> roundingDirection
        else RoundingDirectionEnum -> Nearest

    set roundedRate: RoundToPrecision(baseRate, precision, direction, False)




© 2015 - 2025 Weber Informatics LLC | Privacy Policy