How to use the Swap Instrument package

To follow the code snippets used in this page in Daml Studio, you can clone the Daml Finance repository and run the scripts included in the Instrument/Swap/Test/ folder.

Prerequisites

Swap instruments share many similarities with Bond instruments. This page builds on the page for the Bond Instruments. Please, check it out before reading the Swap specifics below.

How To Create a Swap Instrument

There are different types of swaps, which differ both in the way regular payments are defined and whether notional is exchanged. In order to create a swap instrument, you first have to decide what type of swap you need. The swap instrument package currently supports the following types of swaps:

Interest Rate

Interest rate swap is the type of swap that shares most similarities with a bond. It has two legs: one which pays a fix rate and another one which pays a floating rate. These rates are paid at the end of every payment period.

As an example, we will create a swap instrument paying Libor 3M vs a 2.01% p.a. with a 3M payment period. This example is taken from Instrument/Swap/Test/InterestRate.daml , where all the details are available.

We start by defining the terms:

  let
    issueDate = date 2019 Jan 16
    firstPaymentDate = date 2019 Feb 15
    maturityDate = date 2019 May 15
    referenceRateId = "USD/LIBOR/3M"
    floatingRate = FloatingRate with
      referenceRateId
      referenceRateType = SingleFixing CalculationPeriodStartDate
      fixingDates = DateOffset with
        periodMultiplier = 0
        period = D
        dayType = Some Business
        businessDayConvention = NoAdjustment
        businessCenters = ["USD"]
    ownerReceivesFix = False
    fixRate = 0.0201
    paymentPeriod = M
    paymentPeriodMultiplier = 3
    dayCountConvention = Act360
    businessDayConvention = ModifiedFollowing

The floating leg depends on a reference rate, which is specified in the FloatingRate data structure. It supports two types of reference rates, which are configurable using the ReferenceRateTypeEnum:

  • Libor/Euribor style rates with a single fixing
  • SOFR style reference rates (using a compounded index)

The ownerReceivesFix variable is used to specify whether a holding owner of this instrument receives the fix or the floating leg. This is not needed for bonds, because the regular payments are always in one direction (from the issuer to the holder). However, in the case of a swap with two counterparties A and B, we need the ownerReceivesFix variable to specify who receives fix and who receives floating. In this example, the holding owner receives the floating leg.

Just as for bonds, we can use these variables to create a PeriodicSchedule:

    let
      (y, m, d) = toGregorian firstCouponDate
      periodicSchedule = PeriodicSchedule with
        businessDayAdjustment =
          BusinessDayAdjustment with
            calendarIds = holidayCalendarIds
            convention = businessDayConvention
        effectiveDateBusinessDayAdjustment = None
        terminationDateBusinessDayAdjustment = None
        frequency =
          Periodic Frequency with
            rollConvention = DOM d
            period = Period with
              period = couponPeriod
              periodMultiplier = couponPeriodMultiplier
        effectiveDate = issueDate
        firstRegularPeriodStartDate = Some firstCouponDate
        lastRegularPeriodEndDate = Some maturityDate
        stubPeriodType = None
        terminationDate = maturityDate

For more information on calendar, schedule, and day count functions, see the date utility functions tutorial.

Note that this instrument only has one periodic schedule, which is used for both the fixed and the floating leg. It is also used for both the calculation period (to determine which floating rate to be used) and the payment period (to determine when payments are done). The FpML swap template below offers more flexibility here. It has individual schedules, both for the fixed/floating leg and for the calculation/payment periods. That would allow you to specify whether payments should be made e.g. after each calculation period or only after every second calculation period.

Now that we have defined the terms we can create the swap instrument:

    let
      instrument = InstrumentKey with
        issuer
        depository
        id = Id label
        version = "0"
        holdingStandard

    cid <- submitMulti [issuer] [publicParty] do
      exerciseCmd interestRateSwapFactoryCid InterestRateSwapFactory.Create with
        interestRate = InterestRate with
          instrument
          description
          periodicSchedule
          holidayCalendarIds
          calendarDataProvider
          dayCountConvention
          floatingRate
          fixRate
          ownerReceivesFix
          currency
          lastEventTimestamp
        observers = fromList observers

Once this is done, you can create a holding on it using Account.Credit. The owner of the holding receives the floating leg (and pays the fix leg).

Currency

Currency swaps are quite similar to interest rate swaps, except that the two legs are in different currencies. Consequently, we need to create two cash instruments:

  cashInstrument <- originate custodian issuer "USD" TransferableFungible "US Dollars" observers now
  foreignCashInstrument <- originate custodian issuer "EUR" TransferableFungible "Euro" observers
    now

In the swap template they are referred to as base currency and foreign currency.

Here is an example of a fix vs fix currency swap: 3% p.a. in USD vs 2% p.a. in EUR with payments every 3M:

  let
    issueDate = date 2019 Jan 16
    firstPaymentDate = date 2019 Feb 15
    maturityDate = date 2019 May 15
    ownerReceivesBase = False
    baseRate = 0.03
    foreignRate = 0.02
    fxRate = 1.1
    paymentPeriod = M
    paymentPeriodMultiplier = 3
    dayCountConvention = Act360
    businessDayConvention = ModifiedFollowing

In this example, the holding owner receives the foreign currency leg.

In order to calculate the interest rate payments, a notional is required in each currency. The quantity of the holding refers to the notional of the base currency. The notional of the foreign currency is defined as the quantity of the holding multiplied by the specified fxRate.

Note that this template is limited to fixed rates. It also does not support exchange of notionals. If you need floating rates or exchange of notionals, please use the FpML swap template below. It supports both of those features.

Here is how we create the currency swap instrument, using the two currencies defined above:

    let
      instrument = InstrumentKey with
        issuer
        depository
        id = Id label
        version = "0"
        holdingStandard

    cid <- submitMulti [issuer] [publicParty] do
      exerciseCmd currencySwapFactoryCid CurrencySwapFactory.Create with
        currencySwap = CurrencySwap with
          instrument
          description
          periodicSchedule
          holidayCalendarIds
          calendarDataProvider
          dayCountConvention
          ownerReceivesBase
          baseRate
          foreignRate
          baseCurrency
          foreignCurrency
          fxRate
          lastEventTimestamp
        observers = fromList observers

Once the instrument is created, you can create a holding on it. In our example, it the owner of the holding receives the foreign currency leg (and pays the base currency leg).

Foreign Exchange

Despite the similarities in name, foreign exchange swaps (or FX swaps) are quite different from currency swaps. An FX swap does not pay or receive interest. Instead, the two legs define an initial FX transaction and a final FX transaction. Each transaction requires an FX rate and a transaction date, which are predetermined between the counterparties.

The FX transactions involve two currencies. In the swap template these are referred to as base currency and foreign currency. The convention is that the holding owner receives the foreign currency in the initial transaction (and pays it in the final transaction).

Here is an example of an USD vs EUR FX swap. First, we define the two cash instruments:

  cashInstrument <- originate custodian issuer "USD" TransferableFungible "US Dollars" observers now
  foreignCashInstrument <- originate custodian issuer "EUR" TransferableFungible "Euro" observers
    now

Then, we define the transaction dates and FX rates:

  let
    issueDate = date 2019 Jan 16
    firstPaymentDate = date 2019 Feb 15
    maturityDate = date 2019 May 15
    firstFxRate = 1.1
    finalFxRate = 1.2

The firstPaymentDate variable defines the date of the initial FX transaction. Generally, this is on the issue date or shortly afterwards.

Finally, we create the FX swap instrument:

    let
      instrument = InstrumentKey with
        issuer
        depository
        id = Id label
        version = "0"
        holdingStandard

    cid <- submitMulti [issuer] [publicParty] do
      exerciseCmd foreignExchangeSwapFactoryCid ForeignExchangeSwapFactory.Create with
        foreignExchange = ForeignExchange with
          instrument
          description
          baseCurrency
          foreignCurrency
          firstFxRate
          finalFxRate
          issueDate
          firstPaymentDate
          maturityDate
          lastEventTimestamp
        observers = fromList observers

Once the instrument is created, you can create a holding on it. The owner of the holding receives the foreign currency in the initial transaction. In the final transaction the sides are reversed.

Credit Default

A credit default swap (CDS) pays a protection amount in case of a credit default event, in exchange for a fix rate at the end of every payment period. The protection amount is defined as 1-recoveryRate. The recoveryRate is defined as the amount recovered when a borrower defaults, expressed as a percentage of notional.

If a credit event occurs, the swap expires after the protection amount has been paid, i.e., no more rate payments are required afterwards.

Here is an example of a CDS that pays 1-recoveryRate in the case of a default on TSLA bonds:

issueDate = date 2019 Jan 16
firstPaymentDate = date 2019 Feb 15
maturityDate = date 2019 May 15
defaultProbabilityReferenceId = "TSLA-DEFAULT-PROB"
recoveryRateReferenceId = "TSLA-RECOVERY-RATE"
ownerReceivesFix = False
fixRate = 0.0201
paymentPeriod = M
paymentPeriodMultiplier = 3
dayCountConvention = Act360
businessDayConvention = ModifiedFollowing

In our example, the issuer pays the protection leg of the swap.

As you can see in this example, two observables are required for a CDS:

  1. defaultProbabilityReferenceId: The reference ID of the default probability observable. For example, in case of protection against a “TSLA bond payment default” this should be a valid reference to the “TSLA default probability”.
  2. recoveryRateReferenceId: The reference ID of the recovery rate observable. For example, in case of a “TSLA bond payment default with a 60% recovery rate” this should be a valid reference to the “TSLA bond recovery rate”.

Finally, we create the CDS instrument:

    let
      instrument = InstrumentKey with
        issuer
        depository
        id = Id label
        version = "0"
        holdingStandard

    cid <- submitMulti [issuer] [publicParty] do
      exerciseCmd creditDefaultSwapFactoryCid CreditDefaultSwapFactory.Create with
        creditDefault = CreditDefault with
          instrument
          description
          periodicSchedule
          holidayCalendarIds
          calendarDataProvider
          dayCountConvention
          fixRate
          ownerReceivesFix
          defaultProbabilityReferenceId
          recoveryRateReferenceId
          currency
          lastEventTimestamp
        observers = fromList observers

Once the instrument is created, you can create a holding on it. In our example, the owner of the holding receives the protection leg (and pays the fix leg).

Asset

An asset swap is a general type of swap with two legs: one which pays an interest rate and another one which pays the performance of an asset (or a basket of assets). It can be used to model:

  • equity swaps
  • some types of commodity swaps (of the form performance vs rate)
  • other swaps with the same payoff on other asset types.

Here is an example of an asset swap that pays AAPL total return vs 2.01% fix p.a., payment every 3M:

  let
    issueDate = date 2019 Jan 16
    firstPaymentDate = date 2019 Feb 15
    maturityDate = date 2019 May 15
    referenceAssetId = "AAPL-CLOSE-ADJ"
    ownerReceivesFix = False
    floatingRate = None
    fixRate = 0.0201
    paymentPeriod = M
    paymentPeriodMultiplier = 3
    dayCountConvention = Act360
    businessDayConvention = ModifiedFollowing

In our example, the issuer pays the asset leg of the swap.

Finally, we create the asset swap instrument:

    let
      instrument = InstrumentKey with
        issuer
        depository
        id = Id label
        version = "0"
        holdingStandard

    cid <- submitMulti [issuer] [publicParty] do
      exerciseCmd assetSwapFactoryCid AssetSwapFactory.Create with
        asset = Asset with
          instrument
          description
          periodicSchedule
          holidayCalendarIds
          calendarDataProvider
          dayCountConvention
          floatingRate
          fixRate
          ownerReceivesRate
          underlyings
          currency
          lastEventTimestamp
        observers = fromList observers

Once this is done, you can create a holding on it. The owner of the holding receives the asset leg (and pays the fix leg).

One observable is required: referenceAssetId. The template calculates the performance for each payment period using this observable. Performance is calculated from the start date to the end date of each payment period. The reference asset Observable needs to contain the appropriate type of fixings:

  • unadjusted fixings in case of a price return asset swap
  • adjusted fixings in case of a total return asset swap

There is one exception to this: a total return asset swap with dividend passthrough. In this case, you can use unadjusted fixings for the instrument and lifecycle the dividend event separately using a dedicated asset swap DistributionRule:

  -- Lifecycle the asset swap to create an effect for the dividend.
  (Some swapInstrumentAfterDividend, [effectCid]) <- submitMulti [issuer] [publicParty] do
    exerciseCmd distributionRuleCid Lifecycle.Evolve with
      observableCids = []
      eventCid = aaplDividendDistributionEventCid
      instrument = swapInstrumentAfterFirstPayment

FpML

Unlike the other swap types above, the FpML swap template is not a new type of payoff. Instead, it allows you to input other types of swaps using the FpML schema. Currently, interest rate swaps and currency swaps are supported. The template can quite easily be extended to FX swaps.

Specifically, it allows you to specify one swapStream object for each leg of the swap.

