Peer analysis is one of the most common methods of financial analysis used by analysts and investors to compare stocks and find good candidates among peers in a group. It is also a useful tool for uncovering overvalued and undervalued stocks within the same industry and sector. This article demonstrates how to use the Eikon Data API to retrieve data for peer analysis.
The peers company overview contains statistics like:
Peers - Company Details consist of general information, such as company name, company's incorporation country, industry, sector, Key Multiples & Margins.
Peers - Valuation metrics consist of valuation multiple, such as PE LTM, Forward PE, Price/Sales LTM, Price/Book Value LTM, Price/ CashFlow LTM, etc.
Peers - Profitability ratios consist of ROE LTM, ROA LTM, Gross Margin LTM, Operating Margin LTM, etc.
Peers - Balance Sheet ratios consist of Debt/Equity, Net Debt/EBITDA, Current Ratio, Quick Ratio, etc.
Peers - Growth ratios consists of EPS, Revenue and EBITDA growth rate
The first step is importing required libraries including:
- eikon: The Eikon Data API for Python allows your Python applications to access data directly from Eikon or Refinitv Workspace
- ipywidgets: An interactive HTML widgets for Jupyter notebooks, JupyterLab, and the IPython kernel
IPython.display : Public API for display tools in IPython - pandas: The fast, powerful, flexible, and easy to use open-source data analysis and manipulation tool
- csv: CSV File Reading and Writing
- warnings: Warning control
import eikon as ek
import warnings
import csv
import pandas as pd
import ipywidgets as widgets #IPython widgets
from ipywidgets import Button, HBox, VBox, Layout, Dropdown, Label
from IPython.display import display, clear_output
Next, it prepares an environment to run the application including:
- Disable warning messages generated by the Eikon Data API
- Set the display format of the floating number in the data frame
- Set the default RIC and currency to IBM.N and USD respectively
- Load the list of currencies used by the application
- Set the application key used to connect to Eikon or Refinitiv Workspace
warnings.filterwarnings('ignore')
pd.options.display.float_format = '{:,.2f}'.format
context = {"RIC":"IBM.N","currency":"USD"}
currency_list= [tuple(row) for row in csv.reader(open("currencies.csv", 'rU'))]
ek.set_app_key('<app key>')
Peers - Company Details
The below code is used to create a widget to display company details of the peer group. The widget accepts a RIC and currency. Then, it uses the Eikon Data API to retrieve the following fields of the peer group.
Field | Description |
---|---|
TR.CommonName | The name of the organization most commonly used (Company Name) |
TR.HeadquartersCountry | Country of Headquarters, also known as Country of Domicile (Country) |
TR.ExchangeName | The stock exchange name (Exchange) |
TR.TRBCIndustryGroup | Primary business classification industry group description (Industry) |
TR.GICSSector | Primary global industry classification standard sector description (Sector) |
TR.CompanyMarketCap | The sum of market value for all relevant issue-level share types (Market Cap) |
TR.EV | The sum of market capitalization, total debt, preferred stock, and minority interest minus cash and short term investments for the most recent fiscal period (Enterprise Value) |
It uses the Peers() method to retrieve peer companies of a RIC. For example:
df1, err = ek.get_data("Peers(IBM.N)", ["TR.PrimaryInstrument"])
df2, err = ek.get_data(df1['Primary Instrument RIC'].tolist(),
["TR.CommonName",
"TR.HeadquartersCountry",
"TR.ExchangeName",
"TR.TRBCIndustryGroup",
"TR.GICSSector",
"TR.CompanyMarketCap(scale=6, curn='USD')",
"TR.EV(scale=6, curn='USD')"])
class WidgetPeersGeneralInfo:
#for input RICs
ric_input = widgets.Text(
value = '',
placeholder = 'RIC',
description = 'RIC:',
disabled = False
)
status_label = Label("")
commonname_label = Label(value = r'\(\bf{Name}\)', layout=Layout(width="150px"))
commonname_value_label = Label(value = "", layout=Layout(width="400px"))
exchange_label = Label(value = r'\(\bf{Exchange}\)', layout=Layout(width="150px"))
exchange_value_label = Label("", layout=Layout(width="400px"))
country_label = Label(value = r'\(\bf{Country}\)', layout=Layout(width="150px"))
country_value_label = Label("", layout=Layout(width="400px"))
industry_label = Label(value = r'\(\bf{Industry}\)', layout=Layout(width="150px"))
industry_value_label = Label("", layout=Layout(width="400px"))
sector_label = Label(value = r'\(\bf{Sector}\)', layout=Layout(width="150px"))
sector_value_label = Label("", layout=Layout(width="400px"))
ticker_label = Label(value = r'\(\bf{Ticker}\)', layout=Layout(width="150px"))
ticker_value_label = Label("", layout=Layout(width="400px"))
marketcap_label = Label(value = r'\(\textbf{Market Cap}\)', layout=Layout(width="150px"))
marketcap_value_label = Label("", layout=Layout(width="400px"))
enterprise_label = Label(value = r'\(\textbf{Enterprise Value}\)', layout=Layout(width="150px"))
enterprise_value_label = Label("", layout=Layout(width="400px"))
currency_dropdown = Dropdown(options=currency_list, value='USD', description='Currency:')
#display the widgets
title_label = Label(value='')
linebreak_label = Label('')
#button for submit the input
button = Button(description='Run')
output = widgets.Output()
def __init__(self, _context):
display(HBox([self.ric_input]),
HBox([self.currency_dropdown,self.button]),
self.output)
self.ric_input.on_submit (self.on_button_clicked)
self.button.on_click(self.on_button_clicked)
#self.output
self._context = _context
self.ric_input.value = _context["RIC"]
def on_button_clicked(self,c):
with self.output:
self.output.clear_output() #clear and update output
self.status_label.value="Running..."
display(self.status_label)
_ric = self.ric_input.value #retrieve each ric seperated by ';'
_currency = self.currency_dropdown.value
self._context["RIC"] = _ric
self._context["currency"] = _currency
fields = ["TR.CommonName",
"TR.HeadquartersCountry",
"TR.ExchangeName",
"TR.TRBCIndustryGroup",
"TR.GICSSector",
"TR.TickerSymbol",
"TR.PriceMoPriceCurrency",
"TR.CompanyMarketCap(scale=6, curn='{}')".format(_currency),
"TR.EV(scale=6, curn='{}')".format(_currency)]
#get data
try:
df, err = ek.get_data(_ric,fields )
if err!=None:
raise ValueError(err[0]['message'])
peer_rics, err = ek.get_data("Peers({})".format(_ric), ["TR.PrimaryInstrument"])
if err!= None:
raise ValueError(err[0]['message'])
df1, err= ek.get_data(peer_rics['Primary Instrument RIC'].tolist(),["TR.CommonName",
"TR.HeadquartersCountry",
"TR.ExchangeName",
"TR.TRBCIndustryGroup",
"TR.GICSSector",
"TR.CompanyMarketCap(scale=6, curn='{}')".format(_currency),
"TR.EV(scale=6, curn='{}')".format(_currency)])
if err!= None:
raise ValueError(err[0]['message'])
except ValueError as e:
self.status_label.value = str(e)
return
self.output.clear_output()
self.commonname_value_label.value = df["Company Common Name"][0]
self.country_value_label.value = df["Country of Headquarters"][0]
self.exchange_value_label.value = df["Exchange Name"][0]
self.industry_value_label.value = df["TRBC Industry Group Name"][0]
self.sector_value_label.value = df["GICS Sector Name"][0]
self.ticker_value_label.value = str(df["Ticker Symbol"][0])
df['Company Market Cap'] = df['Company Market Cap'].map('{:,.2f}'.format)
df['Enterprise Value (Daily Time Series)'] = df['Enterprise Value (Daily Time Series)'].map('{:,.2f}'.format)
self.marketcap_value_label.value = df['Company Market Cap'][0]
self.enterprise_value_label.value = df['Enterprise Value (Daily Time Series)'][0]
self.title_label.value = r'\(\underline{\textbf{Peers for %s}}\)'%(df["Company Common Name"][0])
display(VBox([HBox([self.commonname_label,self.commonname_value_label,self.country_label,self.country_value_label]),
HBox([self.exchange_label, self.exchange_value_label,self.industry_label, self.industry_value_label]),
HBox([self.sector_label, self.sector_value_label,self.ticker_label, self.ticker_value_label]),
HBox([self.marketcap_label, self.marketcap_value_label,self.enterprise_label, self.enterprise_value_label]),
HBox([self.linebreak_label]),
HBox([self.title_label])
]))
df1.sort_values(by=['Company Market Cap'], ascending=False, inplace=True)
df1 = df1.set_index('Instrument')
df1.columns=['Company Name',
'Country',
'Exchange',
'Industry',
'Sector',
'Market Cap',
'Enterprise Value']
display(df1)
#add text to show error
if err != None:
print('Error:')
print(err, sep = "\n")
WidgetPeersGeneralInfo(context)
Peers - Valuation metrics
The below code is used to create a widget to display valuation matrics of the peer group, such as PE LTM, Forward PE, Price/Sales LTM, Price/Book Value LTM, Price/ CashFlow LTM, etc. The widget accepts a RIC as a parameter. Then, it uses the Eikon Data API to retrieve the following fields of the peer group.
Field | Description |
---|---|
TR.CommonName | The name of the organization most commonly used (Company Name) |
TR.PE |
|
TR.PtoEPSMeanEst(Period=FY1) | A security's price divided by its earnings per share mean estimate based on the next fiscal year expected period (Forward P/E FY1) |
TR.PriceToSalesPerShare | Price to sales per share calculated by dividing the company's market capitalization by its total sales (Price/Sales LTM) |
TR.EVToEBITDA | Enterprise value to EBITDA measuring how much a company is valued per each dollar of EBITDA (EV/EBITDA LTM) |
TR.PricetoCFPerShare | Price to cash flow per share calculated by dividing the company's LTM cash flow from operating activities by its current shares outstanding (Price/Cash Flow LTM) |
TR.PriceToBVPerShare | Price to book value per share calculated by dividing the company's latest closing price by its book value per share (Price/Book LTM) |
TR.DividendYield | The ratio of the annualized dividends to the price of a stock (Dividend Yield Latest (%)) |
It uses the Peers() method to retrieve peer companies of a RIC. For example:
df1, err = ek.get_data("Peers(IBM.N)", ["TR.PrimaryInstrument"])
df2, err = ek.get_data(df1['Primary Instrument RIC'].tolist(),
["TR.CommonName",
"TR.PE()",
"TR.PtoEPSMeanEst(Period=FY1)",
"TR.PriceToSalesPerShare",
"TR.EVToEBITDA",
"TR.PricetoCFPerShare",
"TR.PriceToBVPerShare",
"TR.DividendYield"])
class WidgetPeersValuation:
#for input RICs
ric_input = widgets.Text(
value = '',
placeholder = 'RIC',
description = 'RIC:',
disabled = False
)
status_label = Label("")
#currency_dropdown = Dropdown(options=currency_list, value='USD', description='Currency:')
#display the widgets
title_label = Label(value='')
linebreak_label = Label('')
#button for submit the input
button = Button(description='Run')
output = widgets.Output()
def __init__(self, _context):
display(HBox([self.ric_input,self.button]),
self.output)
self.ric_input.on_submit (self.on_button_clicked)
self.button.on_click(self.on_button_clicked)
#self.output
self._context = _context
self.ric_input.value = _context["RIC"]
def on_button_clicked(self,c):
with self.output:
self.output.clear_output() #clear and update output
self.status_label.value="Running..."
display(self.status_label)
_ric = self.ric_input.value #retrieve each ric seperated by ';'
#_currency = self.currency_dropdown.value
self._context["RIC"] = _ric
#self._context["currency"] = _currency
fields = ["TR.CommonName",
"TR.PE()",
"TR.PtoEPSMeanEst(Period=FY1)",
"TR.PriceToSalesPerShare",
"TR.EVToEBITDA",
"TR.PricetoCFPerShare",
"TR.PriceToBVPerShare",
"TR.DividendYield"]
#get data
try:
df, err = ek.get_data(_ric,fields )
if err!=None:
raise ValueError(err[0]['message'])
peer_rics, err = ek.get_data("Peers({})".format(_ric), ["TR.PrimaryInstrument"])
if err!=None:
raise ValueError(err[0]['message'])
df1, err = ek.get_data(peer_rics['Primary Instrument RIC'].tolist(), fields)
if err!=None:
raise ValueError(err[0]['message'])
except ValueError as e:
self.status_label.value = str(e)
return
self.output.clear_output()
self.title_label.value = r'\(\underline{\textbf{Valuation - Peers of %s}}\)'%(df["Company Common Name"][0])
df_concat = pd.concat((df, df1))
df = df.set_index('Instrument')
df.loc["Peer Median"] = df_concat.median()
df.loc["Peer Average"] = df_concat.mean()
df.loc["Peer Median", "Company Common Name"] = ""
df.loc["Peer Average", "Company Common Name"] = ""
df.columns=["Company Name",
"Trailing P/E LTM",
"Forward P/E FY1",
"Price/Sales LTM",
"EV/EBITDA LTM",
"Price/Cash Flow LTM",
"Price/Book LTM",
"Dividend Yield Latest(%)"]
display(df)
display(VBox([HBox([self.linebreak_label]),HBox([self.title_label]),HBox([self.linebreak_label])]))
df1 = df1.set_index('Instrument')
df1.columns=["Company Name",
"Trailing P/E LTM",
"Forward P/E FY1",
"Price/Sales LTM",
"EV/EBITDA LTM",
"Price/Cash Flow LTM",
"Price/Book LTM",
"Dividend Yield Latest (%)"]
display(df1)
#add text to show error
if err != None:
print('Error:')
print(err, sep = "\n")
WidgetPeersValuation(context)
Peers - Profitability Ratios
The below code is used to create a widget to display profitability ratios of the peer group, such as ROE LTM, ROA LTM, Gross Margin LTM, Operating Margin LTM, etc. The widget accepts a RIC as a parameter. Then, it uses the Eikon Data API to retrieve the following fields of the peer group.
Field | Description |
---|---|
TR.CommonName | The name of the organization most commonly used (Company Name) |
TR.ReturnonAvgTotEqtyPctNetIncomeBeforeExtraItemsTTM | This value is calculated as the net income before extraordinary items for the trailing twelve months divided by the same period average total equity and is expressed as a percentage (ROE LTM) |
TR.ROAPercentTrailing12M | This value is calculated as the income after taxes for the trailing twelve months divided by the average total assets and is expressed as a percentage (ROA LTM) |
TR.GrossProfit(Period=LTM, Methodology=InterimSum) | A measure of a company's operating performance based on the last twelve months financial period and interim sum methodology |
TR.TotalRevenue(Period=LTM, Methodology=InterimSum) | Revenue based on the last twelve months financial period and interim sum methodology from all of a company's operating activities after deducting any sales adjustments and their equivalents |
TR.GrossProfit(Period=FY0) | Revenue based on the last reported year from all of a company's operating activities after deducting any sales adjustments and their equivalents |
TR.OperatingProfit(Period=LTM) | The operating profit of a company based on the last twelve months financial period |
TR.OperatingProfit(Period=FY0) | The operating profit of a company based on the last reported year |
TR.OperatingProfitMarginPct5YrAvg | The average annual operating profit for 5 years divided by the average of the annual total revenue for the same period expressed as a percentage (Operating Margin 5 Yr Avg) |
TR.PretaxMarginPercent(period=FY0) | The income before tax divided by total revenue, based on the last reported year (Pretax Margin FY0) |
TR.EBITDATotEqtyPctTTM | The percentage of EBITDA for the trailing twelve months to average total equity for the same period (EBITDA/Equity LTM) |
It uses the Peers() method to retrieve peer companies of a RIC. For example:
df1, err = ek.get_data("Peers(IBM.N)", ["TR.PrimaryInstrument"])
df2, err = ek.get_data(df1['Primary Instrument RIC'].tolist(),
["TR.CommonName",
"TR.ReturnonAvgTotEqtyPctNetIncomeBeforeExtraItemsTTM",
"TR.ROAPercentTrailing12M",
"TR.GrossProfit(Period=LTM, Methodology=InterimSum)",
"TR.TotalRevenue(Period=LTM, Methodology=InterimSum)",
"TR.GrossProfit(Period=FY0)",
"TR.TotalRevenue(Period=FY0)",
"TR.OperatingProfit(Period=LTM)",
"TR.OperatingProfit(Period=FY0)",
"TR.OperatingProfitMarginPct5YrAvg",
"TR.PretaxMarginPercent(period=FY0)",
"TR.EBITDATotEqtyPctTTM"])
Then, it calculates the Gross Margin LTM by using the following formula.
Gross Margin LTM = (Gross Profit LTM / Total Revenue LTM) x 100 |
If the Gross Profit LTM is not available, the Total Revenue FY0 is used instead:
Gross Margin LTM = (Gross Profit FY0 / Total Revenue FY0) x 100 |
Next, it calculates the Operating Margin LTM by using the following formula:
Operating Margin LTM = (Operating Profit LTM / Total Revenue LTM) x 100 |
If the Operating Profit LTM is not available, the Total Revenue FY0 is used instead:
Gross Margin LTM = (Operating Profit FY0 / Total Revenue FY0) x 100 |
class WidgetPeersProfitability:
#for input RICs
ric_input = widgets.Text(
value = '',
placeholder = 'RIC',
description = 'RIC:',
disabled = False
)
status_label = Label("")
#currency_dropdown = Dropdown(options=currency_list, value='USD', description='Currency:')
#display the widgets
title_label = Label(value='')
linebreak_label = Label('')
#button for submit the input
button = Button(description='Run')
output = widgets.Output()
def __init__(self, _context):
display(HBox([self.ric_input,self.button]),
self.output)
self.ric_input.on_submit (self.on_button_clicked)
self.button.on_click(self.on_button_clicked)
#self.output
self._context = _context
self.ric_input.value = _context["RIC"]
def reformat_dataframe(self, df):
df2 = df.set_index('Instrument')
df2.columns = ['Company Name',
'ROE LTM',
'ROA LTM',
'Gross Profit LTM',
'Total Revenue LTM',
'Gross Profit FY0',
'Total Revenue FY0',
'Operating Profit LTM',
'Operating Profit FY0',
'Operating Margin 5 Yr Avg',
'Pretax Margin FY0',
'EBITDA/Equity LTM']
df2.loc[df2['Gross Profit LTM'].notnull(),'temp'] = (df2.loc[df2['Gross Profit LTM'].notnull(),'Gross Profit LTM']/df2.loc[df2['Gross Profit LTM'].notnull(),'Total Revenue LTM'])*100
df2.loc[df2['Gross Profit LTM'].isnull(),'temp'] = (df2.loc[df2['Gross Profit LTM'].isnull(),'Gross Profit FY0']/df2.loc[df2['Gross Profit LTM'].isnull(),'Total Revenue FY0'])*100
df2.loc[df2['Operating Profit LTM'].notnull(),'temp1'] = (df2.loc[df2['Operating Profit LTM'].notnull(),'Operating Profit LTM']/df2.loc[df2['Operating Profit LTM'].notnull(),'Total Revenue LTM'])*100
df2.loc[df2['Operating Profit LTM'].isnull(),'temp1'] = (df2.loc[df2['Operating Profit LTM'].isnull(),'Operating Profit FY0']/df2.loc[df2['Operating Profit LTM'].isnull(),'Total Revenue FY0'])*100
df2.drop(['Gross Profit LTM',
'Total Revenue LTM',
'Gross Profit FY0',
'Total Revenue FY0',
'Operating Profit LTM',
'Operating Profit FY0'],
axis=1,
inplace=True)
df2.rename(columns = {'temp': 'Gross Margin LTM', 'temp1': 'Operating Margin LTM'}, inplace = True)
df2 = df2[['Company Name',
'ROE LTM',
'ROA LTM',
'Gross Margin LTM',
'Operating Margin LTM',
'Operating Margin 5 Yr Avg',
'Pretax Margin FY0',
'EBITDA/Equity LTM']]
return df2
def on_button_clicked(self,c):
with self.output:
self.output.clear_output() #clear and update output
self.status_label.value="Running..."
display(self.status_label)
_ric = self.ric_input.value #retrieve each ric seperated by ';'
#_currency = self.currency_dropdown.value
self._context["RIC"] = _ric
#self._context["currency"] = _currency
fields = ["TR.CommonName",
"TR.ReturnonAvgTotEqtyPctNetIncomeBeforeExtraItemsTTM",
"TR.ROAPercentTrailing12M",
"TR.GrossProfit(Period=LTM, Methodology=InterimSum)",
"TR.TotalRevenue(Period=LTM, Methodology=InterimSum)",
"TR.GrossProfit(Period=FY0)",
"TR.TotalRevenue(Period=FY0)",
"TR.OperatingProfit(Period=LTM)",
"TR.OperatingProfit(Period=FY0)",
"TR.OperatingProfitMarginPct5YrAvg",
"TR.PretaxMarginPercent(period=FY0)",
"TR.EBITDATotEqtyPctTTM"]
#get data
try:
df, err = ek.get_data(_ric,fields )
if err!=None:
raise ValueError(err[0]['message'])
peer_rics, err = ek.get_data("Peers({})".format(_ric), ["TR.PrimaryInstrument"])
if err!=None:
raise ValueError(err[0]['message'])
df1, err = ek.get_data(peer_rics['Primary Instrument RIC'].tolist(), fields)
if err!=None:
raise ValueError(err[0]['message'])
except ValueError as e:
self.status_label.value = str(e)
return
self.output.clear_output()
self.title_label.value = r'\(\underline{\textbf{Profitability - Peers of %s}}\)'%(df["Company Common Name"][0])
df = self.reformat_dataframe(df)
df1 = self.reformat_dataframe(df1)
df_concat = pd.concat((df, df1))
df.loc["Peer Median"] = df_concat.median()
df.loc["Peer Average"] = df_concat.mean()
df.loc["Peer Median", "Company Name"] = ""
df.loc["Peer Average", "Company Name"] = ""
display(df)
display(VBox([HBox([self.linebreak_label]),HBox([self.title_label]),HBox([self.linebreak_label])]))
display(df1)
#add text to show error
if err != None:
print('Error:')
print(err, sep = "\n")
WidgetPeersProfitability(context)
Peers - Balance Sheet Ratios
The below code is used to create a widget to display balance sheet ratios of the peer group, such as Debt/Equity, Net Debt/EBITDA, Current Ratio, Quick Ratio, etc. The widget accepts a RIC and currency as parameters. Then, it uses the Eikon Data API to retrieve the following fields of the peer group.
Field | Description |
---|---|
TR.CommonName | The name of the organization most commonly used (Company Name) |
TR.TtlDebtToTtlEquityPct | The percentage of total debt as of the end of the fiscal period to total equity for the same period (Debt/Equity Latest) |
TR.NetDebtToEBITDA | A measurement of leverage calculated as a company's net debt divided by its EBITDA (Net Debt/EBITDA LTM) |
TR.CashandEquivalents(Period=FY0) | The short-term, highly liquid investments based on the last reported year (Cash and Equivalents FY0) |
TR.CurrentRatio | Total current assets divided by total current liabilities (Current Ratio Latest) |
TR.QuickRatio | Total current assets less inventory divided by total current liabilities (Quick Ratio Latest) |
TR.InventoryTurnover | The ratio of total cost of revenue for the fiscal period to the average total inventory for the same period (Inventory Turns Latest) |
TR.AcctsReceivTradeNet(Period=FY0) | Claims held against customers for goods sold or services rendered as part of normal business operations based on the last reported year (Accts Receivable FY0) |
It uses the Peers() method to retrieve peer companies of a RIC. For example:
df1, err = ek.get_data("Peers(IBM.N)", ["TR.PrimaryInstrument"])
df2, err = ek.get_data(df1['Primary Instrument RIC'].tolist(),
["TR.CommonName",
"TR.TtlDebtToTtlEquityPct",
"TR.NetDebtToEBITDA",
"TR.CashandEquivalents(Period=FY0, Scale=6, curn='USD')",
"TR.CurrentRatio",
"TR.QuickRatio",
"TR.InventoryTurnover",
"TR.AcctsReceivTradeNet(Period=FY0,Scale=6, curn='USD')"])
class WidgetPeersBalanceSheet:
#for input RICs
ric_input = widgets.Text(
value = '',
placeholder = 'RIC',
description = 'RIC:',
disabled = False
)
status_label = Label("")
currency_dropdown = Dropdown(options=currency_list, value='USD', description='Currency:')
#display the widgets
title_label = Label(value='')
linebreak_label = Label('')
#button for submit the input
button = Button(description='Run')
output = widgets.Output()
def __init__(self, _context):
display(HBox([self.ric_input]),
HBox([self.currency_dropdown,self.button]),
self.output)
self.ric_input.on_submit (self.on_button_clicked)
self.button.on_click(self.on_button_clicked)
#self.output
self._context = _context
self.ric_input.value = _context["RIC"]
def on_button_clicked(self,c):
with self.output:
self.output.clear_output() #clear and update output
self.status_label.value="Running..."
display(self.status_label)
_ric = self.ric_input.value #retrieve each ric seperated by ';'
_currency = self.currency_dropdown.value
self._context["RIC"] = _ric
self._context["currency"] = _currency
fields = ["TR.CommonName",
"TR.TtlDebtToTtlEquityPct",
"TR.NetDebtToEBITDA",
"TR.CashandEquivalents(Period=FY0, Scale=6, curn='{}')".format(_currency),
"TR.CurrentRatio",
"TR.QuickRatio",
"TR.InventoryTurnover",
"TR.AcctsReceivTradeNet(Period=FY0,Scale=6, curn='{}')".format(_currency)]
#get data
try:
df, err = ek.get_data(_ric,fields )
if err!=None:
raise ValueError(err[0]['message'])
peer_rics, err = ek.get_data("Peers({})".format(_ric), ["TR.PrimaryInstrument"])
if err!=None:
raise ValueError(err[0]['message'])
df1, err = ek.get_data(peer_rics['Primary Instrument RIC'].tolist(), fields)
if err!=None:
raise ValueError(err[0]['message'])
except ValueError as e:
self.status_label.value = str(e)
return
self.output.clear_output()
self.title_label.value = r'\(\underline{\textbf{Balance Sheet - Peers of %s}}\)'%(df["Company Common Name"][0])
df_concat = pd.concat((df, df1))
df = df.set_index('Instrument')
df.loc["Peer Median"] = df_concat.median()
df.loc["Peer Average"] = df_concat.mean()
df.loc["Peer Median", "Company Common Name"] = ""
df.loc["Peer Average", "Company Common Name"] = ""
df.columns=["Company Name",
"Debt/Equity Latest",
"Net Debt/EBITDA LTM",
"Cash and Equivalents FY0 (Mil)",
"Current Ratio Latest",
"Quick Ratio Latest",
"Inventory Turns Latest",
"Accts Receivable FY0 (mil)"]
display(df)
display(VBox([HBox([self.linebreak_label]),HBox([self.title_label]),HBox([self.linebreak_label])]))
df1 = df1.set_index('Instrument')
df1.columns=["Company Name",
"Debt/Equity Latest",
"Net Debt/EBITDA LTM",
"Cash and Equivalents FY0 (Mil)",
"Current Ratio Latest",
"Quick Ratio Latest",
"Inventory Turns Latest",
"Accts Receivable FY0 (mil)"]
display(df1)
#add text to show error
if err != None:
print('Error:')
print(err, sep = "\n")
WidgetPeersBalanceSheet(context)
Peers - Growth Ratios
The below code is used to create a widget to display growth ratios of the peer group, such as EPS, Revenue, and EBITDA growth rate. The widget accepts a RIC as a parameter. Then, it uses the Eikon Data API to retrieve the following fields of the peer group.
Field | Description |
---|---|
TR.CommonName | The name of the organization most commonly used (Company Name) |
TR.EPSMeanEstimate(Period=FQ1) | The estimated mean of Earnings Per Share based on the current fiscal quarter |
TR.EPSMeanEstimate(Period=FY1) | The estimated mean of Earnings Per Share based on the current fiscal year |
TR.EPSActValue(Period=FQ0) | The actual Earnings Per Share based on the last fiscal quarter |
TR.EPSActValue(Period=FQ-3) | The actual Earnings Per Share based on the fiscal quarter - 3 quarters ago |
TR.EPSActValue(Period=FQ-4) | The actual Earnings Per Share based on the fiscal quarter - 1 year ago |
TR.EPSActValue(Period=FY0) | The actual Earnings Per Share based on the last fiscal year |
TR.EPSActValue(Period=FY-1) | The actual Earnings Per Share based on the previous fiscal year |
TR.RevenueMeanEstimate(Period=FQ0) | The estimated mean of revenue based on the last fiscal quarter |
TR.RevenueMeanEstimate(Period=FQ1) | The estimated mean of revenue based on the current fiscal quarter |
TR.RevenueActValue(Period=FQ-3) | The actual revenue based on the fiscal quarter - 3 quarters ago |
TR.RevenueActvalue(Period=FQ-4) | The actual revenue based on the fiscal quarter - 1 year ago |
TR.EBITDAMean(Period=FQ1) | The mean of EBITDA based on the current fiscal quarter |
TR.EBITDAActValue(Period=FQ-3) | The actual EBITDA based on the fiscal quarter - 3 quarters ago |
It uses the Peers() method to retrieve peer companies of a RIC. For example:
df1, err = ek.get_data("Peers(IBM.N)", ["TR.PrimaryInstrument"])
df2, err = ek.get_data(df1['Primary Instrument RIC'].tolist(),
["TR.CommonName",
"TR.EPSMeanEstimate(Period=FQ1)",
"TR.EPSActValue(Period=FQ-3)",
"TR.EPSActValue(Period=FQ0)",
"TR.EPSActValue(Period=FQ-4)",
"TR.EPSMeanEstimate(Period=FY1)",
"TR.EPSActValue(Period=FY0)",
"TR.EPSActValue(Period=FY-1)",
"TR.RevenueMeanEstimate(Period=FQ1)",
"TR.RevenueActValue(Period=FQ-3)",
"TR.RevenueMeanEstimate(Period=FQ0)",
"TR.RevenueActvalue(Period=FQ-4)",
"TR.EBITDAMean(Period=FQ1)",
"TR.EBITDAActValue(Period=FQ-3)"])
Then, it uses the retrieved data to calculate the following values:
1. EPS FQ1 YoY (%): The year-over-year growth rate of the current fiscal quarter Earnings Per Share
EPS FQ1 YoY (%) = (TR.EPSMeanEstimate(Period=FQ1) - TR.EPSActValue(Period=FQ-3)) / TR.EPSActValue(Period=FQ-3) x 100 |
2. EPS FQ0 YoY (%): The year-over-year growth rate of the last fiscal quarter Earnings Per Share
EPS FQ0 YoY (%) = (TR.EPSActValue(Period=FQ0) - TR.EPSActValue(Period=FQ-4)) / TR.EPSActValue(Period=FQ-4) x 100 |
3. EPS FY1 YoY (%): The year-over-year growth rate of the current fiscal year Earnings Per Share
EPS FY1 YoY (%) = (TR.EPSMeanEstimate(Period=FY1) - TR.EPSActValue(Period=FY0)) / TR.EPSActValue(Period=FY0) x 100 |
4. EPS FY0 YoY (%): The year-over-year growth rate of the last fiscal year Earnings Per Share
EPS FY0 YoY (%) = (TR.EPSActValue(Period=FY0) - TR.EPSActValue(Period=FY-1)) / TR.EPSActValue(Period=FY-1) x 100 |
5. Revenue FQ1 YoY (%): The year-over-year growth rate of the current fiscal quarter revenue
Revenue FQ1 YoY (%) = (TR.RevenueMeanEstimate(Period=FQ1) - TR.RevenueActValue(Period=FQ-3)) / TR.RevenueActValue(Period=FQ-3) x 100 |
6. Revenue FQ0 YoY (%): The year-over-year growth rate of the last fiscal quarter revenue
Revenue FQ0 YoY (%) = (TR.RevenueMeanEstimate(Period=FQ0) - TR.RevenueActvalue(Period=FQ-4)) / TR.RevenueActvalue(Period=FQ-4) x 100 |
7. EBITDA FQ1 YoY (%): The year-over-year growth rate of the current fiscal quarter EBITDA
EBITDA FQ1 YoY (%) = (TR.EBITDAMean(Period=FQ1) - TR.EBITDAActValue(Period=FQ-3)) / TR.EBITDAActValue(Period=FQ-3) x 100 |
class WidgetPeersGrowth:
#for input RICs
ric_input = widgets.Text(
value = '',
placeholder = 'RIC',
description = 'RIC:',
disabled = False
)
status_label = Label("")
#currency_dropdown = Dropdown(options=currency_list, value='USD', description='Currency:')
#display the widgets
title_label = Label(value='')
linebreak_label = Label('')
#button for submit the input
button = Button(description='Run')
output = widgets.Output()
def __init__(self, _context):
display(HBox([self.ric_input,self.button]),
self.output)
self.ric_input.on_submit (self.on_button_clicked)
self.button.on_click(self.on_button_clicked)
#self.output
self._context = _context
self.ric_input.value = _context["RIC"]
def reformat_dataframe(self, df):
df2 = df.set_index('Instrument')
df2.columns = ["Company Name",
"TR.EPSMeanEstimate(Period=FQ1)",
"TR.EPSActValue(Period=FQ-3)",
"TR.EPSActValue(Period=FQ0)",
"TR.EPSActValue(Period=FQ-4)",
"TR.EPSMeanEstimate(Period=FY1)",
"TR.EPSActValue(Period=FY0)",
"TR.EPSActValue(Period=FY-1)",
"TR.RevenueMeanEstimate(Period=FQ1)",
"TR.RevenueActValue(Period=FQ-3)",
"TR.RevenueMeanEstimate(Period=FQ0)",
"TR.RevenueActvalue(Period=FQ-4)",
"TR.EBITDAMean(Period=FQ1)",
"TR.EBITDAActValue(Period=FQ-3)"]
df2["EPS FQ1 YoY (%)"] = (df2["TR.EPSMeanEstimate(Period=FQ1)"]-df2["TR.EPSActValue(Period=FQ-3)"])/df2["TR.EPSActValue(Period=FQ-3)"] * 100
df2["EPS FQ0 YoY (%)"] = (df2["TR.EPSActValue(Period=FQ0)"]-df2["TR.EPSActValue(Period=FQ-4)"])/df2["TR.EPSActValue(Period=FQ-4)"] * 100
df2["EPS FY1 YoY (%)"] = (df2["TR.EPSMeanEstimate(Period=FY1)"]-df2["TR.EPSActValue(Period=FY0)"])/df2["TR.EPSActValue(Period=FY0)"] * 100
df2["EPS FY0 YoY (%)"] = (df2["TR.EPSActValue(Period=FY0)"]-df2["TR.EPSActValue(Period=FY-1)"])/df2["TR.EPSActValue(Period=FY-1)"] * 100
df2["Revenue FQ1 YoY (%)"] = (df2["TR.RevenueMeanEstimate(Period=FQ1)"]-df2["TR.RevenueActValue(Period=FQ-3)"])/df2["TR.RevenueActValue(Period=FQ-3)"] * 100
df2["Revenue FQ0 YoY (%)"] = (df2["TR.RevenueMeanEstimate(Period=FQ0)"]-df2["TR.RevenueActvalue(Period=FQ-4)"])/df2["TR.RevenueActvalue(Period=FQ-4)"] * 100
df2["EBITDA FQ1 YoY (%)"] = (df2["TR.EBITDAMean(Period=FQ1)"]-df2["TR.EBITDAActValue(Period=FQ-3)"])/df2["TR.EBITDAActValue(Period=FQ-3)"] * 100
df2.drop(["TR.EPSMeanEstimate(Period=FQ1)",
"TR.EPSActValue(Period=FQ-3)",
"TR.EPSActValue(Period=FQ0)",
"TR.EPSActValue(Period=FQ-4)",
"TR.EPSMeanEstimate(Period=FY1)",
"TR.EPSActValue(Period=FY0)",
"TR.EPSActValue(Period=FY-1)",
"TR.RevenueMeanEstimate(Period=FQ1)",
"TR.RevenueActValue(Period=FQ-3)",
"TR.RevenueMeanEstimate(Period=FQ0)",
"TR.RevenueActvalue(Period=FQ-4)",
"TR.EBITDAMean(Period=FQ1)",
"TR.EBITDAActValue(Period=FQ-3)"],
axis=1,
inplace=True)
return df2
def on_button_clicked(self,c):
with self.output:
self.output.clear_output() #clear and update output
self.status_label.value="Running..."
display(self.status_label)
_ric = self.ric_input.value #retrieve each ric seperated by ';'
#_currency = self.currency_dropdown.value
self._context["RIC"] = _ric
#self._context["currency"] = _currency
fields = ["TR.CommonName",
"TR.EPSMeanEstimate(Period=FQ1)",
"TR.EPSActValue(Period=FQ-3)",
"TR.EPSActValue(Period=FQ0)",
"TR.EPSActValue(Period=FQ-4)",
"TR.EPSMeanEstimate(Period=FY1)",
"TR.EPSActValue(Period=FY0)",
"TR.EPSActValue(Period=FY-1)",
"TR.RevenueMeanEstimate(Period=FQ1)",
"TR.RevenueActValue(Period=FQ-3)",
"TR.RevenueMeanEstimate(Period=FQ0)",
"TR.RevenueActvalue(Period=FQ-4)",
"TR.EBITDAMean(Period=FQ1)",
"TR.EBITDAActValue(Period=FQ-3)"]
#get data
try:
df, err = ek.get_data(_ric,fields )
if err!=None:
raise ValueError(err[0]['message'])
peer_rics, err = ek.get_data("Peers({})".format(_ric), ["TR.PrimaryInstrument"])
if err!=None:
raise ValueError(err[0]['message'])
df1, err = ek.get_data(peer_rics['Primary Instrument RIC'].tolist(), fields)
if err!=None:
raise ValueError(err[0]['message'])
except ValueError as e:
self.status_label.value = str(e)
return
self.output.clear_output()
self.title_label.value = r'\(\underline{\textbf{Growth - Peers of %s}}\)'%(df["Company Common Name"][0])
df = self.reformat_dataframe(df)
df1 = self.reformat_dataframe(df1)
df_concat = pd.concat((df, df1))
df.loc["Peer Median"] = df_concat.median()
df.loc["Peer Average"] = df_concat.mean()
df.loc["Peer Median", "Company Name"] = ""
df.loc["Peer Average", "Company Name"] = ""
display(df)
display(VBox([HBox([self.linebreak_label]),HBox([self.title_label]),HBox([self.linebreak_label])]))
display(df1)
#add text to show error
if err != None:
print('Error:')
print(err, sep = "\n")
WidgetPeersGrowth(context)
Summary
This article demonstrates how to use the Eikon Data API to retrieve data for peer analysis. It uses the Peers() function with the get_data method to retrieve a list of peer companies and financial information or statistics of those companies. Moreover, it also demonstrates how to use the retrieved data to calculate gross margin, operating margin, and growth rates.
References
- Hayes, A., 2020. Peer Group Definition. [online] Investopedia. Available at: <https://www.investopedia.com/terms/p/peer-group.asp#:~:text=Using%20Peer%20Groups,itself%20to%20relative%20value%20analysis.> [Accessed 25 September 2020].
- Gostudy.io. n.d. Why Peer Groups Are Useful For Industry And Company Analysis — Gostudy. [online] Available at: <https://gostudy.io/blog/cfa-l1-peer-groups-for-investing> [Accessed 25 September 2020].
Downloads
GitHub: peer-analysis