Monitoring ESG Trends and Sectoral Stock Dynamics

Нow to integrate ESG scores into stock screening, analyze sector and market trends, and combine sustainability metrics with financial data

EODHD APIs
11 min readNov 26, 2024
Tracking ESG Trends and Stock Movements Across Sector

Environmental, Social, and Governance (ESG) factors have become a cornerstone of contemporary investing, reflecting the increasing demand for sustainable and ethical business practices. ESG assesses companies based on their environmental impact, social responsibility, and governance standards, offering a broader perspective beyond traditional financial metrics. This approach is vital for identifying long-term risks and opportunities while aligning investment portfolios with societal values. With rising concerns over climate change, inequality, and corporate accountability, ESG promotes resilience, reduces risks, and drives meaningful change. By adopting ESG principles, businesses not only strengthen their reputation but also contribute to sustainability and long-term value creation.

A stock screener is a tool designed to filter stocks based on specific criteria, such as financial metrics or ESG factors, to simplify investment decisions. Investors can utilize these tools to:

  • Identify companies that align with ESG and financial objectives.
  • Compare stocks across sectors for sustainability performance.
  • Exclude companies with poor environmental or governance practices.
  • Customize filters to match personal values and strategies.

It’s important to remember that incorporating ESG principles into investing extends beyond financial returns — it is about fostering ethical responsibility. By prioritizing companies with high ESG scores, investors can drive positive change, promote sustainability, and contribute to a more equitable future while ensuring their portfolios align with societal and environmental priorities.

In this article, we will create a stock screener that integrates basic fundamental data along with ESG scores from the past two years.

To achieve this, we will use EODHD APIs to:

  • Retrieve a list of companies from the NYSE,
  • Download key fundamental data,
  • Obtain ESG scores for these companies, and
  • Analyze patterns and correlations between company performance and ESG scores.

Get the data!

First, let’s start with the necessary imports and define our API:

import requests
import json
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

token = "<YOUR TOKEN HERE>"

Now, we’ll define our stock universe to create the stock screener. To achieve this, we’ll use API that provide exchange data. First, let’s explore how the API for retrieving the list of exchanges works:

url = 'https://eodhd.com/api/exchanges-list/'
querystring = {"api_token":token,"fmt":"json"}
response = requests.get(url, params=querystring).json()

df_exchanges = pd.DataFrame.from_dict(response)
df_exchanges[df_exchanges['CountryISO3'] == 'USA']

If you filter for exchanges located in the US, you’ll see only one result.

This indicates that to get all the symbols listed on the NYSE, we need to use the API for symbol listings and filter the results to include only the NYSE. Furthermore, we will focus on equities, so additional filtering for “Common Stock” is required.

EXCHANGE_CODE = 'US'
url = f'https://eodhd.com/api/exchange-symbol-list/{EXCHANGE_CODE}'
querystring = {"api_token":token,"fmt":"json"}
response = requests.get(url, params=querystring).json()

df_symbols = pd.DataFrame.from_dict(response)
df_symbols = df_symbols[(df_symbols['Exchange'] == 'NYSE') & (df_symbols['Type'] == 'Common Stock')]
df_symbols

There are 2,283 stocks in this list. We’ll now keep everything organized in a dictionary as we proceed with the code:

symbols = df_symbols.set_index('Code').to_dict(orient='index')

Next, we will select some fundamental data that every stock screener should include, such as market capitalization, PE ratio, profit margin, PriceSalesTTM, and Analyst Ratings. We’ll use the API for fundamentals. You can refer to the documentation and add data you find relevant for your trading strategy.

