Modelling repurchase agreements in LUSID

Prev Next

You can model a repurchase agreement (“repo”) as a buyer or a seller using the FlexibleRepo instrument type. See all supported instruments.

Note: This article explains how to master an instrument and then load a transaction using the LUSID API. It is possible to simply load a transaction in the LUSID web app and have LUSID master the instrument for you. Contact us for more information.

Mastering an instrument

There are numerous tools you can use to master a FlexibleRepo in the LUSID Security Master.

Some fields are common to all types of instrument, such as an intuitive name, the requirement to specify a set of identifiers, and the facility to store extra information as properties.

Fields in the economic definition object are specific to FlexibleRepo. For more information on these fields, select FlexibleRepo from the definition dropdown in the UpsertInstruments API reference, or alternatively examine the FlexibleRepo schema:

Mastering a collateral instrument

If the repo has collateral that is a supported instrument, master it separately and then provide a reference to a MasteredInstrument. See how to master a bond.

Mastering a FlexibleRepo instrument

The following call to the UpsertInstruments API masters a term repo as a buyer with a vanilla fixed-rate bond as collateral:

curl -X POST 'https://mydomain.lusid.com/api/api/instruments?scope=MyCustomInstrScope'
   -H 'Content-Type: application/json-patch+json'
   -H 'Authorization: Bearer myAPIAccessToken'
   -d '{"upsert-request-1": {
    "name": "Buyer-TermFlexRepo",
    "identifiers": {"ClientInternal": {"value": "Buyer-TermFlexRepo"}},
    "definition": {
      "instrumentType": "FlexibleRepo",
      "startDate": "2025-01-02T00:00:00.0000000+00:00",
      "maturityDate": "2025-03-31T00:00:00.0000000+00:00",
      "buyerOrSeller": "Buyer",
      "repoCcy": "GBP",
      "repoType": "TermRepo",
      "accrualBasis": "Act365",
      "collateral": {
        "collateralInstruments": [{
          "units": 1,
          "instrument": {
            "instrumentType": "MasteredInstrument",
            "identifiers": {"Instrument/default/ClientInternal": "BondCollateral"}
            }
          }
        ],
        "collateralValue": 1100000,
        "buyerReceivesCashflows": false,
        "buyerReceivesCorporateActionPayments": false
      },
      "haircut": 0.091,
      "margin": null,
      "purchasePrice": null,
      "repoRateSchedules": [{
        "scheduleType": "FixedSchedule",
        "couponRate": 0.05,
        "startDate": "2025-01-02T00:00:00.0000000+00:00",
        "maturityDate": "2025-03-31T00:00:00.0000000+00:00",
        "flowConventions": {
          "currency": "GBP",
          "paymentFrequency": "1T",
          "dayCountConvention": "Act365",
          "rollConvention": "None",
          "paymentCalendars": [],
          "resetCalendars": []
        },
        "notional": 1,
        "paymentCurrency": "GBP"
        }
      ],
      "repurchasePrice": null
    }
  }
}'

Note the following:

  • This FlexibleRepo instrument is mastered in a custom instrument scope (specified in the URL).

  • Its identifiers object is set to reference a ClientInternal unique identifier.

  • buyerOrSeller is set to Buyer to receive collateral and send cash on startDate, but it could be Seller to send collateral and receive cash.

  • repoType is TermRepo because maturityDate is known. If it is not, specify OpenRepo and set:

    • maturityDate to a significantly distant date, for example 9999-12-31.

    • openRepoRollingPeriod to a tenor representing an interest payment window, for example 1D or 1W or 1M.

  • accrualBasis is Act365 to count the number of accrual days using a particular convention.

  • The Collateral object:

    • Specifies an instrumentType of MasteredInstrument and a unique identifier (in this case ClientInternal) to resolve to the collateral instrument.

    • Specifies the collateralValue.

    • Retains the default values of false for buyerReceivesCashFlows and buyerReceivesCorporateActionPayments, so the seller keeps payments while the contract is in effect. Note the buyer actually receives the cashflows but LUSID can automatically handle refunding the seller (more information coming soon).

  • The haircut is set to 0.091 but you could specify either a margin or a purchasePrice if these are known instead.

  • The repoRateSchedules array has a single FixedSchedule object to specify an absolute repo rate, though you can specify a single FloatSchedule to link the repo rate to an index instead if you wish:

    • The couponRate (that is, repo rate) is expressed as a fraction, so 0.05 representing 5%. Note you can omit the repoRateSchedules array entirely and specify an explicit repurchasePrice if this is known instead.

    • The startDate and maturityDate must be the same as the FlexibleRepo itself.

    • The FlowConventions object configures the repurchase date. Note the paymentFrequency must be 1T and currency the same as repoCcy. More information on roll and business day conventions.

    • notional should be 1.

    • paymentCurrency must be the same as repoCcy.

