What’s the question?
The cost of equity is the return that shareholders require as compensation for bearing the risk of owning a stock. It is a critical input to discounted cash flow (DCF) models, capital budgeting decisions, and weighted average cost of capital (WACC) calculations. The Capital Asset Pricing Model (CAPM) provides a formula: Cost of Equity = Risk-Free Rate + Beta x Equity Risk Premium. The risk-free rate (Rf) represents the return on a riskless asset — typically the 10-year Treasury yield. Beta measures the stock’s sensitivity to market movements. The equity risk premium (ERP) is the additional return investors demand for holding equities instead of risk-free bonds. The current 10-year Treasury yield is approximately 4.3%, and the long-run ERP is conventionally estimated at 5.0–6.0%.
The approach
Select 10 stocks across risk profiles — from high-beta technology names to low-beta consumer staples. Estimate beta via ordinary least squares (OLS) regression of each stock’s daily returns against SPY over 3 years. Report the standard error of the beta estimate and R-squared to quantify estimation precision. Apply the CAPM formula with Rf = 4.3% and ERP = 5.5% to compute the implied cost of equity for each stock.
import xfinlink as xfl
import pandas as pd
import numpy as np
from scipy import stats
xfl.api_key = "YOUR_API_KEY" # free at https://xfinlink.com/signup
# -- Configuration ----------------------------------------------------------
tickers = ["AAPL", "MSFT", "NVDA", "TSLA", "AMZN", "JPM", "XOM", "UNH", "PG", "JNJ"]
benchmark = "SPY"
rf = 0.043 # 10-year Treasury yield (annualized)
erp = 0.055 # equity risk premium (long-run estimate)
# -- Fetch 3Y daily returns -------------------------------------------------
df = xfl.prices(tickers + [benchmark], period="3y", fields=["return_daily"])
returns = df.pivot_table(index="date", columns="ticker", values="return_daily").dropna()
# -- OLS regression for beta estimation ------------------------------------
market = returns[benchmark]
results = []
for ticker in tickers:
slope, intercept, r_value, p_value, std_err = stats.linregress(
market, returns[ticker]
)
cost_of_equity = rf + slope * erp
results.append({
"ticker": ticker,
"beta": slope,
"beta_se": std_err,
"r_squared": r_value ** 2,
"cost_of_equity": cost_of_equity,
})
rdf = pd.DataFrame(results).sort_values("cost_of_equity", ascending=False)
# -- Print results ---------------------------------------------------------
print("=== CAPM Cost of Equity Estimation ===")
print(f"Risk-free rate (Rf): {rf:.1%} | Equity risk premium (ERP): {erp:.1%}")
print(f"Formula: Ke = Rf + Beta x ERP = {rf:.1%} + Beta x {erp:.1%}")
print()
print(f"{'Ticker':6s} {'Beta':>6s} {'Beta SE':>8s} {'R²':>8s} {'Cost of Equity':>15s}")
print("-" * 46)
for _, r in rdf.iterrows():
print(
f"{r['ticker']:6s} {r['beta']:>6.2f} {r['beta_se']:>8.3f} "
f"{r['r_squared']:>8.3f} {r['cost_of_equity']:>14.1%}"
)
median_ke = rdf["cost_of_equity"].median()
min_ke = rdf["cost_of_equity"].min()
max_ke = rdf["cost_of_equity"].max()
print(f"\nMedian cost of equity: {median_ke:.1%}")
print(f"Range: {min_ke:.1%} to {max_ke:.1%}")
Output:
=== CAPM Cost of Equity Estimation ===
Risk-free rate (Rf): 4.3% | Equity risk premium (ERP): 5.5%
Formula: Ke = Rf + Beta x ERP = 4.3% + Beta x 5.5%
Ticker Beta Beta SE R² Cost of Equity
----------------------------------------------
TSLA 2.22 0.113 0.339 16.5%
NVDA 2.08 0.090 0.416 15.8%
AMZN 1.40 0.054 0.468 12.0%
AAPL 1.13 0.046 0.439 10.5%
MSFT 0.98 0.044 0.399 9.7%
JPM 0.90 0.044 0.363 9.3%
XOM 0.29 0.054 0.037 5.9%
UNH 0.28 0.088 0.013 5.8%
PG 0.15 0.041 0.018 5.1%
JNJ 0.05 0.041 0.002 4.6%
Median cost of equity: 9.5%
Range: 4.6% to 16.5%
What this tells us
The CAPM produces a 12-percentage-point spread in cost of equity, from 4.6% (JNJ) to 16.5% (TSLA). This spread directly impacts valuation: a DCF model using 16.5% discounts TSLA’s future cash flows far more aggressively than one using 4.6% for JNJ. The standard errors are informative — JNJ’s beta standard error (0.041) is nearly as large as its point estimate (0.05), indicating the beta is not reliably distinguishable from zero. Its R-squared of 0.002 confirms JNJ’s returns are almost entirely idiosyncratic — the market explains essentially none of its variation. For such stocks, the CAPM framework provides limited predictive value because the market risk factor is irrelevant.
So what?
When building a DCF model, the cost of equity is the most consequential assumption after the growth rate. Using a single “market average” discount rate for all stocks introduces systematic bias — overvaluing high-beta stocks and undervaluing low-beta ones. Estimate beta from at least 3 years of data, report the standard error, and use the Merrill Lynch adjusted beta (shrunk toward 1.0) for stocks with low R-squared to reduce estimation noise. For defensive stocks like JNJ and PG where market beta is near zero, consider supplementing CAPM with a build-up method that adds company-specific risk premiums.