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

.cdm-java.6.0.0-dev.72.source-code.event-common-func.rosetta Maven / Gradle / Ivy

There is a newer version: 6.0.0-dev.89
Show newest version
namespace cdm.event.common: <"Business event concepts: primitives, contract state and associated state transition function specifications.">
version "${project.version}"

import cdm.base.*
import cdm.base.math.*
import cdm.base.datetime.*
import cdm.base.staticdata.party.*
import cdm.base.staticdata.identifier.*
import cdm.base.staticdata.asset.common.*

import cdm.observable.asset.*
import cdm.observable.common.*
import cdm.observable.event.*
import cdm.product.template.*
import cdm.product.asset.*
import cdm.product.common.schedule.*
import cdm.product.common.settlement.*

import cdm.legaldocumentation.common.*
import cdm.legaldocumentation.master.*

import cdm.event.workflow.*
import cdm.event.position.*

func QuantityIncreased:
    inputs:
        before TradeState (1..1)
        after TradeState (0..*)
    output:
        result boolean (1..1)

    set result: <"Check each after (list item) is greater than before (func input).">
        after
            extract [
                CompareTradeLot(
                        item -> trade -> tradeLot only-element,
                        CompareOp -> GreaterThan,
                        before -> trade -> tradeLot only-element
                    ) = True
            ] all = True

func QuantityDecreased:
    inputs:
        before TradeState (1..1)
        after TradeState (0..*)
    output:
        result boolean (1..1)

    set result:
        after
            extract [
                // check each after (item) is less than before (input)
                CompareTradeLot(
                            item -> trade -> tradeLot only-element,
                            CompareOp -> LessThan,
                            before -> trade -> tradeLot only-element
                        ) = True
                    and // check each after (item) is greater than zero
                    CompareTradeLotToAmount(
                            item -> trade -> tradeLot only-element,
                            CompareOp -> GreaterThan,
                            0.0
                        ) = True
            ] all = True

func QuantityDecreasedToZero:
    inputs:
        before TradeState (0..*)
        after TradeState (0..*)
    output:
        result boolean (1..1)

    set result:
        CompareTradeLotToAmount(
                    before -> trade -> tradeLot only-element,
                    CompareOp -> GreaterThanOrEquals,
                    0.0
                ) = True
            and CompareTradeStatesToAmount(after, CompareOp -> Equals, 0.0) = True

func CompareTradeStatesToAmount: <"For each TradeState, compare the Quantity amounts in each TradeState to the given amount (regardless of unit of amount), based on the CompareOp enum.">
    inputs:
        tradeStates TradeState (0..*) <"List of TradeState to be compared.">
        op CompareOp (1..1) <"Comparison operation to use.">
        amount number (1..1) <"Quantity amount to use.">
    output:
        result boolean (1..1)

    set result:
        tradeStates
            extract [
                CompareTradeLotToAmount(
                        item -> trade -> tradeLot only-element,
                        op,
                        amount
                    )
            ] all = True

func TransfersForDate:
    inputs:
        transfers Transfer (0..*)
        date date (1..1)
    output:
        transfersForDate Transfer (0..*)

    add transfersForDate: transfers filter settlementDate -> adjustedDate = date

func FilterCashTransfers:
    inputs:
        transfers Transfer (0..*)
    output:
        cashTransfers Transfer (0..*)

    add cashTransfers: transfers filter quantity -> unit -> currency exists

func FilterSecurityTransfers:
    inputs:
        transfers Transfer (0..*)
    output:
        securityTransfers Transfer (0..*)

    add securityTransfers: transfers filter asset -> Instrument -> Security exists

func ResolveInterestRateObservationIdentifiers: <"Defines which attributes on the InterestRatePayout should be used to locate and resolve the underlier's price, for example for the reset process.">
    inputs:
        payout InterestRatePayout (1..1)
        date date (1..1)
    output:
        identifiers ObservationIdentifier (1..1)

    set identifiers -> observable -> Index -> FloatingRateIndex:
        payout -> rateSpecification -> FloatingRateSpecification -> rateOption
    set identifiers -> observationDate: date

// ResolveInterestRateReset is similar to ResolveEquityReset as they both only support the basic use cases for reset. Once support is added for stub periods and thus rate interpolation, the formula to derive the reset value will start to look different between the functions.
func ResolveInterestRateReset: <"Defines how to resolve the reset value for an InterestRatePayout.">
    inputs:
        payouts InterestRatePayout (1..*)
        observation Observation (1..1)
        resetDate date (1..1)
        rateRecordDate date (0..1)
    output:
        reset Reset (1..1)

    set reset -> resetValue: <"Assigns the observed value to the reset value.">
        observation -> observedValue
    set reset -> resetDate: resetDate
    set reset -> rateRecordDate: rateRecordDate
    add reset -> observations: <"Assigns the observation required to compute the rest value as audit.">
        observation

func InterestCashSettlementAmount: <"Defines the performance calculations relevent for a fixed or floating rate payout.">
    inputs:
        tradeState TradeState (1..1)
        interestRatePayout InterestRatePayout (1..1)
        resets Reset (1..*)
        date date (1..1)
    output:
        interestCashSettlementAmount Transfer (1..1)

    alias performance:
        if interestRatePayout -> rateSpecification -> FixedRateSpecification exists
        then FixedAmount(
                    interestRatePayout,
                    interestRatePayout -> priceQuantity -> quantitySchedule -> value,
                    date,
                    empty
                )
        else if interestRatePayout -> rateSpecification -> FloatingRateSpecification exists
        then FloatingAmount(
                    interestRatePayout,
                    resets only-element -> resetValue -> value,
                    interestRatePayout -> priceQuantity -> quantitySchedule -> value,
                    date,
                    empty
                )
    alias payer:
        ExtractCounterpartyByRole(
                tradeState -> trade -> counterparty,
                interestRatePayout -> payerReceiver -> payer
            ) -> partyReference
    alias receiver:
        ExtractCounterpartyByRole(
                tradeState -> trade -> counterparty,
                interestRatePayout -> payerReceiver -> receiver
            ) -> partyReference
    set interestCashSettlementAmount -> quantity -> value: performance
    set interestCashSettlementAmount -> quantity -> unit -> currency:
        interestRatePayout -> priceQuantity -> quantitySchedule -> unit -> currency
    set interestCashSettlementAmount -> payerReceiver -> payerPartyReference:
        if performance >= 0 then payer else receiver
    set interestCashSettlementAmount -> payerReceiver -> receiverPartyReference:
        if performance >= 0 then receiver else payer

    set interestCashSettlementAmount -> settlementDate -> adjustedDate: date

    set interestCashSettlementAmount -> settlementOrigin -> interestRatePayout:
        interestRatePayout as-key

func ResolveReset: <"Defines the interface for adopters to resolve a reset, given a trade state and a date.">
    inputs:
        tradeState TradeState (1..1)
        date date (1..1)
    output:
        reset Reset (1..1)

func ResolvePerformanceObservationIdentifiers: <"Defines which attributes on the PerformancePayout should be used to locate and resolve the underlier's price, for example for the reset process.">
    inputs:
        payout PerformancePayout (1..1)
        adjustedDate date (1..1)
    output:
        identifiers ObservationIdentifier (1..1)

    alias adjustedFinalValuationDate:
        ResolveAdjustableDate(
                payout -> valuationDates -> finalValuationDate -> valuationDate
            )
    alias valuationDates: <"Determine which valuation date to get valuation time and type from.">
        if adjustedDate < adjustedFinalValuationDate
        then payout -> valuationDates -> interimValuationDate
        else payout -> valuationDates -> finalValuationDate

    set identifiers -> observable: <"Represents the identifer for the equity underlier.">
        payout -> underlier -> Observable 
    set identifiers -> observationDate: <"Specifies the date for which to retrieve the market data value(s). Selects the most recent valuation date.">
        AdjustedValuationDates(payout -> valuationDates)
            filter item <= adjustedDate
            then last
    set identifiers -> observationTime: <"Specifies the time for which to retrieve the market data value(s).">
        ResolvePerformanceValuationTime(
                valuationDates -> valuationTime,
                valuationDates -> valuationTimeType,
                identifiers -> observable -> Asset ->> identifier only-element,
                valuationDates -> determinationMethod
            )
    set identifiers -> informationSource:
        payout -> observationTerms -> informationSource -> primarySource        
    set identifiers -> determinationMethodology -> determinationMethod: <"Identifies a more specific price should multiple prices for the underlier be available at the given date time, for example bid or ask prices.">
        valuationDates -> determinationMethod

func AdjustedValuationDates:
    inputs:
        valuationDates ValuationDates (1..1)
    output:
        adjustedValuationDates date (0..*)
    set adjustedValuationDates: <"Build sorted list of adjusted valuation dates.">
        [
            ResolveAdjustableDates(
                    valuationDates -> interimValuationDate -> valuationDates
                ),
            ResolveAdjustableDate(valuationDates -> finalValuationDate -> valuationDate)
        ]
            sort

func ResolvePerformanceValuationTime: <"Defines how to resolve the observation time from those specified in the Performance Valuation type.">
    inputs:
        valuationTime BusinessCenterTime (0..1) <"Represents the Equity Valuation terms from the Equity product definition.">
        valuationTimeType TimeTypeEnum (0..1) <"The time of day at which the calculation agent values the underlying, for example the official closing time of the exchange.">
        assetIdentifier AssetIdentifier (1..1) <"Specifies the asset identifier, along with the source, which should be used to determine the correct valuation time i.e. close times are different across exchanges.">
        determinationMethod DeterminationMethodEnum (1..1) <"Specifies the method according to which an amount or a date is determined.">
    output:
        time TimeZone (1..1)
    set time:
        if valuationTime exists
        then TimeZoneFromBusinessCenterTime(valuationTime)
    set time:
        if valuationTimeType exists
        then ResolveTimeZoneFromTimeType(
                    assetIdentifier,
                    valuationTimeType,
                    determinationMethod
                )

func ResolvePerformanceReset: <"Defines how to resolve the reset value for a performance payout.">
    inputs:
        performancePayout PerformancePayout (1..1) <"Represents the PerformancePayout to which the reset will apply.">
        observation Observation (1..1) <"Represents the observation that will be used to compute the reset value.">
        date date (1..1) <"Specifies the date of the reset.">
    output:
        reset Reset (1..1)
    set reset -> resetValue: <"Assigns the observed value to the reset value.">
        observation -> observedValue
    set reset -> resetDate: date
    add reset -> observations: <"Assigns the observation required to compute the rest value as audit.">
        observation

func EquityCashSettlementAmount: <"Represents Part 1 Section 12 of the 2018 ISDA CDM Equity Confirmation for Security Equity Swap, Para 72. 'Equity Cash Settlement Amount' means, in respect of an Equity Cash Settlement Date, an amount in the Settlement Currency determined by the Calculation Agent as of the Equity Valuation Date to which the Equity Cash Settlement Amount relates, pursuant to the following formula: Equity Cash Settlement Amount = ABS(Rate Of Return) * Equity Notional Amount.">
    inputs:
        tradeState TradeState (1..1)
        date date (1..1)
    output:
        equityCashSettlementAmount Transfer (1..1)

    alias equityPerformancePayout:
        tradeState -> trade -> product -> economicTerms -> payout -> performancePayout only-element
    alias equityPerformance:
        EquityPerformance(
                tradeState -> trade,
                tradeState -> resetHistory only-element -> resetValue,
                date
            )
    alias payer:
        ExtractCounterpartyByRole(
                tradeState -> trade -> counterparty,
                equityPerformancePayout -> payerReceiver -> payer
            ) -> partyReference
    alias receiver:
        ExtractCounterpartyByRole(
                tradeState -> trade -> counterparty,
                equityPerformancePayout -> payerReceiver -> receiver
            ) -> partyReference

    set equityCashSettlementAmount -> quantity -> value: <"Equity Cash Settlement Amount is defined here as Abs( Equity Performance ). Per the ISDA Definitions: Equity Performance = (Rate Of Return)  Equity Notional Amount and Equity Cash Settlement Amount = ABS(Rate Of Return)  Equity Notional Amount; so the calculation for Equity Cash Settlement Amount in the CDM is mathematically equivalent, with the added benefit that Rate of Return does not need to be recomputed, since it was already computed in the Reset Event.">
        Abs(equityPerformance)
    set equityCashSettlementAmount -> quantity -> unit -> currency: <"Does not handle the cross currency case. Only works in the case of a single trade lot.">
        ResolveEquityInitialPrice(
                tradeState -> trade -> tradeLot only-element -> priceQuantity -> price
            ) -> unit -> 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 EquityPerformance: <"Part 1 Section 12 of the 2018 ISDA CDM Equity Confirmation for Security Equity Swap, Para 75. 'Equity Performance' means, in respect of an Equity Cash Settlement Date, an amount in the Settlement Currency determined by the Calculation Agent as of the Equity Valuation Date to which the Equity Cash Settlement Amount relates, pursuant to the following formula: Equity Performance = (Rate Of Return)  Equity Notional Amount.">
    inputs:
        trade Trade (1..1)
        observation Price (1..1)
        date date (1..1)
    output:
        equityPerformance number (1..1)

    alias performancePayout:
        trade -> product -> economicTerms -> payout -> performancePayout only-element
    alias periodStartPrice: <"Only works in the case of a single trade lot.">
        ResolvePerformancePeriodStartPrice(
                performancePayout,
                trade -> tradeLot only-element -> priceQuantity -> price,
                trade -> tradeLot -> priceQuantity -> observable only-element,
                date
            )
    alias periodEndPrice: observation
    alias numberOfSecurities:
        performancePayout -> priceQuantity -> quantitySchedule -> value / periodStartPrice -> value
    alias rateOfReturn: RateOfReturn(periodStartPrice, periodEndPrice)
    alias notionalAmount: EquityNotionalAmount(numberOfSecurities, periodEndPrice)

    condition PriceReturnTermsExists:
        trade -> product -> economicTerms -> payout -> performancePayout -> returnTerms -> priceReturnTerms exists

    set equityPerformance: rateOfReturn * notionalAmount