We start by defining the general terms:

  let
    issueDate = date 2022 Sep 14
    firstRegularPeriodDate = date 2022 Sep 20
    lastRegularPeriodDate = date 2023 Jun 20
    maturityDate = date 2023 Sep 14
    firstRegularPeriodDateFixLeg = date 2022 Sep 20
    lastRegularPeriodDateFixLeg = firstRegularPeriodDateFixLeg
    referenceRateId = "USD/LIBOR/3M"
    referenceRateOneMonthId = "USD/LIBOR/1M"
    fixRate = 0.02
    paymentPeriod = Regular M
    paymentPeriodMultiplier = 3
    dayCountConvention = Act360
    businessDayConvention = ModifiedFollowing
    issuerPartyRef = "Counterparty"
    clientPartyRef = "ExecutingParty"

The issuerPartyRef and the clientPartyRef variables are used to specify who pays each leg (see payerPartyReference below).

The fixed leg of the swap can now be defined using Daml data types that correspond to the swapStream schema:

    swapStreamFixedLeg = SwapStream with
      payerPartyReference = clientPartyRef
      receiverPartyReference = issuerPartyRef
      calculationPeriodDates = CalculationPeriodDates with
        id = "fixedLegCalcPeriodDates"
        effectiveDate = AdjustableDate with
          unadjustedDate = issueDate
          dateAdjustments = BusinessDayAdjustments with
            businessDayConvention = NoAdjustment
            businessCenters = []
        terminationDate = AdjustableDate with
          unadjustedDate = maturityDate
          dateAdjustments = BusinessDayAdjustments with
            businessDayConvention = ModifiedFollowing
            businessCenters = holidayCalendarIds
        calculationPeriodDatesAdjustments = CalculationPeriodDatesAdjustments with
          businessDayConvention = ModifiedFollowing
          businessCenters = holidayCalendarIds
        firstPeriodStartDate = None
        firstRegularPeriodStartDate = Some firstRegularPeriodDateFixLeg
        lastRegularPeriodEndDate = Some lastRegularPeriodDateFixLeg
        calculationPeriodFrequency = CalculationPeriodFrequency with
          periodMultiplier = 1
          period = Regular Y
          rollConvention = DOM 20
      paymentDates = PaymentDates with
        calculationPeriodDatesReference = "fixedLegCalcPeriodDates"
        paymentFrequency = PaymentFrequency with
          periodMultiplier = 1
          period = Regular Y
        firstPaymentDate = Some firstRegularPeriodDateFixLeg
        lastRegularPaymentDate = Some lastRegularPeriodDateFixLeg
        payRelativeTo = CalculationPeriodEndDate
        paymentDatesAdjustments = BusinessDayAdjustments with
          businessDayConvention = ModifiedFollowing
          businessCenters = holidayCalendarIds
        paymentDaysOffset = None
      resetDates = None
      calculationPeriodAmount = CalculationPeriodAmount with
        calculation = Calculation with
          notionalScheduleValue = NotionalSchedule_Regular NotionalSchedule with
            id = "fixedLegNotionalSchedule"
            notionalStepSchedule = NotionalStepSchedule with
              initialValue = 1000000.0
              step = []
              currency = "USD"
          rateTypeValue = RateType_Fixed FixedRateSchedule with
            initialValue = fixRate
            step = []
          dayCountFraction = dayCountConvention
          compoundingMethodEnum = None
      stubCalculationPeriodAmount = None
      principalExchanges = None

As you can see, the Daml SwapStream data type matches the swapStream FpML schema. Please note that the actual parsing from FpML to Daml is not done by this template. It has to be implemented on the client side.

