LUSID is an API-first, SaaS-native investment data management platform.

To get started, we'll explore fundamental principles and demonstrate core capabilities by using LUSID to perform the following task:


“As a UK asset manager, I run a single portfolio containing UK equities and investment-grade vanilla bonds, and additionally maintain a cash position. The portfolio contains around 20 positions and trades around 5 positions a week. I want to view the asset allocation (equities vs. bonds vs. cash) on a daily basis.”


We'll see how to:

  • Model this scenario in LUSID using entities such as instruments, portfolios, transactions and more.
  • Load trade and market data into LUSID.
  • Generate positions and assemble the information required to value the portfolio on a per asset class basis.

You can examine and run the complete code sample for this exercise from this Jupyter Notebook, providing you have suitable access control permissions. This should automatically be the case if you set up your own LUSID domain (more on that below). If you are informed you do not have a license to perform a particular operation, please contact support.


Setting up your own LUSID domain

If you haven't already, the first task is set up your own LUSID domain (instance) by starting a free trial.

Your LUSID domain:

  • Is completely private to you. You'll share cloud infrastructure with other triallists in a multi-tenant environment, with strict safeguards in place to ensure data is segregated. When you go live, you can choose to migrate to a single tenant environment. More information.
  • Does not expire (there is no timeout to the trial, although you'll be asked to change your password every six months).
  • Has a standard license. Some advanced functionality is hidden behind additional licenses, but you can explore core capabilities using any of the interfaces and applications described here, including the REST API, SDKs and the web app. If you've never seen LUSID before, sign in to your web app to take a tour.
  • Automatically creates a LUSID user for you, the domain owner, with full administrative privileges. You can onboard as many other users as you like, and restrict their access control permissions to reflect their professional responsibilities.
  • Automatically creates an application that encapsulates the credentials required (client ID and client secret) to interact with LUSID using the REST API and/or SDKs. More information.
  • Can be populated with example data (portfolios, instruments and transactions) if you wish.

Understanding fundamental principles

Before we get started using LUSID to manage investment data, it's important to understand core LUSID concepts.

LUSID has a schema-on-read data model

LUSID's data model is designed to be flexible rather than constrain your data to our view of the world. We require you to model only a small set of real-world objects as entities. For example:

  • An instrument represents a real-world financial asset such as an equity, swap, option, bond, currency and more.
  • A transaction represents economic activity in a particular instrument, such as the purchase or sale of an equity.
  • portfolio represents a store of transactions and other economic activity affecting one or more instruments.
  • A holding represents your position in a particular instrument, as automatically generated by LUSID from the history of activity in a particular portfolio.

See the full list of LUSID entities and their key characteristics. If you need to extend the built-in set, you can create custom entities (see the box below).


By design, an entity has a minimal set of fields. For example, to create a portfolio you only need specify values for the name, scope, code, and base currency fields. A portfolio has a few other optional fields as well that either default to sensible values or can be left empty. However, you can extend a portfolio (and most entities) by adding properties to store as much additional information as you need (see the box below).


LUSID also provides core system settings to make key operations possible out-of-the-box:

  • Transaction types such as Buy and Sell. These define the economic impact of activity, so for example applying the built-in Buy type to an equity transaction automatically increases your position by the number of units bought and decreases your cash balance by the total cost.
  • System properties such as TradeToPortfolioRate and BondInterest. These built-in functions either provide access to useful system information (if read-only), or enable users to enter data that LUSID can then use in calculation or other business operations.
  • Data types such as Rating and AccountingMethod. These constrain and validate property values, so for example the Rating type only allows users to enter values such as AA or BBB into properties representing credit ratings.
  • Cut labels such as LondonOpen or NewYorkClose. These replace timestamps with meaningful names, making it easier to work across multiple time zones.
LUSID's data model is fully extensible

You can extend almost any aspect of LUSID's data model. This means you can consolidate data from different systems without undertaking expensive and time-consuming ETL operations, by mapping discrepancies between systems onto custom properties or entities. Data stored by LUSID in this way retains its format and lineage, so it remains meaningful to the originating system.


You can:

  • Extend most built-in entities by adding properties. For example, you could create an Executing Broker property to add to transactions, or a Manager property to portfolios. Properties can have single values, multiple values, or values derived from mathematical or other operations, and can be optional or mandatory. More information.
  • Create custom entities to model real-world objects that LUSID does not natively represent. For example, you could create an Organisation entity to represent the concept of business units. More information.
  • Create custom settings such as:
    • Transaction types. For example, you could create a BuyPlusCommission type that extends the built-in Buy type to record commission paid to brokers. See how to do this.
    • Data types. For example, you could create a NaceCode type that constrains properties to valid NACE industry codes, and additionally stores additional reference data such as the economic definition of each code. See how to do this.
    • Cut labels. For example, you could create a SingaporeOpen label to represent the start of trading in the Singapore time zone.

Data from different systems can co-exist in LUSID but you can extract business intelligence as though it were a homogeneous set. For example:

  • Instruments can have multiple market identifiers, so you can load transaction data from different systems (one using FIGIs and another ISINs, for example) and LUSID can resolve them to the same instrument, guaranteeing an accurate position.
  • Transaction types can be grouped and aliased, so a Buy transaction from one system can have the same economic impact as a BY or Acheter from others.
  • Derived properties can reconcile information from different systems by mapping, coalescing or transforming properties to a single point of reference.
  • Recipes can marshal pricing data from different vendors and incorporate a waterfall of pricing models and methodologies to enable numerous streams of information to inform valuation operations.
LUSID has a fine-grained entitlements system

LUSID denies access to all resources for every user—whether human being or automated service, either via the web app or by calling the API directly—until explicitly allowed. 


LUSID has separate identity management and access control systems that work together to authenticate users and grant each the permissions they need to access data and perform operations in keeping with their professional responsibilities, and no more. Read our IAM documentation.

LUSID partitions and entitles data using scopes

Almost every data item in LUSID must be assigned to a scope (or namespace). This enables you to:

  • Replicate data in different scopes. For example, you could duplicate a portfolio and evaluate different trading strategies in the two scopes.
  • Store the same kind of data from different systems in separate scopes. For example, you could store equity prices from Refinitiv and Bloomberg in two scopes, and value a portfolio against one and then against the other.
  • Assign access control permissions to scopes. For example, you could assign all US portfolios to a scope that only US-based managers are allowed to manage.

Within a scope, a data item has a code; together, the scope and code uniquely identify that data item. More information.

LUSID is bitemporal and immutable

Almost every data item in LUSID is stored with two timestamps:

  • A read/write effective at timestamp that describes when the data item is valid (that is, meaningful) from a business point of view.
  • A read-only as at timestamp that records when the data item is entered into LUSID.

You can roll back either timeline, which gives you unparalleled audit capability. For example, you could correct a wrongly-entered transaction, which leaves the transaction with the original effective at timestamp but gives it a new as at timestamp. You can then query LUSID for either the data as it is now, or roll back the as at timeline to query for the data as it was before the correction.

The important implication here is that no data is ever truly deleted in LUSID. This is because it must be possible to roll back the as at timeline to recreate the data as it was in the past. So when you 'delete' (for example) an instrument, what you are actually doing is time-limiting it's effective at timestamp from the as at timestamp of the delete operation. More information.

LUSID is an ecosystem of applications

The core LUSID investment management application is a RESTful API that you can integrate or build upon. LUSID also has a web app (GUI front end) that exercises the API and can be used as a standalone application if you wish.


The LUSID ecosystem also includes the following supporting applications:

  • Scheduler: job scheduling and automation
  • Drive: file storage and management
  • Luminesce: data virtualisation and query engine for LUSID and other SQL-compliant applications
  • Configuration Store: central repository for secrets and parameters

See the full list of applications.

LUSID has numerous operational interfaces

You can perform CRUD operations, and also analytical and reporting tasks, on the investment data stored in LUSID using the following tools and interfaces:

  • REST API ('Try it out' facility available in the Swagger specification). Note other interfaces may be better suited to bulk loading data into LUSID.
  • SDKs in five languages and frameworks: Python, C#, Java, JavaScript and Angular.
  • LUSID Python Tools (LPT), which builds upon the Python SDK to make common operations easier in Python environments.
  • Web app. Note not every API operation is available from the GUI front end.
  • Luminesce. Note a separate license is required to read and write data to/from LUSID using this data virtualisation application.
  • Jupyterhub, which can run code in Jupyter Notebooks to perform operations on your LUSID domain.
  • Excel add-in, which provides a set of Excel functions to interact with the LUSID API.

You should now have your own LUSID domain and an understanding of the principles that drive LUSID.

To complete the task of setting up a basic IBOR and valuing our portfolio on a per asset class basis, we need to explore the following tasks in a little more detail.

Populating the LUSID instrument master

The first task is to create one instrument modelling each equity and bond we want to hold in our portfolio. Note the following about instruments:

  • The LUSID instrument master is a central repository that every portfolio in LUSID accesses. You can optionally partition the instrument master into protected scopes, perhaps to hide sensitive contractual information encapsulated in derivative instruments.
  • An instrument is an economic definition. Every instrument must have a name and at least one market identifier, such as a FIGI or ISIN. Other fields are specific to the type of asset, for example coupon rate and payment frequency for bonds. You can of course add properties to instruments to store as much additional information as you like.
  • We provide templates to help you model equities, different types of bond, swaps, options, CFDs, FX forwards and more.
  • Your LUSID domain is prepopulated with a basket of standard currencies, so there is already a GBP currency instrument; you don't need to model currencies explicitly.
  • When you create an instrument, LUSID automatically generates a LUID (LUSID Unique ID), an internal identifier that is guaranteed to be unique and never change.
  • Every transaction you upsert into LUSID must be booked with an identifier (such as a FIGI, ISIN or LUID) that enables LUSID to resolve it to a mastered instrument, in order to guarantee an accurate position.

Read our instrument documentation.

Let's assume we have a CSV file exported from a database containing information about our assets:

For each equity and bond in the file, we need to call the LUSID UpsertInstruments API and provide a suitable economic definition from the available information.

Step 1 of the accompanying Jupyter Notebook demonstrates how to do this using the LUSID Python SDK. You can execute the Notebook in Jupyterhub for your LUSID domain and then sign in to the web app to see the results on the Instruments dashboard, available from the left-hand Data Management menu:

Creating a portfolio

The next task is to create a portfolio to store transactions for the instruments we want to hold, from which LUSID can generate positions. Note the following about portfolios:

  • There are different types of portfolio. We need to create a transaction portfolio.
  • A portfolio must be given a creation date that precedes the date of the first transaction we intend to load into it.
  • You have the option to specify sub-holding keys when you create a portfolio that subsequently enable you to partition individual positions, for example equities into different investment strategies, or cash balances into different types such as income and margin, and so on.

Read our portfolio documentation.

We need to call the LUSID CreatePortfolio API, specifying a suitable scope and code, and name and base currency.

Step 2 of the accompanying Jupyter Notebook demonstrates how to do this using the LUSID Python SDK. You can execute the Notebook in Jupyterhub for your LUSID domain and then sign in to the web app to see the portfolio on the Data Management > Portfolios dashboard.

Setting initial positions

The next task is to set initial positions for the instruments in our portfolio (including an initial cash position). There are two ways of doing this:

  • If we have access to a stream of historical transactions, we can call the LUSID UpsertTransactions API to load them and then have LUSID automatically generate positions from the results of buys and sells.
  • If not, we can call the LUSID SetHoldings API to set positions explicitly.

Read our transaction documentation.

Step 3 of the accompanying Jupyter Notebook demonstrates how to call the SetHoldings API using the LUSID Python SDK. You can execute the Notebook in Jupyterhub for your LUSID domain and then sign in to the web app to see the results on the Dashboard > Transactions:

Generating holdings

The next task is to ask LUSID to generate holdings (positions) for the instruments in our portfolio. Note the following about holdings:

  • LUSID generates a holding on-the-fly by decomposing all the events impacting a particular instrument into their underlying economic movements: these events can be transactions (buys and sells), any manual holdings adjustments you have made, and any corporate actions that affect that instrument (such as a stock split).
  • Each event has a transaction type that controls how and when the holding is updated, whether the effect is positive or negative, and whether other holdings are impacted. For example, the built-in Buy transaction type increases an equity holding by the number of units purchased, and simultaneously decreases your cash holding by the total consideration. You can of course configure transaction types to specify your own economic impacts.
  • A cash holding in a particular currency may therefore be determined by events impacting cash directly (such as an injection of funds using the built-in FundsIn transaction type), but also by events impacting other holdings, including other cash holdings.
  • By default, LUSID reports a single holding of type ‘position’ for non-cash instruments (such as equities and bonds), though you can change this using sub-holding keys. For cash, LUSID reports holdings of different types over time to reflect lifecycle events: ‘cash balance' for settled cash, ’cash commitment' for future payments, ‘cash receivable’ for expected income, and so on.

Read our holdings documentation.

We need to call the LUSID GetHoldings API, specifying the scope and code of the portfolio to generate.

Step 4 of the accompanying Jupyter Notebook demonstrates how to do this using the LUSID Python SDK. You can execute the Notebook in Jupyterhub for your LUSID domain and then sign in to the web app to see the current positions on the Dashboard > Holdings:

Valuing the portfolio

The final task is to configure LUSID to value the positions in our portfolio, aggregating up to asset class. Note the following about valuation:

  • LUSID requires market data to begin the pricing operation. For vanilla equities, this can simply be the current mid price sourced from a data vendor, but more complex instruments typically require complex market data such as FX rates or discount or interest rate curves.
  • Some instruments have lifecycles and/or cashflow implications that affect valuation. For example, a bond's value is affected both by its market price and the interest accrued to date, and has a maturity date after which the instrument drops out of valuations.
  • You must create a recipe that tells LUSID where to find market data, and which pricing model(s) and methodology to use to perform the valuation.
  • You must specify aggregation rules that tell LUSID how to report information in a meaningful way. It's possible to aggregate by properties you've created yourself, but in this case we can also take advantage of a built-in system property (the AssetClass queryable key) to aggregate our valuations by asset class (equities vs. bonds vs. cash).

Read our valuation documentation.

Once market data, a recipe and aggregation rules are in place, we can call the LUSID GetValuation API to actually perform the valuation.

Steps 5 and 6 of the accompanying Jupyter Notebook demonstrate how to do this using the LUSID Python SDK. You can execute the Notebook in Jupyterhub for your LUSID domain and then sign in to the web app to see aggregated valuations on the Dashboard > Valuations

Note to see the dashboard as it is below, you need to click the cog icon (highlighted middle right), choose Add column, select the Queryable Key with an Address Key of Instrument/AssetClass (value), drag it to the grouping position (highlighted left) and set the Effective date to 01/01/2022 (highlighted top right).