func RateOfReturn: <"Part 1 Section 12 of the 2018 ISDA CDM Equity Confirmation for Security Equity Swap, Para 139. 'Rate Of Return' means, in respect of any Equity Valuation Date, the amount determined pursuant to the following formula: Rate Of Return = (Final Price - Initial Price) / Initial Price.">
    inputs:
        initialPrice PriceSchedule (1..1)
        finalPrice PriceSchedule (1..1)
    output:
        rateOfReturn number (1..1)

    alias initialPriceValue: initialPrice -> value
    alias finalPriceValue: finalPrice -> value
    set rateOfReturn:
        if finalPriceValue exists and initialPriceValue exists and initialPriceValue > 0
        then (finalPriceValue - initialPriceValue) / initialPriceValue

func EquityNotionalAmount: <"Part 1 Section 12 of the 2018 ISDA CDM Equity Confirmation for Security Equity Swap, Para 74. 'Equity Notional Amount' means the Number Of Securities times the Initial Price, adjusted, if applicable, as provided in Part 1 Section 2.2, 'Equity Notional Reset'. If 'With Reset' is the Equity Notional Reset Election, then in respect of each Equity Cash Settlement Date: (i) the Equity Notional Amount applicable in respect of the first Equity Cash Settlement Date will be the amount specified as such in the definition of Equity Notional Amount; (ii) the Equity Notional Amount applicable in respect of each subsequent Equity Cash Settlement Date will be the sum of (a) the Equity Notional Amount in respect of the prior Equity Cash Settlement Date and (b) the Equity Performance, whether positive or negative, in respect of the prior Equity Cash Settlement Date; and (iii)	the Floating Notional Amount will be adjusted as provided in sub-clauses (i) and (ii) above as though it were an Equity Notional Amount.">
    inputs:
        numberOfSecurities number (1..1)
        price Price (1..1)
    output:
        equityNotionalAmount number (1..1)
    alias priceValue: price -> value
    set equityNotionalAmount: numberOfSecurities * priceValue

func Create_StockSplit: <"Function specification to create the fully-formed business event which represents the impact of a stock split (or a reverse stock split) on an Equity Derivatives contract on a certain date.">
    inputs:
        stockSplitInstruction StockSplitInstruction (1..1)
        before TradeState (1..1)
    output:
        after TradeState (1..1)

    alias preSplitNumberOfShares: <"Only works in the case of a single trade lot.">
        FilterQuantityByFinancialUnit(
                before -> trade -> tradeLot only-element -> priceQuantity -> quantity,
                FinancialUnitEnum -> Share
            )
            only-element -> value
    alias postSplitNumberOfShares: <"The adjustment ratio is be multiplied by existing shares in an equity derivative contract or other positions to determine the post-split number of shares.">
        NonNegativeQuantitySchedule {
            value: preSplitNumberOfShares * stockSplitInstruction -> adjustmentRatio,
            unit: UnitType {
                    financialUnit: FinancialUnitEnum -> Share,
                    ...
                },
            ...
        }
    alias preSplitPrice:
        before -> trade -> tradeLot -> priceQuantity -> price
            filter perUnitOf -> financialUnit = FinancialUnitEnum -> Share
            then only-element
    alias postSplitPrice: <"The pre-split price is divided by the adjustment ratio to determine the post-split price.">
        Price {
            value: preSplitPrice -> value / stockSplitInstruction -> adjustmentRatio,
            unit: preSplitPrice -> unit,
            perUnitOf: preSplitPrice -> perUnitOf,
            priceType: preSplitPrice -> priceType,
            priceExpression: preSplitPrice -> priceExpression,
            composite: preSplitPrice -> composite,
            arithmeticOperator: preSplitPrice -> arithmeticOperator,
            cashPrice: preSplitPrice -> cashPrice,
            datedValue: empty
        }
    alias postSplitPriceQuantity:
        PriceQuantity {
            price: postSplitPrice,
            quantity: postSplitNumberOfShares,
            ...
        }
    alias quantityChangeInstruction:
        QuantityChangeInstruction {
            change: postSplitPriceQuantity,
            direction: QuantityChangeDirectionEnum -> Replace,
            lotIdentifier: empty
        }
    alias primitiveInstruction:
        PrimitiveInstruction {
            quantityChange: quantityChangeInstruction,
            ...
        }
    set after: Create_TradeState(primitiveInstruction, before)

func Create_Execution: <"Specifies the function to compose an execution based on a minimum required set of inputs: product, quantity, parties, etc.">
    inputs:
        instruction ExecutionInstruction (1..1) <"Instructions to be used as an input to the function">
    output:
        execution TradeState (1..1) <"Execution primitive event with absent before state and an after state containing the tradable product, parties, associated party roles and the known settlement terms.">
    set execution -> trade -> product: <"Assign the product input to the tradable product of the execution object.">
        instruction -> product
    add execution -> trade -> tradeLot: <"Assign the prices and quantities and lot identifier input to the tradable product of the execution object.">
        TradeLot {
            priceQuantity: instruction -> priceQuantity,
            lotIdentifier: instruction -> lotIdentifier
        }

    add execution -> trade -> counterparty: <"Assign the counterparty input to the tradable product of the execution object.">
        instruction -> counterparty
    add execution -> trade -> ancillaryParty: <"Assign the ancillaryRole input to the tradable product of the execution object.">
        instruction -> ancillaryParty
    add execution -> trade -> party: <"Assign the parties input to the execution object.">
        instruction -> parties
    add execution -> trade -> partyRole: <"Assign the party roles input to the execution object.">
        instruction -> partyRoles
    set execution -> trade -> executionDetails: <"Assign the settlement terms input to the execution object.">
        instruction -> executionDetails
    set execution -> trade -> tradeDate: <"Assign the tradeDate input to the execution object.">
        instruction -> tradeDate
    add execution -> trade -> tradeIdentifier: <"Assign the identifier input to the execution object.">
        instruction -> tradeIdentifier
    set execution -> state -> positionState: <"Assign the position status to executed.">
        PositionStatusEnum -> Executed
    set execution -> trade -> collateral: <"Assign the anticpated collateral details to the tradable product of the excution object.">
        instruction -> collateral

func Create_ContractFormationInstruction:
    inputs:
        legalAgreement LegalAgreement (0..*)
    output:
        instruction ContractFormationInstruction (1..1)
    condition ExecutedAgreement: <"The full formation of a contract can only be completed with executed legal agreements if any.">
        if legalAgreement exists
        then legalAgreement -> agreementDate exists

    add instruction -> legalAgreement: legalAgreement

func Create_ContractFormation: <"Function specification that represents an executed trade for a contractual product that has been affirmed (or confirmed) by the two parties. The formed contract can reference a legal agreement for instance a master agreement, by using the optional legalAgreement input.">
    inputs:
        instruction ContractFormationInstruction (1..1) <"Instructions to be used as an input to the function">
        execution TradeState (1..1)
    output:
        contractFormation TradeState (1..1) <"Primitive event containing the execution as its before state and the contract as the after state.">

    set contractFormation: execution
    add contractFormation -> trade -> contractDetails -> documentation: <"Append any legal agreements from the instructions.">
        instruction -> legalAgreement
    set contractFormation -> state -> positionState: <"Assign the position status to formed.">
        PositionStatusEnum -> Formed

func Create_Exercise: <"Defines the process of putting into effect the rights specified in an options contract, such as to buy or sell a security.  Once exercised the option contract is terminated.">
    inputs:
        exerciseInstruction ExerciseInstruction (1..1) <"Instruction containing the terms of the option exercise.">
        originalTrade TradeState (1..1) <"The original trade to be split, which must be of single cardinality.">
    output:
        exercise TradeState (1..*)

    alias optionPayout: <"Extracts the optionPayout from exerciseInstruction if provided or from the original trade if absent">
        if exerciseInstruction -> exerciseOption exists
        then exerciseInstruction -> exerciseOption
        else originalTrade -> trade -> product -> economicTerms -> payout -> optionPayout only-element

    alias underlier: <"Extracts the underlying financial product, upon which the option decision is contingent. Requires that the original contract contains an option payout that contains an Observable or a Product as the underlier.">
        optionPayout -> underlier 

    alias resultProduct:  <"Find or create the the non transferable product that will result from the exercise.">
        if underlier -> Product -> NonTransferableProduct exists // It already exists, no need to create
        then underlier -> Product -> NonTransferableProduct
        else Create_NonTransferableProduct(underlier, optionPayout -> payerReceiver)

    alias productWithDirection:  <"If the option is a Put, then the direction on the result product needs to be flipped from that on the underlier.">
        if optionPayout -> optionType = OptionTypeEnum -> Put
        then Update_ProductDirection(resultProduct, optionPayout -> payerReceiver -> payer, optionPayout -> payerReceiver -> receiver)
        else resultProduct

    alias execution: <"Creates the execution primitive describing the exchange of the underlying product, either as a cash transfer or as the formation of a new contractual product between parties.">
        Create_Execution(
                ExecutionInstruction {
                    product: productWithDirection,
                    priceQuantity: originalTrade -> trade -> tradeLot only-element -> priceQuantity,
                    counterparty: originalTrade -> trade -> counterparty,
                    ancillaryParty: originalTrade -> trade -> ancillaryParty,
                    parties: originalTrade -> trade -> party,
                    partyRoles: originalTrade -> trade -> partyRole,
                    executionDetails: empty,
                    tradeDate: originalTrade -> trade -> tradeDate,
                    tradeIdentifier: exerciseInstruction -> replacementTradeIdentifier,
                    ...
                }
            )

    condition OptionPayoutExists: <"Requires that the original contract contains an option payout.">
        optionPayout exists

    add exercise: <"Reduces notional / quantity of option by the amount exercised.">
        Create_TradeState(exerciseInstruction -> exerciseQuantity, originalTrade)

    add exercise: <"Adds the replacement trade">
        execution

func Update_ProductDirection:  <"Flips the payer and receiver on a product (used when a Put Option is exercised).">
    inputs:
        before NonTransferableProduct (1..1)
        originalPayer CounterpartyRoleEnum (1..1)
        originalReceiver CounterpartyRoleEnum (1..1) 
    output:
        after NonTransferableProduct (1..1)
    
    set after: before
    set after -> economicTerms -> payout -> optionPayout -> payerReceiver -> payer: originalReceiver
    set after -> economicTerms -> payout -> optionPayout -> payerReceiver -> receiver: originalPayer 

func Create_NonTransferableProduct:  <"Creates a NonTransferableProduct (ie EconomicTerms) from an underlier.">
    inputs:
        underlier Underlier (1..1)
        payerReceiver PayerReceiver (1..1)
    output:
        newProduct NonTransferableProduct (1..1)

    set newProduct -> economicTerms -> payout -> settlementPayout -> underlier: underlier
    set newProduct -> economicTerms -> payout -> settlementPayout -> payerReceiver: payerReceiver
    
func Create_Reset: <"Defines how a Reset should be constructed.">
    inputs:
        instruction ResetInstruction (1..1) <"Specifies the reset instructions.">
        tradeState TradeState (1..1) <"Specifies the trade that is resetting.">
    output:
        reset TradeState (1..1)

    alias payout: <"Specifies the payout that is resetting.">
        instruction -> payout

    alias observationDate: <"If the rateRecordDate is provided in the instructions, it should used as the observation date when determining the fixing rate for an interest rate payout.">
        if instruction -> rateRecordDate exists
        then instruction -> rateRecordDate
        else instruction -> resetDate

    alias observationIdentifiers: <"Resolves the ObservationIdentifier to be used to derive the single observation to be used in the reset calculation. Resolving the ObservationIdentifier is dependent on the type of payout in use.">
        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: <"Represents the single observation that will be used to compute the reset value.">
        ResolveObservation([observationIdentifiers], empty)

    set reset: tradeState

    add reset -> resetHistory: <"To handle the various ways Contracts can change over time, ">
        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
                )

func CalculateTransfer: <"Function specification to calculate a transfer, e.g. following a reset on a contract">
    inputs:
        instruction CalculateTransferInstruction (1..1)
    output:
        transfer Transfer (0..*)

    add transfer: <"Assigns the result of the Create_Transfer function to the transferHistory attribute.">
        if instruction -> payout -> interestRatePayout exists
                or instruction -> payout -> performancePayout exists
                or instruction -> payout -> assetPayout exists
        then Create_CashTransfer(instruction)

    add transfer: <"Assigns the result of the Create_AssetTransfer function to the transferHistory attribute.">
        if instruction -> payout -> assetPayout exists
        then Create_AssetTransfer(instruction)

func Create_Transfer: <"Defines how a transfer should be constructed, when representing the exchange of cash between parties.">
    [docReference ICMA GMRA namingConvention "Purchase Price"
        provision "As defined in the GMRA, paragraph 2(nn) The Purchase Price is the price at which the Purchased Securities are sold or are to be sold by Seller to Buyer."]
    [docReference ICMA ERCCBestPractice namingConvention "Purchase Price"
        provision "ERCC Guide: Annex II  Glossary of repo terminology. The term for the sum of money paid by the Buyer to the Seller on the Purchase Date of a repo. It is equal to the initial Market Value of the collateral less any haircut or initial margin (called Margin Ratio in the GMRA)."]
    inputs:
        instruction TransferInstruction (1..1)
        tradeState TradeState (1..1) <"Represents the trade and associated state on which to construct the Transfer data type.">
    output:
        transfer TradeState (1..1)

    set transfer: tradeState

    add transfer -> transferHistory: <"Assigns the transfer contained in the transfer instruction to the transferHistory attribute.">
        instruction -> transferState