Similarly, the floating leg of the swap is defined like this:

    swapStreamFloatingLeg = SwapStream with
      payerPartyReference = issuerPartyRef
      receiverPartyReference = clientPartyRef
      calculationPeriodDates = CalculationPeriodDates with
        id = "floatingLegCalcPeriodDates"
        effectiveDate = AdjustableDate with
          unadjustedDate = issueDate
          dateAdjustments = BusinessDayAdjustments with
            businessDayConvention = NoAdjustment
            businessCenters = []
        terminationDate = AdjustableDate with
          unadjustedDate = maturityDate
          dateAdjustments = BusinessDayAdjustments with
            businessDayConvention = ModifiedFollowing
            businessCenters = holidayCalendarIds
        calculationPeriodDatesAdjustments = CalculationPeriodDatesAdjustments with
          businessDayConvention = ModifiedFollowing
          businessCenters = holidayCalendarIds
        firstPeriodStartDate = None
        firstRegularPeriodStartDate = Some firstRegularPeriodDate
        lastRegularPeriodEndDate = Some lastRegularPeriodDate
        calculationPeriodFrequency = CalculationPeriodFrequency with
          periodMultiplier = paymentPeriodMultiplier
          period = paymentPeriod
          rollConvention = DOM 20
      paymentDates = PaymentDates with
        calculationPeriodDatesReference = "floatingLegCalcPeriodDates"
        paymentFrequency = PaymentFrequency with
          periodMultiplier = paymentPeriodMultiplier
          period = paymentPeriod
        firstPaymentDate = Some firstRegularPeriodDate
        lastRegularPaymentDate = Some lastRegularPeriodDate
        payRelativeTo = CalculationPeriodEndDate
        paymentDatesAdjustments = BusinessDayAdjustments with
          businessDayConvention = ModifiedFollowing
          businessCenters = holidayCalendarIds
        paymentDaysOffset = None
      resetDates = Some ResetDates with
        calculationPeriodDatesReference = "floatingLegCalcPeriodDates"
        resetRelativeTo = CalculationPeriodStartDate
        fixingDates = FixingDates with
          periodMultiplier = -2
          period = D
          dayType = Some Business
          businessDayConvention = NoAdjustment
          businessCenters = fixingHolidayCalendarId
        resetFrequency = ResetFrequency with
          periodMultiplier = paymentPeriodMultiplier
          period = paymentPeriod
        resetDatesAdjustments = ResetDatesAdjustments with
          businessDayConvention = ModifiedFollowing
          businessCenters = holidayCalendarIds
      calculationPeriodAmount = CalculationPeriodAmount with
        calculation = Calculation with
          notionalScheduleValue = NotionalSchedule_Regular NotionalSchedule with
            id = "floatingLegNotionalSchedule"
            notionalStepSchedule = NotionalStepSchedule with
              initialValue = 1000000.0
              step = []
              currency = "USD"
          rateTypeValue = RateType_Floating FloatingRateCalculation with
            floatingRateIndex = referenceRateId
            indexTenor = Some Period with
              periodMultiplier = paymentPeriodMultiplier
              period = M
            spreadSchedule = [SpreadSchedule with initialValue = 0.005]
            finalRateRounding = None
          dayCountFraction = dayCountConvention
          compoundingMethodEnum = Some Straight
      stubCalculationPeriodAmount = Some StubCalculationPeriodAmount with
        calculationPeriodDatesReference = "floatingLegCalcPeriodDates"
        initialStub = Some $ StubValue_StubRate 0.015
        finalStub = Some $ StubValue_FloatingRate
          [ StubFloatingRate with
              floatingRateIndex=referenceRateOneMonthId
              indexTenor = Some (Period with period = M; periodMultiplier = 1)
          , StubFloatingRate with
              floatingRateIndex = referenceRateId
              indexTenor = Some (Period with period = M; periodMultiplier = 3)
          ]
      principalExchanges = None

There are three main ways to define which interest rate should be used for a stub period. They are all included in the fix or floating leg above, either in the inital or in the final stub period. In short, it depends on the content of StubCalculationPeriodAmount:

  1. None: No special stub rate is provided. Instead, use the same rate as was specified in the corresponding Calculation.
  2. Specific stubRate: Use this specific fix rate.
  3. Specific floatingRate: Use this specific floating rate (if one rate is provided). If two rates are provided: use linear interpolation between the two rates.

Finally, we create the FpML swap instrument:

    let
      instrument = InstrumentKey with
        issuer
        depository
        id = Id label
        version = "0"
        holdingStandard

    cid <- submitMulti [issuer] [publicParty] do
      exerciseCmd fpmlSwapFactoryCid FpmlSwapFactory.Create with
        fpml = Fpml with
          instrument
          description
          swapStreams
          issuerPartyRef
          currencies
          calendarDataProvider
          lastEventTimestamp
        observers = fromList observers

Once this is done, you can create a holding on it. In this particular example trade, the notional is specified in the FpML instrument. This means that you would only book a unit holding (quantity=1.0) on the instrument.

Frequently Asked Questions

Why do the swaps have an issuer?

In the case of bonds, the instrument has a well-defined issuer. This is not necessarily the case for swaps, where two counterparties A and B swap the payments associated with each leg. However, in practice one of the counterparties is often a swap dealer, who shares some of the characteristics of a bond issuer. For the purpose of lifecycling in Daml Finance, we require one of the counterparties to take the role as issuer. This counterparty will serve as calculation agent and provide the observables required to calculate the swap payments.

The documentation of the Daml Finance asset model contains an OTC swap example.