Why a Process Model¶
The CDM lays the foundation for the standardisation, automation and inter-operability of industry processes. Industry processes represent events and actions that occur through the transaction’s lifecycle, from negotiating a legal agreement to allocating a block-trade or calculating settlement amounts.
While ISDA defines the protocols for industry processes in its library of ISDA Documentation, differences in the implementation minutia may cause operational friction between market participants. Evidence shows that even when calculations are defined in mathematical notation (for example, day count fraction formulae which are used when calculating interest rate payments) can be a source of dispute between parties in a transaction.
What Is the Process Model¶
The CDM Process Model has been designed to translate the technical standards that support those industry processes into a standardised machine-readable and machine-executable format.
Machine readability and executability is crucial to eliminate implementation discrepancy between market participants and increase interoperability between technology solutions. It greatly minimises the cost of adoption and provides a blueprint on which industry utilities can be built.
How Does It Work¶
The data and proces model definitions of the CDM are systematically translated into executable code using purpose-built code generation technology. The CDM executable code is available in a number of modern, widely adopted and freely available programming languages and is systematically distributed as part of the CDM release.
The code generation process is based on the Rosetta DSL and is further described in the Code Generation Section, including an up-to-date list of available languages. Support for further languages can be added as required by market participants.
The scope of the process model has two dimensions:
Coverage - which industry processes should be covered.
Granularity - at which level of detail each process should be specified.
The CDM process model currently covers the post-trade lifecycle of securities, contractual products, and foreign exchange. Generally, a process is in-scope when it is already covered in ISDA Documentation or other technical documents. For example, the following processes are all in scope:
Trade execution and confirmation
Settlement (including any future contingent cashflow payment)
Return (settlement of the part and/or full return of the loaned security as defined by a Securities Lending transaction.)
Billing (calculation and population of invoicing for Securities Lending transactions)
Exercise of options
Regulatory reporting (although covered in a different documentation section)
It is important for implementors of the CDM to understand the scope of the model with regard to specifications and executable code for the above list of post-trade lifecycle processes.
The CDM process model leverages the function component of the Rosetta DSL. A function receives a set of input values and applies logical instructions to return an output. The input and output are both CDM objects (including basic types). While a function specifies its inputs and output, its logic may be fully defined or only partially defined depending on how much of the output’s attribute values it builds. Unspecified parts of a process represent functionality that firms are expected to implement, either internally or through third-parties such as utilities.
It is not always possible or practical to fully specify the business logic of a process from a model. Parts of processes or sub-processes may be omitted from the CDM for the following reasons:
The sub-process is not needed to create a functional CDM output object.
The sub-process has already been defined and its implementation is widely adopted by the industry.
The sub-process is specific to a firm’s internal process and therefore cannot be specified in an industry standard.
Given these reasons, the CDM process model focuses on the most critical data and processes required to create functional objects that satisfy the below criterion:
All of the qualifiable constituents (such as
Product) of a function’s output can be qualified, which means that they evaluate to True according to at least one of the applicable Qualification functions.
Lineage and cross-referencing between objects is accurate for data integrity purposes.
For any remaining data or processes, implementors can populate the remaining attribute values required for the output to be valid by extending the executable code generated by the process model or by creating their own functions.
For the trade lifecycle processes that are in scope, the CDM process model covers the following sub-process components, which are each detailed in the next sections:
Event creation process
In many legacy models and technical standards, validation rules are generally specified in text-based documentation, which requires software engineers to evaluate and translate the logic into code. The frequently occuring result of this human interpretation process is inconsistent enforcement of the intended logic.
By contrast, in the CDM, validation components are an integral part of the process model specifications and are distributed as executable code in the Java representation of the CDM. The CDM validation components leverage the validation components of the Rosetta DSL.
As an example, the FpML ird validation rule #57, states that if the calculation period frequency is expressed in units of month or year, then the roll convention cannot be a weekday. A machine readable and executable definition of that specification is provided in the CDM, as a
condition attached to the
condition FpML_ird_57: if period = PeriodExtendedEnum -> M or period = PeriodExtendedEnum -> Y then rollConvention <> RollConventionEnum -> NONE and rollConvention <> RollConventionEnum -> SFE and rollConvention <> RollConventionEnum -> MON and rollConvention <> RollConventionEnum -> TUE and rollConvention <> RollConventionEnum -> WED and rollConvention <> RollConventionEnum -> THU and rollConvention <> RollConventionEnum -> FRI and rollConvention <> RollConventionEnum -> SAT and rollConvention <> RollConventionEnum -> SUN
The CDM provides certain ISDA Definitions as machine executable formulas to standardise the industry calculation processes that depend on those definitions. Examples include the ISDA 2006 definitions of Fixed Amount and Floating Amount , the ISDA 2006 definitions of Day Count Fraction rules, and performance calculations for Equity Swaps. The CDM also specifies related utility functions.
These calculation processes leverage the calculation function component of the Rosetta DSL which is associated to a
Explanations of these processes are provided in the following sections.
Base Libraries - Vector Math¶
The CDM includes a very basic library for performing vector math. This is intended to support more complex calculations such as daily compounded floating amounts. The CDM includes a basic implementation of these functions in Java, and allows individual implementations to substitute their own more robust representations.
A small library of functions for working with vectors (ordered collections of numbers) has been added to CDM to support Rosetta functions needing to perform complex mathematical operations. Anticipated uses include averaging and compounding calculations for floating amounts, but the functions are designed to be general use.
The functions are located in
VectorOperation: Generates a result vector by applying the supplied arithmetic operation to each element of the supplied left and right vectors in turn. i.e. result[n] = left[n] [op] right[n], where [op] is the arithmetic operation defined by arithmeticOp. This function can be used to, for example, multiply or add two vectors.
VectorScalarOperation: Generates a result vector by applying the supplied arithmetic operation and scalar right value to each element of the supplied left vector in turn. i.e. result[n] = left[n] [op] right, where [op] is the arithmetic operation defined by arithmeticOp. This function can be used to, for example, multiply a vector by a scalar value, or add a scalar to a vector.
VectorGrowthOperation: Generates a result vector by starting with the supplied base value (typically 1), and then multiplying it in turn by each growth factor, which is typically a number just above 1. For instance, a growth factor of 1.1 represents a 10% increase, and 0.9 a 10% decrease. The results will show the successive results of applying the successive growth factors, with the first value of the list being the supplied baseValue, and final value of the results list being the product of all of the supplied values. i.e. result = baseValue * factor, result[n] = result[n-1] * factor[n]. The resulting list will have the one more element than the supplied list of factors. This function is useful for performing compounding calculations.
AppendToVector: Appends a single value to a vector.
Also a new scalar functions has been added to better support floating rate processing:
RoundToPrecision: Rounds a supplied number to a specified precision (in decimal places) using a roundingMode of type
RoundingDirectionEnum. This is similar to
RoundToNearestbut takes a precision rather than an amount, and uses a different rounding mode enumeration that supports more values.
Base Libraries - Date Math¶
The CDM includes a very basic library for performing date math. This is intended to support more complex calculations such as daily compounded floating amounts. The CDM includes a basic implementation of these functions in Java, and allows individual implementations to substitute their own more robust representations.
A small library of functions for working with dates and lists of dates has been added to CDM to support Rosetta functions needing to perform date mathematics. Anticipated uses include date list generation for modular rate calculations for floating amounts, but the functions are designed to be general use.
There is a basic Java language implementation that can be used, or users can provide their own implementations of these functions using a more robust date math library.
The functions are located in
GetAllBusinessCenters: Returns a merged list of BusinessCenterEnums for the supplied BusinessCenters.
BusinessCenterHolidaysMultiple: Returns a sorted list of holidays for the supplied business centers.
BusinessCenterHolidays: Returns a list of holidays for the supplied business center.
DayOfWeek: Returns the day of week corresponding to the supplied date.
AddDays: Adds the specified number of calendar days to the supplied date. A negative number will generate a date before the supplied date.
DateDifference: Subtracts the two supplied dates to return the number of calendar days between them . A negative number implies first is after second.
LeapYearDateDifference: Subtracts the two supplied dates to return the number of leap year calendar days between them (that is, the number of dates that happen to fall within a leap year). A negative number implies firstDate is after secondDate.
AppendDateToList: Add a date to a list of dates.
PopOffDateList: Remove last element from a list of dates.
The following are implemented in Rosetta based on the above primitives:
IsWeekend: Returns whether the supplied date is a weekend. This implementation currently assumes a 5 day week with Saturday and Sunday as holidays. A more sophisticated implementation might use the business centers to determine which days are weekends, but most jurisdictions where derivatives are traded follow this convention.
IsHoliday: Returns whether a day is a holiday for the specified business centers.
IsBusinessDay: Returns an indicator of whether the supplied date is a good business date given the supplied business centers. True => good date, i.e. not a weekend or holiday. False means that it is either a weekend or a holiday.
AddBusinessDays: Returns a good business date that has been offset by the given number of business days given the supplied business centers. A negative value implies an earlier date (before the supplied originalDate), and a positive value a later date (after the supplied date).
GenerateDateList: Creates a list of good business days starting from the startDate and going to the end date, inclusive, omitting any days that are weekends or holidays according to the supplied business centers.
Base Libraries - Daycounting¶
The CDM includes a library for performing day counting calculations.
It includes functions as follows:
YearFraction: The fraction of a year represented by a date range.
YearFractionForOneDay`: Return the year fraction represented by a single day, i.e. 1 / dayCountBasis, where dayCountBasis represents the denominator of the day count fraction. This perhaps should take into account leap years, though the ISDA compounding formulas do not cover ACT basis at the moment.
DayCountBasis: Return the day count basis (the denominator of the day count fraction) for the day count fraction.
Floating Rate Option/Index Features¶
The CDM includes features for retrieving information about floating rate options and for calculating custom (“modular”) floating rates.
Functions for retrieving information about FROs include:
IndexValueObservation: Retrieve the values of the supplied index on the specified observation date.
IndexValueObservationMultiple: Retrieve the values of the supplied index on the specified observation dates.
FloatingRateIndexMetadata: Retrieve all available metadata for the floating rate index.
ValidateFloatingRateIndexName: Return whether the supplied floating rate index name is valid for the supplied contractual definitions.
Functions for calculating modular floating rates include:
EvaluateCalculatedRate: Evaluate a calculated rate as described in the 2021 ISDA Definitions, Section 7
GenerateObservationDatesAndWeights: Apply shifts to generate the list of observation dates and weights for each of those dates.
ComputeCalculationPeriod: Determine the calculation period to use for computing the calculated rate (it may not be the same as the normal calculation period, for instance if the rate is set in advance)
DetermineObservationPeriod: Determine any applicable offsets/shifts for the period for observing an index, and then generate the date range to be used for observing the index, based on the calculation period, plus any applicable offsets/shifts.
GenerateObservationPeriod: Generate the date range to be used for observing the index, based on the calculation period, plus any applicable offsets/shifts.
GenerateObservationDates: Generate the list of observation dates given an observation period.
DetermineWeightingDates: Determine the dates to be used for weighting observations.
ProcessObservations: Apply daily observation parameters to rate observation. These are discussed in the 2021 ISDA Definitions, section 7.2.3 and 7.2.4.
GenerateWeights: Recursively creates a list of weights based on the date difference between successive days.
ApplyCompoundingFormula: Implements the compounding formula: Product of ( 1 + (rate * weight) / basis), then backs out the final rate. This is used to support section 7.3 of the 2021 ISDA Definitions.
ApplyAveragingFormula: Implements the weighted arithmetic averaging formula. Sums the weighted rates and divides by the total weight. This is used to support section 7.4 of the 2021 ISDA Definitions.
Fixed Amount and Floating Amount Definitions¶
The CDM includes preliminary features for calculating fixed and floating amounts for interest rate payouts.
Base calculation functions include:
FixedAmountCalculation: Calculates the fixed amount for a calculation period by looking up the notional and the fixed rate and multiplying by the year fraction
GetFixedRate: Look up the fixed rate for a calculation period
FloatingAmountCalculation: Calculate a floating amount for a calculation period by determining the raw floating rate, applying any rate treatments, looking up the calculation period notional, then performing the multiplication of the notional, rate, and year fraction. Floating amount calculations are described in the 2021 ISDA Definitions in Section 6 and 7.
GetNotionalAmount: Look up the notional amount in effect for a calculation period
GetQuantityScheduleStepValues: Find all schedule step values whose stepDate is before or equal to the supplied periodStartDate. Returns a list of step values starting from the initial quantity value, to the last step value before the periodStartDate.
CalculateYearFraction: Calculate the year fraction for a single calculation period, by invoking the base year fraction logic
Floating rate processing an calculation functions include:
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.
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.
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).
GetCalculatedFROCalculationParameters: Initialize a calculation parameters block for an OIS or a daily average rate. Used to support FROs that include an embedded calculation.
ProcessFloatingRateReset(processingType: FloatingRateIndexProcessingTypeEnum->CompoundIndex): Call the compounded index processing logic to calculate the reset
EvaluateScreenRate: Evaluate/lookup the value of a screen rate
DetermineResetDate: Determine the value of the reset date given a reset dates structure and a calculation period for which it’s needed. Reset dates are defined in the 2021 ISDA Definition in Section 6.5.5.
DetermineFixingDate: Determine the observation (fixing) date needed given a reset dates structure and a reset date.
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
SpreadAmount: Look up the spread amount for a calculation period.
MultiplierAmount: Look up the multiplier amount for a calculation period.
CapRateAmount: Look up the cap rate amount for a calculation period.
FloorRateAmount: Look up the floor rate amount for a calculation period.
GetRateScheduleAmount: Look up an amount for a calculation period from a rate schedule
ApplyFloatingRateProcessing: Perform rate treatments on floating rates, such as applying spreads, multipliers, caps and floors, rounding, and negative interest treatment.
ApplyFloatingRatePostSpreadProcessing: Perform post-spread rate treatments on floating rates, such as applying caps and floors, rounding, and negative interest treatment.
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
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. (NB: this function does not have an implementation.)
ApplyFinalRateRounding: Apply the final rate rounding treatment logic as described in the 2021 ISDA Definitions, section 4.8.1.
Most of the above have a preliminary implementation for feedback. A few are only defined as “do-nothing” interfaces, and users needing these features would need to implement the functions.
Fixed Amount and Floating Amount Definitions¶
The CDM expressions of
FloatingAmount are similar in structure: a calculation formula that reflects the terms of the ISDA 2006 Definitions and the arguments associated with the formula.
func FloatingAmount: [calculation] inputs: interestRatePayout InterestRatePayout (1..1) rate number (0..1) notional number (0..1) date date (0..1) calculationPeriodData CalculationPeriodData (0..1) output: floatingAmount number (1..1) alias calculationPeriod: if calculationPeriodData exists then calculationPeriodData else CalculationPeriod(interestRatePayout -> calculationPeriodDates, date) alias calcPeriodBase : Create_CalculationPeriodBase(calculationPeriod) alias floatingCalc : FloatingAmountCalculation(interestRatePayout, calcPeriodBase, False, notional, rate) set floatingAmount : floatingCalc-> calculatedAmount
The CDM process model incorporates calculations that represent the set of day count fraction rules specified as part of the ISDA 2006 Definitions, e.g. the ACT/365.FIXED and the 30E/360 day count fraction rules. Although these rules are widely accepted in international markets, many of them have complex nuances which can lead to inconsistent implementations and potentially mismatched settlements.
For example, there are three distinct rule sets in which the length of each month is generally assumed to be 30 days for accrual purposes (and each year is assumed to be 360 days). However there are nuances in the rule sets that distinguish the resulting calculations under different circumstances, such as when the last day of the period is the last day of February. These distinct rule sets are defined by ISDA as 30/360 (also known as 30/360 US), 30E/360 (formerly known as 30/360 ICMA or 30/360 Eurobond), and the 30E/360.ISDA.
The CDM process model eliminates the need for implementors to interpret the logic and write unique code for these rules. Instead, it provides a machine-readable expression that generates executable code, such as the example below:
func YearFraction(dayCountFractionEnum: DayCountFractionEnum -> _30E_360): [calculation] alias startYear: startDate -> year alias endYear: endDate -> year alias startMonth: startDate -> month alias endMonth: endDate -> month alias endDay: Min(endDate -> day, 30) alias startDay: Min(startDate -> day, 30) set result: (360 * (endYear - startYear) + 30 * (endMonth - startMonth) + (endDay - startDay)) / 360
CDM elements often need to be transformed by a function to construct the arguments for a formula in a calculation. A typical example is the requirement to identify a period start date, end date, and other date-related attributes required to compute a cashflow amount in accordance with a schedule (as illustrated in the day count fraction calculation shown above). The CDM has two main types to address this requirement:
CalculationPeriodDatesspecifies the inputs required to construct a calculation period schedule
CalculationPeriodDataspecifies actual attribute values of a calculation period such as start date, end date, etc.
The CalculationPeriod function receives the
CalculationPeriodDates and the current date as the inputs and produces the
CalculationPeriodData as the output, as shown below:
func CalculationPeriod: inputs: calculationPeriodDates CalculationPeriodDates (1..1) date date (1..1) output: result CalculationPeriodData (1..1)
The CDM process model includes calculations to support the equity performance concepts applied to reset and pay cashflows on Equity Swaps. Those calculations follow the definitions as normalised in the new 2018 ISDA CDM Equity Confirmation for Security Equity Swap (although this is a new template that is not yet in use across the industry).
Some of those calculations are presented below:
func EquityCashSettlementAmount: inputs: tradeState TradeState (1..1) date date (1..1) output: equityCashSettlementAmount Transfer (1..1) alias equityPerformancePayout: tradeState -> trade -> tradableProduct -> product -> contractualProduct -> economicTerms -> payout -> performancePayout only-element alias equityPerformance: EquityPerformance(tradeState ->trade, tradeState -> resetHistory only-element -> resetValue, date) alias payer: ExtractCounterpartyByRole( tradeState -> trade -> tradableProduct -> counterparty, equityPerformancePayout -> payerReceiver -> payer ) -> partyReference alias receiver: ExtractCounterpartyByRole( tradeState -> trade -> tradableProduct -> counterparty, equityPerformancePayout -> payerReceiver -> receiver ) -> partyReference set equityCashSettlementAmount -> quantity -> amount: Abs(equityPerformance) set equityCashSettlementAmount -> quantity -> unitOfAmount-> currency: ResolveEquityInitialPrice( tradeState -> trade -> tradableProduct -> tradeLot only-element -> priceQuantity -> price ) -> unitOfAmount -> currency set equityCashSettlementAmount -> payerReceiver -> payerPartyReference: if equityPerformance >= 0 then payer else receiver set equityCashSettlementAmount -> payerReceiver -> receiverPartyReference: if equityPerformance >= 0 then receiver else payer set equityCashSettlementAmount -> settlementDate -> adjustedDate: ResolveCashSettlementDate(tradeState) set equityCashSettlementAmount -> settlementOrigin -> performancePayout: equityPerformancePayout as-key
func RateOfReturn: inputs: initialPrice Price (1..1) finalPrice Price (1..1) output: rateOfReturn number (1..1) alias initialPriceValue: initialPrice->amount alias finalPriceValue: finalPrice->amount set rateOfReturn: if finalPriceValue exists and initialPriceValue exists and initialPriceValue > 0 then (finalPriceValue - initialPriceValue) / initialPriceValue
The CDM process model includes calculations to support the Delivery and Return amount concepts applied to the posting of Initial Margin. Those calculations follow the definitions as normalised in the ISDA 2018 CSA (Security Interest – New York Law)
Some of those calculations are presented below:
func DeliveryAmount: [calculation] inputs: postedCreditSupportItems PostedCreditSupportItem (0..*) priorDeliveryAmountAdjustment Money (1..1) priorReturnAmountAdjustment Money (1..1) disputedTransferredPostedCreditSupportAmount Money (1..1) marginAmount Money (1..1) threshold Money (1..1) marginApproach MarginApproachEnum (1..1) marginAmountIA Money (0..1) minimumTransferAmount Money (1..1) rounding CollateralRounding (1..1) disputedDeliveryAmount Money (1..1) baseCurrency string (1..1) output: result Money (1..1) alias undisputedAdjustedPostedCreditSupportAmount: UndisputedAdjustedPostedCreditSupportAmount(postedCreditSupportItems, priorDeliveryAmountAdjustment, priorReturnAmountAdjustment, disputedTransferredPostedCreditSupportAmount, baseCurrency) alias creditSupportAmount: CreditSupportAmount(marginAmount, threshold, marginApproach, marginAmountIA, baseCurrency) alias deliveryAmount: Max(creditSupportAmount -> amount - undisputedAdjustedPostedCreditSupportAmount -> amount, 0.0) alias undisputedDeliveryAmount: Max(deliveryAmount - disputedDeliveryAmount -> amount, 0.0) condition CurrencyMatches: (baseCurrency = minimumTransferAmount -> unitOfAmount -> currency and (baseCurrency = disputedDeliveryAmount -> unitOfAmount -> currency)) set result -> amount: if undisputedDeliveryAmount >= minimumTransferAmount -> amount then RoundToNearest(undisputedDeliveryAmount, rounding -> deliveryAmount, RoundingModeEnum -> Up) else 0.0 set result -> unitOfAmount -> currency: baseCurrency
func ReturnAmount: [calculation] inputs: postedCreditSupportItems PostedCreditSupportItem (0..*) priorDeliveryAmountAdjustment Money (1..1) priorReturnAmountAdjustment Money (1..1) disputedTransferredPostedCreditSupportAmount Money (1..1) marginAmount Money (1..1) threshold Money (1..1) marginApproach MarginApproachEnum (1..1) marginAmountIA Money (0..1) minimumTransferAmount Money (1..1) rounding CollateralRounding (1..1) disputedReturnAmount Money (1..1) baseCurrency string (1..1) output: result Money (1..1) alias undisputedAdjustedPostedCreditSupportAmount: UndisputedAdjustedPostedCreditSupportAmount( postedCreditSupportItems, priorDeliveryAmountAdjustment, priorReturnAmountAdjustment, disputedTransferredPostedCreditSupportAmount, baseCurrency ) alias creditSupportAmount: CreditSupportAmount( marginAmount, threshold, marginApproach, marginAmountIA, baseCurrency ) alias returnAmount: Max( undisputedAdjustedPostedCreditSupportAmount -> amount - creditSupportAmount -> amount, 0.0 ) alias undisputedReturnAmount: Max( returnAmount - disputedReturnAmount -> amount, 0.0 ) condition CurrencyMatches: (baseCurrency = minimumTransferAmount -> unitOfAmount->currency) and (baseCurrency = disputedReturnAmount -> unitOfAmount->currency) set result -> amount: if undisputedReturnAmount >= minimumTransferAmount -> amount then RoundToNearest( undisputedReturnAmount, rounding -> returnAmount, RoundingModeEnum -> Down ) else 0.0 set result -> unitOfAmount->currency: baseCurrency
The CDM process model includes calculations to support the billing event consisting of the individual amounts that need to be settled in relation to a portfolio of Security Loans. These calculations leverage the FixedAmount, FloatingAmount and Day Count Fraction calculations described earlier in the documentation. A functional model is provided to populate the SecurityLendingInvoice data type following the definitions as normalised in the ISLA best practice handbook
The data type and function to generate a Security Lending Invoice:
type SecurityLendingInvoice: [rootType] [metadata key] sendingParty Party (1..1) receivingParty Party (1..1) billingStartDate date (1..1) billingEndDate date (1..1) billingRecord BillingRecord (1..*) billingSummary BillingSummary (1..*)
func Create_SecurityLendingInvoice: inputs: instruction BillingInstruction (1..1) output: invoice SecurityLendingInvoice (1..1) set invoice -> sendingParty: instruction -> sendingParty set invoice -> receivingParty: instruction -> receivingParty set invoice -> billingStartDate: instruction -> billingStartDate set invoice -> billingEndDate: instruction -> billingEndDate add invoice -> billingRecord: Create_BillingRecords( instruction -> billingRecordInstruction ) add invoice -> billingSummary: Create_BillingSummary( invoice -> billingRecord )
Lifecycle Event Process¶
While the lifecycle event model described in the Event Model provides a standardised data representation of those events using the concept of primitive event components, the CDM must further specify the processing of those events to ensure standardised implementations across the industry. This means specifying the logic of the state-transition as described by each primitive event component.
In particular, the CDM must ensure that:
The lifecycle event process model constructs valid CDM event objects.
The constructed events qualify according to the qualification logic described in the Event Qualification.
The lineage between states allows an accurate reconstruction of the trade’s lifecycle sequence.
There are three levels of function components in the CDM to define the processing of lifecycle events:
Workflow step creation
Each of those components can leverage any calculation or utility function already defined in the CDM. As part of the validation processe embedded in the CDM, an object validation step is included in all these object creation functions to ensure that they each construct valid CDM objects. Further details on the underlying calculation and validation processes are described in the Calculation Process and Validation Process.
Illustration of the three components are given in the sections below.
Primitive creation functions can be thought of as the fundamental mathematical operators that operate on a trade state. While a primitive event object describes each state transition in terms of before and after trade states, a primitive creation function defines the logic to transition from that before trade state to the after trade state, using a set of instructions.
An example of such use is captured in the reset event of an Equity Swap. The reset is processed in following steps:
1. Resolve the
Observation that contains the equity price, using specific product definition terms defined on
1. Construct a
Reset using the equity price on
Observation. In this scenario, the reset value is the equity price.
TradeState, creating a new instance of
At the end of each period in the life of the Equity Swap, the reset process will append further reset values onto the trade state. The series of equity prices then supports equity performance calculation as each reset value will represent the equity price at the end of one period and the start of the next.
These above steps are codified in the
Create_Reset function, which defines how the
Reset instance should be constructed.
func Create_Reset: inputs: instruction ResetInstruction (1..1) tradeState TradeState (1..1) output: reset TradeState (1..1) alias payout: instruction -> payout alias observationDate: if instruction -> rateRecordDate exists then instruction -> rateRecordDate else instruction -> resetDate alias observationIdentifiers: if payout -> performancePayout count = 1 then ResolvePerformanceObservationIdentifiers(payout -> performancePayout only-element, instruction -> resetDate) else if payout -> interestRatePayout exists then ResolveInterestRateObservationIdentifiers(payout -> interestRatePayout only-element, observationDate) alias observation: ResolveObservation([observationIdentifiers], empty) set reset: tradeState add reset -> resetHistory: if payout -> performancePayout count = 1 then ResolvePerformanceReset(payout -> performancePayout only-element, observation, instruction -> resetDate) else if payout -> interestRatePayout exists then ResolveInterestRateReset(payout -> interestRatePayout, observation, instruction -> resetDate, instruction -> rateRecordDate)
ResolvePerformanceObservationIdentifiers defines the specific product definition terms used to resolve
ObservationIdentifier``s. An ``ObservationIdentifier uniquely identifies an
Observation, which inside holds a single item of market data and in this scenario will hold an equity price.
Specifying precisely which attributes from
PerformancePayout should be used to resolve the equity price is important to ensure consistent equity price resolution for all model adopters.
func ResolvePerformanceObservationIdentifiers: inputs: payout PerformancePayout (1..1) adjustedDate date (1..1) output: identifiers ObservationIdentifier (1..1) alias adjustedFinalValuationDate: ResolveAdjustableDate( payout -> valuationDates -> valuationDatesFinal -> valuationDate ) alias valuationDates: if adjustedDate < adjustedFinalValuationDate then payout -> valuationDates -> valuationDatesInterim else payout -> valuationDates -> valuationDatesFinal add identifiers -> observable -> productIdentifier: payout -> underlier -> security -> productIdentifier set identifiers -> observationDate: AdjustedValuationDates( payout -> valuationDates ) filter [ item <= adjustedDate ] last set identifiers -> observationTime: ResolvePerformanceValuationTime(valuationDates -> valuationTime, valuationDates -> valuationTimeType, identifiers -> observable -> productIdentifier only-element, valuationDates -> determinationMethod ) set identifiers -> determinationMethodology -> determinationMethod: valuationDates -> determinationMethod
ResolveObservation provides an interface for adopters to integrate their market data systems. It specifies the input types and the output type, which ensures the integrity of the observed value.
func ResolveObservation: inputs: identifiers ObservationIdentifier (1..*) averagingMethod AveragingMethodEnum (0..1) output: observation Observation (1..1)
The construction of the
Reset in our scenario then becomes trivial, once the equity price has been retrieved, as the equity price and reset date are simply assigned to the corresponding attributes on the
func ResolvePerformanceReset: inputs: performancePayout PerformancePayout (1..1) observation Observation (1..1) date date (1..1) output: reset Reset (1..1) set reset -> resetValue: observation -> observedValue set reset -> resetDate: date add reset -> observations: observation
Workflow Step Creation¶
(This feature is currently being developed and will be documented upon release in the CDM)