func Create_CashTransfer: <"Defines how Transfer that represents an exchange of cash, should be constructed.">
    inputs:
        instruction CalculateTransferInstruction (1..1)
    output:
        transfer Transfer (1..1)

    set transfer: <"Resolves the cashflow due to be transferred from the trade and associated state.">
        ResolveTransfer(instruction)

func Create_AssetTransfer: <"Defines how Transfer that represents an exchange of asset based on an asset payout, should be constructed.">
    inputs:
        instruction CalculateTransferInstruction (1..1)
    output:
        transfer Transfer (1..1)

    alias assetPayout:
        instruction -> tradeState -> trade -> product -> economicTerms -> payout -> assetPayout only-element

    alias tradeQuantity: <"Security quantity obtained by filtering on the trade quantity">
        FilterQuantityByFinancialUnit(
                instruction -> tradeState -> trade -> tradeLot -> priceQuantity -> quantity,
                FinancialUnitEnum -> Share
            )
            only-element

    alias securityQuantity:
        if instruction -> quantity exists
        then instruction -> quantity
        else NonNegativeQuantity {
            value: tradeQuantity -> value,
            unit: tradeQuantity -> unit,
            ...
        }

    alias securityPrice:
        FilterPrice(
                instruction -> tradeState -> trade -> tradeLot -> priceQuantity -> price,
                PriceTypeEnum -> AssetPrice,
                empty,
                empty
            )

    condition ShareUnits:
        if instruction -> quantity exists
        then instruction -> quantity -> unit -> financialUnit = FinancialUnitEnum -> Share

    set transfer -> quantity:
        NonNegativeQuantity {
            value: securityQuantity -> value,
            unit: securityQuantity -> unit,
            ...
        }

    add transfer -> asset -> Instrument -> Security  -> identifier:
        assetPayout -> underlier ->> identifier

    set transfer -> payerReceiver -> payerPartyReference:
        if instruction -> payerReceiver -> payer exists
        then ExtractCounterpartyByRole(
                    instruction -> tradeState -> trade -> counterparty,
                    instruction -> payerReceiver -> payer
                ) -> partyReference
        else if assetPayout -> payerReceiver -> payer exists
        then ExtractCounterpartyByRole(
                    instruction -> tradeState -> trade -> counterparty,
                    assetPayout -> payerReceiver -> payer
                ) -> partyReference

    set transfer -> payerReceiver -> receiverPartyReference:
        if instruction -> payerReceiver -> payer exists
        then ExtractCounterpartyByRole(
                    instruction -> tradeState -> trade -> counterparty,
                    instruction -> payerReceiver -> receiver
                ) -> partyReference
        else if assetPayout -> payerReceiver -> receiver exists
        then ExtractCounterpartyByRole(
                    instruction -> tradeState -> trade -> counterparty,
                    assetPayout -> payerReceiver -> receiver
                ) -> partyReference

    set transfer -> settlementDate -> adjustedDate: instruction -> date

    set transfer -> settlementOrigin -> assetPayout:
        if instruction -> tradeState -> trade -> product -> economicTerms -> payout -> assetPayout exists
        then instruction -> tradeState -> trade -> product -> economicTerms -> payout -> assetPayout only-element
            as-key

func ResolveTransfer: <"Defines how to calculate the amount due to be transferred after a Reset Event.">
    inputs:
        instruction CalculateTransferInstruction (1..1)
    output:
        transfer Transfer (1..1)
    alias payout: instruction -> payout
    set transfer:
        if payout -> assetPayout exists
        then SecurityFinanceCashSettlementAmount(
                    instruction -> tradeState,
                    instruction -> date,
                    instruction -> quantity,
                    instruction -> payerReceiver
                )
        else if payout -> performancePayout exists
        then EquityCashSettlementAmount(instruction -> tradeState, instruction -> date)
        else if payout -> interestRatePayout -> rateSpecification -> FloatingRateSpecification exists
                or payout -> interestRatePayout -> rateSpecification -> FixedRateSpecification exists
        then InterestCashSettlementAmount(
                    instruction -> tradeState,
                    payout -> interestRatePayout only-element,
                    instruction -> resets,
                    instruction -> date
                )
    set transfer -> settlementDate -> adjustedDate: instruction -> date

func ResolveCashSettlementDate: <"A product agnostic function that resolves the settlement date of the payout for the period in question">
    inputs:
        tradeState TradeState (1..1)
    output:
        date date (1..1)

func SecurityFinanceCashSettlementAmount:
    [docReference ICMA GMRA namingConvention "Repurchase Price"
        provision "As defined in GMRA paragraph 2(rr) The Repurchase Price is the sum of Purchase Price and Price Differential."]
    [docReference ICMA ERCCBestPractice namingConvention "Repurchase Price"
        provision "ERCC Guide: Annex II  Glossary of repo terminology. The term for the sum of money to be paid by the Seller of a repo to the Buyer on the Repurchase Date to buy back equivalent collateral. It is equal to the Purchase Price plus repo interest. This term also applies to the value of the cash owed to the Buyer on any day during the term of a repo, that is, the Purchase Price plus repo interest accrued up to that particular date. In the case of Buy/Sell-Backs, the Repurchase Price is net of the amount of any coupon, dividend or other income on the collateral paid to the Buyer during the life of the transaction plus reinvestment income to compensate for the delayed payment."]
    inputs:
        tradeState TradeState (1..1)
        date date (1..1)
        quantity Quantity (0..1) <"Specifies quantity amount returned if not the full amount from the TradeState, e.g. partial return">
        payerReceiver PayerReceiver (0..1)
    output:
        cashSettlementAmount Transfer (1..1)

    alias assetPayout:
        tradeState -> trade -> product -> economicTerms -> payout -> assetPayout only-element

    alias collateral:
        tradeState -> trade -> product -> economicTerms -> collateral

    alias securityQuantity: <"Specifies the number of securities.">
        if quantity exists
        then quantity
        else FilterQuantityByFinancialUnit(
                tradeState -> trade -> tradeLot -> priceQuantity -> quantity,
                FinancialUnitEnum -> Share
            )

    alias securityPrice: <"Specifies the price per security.">
        FilterPrice(
                tradeState -> trade -> tradeLot -> priceQuantity -> price,
                PriceTypeEnum -> AssetPrice,
                empty,
                empty
            )

    alias marginRatio:
        if collateral -> collateralProvisions -> eligibleCollateral only-element -> treatment -> valuationTreatment -> haircutPercentage exists
        then 1 / (1.0 - collateral -> collateralProvisions -> eligibleCollateral only-element -> treatment -> valuationTreatment -> haircutPercentage)
        else if collateral -> collateralProvisions -> eligibleCollateral only-element -> treatment -> valuationTreatment -> marginPercentage exists
        then collateral -> collateralProvisions -> eligibleCollateral only-element -> treatment -> valuationTreatment -> marginPercentage
        else 1.0

    condition ShareUnitExists:
        if quantity exists
        then quantity -> unit -> financialUnit = FinancialUnitEnum -> Share

    condition IdentifiersMatch:
        tradeState -> trade -> tradeLot -> priceQuantity -> observable -> Asset ->> identifier = assetPayout -> underlier ->> identifier

    set cashSettlementAmount -> quantity -> value:
        securityPrice -> value * securityQuantity -> value * marginRatio

    set cashSettlementAmount -> quantity -> unit -> currency:
        securityPrice -> unit -> currency

    set cashSettlementAmount -> payerReceiver -> payerPartyReference:
        if payerReceiver exists
        then ExtractCounterpartyByRole(
                    tradeState -> trade -> counterparty,
                    payerReceiver -> receiver
                ) -> partyReference
        else if assetPayout -> payerReceiver -> receiver exists
        then ExtractCounterpartyByRole(
                    tradeState -> trade ->  counterparty,
                    assetPayout -> payerReceiver -> receiver
                ) -> partyReference

    set cashSettlementAmount -> payerReceiver -> receiverPartyReference:
        if payerReceiver exists
        then ExtractCounterpartyByRole(
                    tradeState -> trade -> counterparty,
                    payerReceiver -> payer
                ) -> partyReference
        else if assetPayout -> payerReceiver -> payer exists
        then ExtractCounterpartyByRole(
                    tradeState -> trade -> counterparty,
                    assetPayout -> payerReceiver -> payer
                ) -> partyReference

    set cashSettlementAmount -> settlementDate -> adjustedDate: date

    set cashSettlementAmount -> settlementOrigin -> assetPayout: assetPayout as-key

func Create_Split: <"Defines the logic for splitting a trade into separate copies. The split instruction contains a breakdown into N set of primitive instructions. Each set contains the primitive instructions to be applied to each post-split trade, eventually producing N trades. The split function underpins a number of business events such as clearing or allocation.">
    inputs:
        breakdown PrimitiveInstruction (1..*) <"Each primitive instruction contains the set of instructions to be applied to each post-split trade.">
        originalTrade TradeState (1..1) <"The original trade to be split, which must be of single cardinality.">
    output:
        splitTrade TradeState (1..*)

    add splitTrade: <"Iterate over each breakdown and apply the set of primitive instructions to each copy of the original trade.">
        breakdown extract Create_TradeState(item, originalTrade)

func Create_PartyChange: <"Defines the logic for changing one of the counterparties on a trade. A new trade identifier must be specified as a change of party results in a new trade. An ancillary party can also be specified, for instance to refer to the original executing party on the new trade.">
    inputs:
        counterparty Counterparty (1..1) <"The counterparty to change and the role it plays in the transaction.">
        ancillaryParty AncillaryParty (0..1) <"Optional ancillary party, which can be used to keep a reference to the original executing party, for instance.">
        partyRole PartyRole (0..1)
        tradeId TradeIdentifier (1..*) <"A mandatory trade identifier must be specified, as the chnage of party results in a new trade.">
        originalTrade TradeState (1..1) <"The original trade on which to update the counterparty. The original trade will be terminated.">
    output:
        newTrade TradeState (1..1)

    alias counterparty1:
        if counterparty -> role = CounterpartyRoleEnum -> Party1
        then Counterparty {
                partyReference: counterparty -> partyReference as-key,
                role: counterparty -> role
            }
        else ExtractCounterpartyByRole(
                originalTrade -> trade -> counterparty,
                CounterpartyRoleEnum -> Party1
            )
    alias counterparty2:
        if counterparty -> role = CounterpartyRoleEnum -> Party2
        then Counterparty {
                partyReference: counterparty -> partyReference as-key,
                role: counterparty -> role
            }
        else ExtractCounterpartyByRole(
                originalTrade -> trade -> counterparty,
                CounterpartyRoleEnum -> Party2
            )
    alias partyToRemove:
        ExtractCounterpartyByRole(
                originalTrade -> trade -> counterparty,
                counterparty -> role
            ) -> partyReference

    set newTrade: <"Copy the original trade.">
        originalTrade
    set newTrade -> trade -> counterparty: <"Assigns the new counterparties.">
        [counterparty1, counterparty2]
    set newTrade -> trade -> party: <"Removes the existing party, and adds the new party.">
        ReplaceParty(
                originalTrade -> trade -> party,
                partyToRemove,
                counterparty -> partyReference
            )
    set newTrade -> trade -> tradeIdentifier: <"Replaces the existing trade identifier with the new trade identifier">
        tradeId
    add newTrade -> trade -> party: <"Add ancillary party as an additional party">
        ancillaryParty -> partyReference
    add newTrade -> trade -> ancillaryParty: <"Add ancillary party role">
        ancillaryParty
    add newTrade -> trade -> party: <"Add party role party reference as an additional party">
        partyRole -> partyReference
    add newTrade -> trade -> partyRole: <"Add party role">
        partyRole
    set newTrade -> transferHistory: <"Clear transfer history.">
        EmptyTransferHistory()

func EmptyTransferHistory:
    output:
        emptyTransferHistory TransferState (0..*)

func Create_QuantityChange: <"A specification of the inputs, outputs and constraints when calculating the after state of a Quantity Change Primitive Event">
    inputs:
        instruction QuantityChangeInstruction (1..1)
        tradeState TradeState (1..1)
    output:
        quantityChange TradeState (1..1)

    alias trade: <"The Trade from the input TradeState">
        tradeState -> trade 

    alias tradeLotExists: <"The quantity change instruction applies to an existing tradeLot">
        FilterTradeLot(trade -> tradeLot, instruction -> lotIdentifier) exists

    alias tradeLot: <"Get the existing trade lot if specified, or return only trade lot">
        if tradeLotExists
        then FilterTradeLot(trade -> tradeLot, instruction -> lotIdentifier)
        else trade -> tradeLot only-element

    alias newPriceQuantity: <"Update the PriceQuantity based on the change and direction inputs. For an increase, if the trade lot exists, apply the changes to the existing PriceQuantity; otherwise, add the changed PriceQuantity to the list of TradeLots. For a decrease or replace, apply the changes to the existing PriceQuantity.">
        if instruction -> direction = QuantityChangeDirectionEnum -> Increase
                and tradeLotExists = False
        then instruction -> change
        else UpdateAmountForEachMatchingQuantity(
                tradeLot -> priceQuantity,
                instruction -> change,
                instruction -> direction
            )

    alias newTradeLots: <"Add or merge updated TradeLot.">
        if instruction -> direction = QuantityChangeDirectionEnum -> Increase
                and tradeLotExists = False
        then AddTradeLot(
                    trade,
                    TradeLot {
                        lotIdentifier: instruction -> lotIdentifier,
                        priceQuantity: newPriceQuantity
                    }
                ) -> tradeLot
        else ReplaceTradeLot(
                trade -> tradeLot,
                TradeLot {
                    lotIdentifier: instruction -> lotIdentifier,
                    priceQuantity: newPriceQuantity
                }
            )

    condition CashPriceOnly: <"Only termination where the termination price is specified as a cash price is supported for now.">
        if instruction -> direction = QuantityChangeDirectionEnum -> Decrease
                and instruction -> change -> price exists
        then instruction -> change -> price -> priceType all = PriceTypeEnum -> CashPrice

    set quantityChange: tradeState

    // Update trade with new TradableProduct.
    set quantityChange -> trade -> product: trade -> product
    set quantityChange -> trade -> tradeLot: newTradeLots  
    set quantityChange -> trade -> counterparty: trade -> counterparty
    set quantityChange -> trade -> ancillaryParty: trade -> ancillaryParty
    set quantityChange -> trade -> adjustment: trade -> adjustment

    set quantityChange -> state -> positionState:
        if newTradeLots -> priceQuantity -> quantity -> value all = 0
        then PositionStatusEnum -> Closed

