Article

Understand and Retrieve your portfolio's credit risk exposures

Yao Koffi Kouassi
Solutions Consultant Solutions Consultant
Nick Zincone
Lead Developer Advocate Lead Developer Advocate

Overview

A UK based food manufacturer has excess cash and has set up its own fund to invest into equities and shares. For reporting purposes, this company wants to know for each position in their 15 portfolios, what is its credit exposure? By knowing the price of the CDS 5Y, the food manufacturer can determine how much they have to pay to offset the credit risk associated to an instrument within a portfolio. When utilizing Refinitiv's desktop Portfolio management tools, users have access to a powerful suite of details. Unfortunately, the credit exposure information is neither available directly within the portfolio nor in any templates of the portfolio reporting tool.

Does that mean it’s not possible to provide this information when the CDS 5Y price is quoted by Refinitiv? Absolutely not! In this article, we will describe how to leverage Python to enrich the portfolio details with the credit risk exposures.

Getting Started

The following notebook utilizes our Portfolio Analytics desktop capabilities to review and assess your issuer level and portfolios' credit risk exposure. Refinitiv's extensive content set, coupled with our Refinitiv Data Libraries offers a simple mechanism to retrieve your portfolio details and retrieve current pricing data used to generate desired results.

For convenience, the workflow generates output in an Excel sheet containing the results of our analysis.

Learn more

To learn more about the Refinitiv Data Library for Python please join the Refinitiv Developer Community. By registering and logging into the Refinitiv Developer Community portal you will have free access to a number of learning materials like Quick Start guidesTutorialsDocumentation and much more.

Getting Help and Support

If you have any questions regarding using the API, please post them on the Refinitiv Data Q&A Forum. The Refinitiv Developer Community will be happy to help.

Some Imports to start with

    	
            

# The Refinitiv Data Library for Python

import refinitiv.data as rd

 

# Popular container/dataframe to capture and minipulate data we extract

import pandas as pd

 

# Some basic UI

from refinitiv_widgets import Checkbox

from refinitiv_widgets import ProgressBar

 

rd.__version__

Open the data session

The open_session() function establishes a data session to retrieve our content within the desktop.

Note: A desktop session is intentionally defined here to take advantage of some convenient capabilities within the desktop application, such as the ability to use the Portfolio & Lists Manager (PAL) feature.

    	
            rd.open_session()
        
        
    

Code Setup

It's usually best practice to define constants that are potentially used through the coding segments within your notebook. A constant is a special type of variable whose value cannot be changed. Using a constant in a script improves its readability, its reusability and its maintainability.

    	
            

# Maximum number of items a request to get data can retrieve

MAX_ITEMS_PER_REQUEST = 10000

 

# Fields to request

PORTFOLIO_NAME_FLD = "TR.PortfolioName"

PORTFOLIO_CONSTITUENTS_FLD = "TR.PortfolioConstituentName"

PORTFOLIO_SHARES_FLD = "TR.PortfolioShares"

ASSET_CATEGORY_FLD = "TR.AssetCategory"

CDS_PRIMARY_RIC_FLD = "TR.CDSPrimaryCDSRic"

 

# Some columns used below by the dataframe

ASSET_CATEGORY_COL = "Asset Category Description"

PRIMARY_CDS_RIC_COL = "Primary CDS RIC"

CLOSE_PRICE_COL = "Close Price"

 

# Price data

HISTORICAL_CLOSE = "HST_CLOSE"

Portfolio Definition

At the heart of the following workflow is the ability for users to evaluate their portfolios to determine the credit exposure. For simplicity, we are going to use a pre-built portfolio defining the list of instruments that can be used within our analysis.

Note: Users can define their own portfolios by utilizing the power and capabilities of the Portfolio & List Manager service within the desktop.

The following fields are requested to provide a breakdown of the constituents within the portfolio:

  1. The Name of the Portfolio                                         [TR.PortfolioName]

  2. The issuer Name of the Constituents in Portfolio   [TR.PortfolioConstituentName]

  3. The Number of units of portfolio constituent         [TR.PortfolioShares]

  4. The full description of the asset category                [TR.AssetCategory]

  5. The primary CDS RIC for this reference entity        [TR.CDSPrimaryCDSRic]

The 'TR.CDSPrimaryCDSRic' field represents the fundamental data field defining the RIC (Refinitiv Identification Code) of the 5-year Credit Default Swap (CDS 5Y). This field is important for portfolio managers as it allows them to monitor how much credit exposure they have on the securities they are placing their bets on.

The id of the portfolio.

    	
            

# The id of the portfolio as defined within the desktop (Eikon/Refinitiv Workspace)

portfolio_id = "SAMPLE_EU_DEV_FI"

Load the portfolio data...

The Refinitiv Data Library for Python utilizes the 'Portfolio()' syntax to extract and pull multiple attributes specific to the referenced portfolio, in particular, the credit risk instrument.

    	
            

# Open the portfolio.  Define the list of fields required for our analysis

portfolio_columns = [PORTFOLIO_NAME_FLD,PORTFOLIO_CONSTITUENTS_FLD,PORTFOLIO_SHARES_FLD,

                     ASSET_CATEGORY_FLD,CDS_PRIMARY_RIC_FLD]

 

portfolio = f"Portfolio({portfolio_id})"

df = rd.get_data(portfolio, portfolio_columns)

if "Instrument" not in df.columns:

    print(f"Impossible to open the portfolio {portfolio_id}.")

 

# Display some of the data...

df.head(10)

Data Cleansing

In some cases, the referenced portfolio of instruments may include entries not related to CDS-based positions. As such, we'll need to clean the data by removing all unrelated entries. Specifically, the rows where the Primary CDS RIC cell is unavailable, i.e. missing values or values filled with <NA>.

For example, the above display shows the first 10 positions within our portfolio where a number of them contain missing values for the Primary CDS RIC. We are only interested in the positions where a valid RIC is present.

    	
            

# Remove all rows/entries where we are missing relevant data.  

# To simplify this, we'll first ensure blank values contain <NA>.

df[ASSET_CATEGORY_COL] = df[ASSET_CATEGORY_COL].replace('', pd.NaT)

df[PRIMARY_CDS_RIC_COL] = df[PRIMARY_CDS_RIC_COL].replace('', pd.NaT)

 

# Now we can simply remove all rows where the following columns contain <NA>

df = df.dropna(subset=[ASSET_CATEGORY_COL, PRIMARY_CDS_RIC_COL], axis=0)

 

# The results will only contain entries where we have populated data

df.head(10)

If you pay attention to the left column value, which represents an index into the table, you can get a sense of specific rows we filtered out.

Return only price data for bonds?

As a final step to data cleansing, we can optionally choose to process only bonds within our portfolio. The following UI prompt is a simple way to filter out all positions that are not classified as a bond.

    	
            

# The final, cleansed data will live within a container called 'assets'

assets = df

bonds = Checkbox(label='Check to retrieve bonds only')

bonds

    	
            

if bonds.checked:

    assets = assets[assets[ASSET_CATEGORY_COL].str.contains('Bond')].copy()

 

assets

Price Data

At this step, we want to retrieve the snapshot price for all the Primary CDS RICs. This is the key step within our workflow as this value represents the price of the CDS instrument that we'll assess as the credit risk value. Refinitiv allows us to retrieve snapshot data for a list of instruments up to MAX_ITEMS_PER_REQUEST size. In that case, we must split the list of instruments into manageable chunks. After retrieving the snapshot data of each chunk, we'll merge the prices within our the original filtered portfolio.

    	
            

# split a list into 'nbItems' chunks

def split_list_into_chunks(rics, nbItems):

    n = max(1, nbItems)

    return (rics[i:i+n] for i in range(0, len(rics), n))

 

# In the case our universe of RICs is very large, we'll capture the universe within manageable chunks

rics = list(assets[PRIMARY_CDS_RIC_COL])

rics_cnt = len(rics)

cds_5Y_rics_batch = split_list_into_chunks(rics, MAX_ITEMS_PER_REQUEST)

    	
            

# Request for the pricing data for each item within our batch

#

# Note: The batch (cds_5Y_rics_batch), is a special type that returns an iterator. Once iterated, 

#       the variable has completed.  That is, you will not be able to run through the batch again.

#       If yhou wish to iterate again, you will have generate the value again by executing the 

#       cell above.

cds_5y_prices_df = pd.DataFrame()

 

# Simple progress bar

pb = ProgressBar(value=0, color="green")

display(pb)

print(f"Processing a total of {rics_cnt} positions...")

 

for items in cds_5Y_rics_batch:

    pb.value += int(min(MAX_ITEMS_PER_REQUEST, len(items))/rics_cnt * 100)  # Progress bar increment

    res = rd.get_data(universe = items, fields = [HISTORICAL_CLOSE])

    cds_5y_prices_df = cds_5y_prices_df.append(res, ignore_index=True)

print("Done")

Processing a total of 72 positions...
Done

    	
            

# Display the price data for each constituent within the portfolio

cds_5y_prices_df.head(10)

Merge Data

The final step is to merge the price data within the portfolio. In some cases, we may not have price data available for our constituents and will also filter out those unwanted values.

    	
            

# Merge the initial dataframe with the realtime values

assets[CLOSE_PRICE_COL] = cds_5y_prices_df[HISTORICAL_CLOSE].to_list()

 

# Clean out any missing values

result = assets.dropna(subset=[CLOSE_PRICE_COL])

 

result.head(10)

Analysis

Now that we have successfully cleaned and priced the CDS 5Y positions, we can now use this value to derive our credit risk. That is, the 'Close Price' value is by definition a financial derivative that allows an investor to swap or offset their credit risk with that of another investor. With this data, it may be desirable to export the results within a simple spreadsheet for further analysis. We perform this task next.

Export to excel

Export the result to excel for future usage.

    	
            

filename = f"Credit_Risk_{portfolio_id}.csv"

result.to_csv(filename)

 

# export to excel

filename = f"Credit_Risk_{portfolio_id}.xlsx"

result.to_excel(filename)

Conclusion

While the strengths of the PAL - Portfolio & List Manager within the desktop are extremely powerful, we may come across scenarios where we need to extend the capabilities of what is available. By coupling the features of PAL and the Refinitiv Data Libraries, we can easily extract the required CDS 5Y price values for a given portfolio. By retrieving the CDS 5Y price, we can assess the credit risk exposure of the portfolio.

  • Register or Log in to applaud this article
  • Let the author know how much this article helped you
If you require assistance, please contact us here