In summary:

  • You must specify collateralValue and one of haircut, margin or purchasePrice to determine the purchase price. Note if you do not specify an explicit purchasePrice then LUSID calculates it as follows:

    • purchasePrice = collateralValue * (1 - haircut). In our example, this yields 1000000.

    • purchasePrice = collateralValue / margin

  • You must specify either couponRate (within the repoRateSchedules array) or repurchasePrice to determine the repurchase price. Note if you do not specify an explicit repurchasePrice then LUSID calculates it as follows:

    repurchasePrice = (1 + couponRate * <day-count-fraction>) * purchasePrice

    …where <day-count-fraction> depends on the number of days in the contract and the day count convention. In our example, this yields 1012054.79.

Providing the request is successful, the response:

  • Confirms the globally-unique LUID of the FlexibleRepo instrument (in this case LUID_00003EPX).

  • Confirms the LUID of the collateral MasteredInstrument providing LUSID is able to resolve it correctly (in this case LUID_00003EPW). If not, the unknown instrument is returned.

  • Generates extra fields that are stored as part of the instrument definition and can be filtered on.

  • Supplies default values for fields not explicitly specified in the request:

{
  "values": {
    "upsert-request-1": {
      "scope": "MyCustomInstrScope",
      "lusidInstrumentId": "LUID_00003EPX",
      "name": "Buyer-TermFlexRepo",
      "identifiers": {
        "ClientInternal": "Buyer-TermFlexRepo",
        "LusidInstrumentId": "LUID_00003EPX"
      },
      "properties": [],
      "instrumentDefinition": {
        "startDate": "2025-01-02T00:00:00.0000000+00:00",
        "maturityDate": "2025-03-31T00:00:00.0000000+00:00",
        "buyerOrSeller": "Buyer",
        "repoCcy": "GBP",
        "repoType": "TermRepo",
        "accrualBasis": "Actual365",
        "collateral": {
          "buyerReceivesCashflows": false,
          "buyerReceivesCorporateActionPayments": false,
          "collateralInstruments": [
            {
              "units": 1,
              "instrument": {
                "identifiers": {
                  "Instrument/default/ClientInternal": "BondCollateral"
                },
                "masteredDomCcy": "GBP",
                "masteredInstrumentType": "Bond",
                "masteredLusidInstrumentId": "LUID_00003EPW",
                "masteredName": "BondCollateral",
                "masteredScope": "MyCustomInstrScope",
                "masteredAssetClass": "Credit",
                "instrumentType": "MasteredInstrument"
              }
            }
          ],
          "collateralValue": 1100000
        },
        "haircut": 0.091,
        "repoRateSchedules": [
          {
            "startDate": "2025-01-02T00:00:00.0000000+00:00",
            "maturityDate": "2025-03-31T00:00:00.0000000+00:00",
            "flowConventions": {
              "currency": "GBP",
              "paymentFrequency": "1T",
              "dayCountConvention": "Actual365",
              "rollConvention": "None",
              "paymentCalendars": [],
              "resetCalendars": [],
              "settleDays": 0,
              "resetDays": 0,
              "leapDaysIncluded": true,
              "accrualDateAdjustment": "Adjusted",
              "businessDayConvention": "None",
              "accrualDayCountConvention": "Actual365"
            },
            "couponRate": 0.05,
            "notional": 1,
            "paymentCurrency": "GBP",
            "stubType": "None",
            "scheduleType": "FixedSchedule"
          }
        ],
        "tradingConventions": {
          "priceScaleFactor": 1,
          "minimumOrderSize": 0,
          "minimumOrderIncrement": 0
        },
        "instrumentType": "FlexibleRepo"
      },
      "state": "Active",
      "assetClass": "InterestRates",
      "domCcy": "GBP",
      "relationships": [],
      "dataModelMembership": {
        "membership": []
      }
    }
  },
  ...
}