for symbol in symbols:
url = f'https://eodhd.com/api/fundamentals/{symbol}.{EXCHANGE_CODE}'
querystring = {"api_token":token,"fmt":"json"}
try:
response = requests.get(url, params=querystring).json()
symbols[symbol]['Sector'] = response.get('General', {}).get('Sector', None)
symbols[symbol]['Industry'] = response.get('General', {}).get('Industry', None)
symbols[symbol]['MarketCapitalization'] = response.get('Highlights', {}).get('MarketCapitalization', None)
symbols[symbol]['PERatio'] = response.get('Highlights', {}).get('PERatio', None)
symbols[symbol]['ProfitMargin'] = response.get('Highlights', {}).get('ProfitMargin', None)
symbols[symbol]['PriceSalesTTM'] = response.get('Valuation', {}).get('PriceSalesTTM', None)
symbols[symbol]['AnalystRating'] = response.get('AnalystRatings', {}).get('Rating', None)
except Exception as e:
print(f"Error for {symbol} with error {e}")
continue

As this article focuses on ESG data for companies, we will use the ESG API to gather ESG ratings for each stock.
We will retrieve only the last 2 years of data for our case, though EODHD API provides over 10 years of detailed yearly and quarterly ESG scores, including e (environmental), s (social), and g (governance) metrics.

for symbol in symbols:
for year in [2022, 2023]:
url = f'https://eodhd.com/api/mp/investverte/esg/{symbol}'
querystring = {"api_token": token, "fmt": "json", 'frequency': 'FY', 'year': year}
try:
response = requests.get(url, params=querystring).json()
symbols[symbol][f'{str(year)}_esg'] = response[0].get('esg', None)
symbols[symbol][f'{str(year)}_e'] = response[0].get('e', None)
symbols[symbol][f'{str(year)}_s'] = response[0].get('s', None)
symbols[symbol][f'{str(year)}_g'] = response[0].get('g', None)
except Exception as e:
print(f"Error for {symbol} and {year} with error {e}")
continue

Finally, we’ll convert the collected data into a DataFrame and drop rows with missing values:

df = pd.DataFrame(symbols).transpose()

# Drop rows where 2022_esg or 2023_esg with no value
df.dropna(subset=['2022_esg', '2023_esg'], inplace=True)
df = df[(df['2022_esg'] != 0) & (df['2023_esg'] != 0)]

# Drop rows where sector with no value
df.dropna(subset=['Sector'], inplace=True)
df = df[df['Sector'] != ""]

Ready for action!

Now that our data is collected, we need to pre-calculate some critical metrics for our stock screener.

Ranking ESG Scores

First, we’ll assign ESG rankings to each symbol. Rankings will be calculated both globally (across the entire dataset) and within each sector. We’ll also compute the difference in ranking positions between 2022 and 2023.

df['ESG_Rank_2022'] = df[['2022_esg']].rank(ascending=False)
df['ESG_Rank_2023'] = df[['2023_esg']].rank(ascending=False)
df['Places_Difference'] = df['ESG_Rank_2022'] - df['ESG_Rank_2023']


df['ESG_Rank_Sector_2022'] = df.groupby('Sector')['2022_esg'].rank(ascending=False)
df['ESG_Rank_Sector_2023'] = df.groupby('Sector')['2023_esg'].rank(ascending=False)
df['Places_Difference_Sector'] = df['ESG_Rank_Sector_2022'] - df['ESG_Rank_Sector_2023']

Categorizing Market Capitalization

To better understand the data, we’ll categorize companies based on their market capitalization into groups like mega, large, mid, small, micro, and nano.

# Define the bins and labels for each capitalization category
bins = [0, 50_000_000, 300_000_000, 2_000_000_000, 10_000_000_000, 200_000_000_000, float('inf')]
labels = ['nano', 'micro', 'small', 'mid', 'large', 'mega']

# Filter out rows with None values in 'MarketCapitalization'
filtered_df = df.dropna(subset=['MarketCapitalization'])
# Apply pd.cut to the filtered DataFrame
filtered_df.loc[:, 'MarketCapitalization_Binned'] = pd.cut(filtered_df['MarketCapitalization'], bins=bins, labels=labels)

# Merge the result back to the original DataFrame to maintain the structure
df = df.drop(columns=['MarketCapitalization_Binned'], errors='ignore')
df = df.merge(filtered_df[['MarketCapitalization', 'MarketCapitalization_Binned']], how='left',
on='MarketCapitalization')

Insights From ESG Scores

ESG Scores by Sector

To analyze ESG scores by sector, we use a boxplot:

plt.figure(figsize=(12, 8))
sns.boxplot(x='Sector', y='2023_esg', data=df)
plt.title('ESG Score by Sector for 2023')
plt.xticks(rotation=90)
plt.xlabel('Sector')
plt.ylabel('ESG Score')
plt.show()

This provides a high-level overview, showing that certain sectors tend to have higher ESG scores compared to others. In summary:

  • Most sectors have a median ESG score of around 60+, suggesting moderate sustainability performance.
  • The financial sector appears to have slightly higher scores, likely due to stricter regulations promoting sustainable finance.
  • Sectors like Financials, Consumer Cyclical, and Basic Materials exhibit tighter interquartile ranges, indicating consistent ESG performance. However, ESG scores may not provide a strong competitive edge within these sectors.

ESG Scores by Market Capitalization

Similarly, we analyze ESG scores based on market capitalization:

# Define the order of categories explicitly
category_order = ['nano', 'micro', 'small', 'mid', 'large', 'mega']

plt.figure(figsize=(12, 8))
sns.boxplot(x='MarketCapitalization_Binned', y='2023_esg', data=df, order=category_order)
plt.title('ESG Score by Market Capitalization for 2023')
plt.xticks(rotation=90)
plt.xlabel('Market Capitalization')
plt.ylabel('ESG Score')
plt.show()

Observations:

  • The ESG scores across different capitalization categories are generally consistent.
  • Mega-cap companies exhibit tighter score distributions, possibly reflecting their efforts to avoid being seen as the “bad guys” while not needing to strive for “best in class” status.

The Screener

As promised, this article focuses on creating a custom screener. Let’s move beyond charts and see how the screener works.

Exporting the Screener

First, save the screener in CSV format for easy manipulation in Excel, where you can filter and sort to identify opportunities.

df.to_csv('screener.csv', index=False)

Then, the possibilities are endless. You can begin filtering and sorting the data to uncover opportunities for further investigation. (This can also be achieved using Python and pandas, which we will demonstrate shortly.)

As mentioned earlier, everyone has their own approach to selecting stocks that they believe have higher profit potential. Naturally, this is a broad topic that cannot be fully detailed here. Instead, our goal is to inspire you by addressing questions that might arise as you explore an Excel file with thousands of data points.

Which Stock Has the Best ESG Score?

To identify the stock with the top ESG score:

# Which stock has the best ESG score
df[df['ESG_Rank_2023'] == 1]

Result:
The winner is Fresenius Medical Care Corporation (FMS) with an ESG score of 81.79.

To analyze further in Python:

symbol = 'FMS'
selected = df[df['Symbol'] == symbol]

if not selected.empty:
# get the sector and its dataframe
sector = selected['Sector'].values[0]
sector_df = df[df['Sector'] == sector]
# ESG Report
esg_rank = selected['ESG_Rank_2023'].values[0]
place_diff = selected['Places_Difference'].values[0]
esg_rank_sector = selected['ESG_Rank_Sector_2023'].values[0]
place_diff_sector = selected['Places_Difference_Sector'].values[0]
# PE Ratio
pe_ratio = selected['PERatio'].values[0]
better_overall_pe_ratio = (df['PERatio'] > pe_ratio).sum() / len(df) * 100
better_sector_pe_ratio = (sector_df['PERatio'] > pe_ratio).sum() / len(sector_df) * 100
# Profit Margin
profit_margin = selected['ProfitMargin'].values[0]
better_overall_profit_margin = (df['ProfitMargin'] > profit_margin).sum() / len(df) * 100
better_sector_profit_margin = (sector_df['ProfitMargin'] > profit_margin).sum() / len(sector_df) * 100
# PriceSalesTTM
price_sales_ttm = selected['PriceSalesTTM'].values[0]
better_overall_price_sales_ttm = (df['PriceSalesTTM'] > price_sales_ttm).sum() / len(df) * 100
better_sector_price_sales_ttm = (sector_df['PriceSalesTTM'] > price_sales_ttm).sum() / len(sector_df) * 100
# AnalystRating
analyst_rating = selected['AnalystRating'].values[0]
better_overall_analyst_rating = (df['AnalystRating'] < analyst_rating).sum() / len(df) * 100
better_sector_analyst_rating = (sector_df['AnalystRating'] < analyst_rating).sum() / len(sector_df) * 100