func Create_TermsChange: <"A specification of the inputs, outputs and constraints when calculating the after tradeState based Terms Change Primitive Instruction.">
    inputs:
        termsChange TermsChangeInstruction (1..1) <"Instructions to be used as an input to the function">
        before TradeState (1..1) <"current trade to be ammended">
    output:
        tradeState TradeState (1..1)

    alias newProduct:
        if termsChange -> product exists
        then termsChange -> product
        else before -> trade -> product

    alias newAncillaryParty:
        if termsChange -> ancillaryParty exists
        then termsChange -> ancillaryParty
        else before -> trade -> ancillaryParty

    alias newAdjustment:
        if termsChange -> adjustment exists
        then termsChange -> adjustment
        else before -> trade -> adjustment

    set tradeState: before

    // Contract to be updated based on the new terms change inputs.
    set tradeState -> trade -> product: newProduct
    set tradeState -> trade -> tradeLot: tradeState -> trade -> tradeLot
    set tradeState -> trade -> counterparty: tradeState -> trade -> counterparty
    set tradeState -> trade -> ancillaryParty: newAncillaryParty
    set tradeState -> trade -> adjustment: newAdjustment

func FilterOpenTradeStates: <"Filter to only 'open' TradeState - where both the closedState and positionState are not set.">
    inputs:
        tradeStates TradeState (0..*)
    output:
        openTradeStates TradeState (0..*)

    add openTradeStates: tradeStates filter state -> closedState is absent

func FilterClosedTradeStates: <"Filter to only 'closed' TradeState - where either the closedState or positionState are set.">
    inputs:
        tradeStates TradeState (0..*)
    output:
        closedTradeStates TradeState (0..*)

    add closedTradeStates: tradeStates filter state -> closedState exists

func NewEquitySwapProduct: <"Function specification to create an Equity Swap according to the 2018 ISDA CDM Equity Confirmation Template, based on a minimum set of inputs which can (optionally) include a Master Confirmation Agreement. The inputs represent the minimum set of inputs required to create an Equity Swap, either based on an existing Master Confirmation Agreement or as a stand-alone Equity Swap">
    inputs:
        security Security (1..1) <"The underlying Equity asset for the swap.">
        masterConfirmation EquitySwapMasterConfirmation2018 (0..1) <"An (optional) pointer to the Master Confirmation Agreement, if any, that holds further inputs to the Equity Swap">
    // performancePayout PerformancePayout (1..1)
    output:
        product NonTransferableProduct (1..1)

    alias payout: product -> economicTerms -> payout

//	condition PriceReturnTermsOnlyExists:  performancePayout -> returnTerms -> priceReturnTerms only exists
    condition EquitySecurityType: <"Security must be equity (single name).">
        security -> securityType = SecurityTypeEnum -> Equity

    add payout -> performancePayout:
        NewSingleNameEquityPerformancePayout(security, masterConfirmation)
    add payout -> interestRatePayout: <"Equity and interest rate payouts must be set-up according to their corresponding payout specifications">
        if masterConfirmation exists
        then NewFloatingPayout(masterConfirmation)

    post-condition PayoutType: <"Other payout types must be absent.">
        if masterConfirmation is absent
        then payout -> interestRatePayout is absent
                and payout -> cashflow is absent
                and payout -> creditDefaultPayout is absent
                and payout -> settlementPayout is absent
                and payout -> fixedPricePayout is absent
                and payout -> optionPayout is absent

func NewSingleNameEquityPerformancePayout: <"Function specification to create the equity payout part of an Equity Swap according to the 2018 ISDA CDM Equity Confirmation template.">
    inputs:
        security Security (1..1)
        masterConfirmation EquitySwapMasterConfirmation2018 (0..1)
    output:
        performancePayout PerformancePayout (1..1)

    condition EquitySecurityType: <"Security must be equity (single name).">
        security -> securityType = SecurityTypeEnum -> Equity

    set performancePayout -> returnTerms -> priceReturnTerms -> returnType: <"Equity payout must inherit terms from the Master Confirmation Agreement.">
        // if masterConfirmation -> typeOfSwapElection -> Price exists
        // or masterConfirmation -> typeOfSwapElection -> Total exists then
        masterConfirmation -> typeOfSwapElection

    set performancePayout -> valuationDates: <"Equity payout must inherit terms from the Master Confirmation Agreement.">
        masterConfirmation -> valuationDates
    set performancePayout -> paymentDates: <"Equity payout must inherit terms from the Master Confirmation Agreement.">
        masterConfirmation -> equityCashSettlementDates
    set performancePayout -> settlementTerms: <"Equity payout must inherit terms from the Master Confirmation Agreement.">
        masterConfirmation -> settlementTerms

func NewFloatingPayout: <"Function specification to create the interest rate (floating) payout part of an Equity Swap according to the 2018 ISDA CDM Equity Confirmation template.">
    inputs:
        masterConfirmation EquitySwapMasterConfirmation2018 (0..1)
    output:
        interestRatePayout InterestRatePayout (1..1)

    post-condition InterestRatePayoutTerms: <"Interest rate payout must inherit terms from the Master Confirmation Agreement when it exists.">
        if masterConfirmation exists
        then // interestRatePayout -> calculationPeriodDates = masterConfirmation -> equityCalculationPeriod and
            interestRatePayout -> paymentDates = masterConfirmation -> equityCashSettlementDates

func Create_IndexTransitionTermsChange: <"Function specification to create a terms change that contains changes to the floating rate indexes and adds an adjustment spread to any existing spread.">
    inputs:
        instruction IndexTransitionInstruction (1..1) <"Specifies the instructions containing the floating rate index, spread adjustment for each leg to be updated, and the effective date.">
        tradeState TradeState (1..1) <"Specifies the trade to be updated.">
    output:
        termsChange TradeState (1..1) <"Specifies the resulting term change.">

    set termsChange: <"Updates the trade based on each instruction priceQuantity (e.g. one for each floating rate leg).">
        UpdateSpreadAdjustmentAndRateOptions(tradeState, instruction -> priceQuantity)

func Create_Observation: <"Function specification to create an observation that incorporates an observation event into the observation history of a given trade state.">
    inputs:
        instruction ObservationInstruction (1..1)
        before TradeState (1..1) <"Specifies the trade to be updated.">
    output:
        after TradeState (1..1) <"Specifies the resulting trade state incorporating the observation event in the observation history.">

    set after: before
    add after -> observationHistory: instruction -> observationEvent

func Create_Valuation: <"Function specification to incorporate a new assessment of the valuation in the valuation history of a given trade state.">
    inputs:
        instruction ValuationInstruction (1..1)
        before TradeState (1..1) <"Specifies the trade to be updated.">
    output:
        after TradeState (1..1) <"Specifies the resulting trade state incorporating the valuation update in the valuation history.">

    alias beforeValuationHistory:
        if instruction -> replace = True
        then []
        else before -> valuationHistory

    set after: before

    set after -> valuationHistory: beforeValuationHistory

    add after -> valuationHistory: instruction -> valuation

func UpdateSpreadAdjustmentAndRateOptions: <"For each of the trade state's price quantity, find a matching price quantity instruction, and call the update function.">
    inputs:
        tradeState TradeState (1..1) <"Specifies the trade to be updated.">
        instructions PriceQuantity (1..*) <"List of PriceQuantity from the IndexTransitionInstruction (e.g. one for each floating rate leg).">
    output:
        updatedTradeState TradeState (1..1) <"Specifies the updated trade.">

    set updatedTradeState: tradeState

    set updatedTradeState -> trade -> tradeLot -> priceQuantity:
        tradeState -> trade -> tradeLot only-element -> priceQuantity
            extract
                UpdateIndexTransitionPriceAndRateOption(
                        item,
                        FindMatchingIndexTransitionInstruction(instructions, item)
                    )

func UpdateIndexTransitionPriceAndRateOption:
    inputs:
        priceQuantity PriceQuantity (1..1)
        instruction PriceQuantity (0..1)
    output:
        updatedPriceQuantity PriceQuantity (1..1)

    set updatedPriceQuantity: priceQuantity

    set updatedPriceQuantity -> price -> value: <"If instruction exists, sum the existing and instruction spread adjustments.">
        if instruction exists
        then priceQuantity -> price only-element -> value + instruction -> price only-element -> value
        else priceQuantity -> price only-element -> value

    set updatedPriceQuantity -> observable -> Index -> FloatingRateIndex: <"If instruction exists, update the rate option.">
        if instruction exists
        then instruction -> observable -> Index -> FloatingRateIndex
        else priceQuantity -> observable -> Index -> FloatingRateIndex

func FindMatchingIndexTransitionInstruction:
    inputs:
        instructions PriceQuantity (1..*)
        priceQuantity PriceQuantity (1..1)
    output:
        matchingInstruction PriceQuantity (0..1)

    set matchingInstruction:
        instructions
            filter
                // indexTenor period matches
                observable -> Index -> FloatingRateIndex ->> indexTenor -> period = priceQuantity -> observable -> Index -> FloatingRateIndex ->> indexTenor -> period
                        // indexTenor periodMultiplier matches
                    and observable -> Index -> FloatingRateIndex ->> indexTenor -> periodMultiplier = priceQuantity -> observable -> Index -> FloatingRateIndex ->> indexTenor -> periodMultiplier
                        // quantity currency or price currency matches
                    and (quantity -> unit -> currency = priceQuantity -> quantity -> unit -> currency
                        or price -> unit -> currency = priceQuantity -> price -> unit -> currency)
            then first

func Create_SecurityLendingInvoice: <"Defines the process of calculating and creating a Security Lending Invoice.">
    inputs:
        instruction BillingInstruction (1..1) <"Specifies the instructions for creation of a Security Lending billing invoice.">
    output:
        invoice SecurityLendingInvoice (1..1) <"Produces the Security Lending Invoice">

    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)

func Create_BillingRecords: <"Creates for each billing instruction an individual billing record to be included in a Security Lending Billing Invoice">
    inputs:
        billingInstruction BillingRecordInstruction (1..*) <"Instruction for creating the billing records contained within the invoice">
    output:
        billingRecord BillingRecord (1..*)

    add billingRecord: billingInstruction extract Create_BillingRecord(item)

func Create_BillingRecord: <"Creates an individual billing record to be included in a Security Lending Billing Invoice">
    inputs:
        billingInstruction BillingRecordInstruction (1..1) <"Instruction for creating the billing records contained within the invoice">
    output:
        billingRecord BillingRecord (1..1) <"The billing record">

    alias tradeState: <"Creates a trade state with observations attached.">
        Create_AssetPayoutTradeStateWithObservations(billingInstruction)

    alias billingAmount: <"Resolves the billing amount for the individual trade record.">
        ResolveSecurityFinanceBillingAmount(
                tradeState,
                tradeState -> resetHistory only-element,
                billingInstruction -> recordStartDate,
                billingInstruction -> recordEndDate,
                billingInstruction -> settlementDate
            )

    set billingRecord -> recordStartDate: billingInstruction -> recordStartDate

    set billingRecord -> recordEndDate: billingInstruction -> recordEndDate

    set billingRecord -> tradeState: tradeState

    set billingRecord -> recordTransfer: billingAmount