Booking a transaction to establish a position

Once a FlexibleRepo instrument is mastered, you can call the BatchUpsertTransactions API to record the acquisition of a number of contracts in a particular portfolio, for example:

curl -X POST 'https://mydomain.lusid.com/api/api/transactionportfolios/MyPortfolioScope/MyPortfolioCode/transactions/$batchUpsert?successMode=Partial&preserveProperties=true'
  -H 'Content-Type: application/json-patch+json'
  -H 'Authorization: Bearer myAPIAccessToken'
  -d '{
  "transactionRequest-1": {
    "transactionId": "my_repo_purchase_001",
    "type": "StockIn",
    "instrumentIdentifiers": {"Instrument/default/ClientInternal": "Buyer-TermFlexRepo"},
    "transactionDate": "2025-01-01T00:00:00.0000000+00:00",
    "settlementDate": "2025-01-01T00:00:00.0000000+00:00",
    "units": 1,
    "transactionPrice": {
      "price": 1000000,
      "type": "Price"
    },
    "totalConsideration": {
      "amount": 1000000,
      "currency": "GBP"
    }
  }
}'

Note the following:

  • The type field invokes the built-in StockIn transaction type to acquire a single unit of the repo without impacting cash holdings, though you can create a custom transaction type with a different economic impact if you wish.

  • The transactionDate and settlementDate must be before the start date of the repo in the instrument definition. This is so LUSID can automatically handle the transfer of collateral and cash between buyer and seller. More information.

  • The totalConsideration.amount (cost) is set to the purchasePrice of the FlexibleRepo to yield the correct accounting treatment. See the previous section for how to work this out if not explicitly known.

Note: This example assumes the transaction, settlement and portfolio currencies are all the same. If not, you can specify exchange rates.

Confirming positions

We can generate a holdings report on the transaction date of 1 January 2025 to see that we have:

  • One unit of the repo holding

  • Three units of a holding in the bond collateral instrument (this transaction isn’t shown above but you can see an example here):

If we fast-forward to the start date of the instrument on 2 January 2025 we see that we have:

  • One unit of the repo holding

  • Four units of the bond holding (LUSID has automatically transferred one unit from the seller)

  • A cash holding of -£1000000 (LUSID has automatically transferred purchasePrice to the seller):

Auditing LUSID’s automatically-generated transactions

We can examine the output transactions generated by instrument events to understand how LUSID automatically transfers collateral and cash between buyer and seller on 2 January 2025:

Valuing your position

To value a position in a FlexibleRepo (and also any collateral instrument) held in a portfolio, work through our valuation checklist.

Note: The default pricing model for a FlexibleRepo is SimpleStatic. We recommend keeping this default.