print(f'===== ESG ======')
print(f"ESG Rank 2023: {esg_rank} ({place_diff:+.0f} from 2022)")
print(f"ESG Rank 2023 in {sector}: {esg_rank_sector} ({place_diff_sector:+.0f} from 2022)")
print(f'===== PE Ratio ======')
print(f"PE Ratio: {pe_ratio}")
print(f"Percentage of symbols with higher PE Ratio overall: {better_overall_pe_ratio:.2f}% and in {sector} {better_sector_pe_ratio:.2f}%")
print(f'===== Profit Margin ======')
print(f"Profit Margin: {profit_margin}")
print(f"Percentage of symbols with higher Profit Margin overall: {better_overall_profit_margin:.2f}% and in {sector} {better_sector_profit_margin:.2f}%")
print(f'===== PriceSalesTTM ======')
print(f"PriceSalesTTM: {price_sales_ttm}")
print(f"Percentage of symbols with higher PriceSalesTTM overall: {better_overall_price_sales_ttm:.2f}% and in {sector} {better_sector_price_sales_ttm:.2f}%")
print(f'===== AnalystRating ======')
print(f"AnalystRating: {analyst_rating}")
print(f"Percentage of symbols with lower AnalystRating overall: {better_overall_analyst_rating:.2f}% and in {sector} {better_sector_analyst_rating:.2f}%")
else:
print(f"Symbol '{symbol}' not found in the dataset.")

The results are:

===== ESG ======
ESG Rank 2023: 1.0 (+0 from 2022)
ESG Rank 2023 in Healthcare: 1.0 (+0 from 2022)
===== PE Ratio ======
PE Ratio: 18.7458
Percentage of symbols with higher PE Ratio overall: 46.80% and in Healthcare 51.72%
===== Profit Margin ======
Profit Margin: 0.0343
Percentage of symbols with higher Profit Margin overall: 65.51% and in Healthcare 50.57%
===== PriceSalesTTM ======
PriceSalesTTM: 0.6747
Percentage of symbols with higher PriceSalesTTM overall: 75.47% and in Healthcare 72.41%
===== AnalystRating ======
AnalystRating: 3.0
Percentage of symbols with lower AnalystRating overall: 5.83% and in Healthcare 3.45%

Fresenius Medical Care stands out with strong ESG performance and attractive valuation metrics, including a low P/S ratio, suggesting it may be undervalued. However, its modest profit margins and neutral analyst sentiment point to operational challenges and limited short-term growth potential.

Best ESG Score Among Mega Stocks

To identify the mega stock with the highest ESG score:

mega_stocks = df[df['MarketCapitalization_Binned'] == 'mega']
mega_stocks.loc[mega_stocks['2023_esg'].idxmax()]

Accenture plc (ACN) stands out with a score of 75.78. A quick analysis (using the script mentioned above) is as follows:

===== ESG ======  
ESG Rank 2023: 9.0 (-2 from 2022)
ESG Rank 2023 in Technology: 1.0 (+0 from 2022)
===== PE Ratio ======
PE Ratio: 30.9668
Percentage of symbols with higher PE Ratio overall: 23.97% and in Technology 28.17%
===== Profit Margin ======
Profit Margin: 0.1119
Percentage of symbols with higher Profit Margin overall: 32.33% and in Technology 30.99%
===== PriceSalesTTM ======
PriceSalesTTM: 3.4155
Percentage of symbols with higher PriceSalesTTM overall: 24.53% and in Technology 26.76%
===== AnalystRating ======
AnalystRating: 4.0
Percentage of symbols with lower AnalystRating overall: 50.38% and in Technology 50.70%

Accenture’s elevated P/E and price-to-sales ratios indicate a premium valuation, backed by strong profit margins and balanced analyst sentiment with a 4.0 rating.

Top ESG Performer in the Financial Sector

For the financial sector, find the stock with the highest ESG score:

mega_stocks = df[df['Sector'] == 'Financial Services']
mega_stocks.loc[mega_stocks['2023_esg'].idxmax()]

Janus Henderson Group PLC (JHG) emerges as the leader in the Financial Services sector with an ESG score of 75.24.

===== ESG ======
ESG Rank 2023: 12.0 (+10 from 2022)
ESG Rank 2023 in Financial Services: 1.0 (+0 from 2022)
===== PE Ratio ======
PE Ratio: 17.5494
Percentage of symbols with higher PE Ratio overall: 50.47% and in Financial Services 48.41%
===== Profit Margin ======
Profit Margin: 0.175
Percentage of symbols with higher Profit Margin overall: 17.29% and in Financial Services 51.59%
===== PriceSalesTTM ======
PriceSalesTTM: 3.0314
Percentage of symbols with higher PriceSalesTTM overall: 28.20% and in Financial Services 69.84%
===== AnalystRating ======
AnalystRating: 3.0
Percentage of symbols with lower AnalystRating overall: 5.83% and in Financial Services 8.73%

Insights

A closer look at the fundamentals reveals interesting findings: the P/E ratio appears to be in a moderate range, while the company’s profit margin and price-to-sales ratio are strong globally and average within a sector where these figures are already relatively high. Notably, it is not favored by analysts. However, this is a company that, as of YTD (~11 months at the time this article was written), has seen a steady 75% increase in its stock price.

Let’s Wrap It Up and Key Takeaways

The purpose of this article was to guide you through the process of downloading data, understanding its basics, and creating a dataset. This dataset can be explored with tools like Excel, enabling you to experiment with different approaches and address key questions. The ultimate goal is to provide insights for making informed decisions.

ESG Scores as a Strategic Filter

This article demonstrated how to incorporate Environmental, Social, and Governance (ESG) scores into a stock screener. Ranking companies by ESG performance helps investors identify businesses that align with sustainability goals and societal values. For example, the Financial Services sector often shows consistent ESG performance due to regulatory requirements. Such insights enable investors to focus on industries or companies with strong ESG practices, often associated with long-term resilience and reduced risk exposure.

Sector and Market Capitalization Insights

Analyzing ESG scores by sector and market capitalization uncovers trends that investors can use strategically. For example, mega-cap companies tend to have narrower ESG score ranges, reflecting their focus on maintaining reputation and avoiding extreme outliers. Similarly, sectors like Consumer Cyclical or Basic Materials show tighter ESG performance ranges, indicating less differentiation among peers. These findings assist in tailoring investment strategies, such as targeting undervalued companies in high-performing sectors or avoiding sectors with limited ESG variability.

Customizable Screening for Investment Decisions

The tools outlined in this article allow for the creation of a custom stock screener that integrates ESG data with financial metrics like P/E ratios, profit margins, and analyst ratings. For instance, Fresenius Medical Care Corporation (FMS) stands out with its high ESG score, though modest profit margins suggest potential operational challenges. Investors can use these screeners, whether in Excel or Python, to filter stocks based on individual criteria, facilitating data-driven decisions that align with both financial objectives and ethical considerations.

While we are still far from conclusively proving that companies with high ESG scores consistently outperform others, advancements in methodologies and data will likely strengthen the link between robust ESG practices and financial success.

To close, there’s not much left to say — just four simple words: Invest green, profit clean!

Stay tuned for more valuable articles that aim to enhance your data science skills and market analysis capabilities.

The original article was published in the EODHD Academy by Nikhil Adithyan

Please note that this article is for informational purposes only and should not be taken as financial advice. We do not bear responsibility for any trading decisions made based on the content of this article. Readers are advised to conduct their research or consult with a qualified financial professional before making any investment decisions.

For those eager to delve deeper into such insightful articles and broaden their understanding of different strategies in financial markets, we invite you to follow our account and subscribe for email notifications.

--

--

EODHD APIs
EODHD APIs

Written by EODHD APIs

eodhd.com — stock market fundamental and historical prices API for stocks, ETFs, mutual funds and bonds all over the world.

No responses yet