Setting up and valuing a fund of funds portfolio

In this tutorial we'll see how to set up a ‘parent’ portfolio so that it holds a position in a ‘child’ portfolio. The child portfolio must first be securitised; that is, turned into an instrument. We can then purchase a quantity of this instrument in the parent portfolio in the normal way.

Note: To complete this tutorial, you must have suitable permissions. This can most easily be achieved by assigning your LUSID user the built-in lusid-administrator role. This should already be the case if you are the domain owner.

We can then value the parent portfolio and drill down (or ‘lookthrough’) to value individual holdings in the securitised child portfolio. We can choose to scale the value of each child holding relative to the value of the child portfolio holding in the parent portfolio.

For further information and a more complex example, see this Jupyter Notebook. In particular, the Notebook includes an example of pricing a future on an equity index, and then expanding the price over the constituents of the underlying index.

Understanding fund of funds hierarchy

Consider the following example of a parent fund holding positions in three child funds, two of which themselves have children:


Note the following:

  • The root portfolio must be a transaction portfolio.

  • A child portfolio can either be a transaction portfolio or a reference portfolio.

  • A child portfolio can itself be a parent portfolio; that is, you can nest to any depth. However, looping is not permitted; a parent portfolio cannot hold a position in a child that holds a position in the parent, and so on.

Securitising an existing child transaction portfolio

Imagine we have a GBP-denominated transaction portfolio with a scope of Lookthrough, a code of Child and holdings in a mix of US and UK equities and bonds:

The first step is to securitise this portfolio by obtaining an API token and calling the UpsertInstruments API, specifying:

  • A friendly name for the instrument.

  • At least one of the unique identifiers (see a list), for example ClientInternal.

  • A suitable economic definition. This can use any of the supported templates, but SimpleInstrument is recommended. Note the domCcy of the instrument should be set to the base currency of the child portfolio.

  • A lookthroughPortfolioId consisting of the scope and code of the child portfolio.

More information about creating instruments.

For example, to create an instrument with a ClientInternal identifier value of ChildInstrument:

curl -X POST "https://<your-domain>.lusid.com/api/api/instruments"
  -H "Authorization: Bearer <your-API-access-token>"
  -H "Content-Type: application/json"
  -d '{
  "upsert_request_1": {
    "name": "ChildInstrument",
    "identifiers": {
      "ClientInternal": {
        "value": "ChildInstrument",
      }
    },
    "lookThroughPortfolioId": {
      "scope": "Lookthrough",
      "code": "Child"
    },
    "definition": {
      "instrumentType": "SimpleInstrument",
      "domCcy": "GBP",
      "assetClass": "Unknown",
      "simpleInstrumentType": "Fund"
    }
  }
}'

Creating a parent transaction portfolio

We can call the CreatePortfolio API to create a parent transaction portfolio in a particular scope, specifying a suitable code, baseCurrency and a created date likely to precede that of any transactions loaded into it. More information about creating portfolios.

For example, to create a portfolio with a scope of Lookthrough and code of Parent:

curl -X POST "https://<your-domain>.lusid.com/api/api/transactionportfolios/Lookthrough"
  -H "Authorization: Bearer <your-API-access-token>"
  -H "Content-Type: application/json"
  -d '{
  "displayName": "Parent lookthrough portfolio",
  "code": "Parent",
  "created": "2022-01-01T00:00:00Z",
  "baseCurrency": "GBP"
}'

Purchasing a quantity of the securitised instrument in the parent portfolio

We can call the UpsertTransactions API with the scope and code of the parent portfolio to establish a position in the child portfolio, ensuring the instrumentIdentifiers section of the transaction contains the unique identifier type and value of the securitised instrument.

For example, to purchase 5 units of ChildInstrument at a price of 20 per unit:

curl -X POST "https://<your-domain>.lusid.com/api/api/transactionportfolios/Lookthrough/Parent/transactions"
  -H "Authorization: Bearer <your-API-access-token>"
  -H "Content-Type: application/json"
  -d '[
  {
    "transactionId": "Txn-0001",
    "type": "StockIn",
    "instrumentIdentifiers": {
      "instrument/default/ClientInternal": "ChildInstrument"
    },
    "transactionDate": "2022-03-01T00:00:00Z",
    "settlementDate": "2022-03-03T00:00:00Z",
    "units": 5,
    "transactionPrice": {
      "price": 20,
      "type": "Price"
    },
    "totalConsideration": {
      "amount": 100,
      "currency": "GBP"
    },
    "transactionCurrency": "GBP"
  }
]'

More information about upserting transactions.

To confirm the position, we can call the GetHoldings API with the scope and code of the parent portfolio:

Loading market data into the LUSID quote store

We can call the UpsertQuotes API to load market data (prices and, if necessary, FX rates) for ChildInstrument, and for all the instruments in the child portfolio, into a particular quote scope. More information about upserting quotes

For example, to upsert a price of 25 for ChildInstrument effective 7 March 2022 into a quote scope of LookthroughQuotes (in the URL):

curl -X POST "https://<your-domain>.lusid.com/api/api/quotes/LookthroughQuotes"
  -H "Authorization: Bearer <your-API-access-token>"
  -H "Content-Type: application/json"
  -d '{
  "Quote-0001": {
    "quoteId": {
      "quoteSeriesId": {
        "provider": "Lusid",
        "instrumentIdType": "ClientInternal",
        "instrumentId": "ChildInstrument",
        "quoteType": "Price",
        "field": "mid"
      },
      "effectiveAt": "2022-03-07T00:00:00Z"
    },
    "metricValue": {
      "value": 25,
      "unit": "GBP"
    }
  }
}'

Creating a suitable valuation recipe

We can call the UpsertConfigurationRecipe API to create a valuation recipe. Note the following:

  • The market section must have market rules enabling LUSID to find quotes for ChildInstrument and for all the instruments in the child portfolio.

  • The pricing section must have a vendor model rule that enables lookthrough for the securitised instrument type, which in this case is SimpleInstrument.

More information about creating recipes.

In the following example:

  • The Quote.Figi.* market rule locates quotes for the equities and bonds in the child portfolio.

  • The Quote.ClientInternal.* market rule locates quotes for ChildInstrument.

  • The Fx.CurrencyPair.* market rule locates USD/GBP exchange rates.

  • The vendor model rule chooses the SimpleStatic pricing model for the SimpleInstrument type, and enables lookthrough by setting portfolioScaling to Sum and modelOptionsType to IndexModelOptions. Note an alternative portfolio scaling option is Unity; see Appendix A for more information.

curl -X POST "https://<your-domain>.lusid.com/api/api/recipes"
  -H "Authorization: Bearer <your-API-access-token>"
  -H "Content-Type: application/json"
  -d '{
  "configurationRecipe": {
    "scope": "Lookthrough",
    "code": "ParentIntoChildRecipe",
    "market": {
      "marketRules": [
        {
          "key": "Quote.Figi.*",
          "supplier": "Lusid",
          "dataScope": "LookthroughQuotes",
          "quoteType": "Price",
          "field": "mid"
        },
        {
          "key": "Quote.ClientInternal.*",
          "supplier": "Lusid",
          "dataScope": "LookthroughQuotes",
          "quoteType": "Price",
          "field": "mid"
        },
        {
          "key": "Fx.CurrencyPair.*",
          "supplier": "Lusid",
          "dataScope": "LookthroughQuotes",
          "quoteType": "Rate",
          "field": "mid"
        }
      ]
    },
    "pricing": {
      "modelRules": [
        {
          "supplier": "Lusid",
          "modelName": "SimpleStatic",
          "instrumentType": "SimpleInstrument",
          "modelOptions": {
            "portfolioScaling": "Sum",
            "modelOptionsType": "IndexModelOptions"
          }
        }
      ]
    }
  }
}'

Note: It is possible to request many metrics when calling the GetValuation API, but not all are meaningful in a lookthrough valuation report. In particular, metrics relating to cost and PnL do not scale properly, since scaling computation happens at a point in time different to that when the costs were calculated. More information about metrics.​