For example, to value the portfolio shown above on 15 February 2025:

  1. Load market prices into the LUSID Quote Store:

    1. A dummy price of 1 for the FlexibleRepo. The SimpleStatic model has a dependency on this data, but it can be unitised and valid for the lifetime of the contract.

    2. A price for the bond collateral instrument valid for the valuation date:

    curl -X POST 'https://mydomain.lusid.com/api/api/quotes/MyRepoPortfolioQuotes'
      -H 'Authorization: Bearer myAPIAccessToken'
      -H 'Content-Type: application/json-patch+json'
      -d '{
        "Quote-0001": {
          "quoteId": {
            "quoteSeriesId": {
              "provider": "Lusid",
              "instrumentIdType": "ClientInternal",
              "instrumentId": "Buyer-TermFlexRepo",
              "quoteType": "Price",
              "field": "mid"
            },
            "effectiveAt": "2025-01-01T00:00:00Z"
          },
          "metricValue": {
            "value": 1, "unit": "GBP"
          }
        },
        "Quote-0002": {
          "quoteId": {
            "quoteSeriesId": {
              "provider": "Lusid",
              "instrumentIdType": "ClientInternal",
              "instrumentId": "BondCollateral",
              "quoteType": "Price",
              "field": "mid"
            },
            "effectiveAt": "2025-02-15T00:00:00Z"
          },
          "metricValue": {
            "value": 101, "unit": "GBP"
          },
          "scaleFactor": 100
        }
      }'
  2. Create a recipe to locate this market data and change the default pricing model for the bond collateral instrument. Note the ‘look back’ quoteInterval for the dummy FlexibleRepo price is equivalent to the length of the contract:

    curl -X POST 'https://mydomain.lusid.com/api/api/recipes'
      -H 'Content-Type: application/json-patch+json'
      -H 'Authorization: Bearer myAPIAccessToken'
      -d '{
      "configurationRecipe": {
        "scope": "MyRecipes",
        "code": "MyRepoValuationRecipe",
        "market": {
          "marketRules": [
            {
              "key": "Quote.ClientInternal.*",
              "dataScope": "MyRepoPortfolioQuotes",
              "supplier": "Lusid",
              "quoteType": "Price",
              "field": "mid",
              "quoteInterval": "3M.0D"
            }
          ]
        },
        "pricing": {
          "modelRules": [
            {
              "instrumentType": "Bond",
              "modelName": "BondLookupPricer"
            }
          ]
        }
      }
    }'
  3. Generate a valuation report with appropriate metrics, for example:

Assessing risk

For more on how LUSID calculates exposure, see this article.

LUSID supports both analytic and bump and valuation mechanisms for assessing risk; contact Technical Support for more information.

Handling the lifecycle of the instrument

A FlexibleRepo instrument is tightly integrated into LUSID’s instrument event framework. To enable this for your domain, you must:

  1. Register a recipe with every portfolio holding a FlexibleRepo.

  2. Create transaction types to determine the economic impact of the transactions automatically generated by FlexibleRepo events.

For much more on the instrument event framework, start here.

The following events are available for a FlexibleRepo:

Instrument event type

Repo type

Event emission criteria

If emitted, effect of LUSID default transaction template

Transaction type recommendations

FlexibleRepoCashFlowEvent

Any

This event is automatically emitted by LUSID:

  • On the start date to transfer purchasePrice from buyer to seller.

  • On the maturity date to transfer repurchasePrice from seller to buyer.

One transaction for a cash amount is automatically generated on each date.

More information coming soon.

FlexibleRepoCollateralEvent


Note: You can choose to ignore this event if you do not want to transfer collateral between buyer and seller

Any

This event is automatically emitted by LUSID:

  • On the start date to transfer collateral unit(s) from seller to buyer.

  • On the maturity date to transfer collateral unit(s) from buyer to seller.

One transaction for a number of collateral units at zero cost is automatically generated on each date.

FlexibleRepoInterestPaymentEvent

OpenRepo

This event is automatically emitted by LUSID on each payment window date to transfer accrued interest from seller to buyer.

One transaction for a cash amount is automatically generated on each date.

FlexibleRepoPartialClosureEvent

Any

This event is not automatically emitted by LUSID. You can manually load it to partially close a repo.

N/A

FlexibleRepoFullClosureEvent

OpenRepo

This event is not automatically emitted by LUSID. You should manually load it to close an open repo.

N/A

MaturityEvent

Any

This event is automatically emitted by LUSID on the maturity date.

One transaction for all units at zero cost is automatically generated to reduce the holding to zero.