func ResolveSecurityFinanceBillingAmount: <"Calculates the billing amount for a Security Finance transaction.">
    inputs:
        tradeState TradeState (1..1)
        reset Reset (1..1)
        recordStartDate date (1..1)
        recordEndDate date (1..1)
        transferDate date (1..1)
    output:
        transfer Transfer (1..1)

    alias securityQuantity: <"Specifies the number of securities.">
        FilterQuantityByFinancialUnit(
                tradeState -> trade -> tradeLot -> priceQuantity -> quantity,
                FinancialUnitEnum -> Share
            )

    alias interestRatePayout: <"The interest payout that represents the lending fee.">
        tradeState -> trade -> product -> economicTerms -> payout -> interestRatePayout only-element

    alias assetPayout: <"The security finance payout that represents the securities lent.">
        tradeState -> trade -> product -> economicTerms -> collateral -> collateralPortfolio -> collateralPosition -> product ->> economicTerms -> payout -> assetPayout only-element

    alias collateral:
        tradeState -> trade -> product -> economicTerms -> collateral

    alias haircutPercentage:
        (1.0 - collateral -> collateralProvisions -> eligibleCollateral only-element -> treatment -> valuationTreatment -> haircutPercentage)

    alias valuationPercentage: (1 / haircutPercentage)

    alias marginRatio:
        if collateral -> collateralProvisions -> eligibleCollateral only-element -> treatment -> valuationTreatment -> haircutPercentage exists
        then valuationPercentage
        else if collateral -> collateralProvisions -> eligibleCollateral only-element -> treatment -> valuationTreatment -> marginPercentage exists
        then collateral -> collateralProvisions -> eligibleCollateral only-element -> treatment -> valuationTreatment -> marginPercentage
        else 1.0

    alias billingQuantity:
        reset -> resetValue -> value * securityQuantity -> value * marginRatio

    alias calculationPeriodRange:
        CalculationPeriodRange(recordStartDate, recordEndDate, empty)

    alias performance:
        if interestRatePayout -> rateSpecification -> FixedRateSpecification exists
        then FixedAmount(
                    interestRatePayout,
                    billingQuantity,
                    recordEndDate,
                    calculationPeriodRange
                )
        else if interestRatePayout -> rateSpecification -> FloatingRateSpecification exists
        then FloatingAmount(
                    interestRatePayout,
                    reset -> resetValue -> value,
                    billingQuantity,
                    recordEndDate,
                    calculationPeriodRange
                )

    alias payerPartyReference:
        ExtractCounterpartyByRole(
                tradeState -> trade -> counterparty,
                interestRatePayout -> payerReceiver -> payer
            ) -> partyReference

    alias receiverPartyReference:
        ExtractCounterpartyByRole(
                tradeState -> trade -> counterparty,
                interestRatePayout -> payerReceiver -> receiver
            ) -> partyReference

    set transfer -> quantity -> value: performance

    set transfer -> quantity -> unit -> currency:
        interestRatePayout -> priceQuantity -> quantitySchedule -> unit -> currency

    set transfer -> payerReceiver -> payerPartyReference:
        if performance >= 0
        then payerPartyReference
        else receiverPartyReference

    set transfer -> payerReceiver -> receiverPartyReference:
        if performance >= 0
        then receiverPartyReference
        else payerPartyReference

    set transfer -> settlementDate -> adjustedDate: transferDate

func ToMoney:
    inputs:
        quantity Quantity (1..1)
    output:
        money Money (1..1)

    set money -> value: quantity -> value
    set money -> unit -> currency: quantity -> unit -> currency

func Create_BillingSummary: <"Creates a billing summary to be included in a Security Lending Billing Invoice.">
    inputs:
        billingRecord BillingRecord (1..*)
    output:
        billingSummary BillingSummary (1..1)

//sums all billing records and assigns value to billing summary
//sets enum to ParentTotal
func Create_Return: <"Defines the process of partially or fully returning a Security Lending Transaction.">
    [creation BusinessEvent]
    inputs:
        tradeState TradeState (1..1) <"Specifies a previously formed contractual product with a Security Finance payout. It is required that the description of the contractual product be contained within the previous business event, i.e. its lineage must contain the formation of a contractual product.">
        returnInstruction ReturnInstruction (1..1) <"Specifies the information required to fully return the Stock Loan in accordance with the economic terms of the contractual product.">
        returnDate date (1..1) <"Specifies the date of the full return.">
    output:
        returnEvent BusinessEvent (1..1) <"Produces the business event composed of primitive events describing the transfer and termination, as a result of the input return instruction.">

    alias quantitySchedule:
        returnInstruction -> quantity
            extract
                NonNegativeQuantitySchedule {
                    value: value,
                    unit: unit,
                    ...
                }

    alias changePriceQuantity:
        PriceQuantity {
            quantity: quantitySchedule,
            ...
        }

    add returnEvent -> after: <"Creates a new contract within the quantity change primitive's after state equivalent to the new notional on the partially returned original contract, assuming there's a single security finance transaction in the original financial contract that is part returned.">
        Create_QuantityChange(
                QuantityChangeInstruction {
                    change: changePriceQuantity,
                    direction: QuantityChangeDirectionEnum -> Decrease,
                    lotIdentifier: empty
                },
                tradeState
            )

    set returnEvent -> eventDate: returnDate

func Qualify_Repurchase: <"The qualification of a repurchase event from the fact that (i) a quantityChange instruction exists, (ii) an assetPayout exists, (iii) the remaining quantity = 0, (iv) the closedState of the contract is Terminated, and (v) the intent of the event is 'Repurchase'.">
    [qualification BusinessEvent]
    inputs:
        businessEvent BusinessEvent (1..1)
    output:
        is_event boolean (1..1)
    set is_event:
        businessEvent -> intent = EventIntentEnum -> Repurchase
            and businessEvent -> after -> trade -> product -> economicTerms -> collateral -> collateralPortfolio -> collateralPosition -> product ->> economicTerms -> payout -> assetPayout exists
            and (businessEvent -> instruction count = 1
                and (businessEvent -> instruction -> primitiveInstruction -> quantityChange, businessEvent -> instruction -> primitiveInstruction -> transfer) only exists)
            and QuantityDecreasedToZero(
                    businessEvent -> instruction -> before,
                    businessEvent -> after
                ) = True
            and businessEvent -> after -> state -> closedState -> state all = ClosedStateEnum -> Terminated

func ResolveRepurchaseTransferInstruction: <"Resolves an instruction for settlement of a Repurchase Event">
    inputs:
        tradeState TradeState (1..1)
        repurchaseDate date (1..1)
    output:
        repurchaseInstruction EventInstruction (1..1)

    alias changeQuantity: <"Create distinct list of Quantity with value set to zero.">
        tradeState -> trade -> tradeLot -> priceQuantity -> quantity
            extract
                NonNegativeQuantitySchedule {
                    value: 0.0,
                    unit: unit,
                    ...
                }
            then distinct

    alias changePriceQuantity: <"Create change PriceQuantity for QuantityChangeInstruction.">
        PriceQuantity {
            quantity: changeQuantity,
            ...
        }

    set repurchaseInstruction -> intent: EventIntentEnum -> Repurchase

    set repurchaseInstruction -> instruction -> before: tradeState

    set repurchaseInstruction -> instruction -> primitiveInstruction -> quantityChange:
        QuantityChangeInstruction {
            change: changePriceQuantity,
            direction: QuantityChangeDirectionEnum -> Replace,
            lotIdentifier: empty
        }

func Create_RollPrimitiveInstruction: <"Creates the primitive instructions for a trade roll. A trade roll consists in closing an existing trade and entering into a new one which has the same characteristics as the old one, except with an extended termination date and (possibly) a different price.">
    inputs:
        tradeState TradeState (1..1) <"The original trade to be rolled.">
        effectiveRollDate AdjustableOrRelativeDate (1..1) <"The date to close and open a new position.">
        terminationDate AdjustableOrRelativeDate (1..1) <"The new termination date.">
        priceQuantity PriceQuantity (1..*) <"The price and quantity of the trade to roll into.">
    output:
        instruction PrimitiveInstruction (1..1)

    set instruction -> split -> breakdown: <"Sets the first part of the split to be a termination instruction for the existing trade.">
        [Create_TerminationInstruction(tradeState)]

    add instruction -> split -> breakdown: <"Sets the second part of the split to be a new contract with the same details as the old one but with effective and termination dates changed (i.e. terms change instruction) and price / quantity changed.">
        [
            PrimitiveInstruction {
                quantityChange: QuantityChangeInstruction {
                        change: priceQuantity,
                        direction: QuantityChangeDirectionEnum -> Replace,
                        lotIdentifier: empty
                    },
                termsChange: Create_RollTermChangeInstruction(
                            tradeState -> trade -> product,
                            effectiveRollDate,
                            terminationDate
                        ),
                ...
            }
        ]

func Create_EffectiveOrTerminationDateTermChangeInstruction: <"Creates the relevant terms change primitive instruction object for rolling a contractual product, which consists in the same terms as the original contractual product but with different effective and termination dates.">
    inputs:
        product NonTransferableProduct (1..1) <"The original contractual product to be rolled.">
        effectiveRollDate AdjustableOrRelativeDate (0..1) <"The date to close and open a new position.">
        terminationDate AdjustableOrRelativeDate (0..1) <"The new termination date.">
    output:
        termsChangeInstruction TermsChangeInstruction (1..1) <"The relevant primitive instruction for the roll, which is a terms change.">

    condition DateExists:
        effectiveRollDate exists or terminationDate exists

    set termsChangeInstruction -> product: product

    set termsChangeInstruction -> product -> economicTerms -> effectiveDate:
        if effectiveRollDate exists
        then effectiveRollDate
        else product -> economicTerms -> effectiveDate

    set termsChangeInstruction -> product -> economicTerms -> terminationDate:
        if terminationDate exists
        then terminationDate
        else product -> economicTerms -> terminationDate

func Create_RollTermChangeInstruction: <"Creates the relevant terms change primitive instruction object for rolling a contractual product, which consists in the same terms as the original contractual product but with different effective and termination dates.">
    inputs:
        product NonTransferableProduct (1..1) <"The original contractual product to be rolled.">
        effectiveRollDate AdjustableOrRelativeDate (1..1) <"The date to close and open a new position.">
        terminationDate AdjustableOrRelativeDate (1..1) <"The new termination date.">
    output:
        termsChangeInstruction TermsChangeInstruction (1..1) <"The relevant primitive instruction for the roll, which is a terms change.">

    set termsChangeInstruction -> product: product
    set termsChangeInstruction -> product -> economicTerms -> effectiveDate:
        effectiveRollDate
    set termsChangeInstruction -> product -> economicTerms -> terminationDate:
        terminationDate

func Qualify_Roll: <"Qualification of a roll event based on: (i) terminating a single existing trade, (ii) entering into a new trade with the same details as the old trade, except for the effective and termination date where the effective date. The roll qualification does not make any assumption on the resulting quantity which may change compared to the original trade (it may only be partially rolled). The price is also likely different as market conditions may have evolved.">
    [qualification BusinessEvent]
    inputs:
        businessEvent BusinessEvent (1..1)
    output:
        is_event boolean (1..1)

    alias beforeEconomicterms:
        businessEvent -> instruction only-element -> before -> trade -> product -> economicTerms
    alias openEconomicTerms:
        FilterOpenTradeStates(businessEvent -> after) only-element -> trade -> product -> economicTerms
    alias closedTradeState: FilterClosedTradeStates(businessEvent -> after)

    set is_event:
        // The first 2 conditions imply that there is 1 and only 1 before and 1 open thanks to the "only-element" modifier
        beforeEconomicterms exists
            and openEconomicTerms exists
            and closedTradeState count = 1
            and openEconomicTerms -> payout = beforeEconomicterms -> payout
            and openEconomicTerms -> collateral = beforeEconomicterms -> collateral
            and openEconomicTerms -> effectiveDate = beforeEconomicterms -> terminationDate
            and openEconomicTerms -> terminationDate <> beforeEconomicterms -> terminationDate

func Create_OnDemandRateChangePrimitiveInstruction: <"Creates a full primitive instruction for an on-demand rate change event. A rate change consists in closing the original trade and opening a new one with the same details as the original one, but with a new rate (price) and effective date. The business event logic checks that there is only 1 rate price in the original trade to be updated.">
    inputs:
        tradeState TradeState (1..1) <"The original trade to be modified with new rate.">
        effectiveDate AdjustableOrRelativeDate (1..1) <"The date to close and open a new position.">
        agreedRate number (1..1) <"The new rate agreed between the parties.">
    output:
        instruction PrimitiveInstruction (1..1)

    condition SingleTradeLot: <"Rate change only works for a trade with a single trade lot.">
        tradeState -> trade -> tradeLot count = 1

    set instruction -> split -> breakdown: <"Sets the first part of the split to be a termination instruction for the existing trade.">
        [Create_TerminationInstruction(tradeState)]

    add instruction -> split -> breakdown: <"Sets the second part of the split to be a new contract with the same details as the old one but with effective date and price (rate) changed.">
        [
            PrimitiveInstruction {
                quantityChange: Create_OnDemandRateChangePriceChangeInstruction(
                            tradeState -> trade -> tradeLot only-element -> priceQuantity,
                            agreedRate
                        ),
                termsChange: Create_OnDemandRateChangeTermsChangeInstruction(
                            tradeState -> trade -> product,
                            effectiveDate
                        ),
                ...
            }
        ]

func Create_OnDemandRateChangePriceChangeInstruction: <"Creates a price change instruction for an on-demand rate change, based on a new rate provided as a single number by matching it to a single rate price.">
    inputs:
        priceQuantity PriceQuantity (1..*) <"The original price / quantity to be modified with the new rate.">
        newRate number (1..1) <"The new rate value, provided as a single number.">
    output:
        quantityChangeInstruction QuantityChangeInstruction (1..1)

    alias currentRatePrice: <"Filter interest rate price and make it into a single element">
        priceQuantity
            extract price
            then flatten
            then filter priceType = PriceTypeEnum -> InterestRate
            then only-element
    alias newPrice: <"Create the new price object.">
        Price {
            value: newRate,
            unit: currentRatePrice -> unit,
            perUnitOf: currentRatePrice -> perUnitOf,
            priceType: currentRatePrice -> priceType,
            priceExpression: currentRatePrice -> priceExpression,
            composite: currentRatePrice -> composite,
            arithmeticOperator: currentRatePrice -> arithmeticOperator,
            cashPrice: currentRatePrice -> cashPrice,
            datedValue: empty
        }
    alias newPriceQuantity: <"Create the new price quantity object.">
        PriceQuantity {
            price: newPrice,
            ...
        }

    condition OneRatePrice: <"There should be 1 and only 1 rate type price in the current price.">
        currentRatePrice exists

    set quantityChangeInstruction:
        QuantityChangeInstruction {
            change: newPriceQuantity,
            direction: QuantityChangeDirectionEnum -> Replace,
            lotIdentifier: empty
        }

func Create_OnDemandRateChangeTermsChangeInstruction: <"Creates a terms change instruction for an on-demand rate change, based on a new rate provided as a single number. This instruction only updates the effective date but keeps other details of the trade unchanged.">
    inputs:
        product NonTransferableProduct (1..1) <"The original contractual product whose rate is changed.">
        effectiveDate AdjustableOrRelativeDate (1..1) <"The date to open the new position.">
    output:
        termsChangeInstruction TermsChangeInstruction (1..1)

    set termsChangeInstruction -> product: <"Keep the same contractual product as the original trade">
        product
    set termsChangeInstruction -> product -> economicTerms -> effectiveDate: <"Updates the contractual product's effective date to be the new effective date.">
        effectiveDate

func Qualify_OnDemandRateChange: <"The qualification of on an-demand rate change event from the fact that the only primitive is the reset.">
    [qualification BusinessEvent]
    inputs:
        businessEvent BusinessEvent (1..1)
    output:
        is_event boolean (1..1)

    alias beforeTrade:
        businessEvent -> instruction only-element -> before -> trade
    alias beforeProduct:
        beforeTrade -> product
    alias beforeEconomicterms:
        beforeProduct -> economicTerms
    alias openTrade:
        FilterOpenTradeStates(businessEvent -> after) only-element -> trade    
    alias openEconomicTerms:
        openTrade -> product -> economicTerms
    alias closedTradeState: FilterClosedTradeStates(businessEvent -> after)

    alias beforePriceQuantityRateOnly: <"The rate value before. There must be 1 and only 1.">
        beforeTrade -> tradeLot only-element -> priceQuantity
            extract price
            then flatten
            then filter priceType = PriceTypeEnum -> InterestRate
            then extract value

    alias openPriceQuantityRateOnly: <"The rate value after. There must be 1 and only 1, and it must be different from the rate before.">
        openTrade -> tradeLot only-element -> priceQuantity
            extract price
            then flatten
            then filter priceType = PriceTypeEnum -> InterestRate
            then extract value

    alias beforePriceQuantityNoRate: <"The price and quantity attributes before, excluding any rate price.">
        beforeTrade -> tradeLot only-element -> priceQuantity
            extract
                PriceQuantity {
                    price: price
                            filter p [ p -> priceType <> PriceTypeEnum -> InterestRate ],
                    quantity: quantity,
                    observable: observable,
                    ...
                }

    alias openPriceQuantityNoRate: <"The price and quantity attributes after, excluding any rate price. They must be equal to the price and quantity before, excluding any rate price">
        openTrade -> tradeLot only-element -> priceQuantity
            extract
                PriceQuantity {
                    price: price
                            filter p [ p -> priceType <> PriceTypeEnum -> InterestRate ],
                    quantity: quantity,
                    observable: observable,
                    ...
                }

    set is_event:
        // The first 2 conditions imply that there is 1 and only 1 before and 1 open thanks to the "only-element" modifier
        beforeEconomicterms exists
            and openEconomicTerms exists
            and closedTradeState count = 1
            and // openEconomicTerms -> payout = beforeEconomicterms -> payout and
            openEconomicTerms -> collateral = beforeEconomicterms -> collateral
            and beforePriceQuantityRateOnly count = 1
            and openPriceQuantityRateOnly count = 1
            and beforePriceQuantityRateOnly only-element
                <> openPriceQuantityRateOnly only-element
            and beforePriceQuantityNoRate = openPriceQuantityNoRate

func Create_CancellationPrimitiveInstruction: <"Creates a primitive instruction for early cancellation.">
    inputs:
        tradeState TradeState (1..1) <"The original trade to be rolled.">
        newRepurchasePrice number (0..1) <"The new repurchase price after the new termination date is set.">
        cancellationDate AdjustableOrRelativeDate (1..1) <"The new termination date.">
    output:
        instruction PrimitiveInstruction (1..1)

    set instruction -> split -> breakdown: <"Sets the first part of the split to be a termination instruction for the existing trade.">
        [Create_TerminationInstruction(tradeState)]

    add instruction -> split -> breakdown: <"Sets the second part of the split to be a new contract with the same details as the old one but with termination date changed and price / quantity changed (taking new repurchase price into account).">
        [
            PrimitiveInstruction {
                quantityChange: QuantityChangeInstruction {
                        change: tradeState -> trade -> tradeLot -> priceQuantity,
                        direction: QuantityChangeDirectionEnum -> Replace,
                        lotIdentifier: empty
                    },
                termsChange: Create_CancellationTermChangeInstruction(
                            tradeState -> trade -> product,
                            cancellationDate
                        ),
                ...
            }
        ]

func Create_CancellationTermChangeInstruction: <"Create a terms change instruction for a cancellation that consists in bringing the termination date forward.">
    inputs:
        product NonTransferableProduct (1..1) <"Contractual product of original trade">
        cancellationDate AdjustableOrRelativeDate (1..1) <"The new termination date.">
    output:
        termsChangeInstruction TermsChangeInstruction (1..1)

    set termsChangeInstruction -> product: product
    set termsChangeInstruction -> product -> economicTerms -> terminationDate:
        cancellationDate

func Qualify_Cancellation: <"Qualification of an cancellation event.">
    [qualification BusinessEvent]
    inputs:
        businessEvent BusinessEvent (1..1)
    output:
        is_event boolean (1..1)

    alias closedEconomicTerms:
        FilterClosedTradeStates(businessEvent -> after) only-element -> trade -> product -> economicTerms
    alias openEconomicTerms:
        FilterOpenTradeStates(businessEvent -> after) only-element -> trade -> product -> economicTerms

    set is_event:
        businessEvent -> instruction -> before count = 1
            and closedEconomicTerms exists
            and openEconomicTerms exists
                // and openEconomicTerms -> payout = closedEconomicTerms -> payout
                // and openEconomicTerms -> collateral = closedEconomicTerms -> collateral
            and (if openEconomicTerms -> terminationDate exists
                        and closedEconomicTerms -> terminationDate exists
                then openEconomicTerms -> terminationDate -> adjustableDate -> unadjustedDate < closedEconomicTerms -> terminationDate -> adjustableDate -> unadjustedDate
                else openEconomicTerms -> terminationDate exists)

func Create_PairOffInstruction: <"Creates a set of instructions to pair-off a set of trades based on a pair reference. A package component is created based on that pair reference and the list of identifiers for the underlying trades. That package component is then added onto the execution details of every underlying trade. The existing trades are not terminated.">
    inputs:
        tradeState TradeState (2..*) <"The trades to pair-off. There must be at least 2.">
        pairReference Identifier (1..1) <"The reference ID of the paired trades.">
    output:
        instruction Instruction (1..*)

    alias componentId: <"Extract the trade identifier from each trade. This list will be used as the componentId attribute of the package.">
        tradeState extract trade -> tradeIdentifier only-element

    set instruction: <"Create a list of new execution instructions for each trade. The new execution instructions include new execution details, with the package component created using the pair reference and the componentId list.">
        tradeState
            extract
                Instruction {
                    before: item,
                    primitiveInstruction: PrimitiveInstruction {
                            contractFormation: if item -> state -> positionState = PositionStatusEnum -> Formed
                                then Create_ContractFormationInstruction(
                                            item -> trade -> contractDetails -> documentation
                                        ),
                            execution: ExecutionInstruction {
                                    product: item -> trade -> product,
                                    priceQuantity: item -> trade -> tradeLot only-element -> priceQuantity,
                                    counterparty: item -> trade -> counterparty,
                                    ancillaryParty: item -> trade -> ancillaryParty,
                                    parties: item -> trade -> party,
                                    partyRoles: item -> trade -> partyRole,
                                    executionDetails: Create_PackageExecutionDetails(
                                                item -> trade -> executionDetails,
                                                pairReference,
                                                componentId
                                            ),
                                    tradeDate: item -> trade -> tradeDate,
                                    tradeIdentifier: item -> trade -> tradeIdentifier,
                                    ...
                                },
                            ...
                        }
                }

func Qualify_PairOff: <"Qualifies an event as a pair-off when all the details of the existing trades are maintained, except for their execution details which are updated to include a package component. This package component must be unique across all trades.">
    [qualification BusinessEvent]
    inputs:
        businessEvent BusinessEvent (1..1)
    output:
        is_event boolean (1..1)

    alias openTradeState: FilterOpenTradeStates(businessEvent -> after)

    alias newTradeInstruction: <"New trade instructions, that contain only an execution primitive and (optionally) a contract formation primitive.">
        businessEvent -> instruction
            filter NewTradeInstructionOnlyExists(item -> primitiveInstruction)

    alias packageRef: <"Package details on the new trades.">
        openTradeState -> trade -> executionDetails -> packageReference

    set is_event:
        // The first condition asserts that there are only new executions
        newTradeInstruction count = businessEvent -> instruction count
                // All the trade details (except the execution instructions) are unchanged
                // and openTradeNoExecutionDetails = beforeTradeNoExecutionDetails
            and openTradeState -> trade -> product = newTradeInstruction -> before -> trade -> product
            and openTradeState -> trade -> tradeLot = newTradeInstruction -> before -> trade -> tradeLot
            and openTradeState -> trade -> counterparty = newTradeInstruction -> before -> trade -> counterparty
            and openTradeState -> trade -> ancillaryParty = newTradeInstruction -> before -> trade -> ancillaryParty
            and openTradeState -> trade -> adjustment = newTradeInstruction -> before -> trade -> adjustment
                // All open trades are associated to a package, and that package is the same across all trades
            and packageRef count = openTradeState count
            and packageRef distinct count = 1

func Create_ShapingInstruction: <"Creates a set of instructions to shape a trade based on shaped quantities and a package ID. The original trade is closed and split into (smaller) shaped trades based on a set of trade lots containing the shaped quantities and an identifier for each shaped trade. A package component is created based on the package ID and the list of identifiers for the shaped trades. That package component is then added onto the execution details of every shaped trade.">
    inputs:
        tradeState TradeState (1..1) <"The original trade to be shaped.">
        tradeLots TradeLot (2..*) <"The shaped quantities provided as full set of trade lots with price and quantity. Each trade lot also contains an identifier to associate to the corresponding shaped trade. Shaping must result in at least 2 shaped trades.">
        shapeIdentifier Identifier (1..1) <"The package ID of the shaped trades.">
    output:
        instruction PrimitiveInstruction (1..1)

    alias componentId: <"Extract the trade identifier from each trade lot. This list will be used as the componentId attribute of the package.">
        tradeLots extract item -> lotIdentifier only-element

    set instruction -> split -> breakdown: <"Sets the first part of the split to be a termination instruction for the existing trade.">
        [Create_TerminationInstruction(tradeState)]

    add instruction -> split -> breakdown: <"The second part of the split consists in a quantity change and a new execution for each provided trade lot. The quantity change takes care of the shaping according to the provided quantities. The execution adds the required package component to the execution details.">
        tradeLots
            extract priceQuantity
            then extract
                PrimitiveInstruction {
                    contractFormation: if tradeState -> state -> positionState = PositionStatusEnum -> Formed
                        then Create_ContractFormationInstruction(
                                    tradeState -> trade -> contractDetails -> documentation
                                ),
                    execution: ExecutionInstruction {
                            product: tradeState -> trade -> product,
                            priceQuantity: tradeState -> trade -> tradeLot only-element -> priceQuantity,
                            counterparty: tradeState -> trade -> counterparty,
                            ancillaryParty: tradeState -> trade -> ancillaryParty,
                            parties: tradeState -> trade -> party,
                            partyRoles: tradeState -> trade -> partyRole,
                            executionDetails: Create_PackageExecutionDetails(
                                        tradeState -> trade -> executionDetails,
                                        shapeIdentifier,
                                        componentId
                                    ),
                            tradeDate: tradeState -> trade -> tradeDate,
                            tradeIdentifier: tradeState -> trade -> tradeIdentifier,
                            ...
                        },
                    quantityChange: QuantityChangeInstruction {
                            change: item,
                            direction: QuantityChangeDirectionEnum -> Replace,
                            lotIdentifier: empty
                        },
                    ...
                }

func Qualify_Shaping: <"The qualification of a shaping event from the fact that (i) the only primitive is a split where the original trade is closed, (ii) the parties before and after the split remain the same (by contrast with an allocation, for instance) and (iii) the split trades contain a package component in their execution details. This package ties together the resulting shapes trades' identifiers and must be the same across all shaped trades. Note that SplitPrimitive type has a condition to check that the post-split quantities sum to the pre-split quantity.">
    [qualification BusinessEvent]
    inputs:
        businessEvent BusinessEvent (1..1)
    output:
        is_event boolean (1..1)

    alias beforeTradeState: businessEvent -> instruction -> before only-element
    alias closedTradeState: FilterClosedTradeStates(businessEvent -> after) only-element
    alias openTradeStates: FilterOpenTradeStates(businessEvent -> after)

    alias packageRef: <"Package details on the new trades.">
        openTradeStates -> trade -> executionDetails -> packageReference
    alias openTradeNoExecutionDetails: <"List of open trades with no execution details on, for comparison.">
        openTradeStates extract TradeNoExecutionDetails(item -> trade)

    set is_event:
        // There is a single before trade with a split instruction, resulting in a single closed trade and multiple open trades
        beforeTradeState exists
            and closedTradeState exists
            and openTradeStates count > 1
            and businessEvent -> instruction -> primitiveInstruction -> split only exists
                // Open trade counterparties should match before trade counterparties
            and openTradeStates
                extract [
                    item -> trade -> counterparty -> partyReference = beforeTradeState -> trade -> counterparty -> partyReference
                ] all = True
                // All open trades are associated to a package, and that package is the same across all trades
            and packageRef count = openTradeNoExecutionDetails count
            and packageRef distinct count = 1