In our example, we'll request the following metrics:

  • Holding/default/Units to scale the number of units in each child portfolio holding.

  • Valuation/PV to scale PV in the transaction currency for each holding.

  • Valuation/Accrued to scale accrual in the transaction currency for each bond holding.

  • Valuation/PVInPortfolioCcy to scale PV in the portfolio currency for each holding (GBP).

  • Valuation/AccruedInPortfolioCcy to scale accrual in the portfolio currency for each bond holding.

  • Holding/default/FundLineage to track the scope and code of the parent and child portfolios

Note also that reportCurrency should be set to the portfolio currency of the root portfolio in a hierarchy, in this case GBP:

curl -X POST "https://<your-domain>.lusid.com/api/api/aggregation/$valuation"
  -H "Authorization: Bearer <your-API-access-token>"
  -H "Content-Type: application/json"
  -d '{
    "recipeId": {
      "scope": "Lookthrough",
      "code": "ParentIntoChildRecipe"
    },
    "metrics": [
      { "key": "Holding/default/Units", "op": "Value" },
      { "key": "Valuation/PV", "op": "Value" },
      { "key": "Valuation/Accrued", "op": "Value" },
      { "key": "Valuation/PvInPortfolioCcy", "op": "Value" },
      { "key": "Valuation/AccruedInPortfolioCcy", "op": "Value" },
      { "key": "Holding/default/FundLineage", "op": "Value" },
    ],
    "reportCurrency": "GBP",
    "portfolioEntityIds": [
      {
        "scope": "Lookthrough",
        "code": "Parent",
      }
    ],
    "valuationSchedule": {
      "effectiveAt": "2022-03-07T00:00:00Z",
    }
 }'

Valuing the parent portfolio

When we value our parent portfolio with lookthrough, holdings in the child portfolio are scaled relative to the value of the securitised instrument in the parent portfolio. 

The easiest way to understand the scaling calculations is to work through an example. Imagine we value the child portfolio independently on 7 March 2022; we can see that the total PV in GBP (the child portfolio currency) is 295,236.04 (the sum of 120,000 + 37,800 + 101,340.11 + 36,095.93):

Note: Throughout this example the USD/GBP trade to portfolio rate is fixed at 0.7.

When we value the parent portfolio without lookthrough on 7 March 2022, we can see that the PV in GBP (the parent portfolio currency) of the securitised instrument is 125:

Now when we value the parent portfolio with lookthrough on 7 March 2022 (using this recipe and metrics), we see that the unit, PV and accrual figures have been scaled down relative to its value:

The calculations are as follows:

Scaled metric

Calculation

BP

Microsoft

UKT 0 ⅜ 10/22/26

T 2.375% Aug 15 2024

PV in GBP

(125 / 295236.04) * 120000 = 50.81

(125 / 295236.04) * 37800 = 16.00

(125 / 295236.04) * 101340.11 = 42.91 

(125 / 295236.04) * 36095.93 = 15.28

Units

(125 / 295236.04) * 4000 = 1.69

(125 / 295236.04) * 3000 = 1.27

(125 / 295236.04) * 100000 = 42.34

(125 / 295236.04) * 50000 = 21.17

Accrual in GBP

n/a

n/a

(125 / 295236.04) * 140.11 = 0.06

(125 / 295236.04) * 45.93 = 0.02

Note

LUSID’s lookthrough capability allows you to price a parent portfolio with a holding in a securitised portfolio without requiring direct access to view underlying transactions and holdings.

Appendix A: Unity scaling

You can select Unity rather than Sum in your recipe to value a parent portfolio with lookthrough and scale holdings in the child portfolio directly by the number of units held in the securitised instrument rather than relative to its value: 

"pricing": {
  "modelRules": [
    {
      "supplier": "Lusid",
      "modelName": "SimpleStatic",
      "instrumentType": "SimpleInstrument",
      "modelOptions": {
        "portfolioScaling": "Unity",
        "modelOptionsType": "IndexModelOptions"
      }
    }
  ]
}

For example, if we hold 5 units of the securitised instrument:

...then unit, PV and accrual figures are scaled 5 times: