How To Use the Swap Extension Package¶
To follow the script used in this tutorial, you can
clone the Daml Finance repository. In particular,
the Swap test folder src/test/daml/Daml/Finance/Instrument/Swap/Test/
is the starting point of
this tutorial.
Prerequisites¶
The Swap extension has many similarities with the Bond extension. This tutorial builds on the Bond Tutorial. 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 extension 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
src/test/daml/Daml/Finance/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"
ownerReceivesFix = False
fixRate = 0.0201
paymentPeriod = M
paymentPeriodMultiplier = 3
dayCountConvention = Act360
businessDayConvention = ModifiedFollowing
The floating leg depends on a reference rate, which is defined by the referenceRateId variable. The value of the reference rate is observed at the beginning of each payment period.
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 =
Frequency with
rollConvention = DOM d
period = couponPeriod
periodMultiplier = couponPeriodMultiplier
effectiveDate = issueDate
firstRegularPeriodStartDate = Some firstCouponDate
lastRegularPeriodEndDate = Some maturityDate
stubPeriodType = None
terminationDate = maturityDate
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:
cid <- toInterfaceContractId <$> submitMulti [depository, issuer] [] do
createCmd InterestRateSwap.Instrument with
depository; issuer; id = Id label; version = "0"; description
observers = M.fromList observers; lastEventTimestamp; periodicSchedule; holidayCalendarIds
calendarDataProvider; dayCountConvention; ownerReceivesFix; fixRate; referenceRateId; currency
Once the instrument is created, you can book 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:
cashInstrumentCid <- Instrument.originate custodian issuer "USD" "US Dollars" observers now
foreignCashInstrumentCid <- Instrument.originate custodian issuer "EUR" "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:
cid <- toInterfaceContractId <$> submitMulti [depository, issuer] [] do
createCmd CurrencySwap.Instrument with
depository; issuer; id = Id label; version = "0"; description
observers = M.fromList observers; lastEventTimestamp; periodicSchedule; holidayCalendarIds
calendarDataProvider; dayCountConvention; ownerReceivesBase; baseRate; foreignRate
baseCurrency; foreignCurrency; fxRate
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:
cashInstrumentCid <- Instrument.originate custodian issuer "USD" "US Dollars" observers now
foreignCashInstrumentCid <- Instrument.originate custodian issuer "EUR" "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:
cid <- toInterfaceContractId <$> submitMulti [depository, issuer] [] do
createCmd ForeignExchange.Instrument with
depository; issuer; id = Id label; version = "0"; description
observers = M.fromList observers; lastEventTimestamp; firstFxRate; finalFxRate; issueDate
firstPaymentDate; maturityDate, baseCurrency; foreignCurrency
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:
- 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”.
- 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:
cid <- toInterfaceContractId <$> submitMulti [depository, issuer] [] do
createCmd CreditDefaultSwap.Instrument with
depository; issuer; id = Id label; version = "0"; description
observers = M.fromList observers; lastEventTimestamp; periodicSchedule; holidayCalendarIds
calendarDataProvider; dayCountConvention; ownerReceivesFix; fixRate
defaultProbabilityReferenceId; recoveryRateReferenceId; currency
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 a fix rate and another one which pays the performance of an asset. 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
fixRate = 0.0201
paymentPeriod = M
paymentPeriodMultiplier = 3
dayCountConvention = Act360
businessDayConvention = ModifiedFollowing
In our example, the issuer pays the asset leg of the swap.
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
Finally, we create the asset swap instrument:
cid <- toInterfaceContractId <$> submitMulti [depository, issuer] [] do
createCmd AssetSwap.Instrument with
depository; issuer; id = Id label; version = "0"; description
observers = M.fromList observers; lastEventTimestamp; periodicSchedule; holidayCalendarIds
calendarDataProvider; dayCountConvention; ownerReceivesFix; fixRate; referenceAssetId; currency
Once the instrument is created, you can book a holding on it. The owner of the holding receives the asset leg (and pays the fix leg).
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 = 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 = holidayCalendarId
calculationPeriodDatesAdjustments = CalculationPeriodDatesAdjustments with
businessDayConvention = ModifiedFollowing
businessCenters = holidayCalendarId
firstRegularPeriodStartDate = Some firstRegularPeriodDateFixLeg
lastRegularPeriodEndDate = Some lastRegularPeriodDateFixLeg
calculationPeriodFrequency = CalculationPeriodFrequency with
periodMultiplier = 1
period = Y
rollConvention = DOM 20
paymentDates = PaymentDates with
calculationPeriodDatesReference = "fixedLegCalcPeriodDates"
paymentFrequency = PaymentFrequency with
periodMultiplier = 1
period = Y
firstPaymentDate = Some firstRegularPeriodDateFixLeg
lastRegularPaymentDate = Some lastRegularPeriodDateFixLeg
payRelativeTo = CalculationPeriodEndDate
paymentDatesAdjustments = BusinessDayAdjustments with
businessDayConvention = ModifiedFollowing
businessCenters = holidayCalendarId
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
dayCountFraction = dayCountConvention
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 = holidayCalendarId
calculationPeriodDatesAdjustments = CalculationPeriodDatesAdjustments with
businessDayConvention = ModifiedFollowing
businessCenters = holidayCalendarId
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 = holidayCalendarId
resetDates = Some ResetDates with
calculationPeriodDatesReference = "floatingLegCalcPeriodDates"
resetRelativeTo = CalculationPeriodStartDate
fixingDates = FixingDates with
periodMultiplier = -2
period = D
dayType = Business
businessDayConvention = NoAdjustment
businessCenters = fixingHolidayCalendarId
resetFrequency = ResetFrequency with
periodMultiplier = paymentPeriodMultiplier
period = paymentPeriod
resetDatesAdjustments = ResetDatesAdjustments with
businessDayConvention = ModifiedFollowing
businessCenters = holidayCalendarId
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 = paymentPeriod
spreadSchedule = SpreadSchedule with
initialValue = 0.005
dayCountFraction = dayCountConvention
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:
- None: No special stub rate is provided. Instead, use the same rate as was specified in the corresponding Calculation.
- Specific stubRate: Use this specific fix rate.
- 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:
cid <- toInterfaceContractId <$> submitMulti [depository, issuer] [] do
createCmd FpmlSwap.Instrument with
depository; issuer; id = Id label; version = "0"; description
observers = M.fromList observers; lastEventTimestamp; swapStreams; issuerPartyRef
calendarDataProvider; currencies
Once the instrument is created, you can book 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.