func Create_PartialDeliveryPrimitiveInstruction: <"Creates the primitive instruction for partial delivery of a repo transaction at settlement.">
    inputs:
        tradeState TradeState (1..1) <"The original trade to be closed.">
        deliveredPriceQuantity PriceQuantity (1..*) <"The price and quantity of the delivered amount.">
    output:
        instruction PrimitiveInstruction (1..1)

    set instruction -> split -> breakdown: <"Sets the first part of the split to be a termination instruction for the existing trade.">
        [Create_TerminationInstruction(tradeState)]

    set instruction -> split -> breakdown: <"Sets the first part of the split to be a termination instruction for the existing trade.">
        [
            PrimitiveInstruction {
                quantityChange: QuantityChangeInstruction {
                        change: deliveredPriceQuantity,
                        direction: QuantityChangeDirectionEnum -> Replace,
                        lotIdentifier: tradeState -> trade -> tradeLot -> lotIdentifier
                    },
                ...
            }
        ]

func Qualify_PartialDelivery: <"Qualification of a partial delivery which constitutes a change in quantity and open with the remaining quantity and termination date.">
    [qualification BusinessEvent]
    inputs:
        businessEvent BusinessEvent (1..1)
    output:
        is_event boolean (1..1)

    alias beforeEconomicterms: ExtractBeforeEconomicTerms(businessEvent)

    alias openEconomicTerms: ExtractOpenEconomicTerms(businessEvent)

    alias openTrades: FilterOpenTradeStates(businessEvent -> after) -> trade
    alias closedTradeState: FilterClosedTradeStates(businessEvent -> after)

    alias beforeTrade: ExtractBeforeTrade(businessEvent)

    alias afterTrade: ExtractAfterTrade(businessEvent)

    alias beforeTradeCollateralQuantity:
        ExtractTradeCollateralQuantity(beforeTrade)

    alias afterTradeCollateralQuantity: ExtractTradeCollateralQuantity(afterTrade)

    set is_event:
        beforeEconomicterms exists
            and openEconomicTerms exists
            and openTrades count = 1
            and closedTradeState count = 1
            and openEconomicTerms -> payout -> interestRatePayout = beforeEconomicterms -> payout -> interestRatePayout
            and openEconomicTerms -> collateral = beforeEconomicterms -> collateral
            and beforeTradeCollateralQuantity > afterTradeCollateralQuantity
            and openEconomicTerms -> terminationDate = beforeEconomicterms -> terminationDate
            and openEconomicTerms -> effectiveDate = beforeEconomicterms -> effectiveDate

func Create_RepricePrimitiveInstruction: <"Creates the primitive instructions for a repricing that alters the cash amount of the trade. Transaction value and variation margin are processed separately as are transfers of cash and securities.">
    inputs:
        tradeState TradeState (1..1) <"The original trade state and trade to be repriced.">
        newAllinPrice number (1..1) <"The collateral new all-in price.">
        newCashValue number (1..1) <"The new cash amount.">
        effectiveRepriceDate AdjustableOrRelativeDate (1..1) <"The date to reprice the collateral">
    output:
        instruction PrimitiveInstruction (1..1)

    alias oldPriceQuantity:
        tradeState -> trade -> tradeLot -> priceQuantity

    alias currentAssetPrice: <"Filter interest rate price and make it into a single element">
        oldPriceQuantity
            extract price
            then flatten
            then filter priceType = PriceTypeEnum -> AssetPrice
            then only-element

    alias newPrice: <"Create the new price object.">
        Price {
            value: newAllinPrice,
            unit: currentAssetPrice -> unit,
            perUnitOf: currentAssetPrice -> perUnitOf,
            priceType: currentAssetPrice -> priceType,
            priceExpression: currentAssetPrice -> priceExpression,
            composite: currentAssetPrice -> composite,
            arithmeticOperator: currentAssetPrice -> arithmeticOperator,
            cashPrice: currentAssetPrice -> cashPrice,
            datedValue: empty
        }

    alias changeCashQuantity: <"Create distinct list of Quantity with value set to newAssetQuantity">
        tradeState -> trade -> tradeLot only-element -> priceQuantity -> quantity
            extract
                NonNegativeQuantitySchedule {
                    value: newCashValue,
                    unit: unit,
                    ...
                }
            then distinct

    alias newPriceQuantity: <"Create the new price quantity object.">
        PriceQuantity {
            price: [newPrice],
            quantity: changeCashQuantity,
            ...
        }

    set instruction -> split -> breakdown: [Create_TerminationInstruction(tradeState)]

    add instruction -> split -> breakdown: <"Sets the second part of the split to be a new contract with a new asset payout.">
        [
            PrimitiveInstruction {
                quantityChange: QuantityChangeInstruction {
                        change: [newPriceQuantity],
                        direction: QuantityChangeDirectionEnum -> Replace,
                        lotIdentifier: empty
                    },
                termsChange: Create_EffectiveOrTerminationDateTermChangeInstruction(
                            tradeState -> trade -> product,
                            effectiveRepriceDate,
                            empty
                        ),
                ...
            }
        ]

func Create_AdjustmentPrimitiveInstruction: <"Creates the primitive instructions for a repricing that alters the collateral quantity and value of the trade. Transaction value and variation margin are processed separately as are transfers of cash and securities.">
    inputs:
        tradeState TradeState (1..1) <"The original trade state and trade to be repriced.">
        newAllinPrice number (1..1) <"The collateral new all-in price.">
        newAssetQuantity number (1..1) <"The collateral new quantity.">
        effectiveRepriceDate AdjustableOrRelativeDate (1..1) <"The date to reprice the collateral">
    output:
        instruction PrimitiveInstruction (1..1)

    alias oldPriceQuantity:
        tradeState -> trade -> tradeLot -> priceQuantity

    alias currentAssetPrice: <"Filter interest rate price and make it into a single element">
        oldPriceQuantity
            extract price
            then flatten
            then filter priceType = PriceTypeEnum -> AssetPrice
            then only-element

    alias newPrice: <"Create the new price object.">
        Price {
            value: newAllinPrice,
            unit: currentAssetPrice -> unit,
            perUnitOf: currentAssetPrice -> perUnitOf,
            priceType: currentAssetPrice -> priceType,
            priceExpression: currentAssetPrice -> priceExpression,
            composite: currentAssetPrice -> composite,
            arithmeticOperator: currentAssetPrice -> arithmeticOperator,
            cashPrice: currentAssetPrice -> cashPrice,
            datedValue: empty
        }

    alias changeQuantity: <"Create distinct list of Quantity with value set to newAssetQuantity">
        tradeState -> trade -> tradeLot only-element -> priceQuantity -> quantity
            extract
                NonNegativeQuantitySchedule {
                    value: newAssetQuantity,
                    unit: unit,
                    ...
                }
            then distinct

    alias newPriceQuantity: <"Create the new price quantity object.">
        PriceQuantity {
            price: [newPrice],
            quantity: changeQuantity,
            ...
        }

    condition SingleTradeLot: <"This repricing function applies only to trades with a single lot.">
        tradeState -> trade -> tradeLot count = 1

    set instruction -> split -> breakdown: [Create_TerminationInstruction(tradeState)]

    add instruction -> split -> breakdown: <"Sets the second part of the split to be a new contract with a new asset payout.">
        [
            PrimitiveInstruction {
                quantityChange: QuantityChangeInstruction {
                        change: [newPriceQuantity],
                        direction: QuantityChangeDirectionEnum -> Replace,
                        lotIdentifier: empty
                    },
                termsChange: Create_EffectiveOrTerminationDateTermChangeInstruction(
                            tradeState -> trade -> product,
                            effectiveRepriceDate,
                            empty
                        ),
                ...
            }
        ]

func Qualify_Reprice: <"This qualification function is used to qualify repricing of a contractual product with an interest rate payout and assetPayout.">
    [qualification BusinessEvent]
    inputs:
        businessEvent BusinessEvent (1..1)
    output:
        is_event boolean (1..1)

    alias openTrades: FilterOpenTradeStates(businessEvent -> after) -> trade
    alias closedTradeState: FilterClosedTradeStates(businessEvent -> after)

    alias beforeTrade: ExtractBeforeTrade(businessEvent)

    alias afterTrade: ExtractAfterTrade(businessEvent)

    alias beforeTradePurchasePrice: ExtractTradePurchasePrice(beforeTrade)

    alias afterTradePurchasePrice: ExtractTradePurchasePrice(afterTrade)

    alias beforeTradeCollateralQuantity:
        ExtractTradeCollateralQuantity(beforeTrade)

    alias afterTradeCollateralQuantity: ExtractTradeCollateralQuantity(afterTrade)

    alias beforeTradeCollateralPrice: ExtractTradeCollateralPrice(beforeTrade)

    alias afterTradeCollateralPrice: ExtractTradeCollateralPrice(afterTrade)

    alias beforeEconomicterms: ExtractBeforeEconomicTerms(businessEvent)

    alias openEconomicTerms: ExtractOpenEconomicTerms(businessEvent)

    set is_event:
        businessEvent -> after -> trade -> product -> economicTerms -> payout -> interestRatePayout exists
            and openTrades count = 1
            and closedTradeState count = 1
            and beforeTradePurchasePrice exists
            and afterTradePurchasePrice exists
            and afterTradePurchasePrice <> beforeTradePurchasePrice
            and beforeTradeCollateralQuantity = afterTradeCollateralQuantity
            and beforeTradeCollateralPrice <> afterTradeCollateralPrice
            and beforeEconomicterms exists
            and openEconomicTerms exists
            and openEconomicTerms -> terminationDate = beforeEconomicterms -> terminationDate

func Qualify_Adjustment: <"This qualification function is used to qualify adjustment of the collateral amount when a transaction is repriced.">
    [qualification BusinessEvent]
    inputs:
        businessEvent BusinessEvent (1..1)
    output:
        is_event boolean (1..1)

    alias beforeTrade: ExtractBeforeTrade(businessEvent)

    alias afterTrade: ExtractAfterTrade(businessEvent)

    alias beforeTradePurchasePrice: ExtractTradePurchasePrice(beforeTrade)

    alias afterTradePurchasePrice: ExtractTradePurchasePrice(afterTrade)

    alias beforeTradeCollateralQuantity:
        ExtractTradeCollateralQuantity(beforeTrade)

    alias afterTradeCollateralQuantity: ExtractTradeCollateralQuantity(afterTrade)

    alias beforeTradeCollateralPrice: ExtractTradeCollateralPrice(beforeTrade)

    alias afterTradeCollateralPrice: ExtractTradeCollateralPrice(afterTrade)

    alias beforeEconomicterms: ExtractBeforeEconomicTerms(businessEvent)

    alias openEconomicTerms: ExtractOpenEconomicTerms(businessEvent)

    set is_event:
        businessEvent -> after -> trade -> product -> economicTerms -> payout -> interestRatePayout exists
            and openEconomicTerms -> payout = beforeEconomicterms -> payout
            and beforeTradePurchasePrice exists
            and afterTradePurchasePrice exists
            and afterTradePurchasePrice = beforeTradePurchasePrice
            and beforeTradeCollateralQuantity <> afterTradeCollateralQuantity
            and beforeTradeCollateralPrice <> afterTradeCollateralPrice
            and beforeEconomicterms exists
            and openEconomicTerms exists
            and openEconomicTerms -> terminationDate = beforeEconomicterms -> terminationDate
            and openEconomicTerms -> effectiveDate <> beforeEconomicterms -> effectiveDate

func Create_SubstitutionPrimitiveInstruction: <"Creates the primitive instructions for a substitution of collateral by replacing the assetpayout of the trade.">
    inputs:
        tradeState TradeState (1..1) <"The original trade to be for substitution of collateral.">
        effectiveDate AdjustableOrRelativeDate (1..1) <"The date to close and open a new trade with new collateral.">
        newCollateralPortfolio CollateralPortfolio (1..1) <"New collateral portfolio to subtitute for the original collateral.">
        priceQuantity PriceQuantity (1..*) <"The price and quantity of the substituted product.">
    output:
        instruction PrimitiveInstruction (1..1)

    condition SecurityFinance: <"Only security finance products can substitute collateral.">
        tradeState -> trade -> product -> economicTerms -> collateral exists

    set instruction: <"Sets the second part of the split to be a new contract with a new asset payout.">
        PrimitiveInstruction {
            quantityChange: QuantityChangeInstruction {
                    change: priceQuantity,
                    direction: QuantityChangeDirectionEnum -> Replace,
                    lotIdentifier: empty
                },
            termsChange: Create_SubstitutionInstruction(
                        tradeState -> trade -> product,
                        effectiveDate,
                        newCollateralPortfolio
                    ),
            ...
        }

func Create_SubstitutionInstruction: <"Creates the terms change instruction that updates the payout with the new substitution payout.">
    inputs:
        product NonTransferableProduct (1..1) <"The original contractual product to be used as the basis of the new trade.">
        effectiveDate AdjustableOrRelativeDate (1..1) <"The effective date of the substitution.">
        newCollateralPortfolio CollateralPortfolio (1..1) <"New collateral portfolio to substitute for the original collateral.">
    output:
        termsChangeInstruction TermsChangeInstruction (1..1)

    set termsChangeInstruction:
        Create_EffectiveOrTerminationDateTermChangeInstruction(
                product,
                effectiveDate,
                empty
            )

    set termsChangeInstruction -> product -> economicTerms -> collateral -> collateralPortfolio:
        newCollateralPortfolio

func Qualify_Substitution: <"Qualification of a collateral substitution event.">
    [qualification BusinessEvent]
    inputs:
        businessEvent BusinessEvent (1..1)
    output:
        is_event boolean (1..1)

    alias beforeEconomicterms: ExtractBeforeEconomicTerms(businessEvent)

    alias openEconomicTerms: ExtractOpenEconomicTerms(businessEvent)

    set is_event:
        beforeEconomicterms exists
            and openEconomicTerms exists
            and openEconomicTerms -> payout <> beforeEconomicterms -> payout
            and openEconomicTerms -> collateral <> beforeEconomicterms -> collateral
            and openEconomicTerms -> effectiveDate = beforeEconomicterms -> terminationDate
            and openEconomicTerms -> terminationDate = beforeEconomicterms -> terminationDate

func Create_PackageExecutionDetails: <"Add a package component to an execution details object. This package component is constructed using an identifier for the package and the list of identifiers for its components.">
    inputs:
        executionDetails ExecutionDetails (0..1) <"The original execution details. These may be empty.">
        listId Identifier (1..1) <"The identifier for the package.">
        componentId Identifier (2..*) <"The list of identifiers for the package components. There must be at least 2.">
    output:
        newExecutionDetails ExecutionDetails (1..1)

    set newExecutionDetails -> executionType: executionDetails -> executionType
    set newExecutionDetails -> executionVenue: executionDetails -> executionVenue
    set newExecutionDetails -> packageReference -> listId: listId
    set newExecutionDetails -> packageReference -> componentId: componentId

func NewTradeInstructionOnlyExists:
    inputs:
        primitiveInstruction PrimitiveInstruction (1..1)
    output:
        result boolean (1..1)
    set result:
        primitiveInstruction -> execution only exists
            or (primitiveInstruction -> execution, primitiveInstruction -> contractFormation) only exists

func TradeNoExecutionDetails:
    inputs:
        trade Trade (1..1)
    output:
        newTrade Trade (1..1)

    set newTrade: trade
    set newTrade -> executionDetails: EmptyExecutionDetails()

func EmptyExecutionDetails:
    output:
        executionDetails ExecutionDetails (0..1)

func Create_OnDemandInterestPaymentPrimitiveInstruction: <"An instruction to make a interium interest payment by adding a payout leg to the deal.">
    inputs:
        tradeState TradeState (1..1) <"The original trade to be modified.">
        interestAmount Money (1..1)
        settlementDate SettlementDate (1..1)
    output:
        instruction PrimitiveInstruction (1..1) <"Result is a Terms Change Instruction.">

    alias interestRatePayout:
        tradeState -> trade -> product -> economicTerms -> payout -> interestRatePayout only-element

    alias cashflow: <"A fully structured CashFlow or the following need to be provided to create a cashflow.">
        Create_Cashflow(
                interestAmount -> value,
                interestRatePayout -> priceQuantity -> quantitySchedule -> unit -> currency,
                settlementDate,
                interestRatePayout -> payerReceiver,
                CashflowType {
                    cashflowType: ScheduledTransferEnum -> NetInterest,
                    ... // TODO: set either cashPrice or priceExpression.
                },
                empty
            )

    condition InterestRatePayoutExists: <"Only a contractual product with a single interest rate payout can have an on-demand interest payment.">
        interestRatePayout exists

    condition Currency: <"The currency of the interest amount must match the currency of the original interest rate payout.">
        interestAmount -> unit -> currency = interestRatePayout -> priceQuantity -> quantitySchedule -> unit -> currency

    set instruction:
        PrimitiveInstruction {
            termsChange: Create_CashflowTermsChangeInstruction(
                        tradeState -> trade -> product,
                        cashflow
                    ),
            ...
        }

func Qualify_OnDemandPayment: <"Qualification of a on-demand payment.">
    [qualification BusinessEvent]
    inputs:
        businessEvent BusinessEvent (1..1)
    output:
        is_event boolean (1..1)

    alias afterTradeStates: FilterOpenTradeStates(businessEvent -> after)

    alias beforeCashFlow:
        FilterClosedTradeStates(businessEvent -> after) only-element -> trade -> product -> economicTerms -> payout -> cashflow
    alias afterCashFlow:
        FilterOpenTradeStates(businessEvent -> after) only-element -> trade -> product -> economicTerms -> payout -> cashflow

    set is_event:
        businessEvent -> instruction -> before count = 1
            and businessEvent -> after count = 1
            and afterTradeStates count = 1
            and businessEvent -> instruction -> primitiveInstruction -> termsChange only exists
            and afterCashFlow count > beforeCashFlow count // allows for adding multiple cashflows
            and afterCashFlow -> cashflowType -> cashflowType all = ScheduledTransferEnum -> NetInterest

func Create_CashflowTermsChangeInstruction:
    inputs:
        product NonTransferableProduct (1..1)
        cashFlow Cashflow (1..1)
    output:
        termsChangeInstruction TermsChangeInstruction (1..1)

    set termsChangeInstruction -> product: product
    add termsChangeInstruction -> product -> economicTerms -> payout -> cashflow:
        cashFlow

func Create_Cashflow:
    inputs:
        amount number (1..1)
        currency string (1..1)
        settlementDate SettlementDate (1..1)
        payerReceiver PayerReceiver (1..1)
        cashflowType CashflowType (1..1)
        paymentDiscounting PaymentDiscounting (0..1)
    output:
        cashflow Cashflow (1..1)

    set cashflow -> settlementTerms -> settlementDate: settlementDate
    set cashflow -> payerReceiver: payerReceiver
    set cashflow -> cashflowType: cashflowType
    set cashflow -> paymentDiscounting: paymentDiscounting

    set cashflow -> priceQuantity:
        ResolvablePriceQuantity {
            quantitySchedule: NonNegativeQuantitySchedule {
                    value: amount,
                    unit: UnitType {
                            currency: currency,
                            ...
                        },
                    ...
                },
            ...
        }

func Create_TerminationInstruction: <"Creates the relevant primitive instruction for a termination, which consists in a quantity change to bring the quantity to zero.">
    inputs:
        tradeState TradeState (1..1) <"The original trade to be termintaed.">
    output:
        instruction PrimitiveInstruction (1..1)

    alias changeQuantity: <"Create distinct list of Quantity with value set to zero.">
        tradeState -> trade -> tradeLot only-element -> priceQuantity -> quantity
            extract
                NonNegativeQuantitySchedule {
                    value: 0.0,
                    unit: item -> unit,
                    ...
                }
            then distinct

    alias changePriceQuantity: <"Create change PriceQuantity for QuantityChangeInstruction.">
        PriceQuantity {
            quantity: changeQuantity,
            ...
        }

    set instruction -> quantityChange: <"Set primitive instruction to be only a quantity change instruction (with values set to zero).">
        QuantityChangeInstruction {
            change: changePriceQuantity,
            direction: QuantityChangeDirectionEnum -> Replace,
            lotIdentifier: empty
        }

// End of ICMA - Phase 2 Contribution
func Create_BusinessEvent: <"Creates a business event from instructions containing primitive instructions and optionally a trade state.">
    [creation BusinessEvent]
    inputs:
        instruction Instruction (1..*)
        intent EventIntentEnum (0..1)
        eventDate date (1..1)
        effectiveDate date (1..1)
    output:
        businessEvent BusinessEvent (1..1)

    add businessEvent -> instruction: instruction

    set businessEvent -> intent: intent

    set businessEvent -> eventDate: eventDate

    set businessEvent -> effectiveDate: effectiveDate

    add businessEvent -> after:
        instruction
            extract
                if item -> primitiveInstruction -> split exists
                then Create_Split(
                            item -> primitiveInstruction -> split -> breakdown,
                            item -> before
                        )
                else if item -> primitiveInstruction -> exercise exists
                then Create_Exercise(
                            item -> primitiveInstruction -> exercise,
                            item -> before
                        )
                else [Create_TradeState(item -> primitiveInstruction, item -> before)]
            then flatten

// TODO: we should have a condition to ensure that no trade is 'lost' between the before(s) and the after(s).
// This can be implemented by looking at the trade identifier attribute on the before state, and making sure it exists in the after state.
// So for instance where there is a party change (which results in a different trade with a different trade id), the original trade should be split first, and one of the copies should 'close' the trade.
func Create_TradeState: <"Creates a single trade state by applying primitive instructions to an existing trade state (optional in case an execution instruction is included).
    The primitive instructions are applied in the following order:
        Always first:
            - execution, if it exists, otherwise a before state must be provided
        The following 3 can be executed in any order, because they touch separate components of the trade:
            - quantity change
            - terms change
            - party change
        Always last:
            - contract formation, otherwise the contract could be invalid.">
    inputs:
        primitiveInstruction PrimitiveInstruction (0..1) <"The set of primitive instructions to apply to the trade.">
        before TradeState (0..1) <"The original trade on which the primitive instructions are applied">
    output:
        after TradeState (1..1) <"The returned trade state must be of single cardinality. Where a different trade is created and the original trade must be persisted (for instance showing as 'closed'), it should be preceded by a split instruction.">

    alias execution: <"Create execution if instruction exists. If not, then before must exist.">
        if primitiveInstruction -> execution is absent
        then before
        else Create_Execution(primitiveInstruction -> execution)

    alias quantityChange: <"Apply quantity change if instructions exist.">
        if primitiveInstruction -> quantityChange is absent
        then execution
        else Create_QuantityChange(primitiveInstruction -> quantityChange, execution)

    alias termsChange: <"Apply terms change if instructions exist.">
        if primitiveInstruction -> termsChange is absent
        then quantityChange
        else Create_TermsChange(primitiveInstruction -> termsChange, quantityChange)

    alias partyChange: <"Apply party change if instructions exist.">
        if primitiveInstruction -> partyChange is absent
        then termsChange
        else Create_PartyChange(
                primitiveInstruction -> partyChange -> counterparty,
                primitiveInstruction -> partyChange -> ancillaryParty,
                primitiveInstruction -> partyChange -> partyRole,
                primitiveInstruction -> partyChange -> tradeId,
                termsChange /*after*/
            )

    alias contractFormation: <"Create contract formation if instructions exist.">
        if primitiveInstruction exists
                and primitiveInstruction -> contractFormation is absent
        then partyChange
        else Create_ContractFormation(
                primitiveInstruction -> contractFormation,
                partyChange
            )

    alias transfer:
        if primitiveInstruction -> transfer is absent
        then contractFormation
        else Create_Transfer(primitiveInstruction -> transfer, contractFormation)

    alias reset:
        if primitiveInstruction -> reset is absent
        then transfer
        else Create_Reset(primitiveInstruction -> reset, transfer)

    alias indexTransition:
        if primitiveInstruction -> indexTransition is absent
        then reset
        else Create_IndexTransitionTermsChange(
                primitiveInstruction -> indexTransition,
                reset
            )

    alias observation:
        if primitiveInstruction -> observation is absent
        then indexTransition
        else Create_Observation(primitiveInstruction -> observation, indexTransition)

    alias valuation:
        if primitiveInstruction -> valuation is absent
        then observation
        else Create_Valuation(primitiveInstruction -> valuation, observation)

    alias stockSplit:
        if primitiveInstruction -> stockSplit is absent
        then valuation
        else Create_StockSplit(primitiveInstruction -> stockSplit, valuation)

    condition NoSplit: <"The primitive instruction cannot contain a split, as this function is designed to return a single trade state.">
        primitiveInstruction -> split is absent

    set after: <"Initiate applying primitive instructions.">
        stockSplit

    set after -> state -> closedState:
        if contractFormation -> state -> positionState = PositionStatusEnum -> Closed
        then ClosedState {
                state: ClosedStateEnum -> Terminated,
                activityDate: empty, // TODO: set this property
                ...
            }

func ExtractBeforeEconomicTerms:
    inputs:
        businessEvent BusinessEvent (1..1)
    output:
        economicTerms EconomicTerms (0..1)

    set economicTerms:
        businessEvent -> instruction only-element -> before -> trade -> product -> economicTerms

func ExtractOpenEconomicTerms:
    inputs:
        businessEvent BusinessEvent (1..1)
    output:
        economicTerms EconomicTerms (0..1)

    set economicTerms:
        FilterOpenTradeStates(businessEvent -> after) only-element -> trade -> product -> economicTerms

func ExtractBeforeTrade:
    inputs:
        businessEvent BusinessEvent (1..1)
    output:
        trade Trade (0..1)

    set trade:
        businessEvent -> instruction only-element -> before -> trade

func ExtractAfterTrade:
    inputs:
        businessEvent BusinessEvent (1..1)
    output:
        trade Trade (0..1)

    set trade:
        FilterOpenTradeStates(businessEvent -> after) only-element -> trade

func ExtractTradePurchasePrice:
    inputs:
        tradableProduct TradableProduct (1..1)
    output:
        value number (0..*)

    set value:
        tradableProduct -> tradeLot only-element -> priceQuantity
            extract item -> quantity
            then flatten
            then extract item -> value

func ExtractTradeCollateralQuantity:
    inputs:
        tradableProduct TradableProduct (1..1)
    output:
        value number (0..*)

    set value:
        tradableProduct -> tradeLot only-element -> priceQuantity
            extract item -> quantity
            then flatten
            then extract item -> value

func ExtractTradeCollateralPrice:
    inputs:
        tradableProduct TradableProduct (1..1)
    output:
        value number (0..*)

    set value:
        tradableProduct -> tradeLot only-element -> priceQuantity
            extract item -> price
            then flatten
            then filter item -> priceType = PriceTypeEnum -> AssetPrice
            then extract item -> value




© 2015 - 2025 Weber Informatics LLC | Privacy Policy