ARTICLE

Peer Analysis

Jirapongse Phuriphanvichai
Developer Advocate Developer Advocate

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
A valuation ratio of a company's current share price relative to its earnings per share (Trailing P/E LTM)
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

  1. 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].
  2. 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