Back To Top

February 13, 2025

Decomposing a Stock’s 5 ROE Drivers

Using the Merton Model to estimate credit risk, simulate default probabilities, and assess financial stability

There are investors such as Joel Greenblatt who note the great importance of ROE is a metric for identifying undervalued businesses. Joel goes as far as including ROE in his ‘Magic Formula’ for investing by combining it with earnings yield.

ROE assesses how well a firm transforms equity into profit. However, companies vary in their strategies and capital structures. A single percentage, therefore, does not show which part of the business drives performance. Advanced Dupont ROE Decomposition solves this.

It splits one aggregate measure into smaller components. This offers a deeper view of profitability, operating efficiency, and financial leverage. This is very valuable. Warren Buffet, for example, studies companies that grow ROE without piling on excessive debt.

Historical cases include IBM in the 1970s, which pushed margins and turnover to maintain ROE (Arden Tools). Another example is Apple, which used share buybacks to influence equity levels (SF Maganize).

In this article, I implement Advanced Dupont ROE Decomposition Analysis in Python with freely available data from Yahoo Finance. 

Use Entreprenerdly’s Real-time ROE  Decomposition tool to explore the key drivers of ROE across 72k+ tickers:

ROE Decomposition Tool demo 1 AVIF
ROE Decomposition Tool demo 2 AVIF

The article is structured as follows:

  • Why ROE Decomposition Matters
  • The 5 ROE drivers in Advanced DuPont Analysis
  • Data Fetching From Yahoo Finance with Python
  • Implementing DuPont Analysis Over Time
  • Equity Multiplier : Assets vs. Liabilities vs. Equity
  • Equity Multiplier: Net Income, ICR, Cash Flow

1. Why Do We Care About ROE Decomposition?

We care because pure ROE can hide important shifts. A firm may raise profit by lowering taxes, or it might expand by taking on more debt. A decomposition of ROE would reveal how each lever affects final returns.

For instance, a rising ROE may come from improved operating margin or from rising interest burden. In real life, a bank may show stable ROE, yet rely more on leverage. That can be risky if conditions change. Meanwhile, a tech firm may show strong ROE thanks to high margins.

Past scenarios also show that debt spikes can inflate ROE but raise default risk. Consider airlines before downturns. Many had higher equity multipliers, so their ROE looked respectable. However, once traffic reduced, interest coverage became a challenge.

ROE Decomposition helps you see if return changes come from genuine operational improvements or from risky balance sheet shifts. Ultimately, it helps us spot vulnerabilities in financial management.

2. Advanced DuPont Analysis: The 5 ROE Drivers

Traditional DuPont analysis splits ROE into net profit margin, asset turnover, and equity multiplier. The advanced version adds tax burden and interest burden. Together, they form the following formula:

formula 1 ADVANCED ROE DECOMPOSITION

Each fraction captures a separate driver:

  • Tax Burden checks how much tax reduces earnings.
  • Interest Burden checks how interest affects pretax results.
  • Operating Margin checks profit from operations relative to sales.
  • Asset Turnover checks efficiency in generating revenue from assets.
  • Equity Multiplier checks the leverage effect by comparing total assets to equity.

Which factor moves the final ROE figure the most? If tax burden increases due to a new tax break, the net margin jumps. If equity multiplier climbs from share buybacks, leverage plays a larger role.

Past studies show that stable interest burdens and decent operating margins often create more reliable returns (e.g. see StanfordAbacademies).

Meanwhile, big leaps in asset turnover can happen in retail or e-commerce, where sales volume is high but margins may be narrow.

Advanced DuPont shows if a firm’s competitive advantage lies in cost control, capital structure, or strong sales relative to assets.

Dupont Over Time (OPTIMIZED)

3. Data Fetching with Python

Since we’ll implement the analyses over time, we need data for each fiscal period. The code below uses yfinance to pull three statements: income statement, balance sheet, and cash flow from the last 4 years.

In our example below, we’ll explore the latest ROE dynamics for Apple. You can easily change the ticker to explore other companies.

				
					import yfinance as yf
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt


# STEP 1) DATA FETCHING
def fetch_data(ticker_symbol="AAPL"):
    ticker = yf.Ticker(ticker_symbol)

    # Pull statements
    income_statement = ticker.financials
    balance_sheet = ticker.balance_sheet
    cash_flow = ticker.cashflow

    # Build a set of all statement date strings
    all_cols = set(income_statement.columns).union(balance_sheet.columns).union(cash_flow.columns)

    end_prices = {}
    for date_str in all_cols:
        try:
            dt = pd.to_datetime(date_str)
        except ValueError:
            end_prices[date_str] = np.nan
            continue

        # We'll fetch ~10 days prior to dt so we can find the closest date <= dt
        start_fetch = dt - pd.Timedelta(days=10)
        end_fetch   = dt + pd.Timedelta(days=1)

        hist_data = yf.download(ticker_symbol, start=start_fetch, end=end_fetch, progress=False)
        if not hist_data.empty:
            # Grab all rows up to and including dt
            sub_data = hist_data.loc[:dt]
            if not sub_data.empty:
                # Last available close on or before dt
                end_prices[date_str] = sub_data.iloc[-1]["Close"]
            else:
                end_prices[date_str] = np.nan
        else:
            end_prices[date_str] = np.nan

    return {
        "income_statement": income_statement,
        "balance_sheet": balance_sheet,
        "cash_flow": cash_flow,
        "end_prices": end_prices
    }
				
			

We implement the function above to retrieve all the financial statements and share prices accordingly for each fiscal period:

				
					data_dict = fetch_data("AAPL")
income_statement = data_dict["income_statement"]
balance_sheet    = data_dict["balance_sheet"]
cash_flow_df     = data_dict["cash_flow"]
end_prices       = data_dict["end_prices"]
				
			

4. Implementing Advanced DuPont Analysis

We begin by extracting six core data points for each period: net income, EBT, EBIT, revenue, total assets, and total equity.

The code matches labels like “Net Income” or “Total Equity” from the statements, then calculates the 5 DuPont drivers and final ROE.

The multiple label approach is implemented for each data point to prevent missing data due to changes in data structures from yfinance.

Prev Post

Impact of Medical Research Cuts on Key Biotechnology Stocks

Next Post

Expert Insight: Delayed Tariff Plans May Impact Markets

post-bars
Mail Icon

Newsletter

Get Every Weekly Update & Insights

[mc4wp_form id=]

Leave a Comment