What Is Adjusted Beta? Merrill Lynch Beta Shrinkage in Python
May 15, 2026
What’s the question?
Raw beta from OLS regression measures a stock’s historical market sensitivity. But raw betas are noisy — they fluctuate substantially depending on the estimation period. The Merrill Lynch adjusted beta (also called Bloomberg beta) addresses this by shrinking the raw estimate toward 1.0 using the formula: Adjusted Beta = (2/3) × Raw Beta + (1/3) × 1.0. The rationale: betas tend to mean-revert toward 1.0 over time (high-beta stocks get less volatile, low-beta stocks become more correlated with the market). The 2/3 weight is empirically calibrated.
The approach
Select 10 stocks across risk profiles — from high-volatility names (TSLA, NVDA) to defensive consumer staples (PG, JNJ). Run OLS regression of each stock’s daily returns against SPY over 1 year to obtain the raw beta, then apply the Merrill Lynch shrinkage formula. Compare both estimates side by side with the R-squared from each regression.
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", "XOM", "JNJ", "PG", "JPM", "GS", "UNH"]
benchmark = "SPY"
# -- Fetch 1Y daily returns -------------------------------------------------
df = xfl.prices(tickers + [benchmark], period="1y", fields=["return_daily"])
returns = df.pivot_table(index="date", columns="ticker", values="return_daily").dropna()
# -- OLS regression + Merrill Lynch adjustment ------------------------------
market = returns[benchmark]
results = []
for ticker in tickers:
slope, intercept, r_value, p_value, std_err = stats.linregress(
market, returns[ticker]
)
adj_beta = (2 / 3) * slope + (1 / 3) * 1.0
results.append({
"ticker": ticker,
"raw_beta": slope,
"adj_beta": adj_beta,
"r_squared": r_value ** 2,
"shrinkage": slope - adj_beta,
})
rdf = pd.DataFrame(results).sort_values("raw_beta", ascending=False)
print("=== Raw Beta vs Merrill Lynch Adjusted Beta (1Y vs SPY) ===")
print(f"{'Ticker':6s} {'Raw Beta':>9s} {'Adj Beta':>9s} {'Shrinkage':>10s} {'R²':>6s}")
print("-" * 46)
for _, r in rdf.iterrows():
print(
f"{r['ticker']:6s} {r['raw_beta']:>9.3f} {r['adj_beta']:>9.3f} "
f"{r['shrinkage']:>+10.3f} {r['r_squared']:>6.3f}"
)
print(f"\nAdjustment formula: Adj Beta = (2/3) * Raw Beta + (1/3) * 1.0")
print(f"Average raw beta: {rdf['raw_beta'].mean():.3f}")
print(f"Average adj beta: {rdf['adj_beta'].mean():.3f}")
Output:
=== Raw Beta vs Merrill Lynch Adjusted Beta (1Y vs SPY) ===
Ticker Raw Beta Adj Beta Shrinkage R²
----------------------------------------------
TSLA 2.041 1.694 +0.347 0.280
NVDA 1.803 1.535 +0.268 0.429
GS 1.471 1.314 +0.157 0.444
AAPL 0.984 0.989 -0.005 0.277
JPM 0.982 0.988 -0.006 0.315
MSFT 0.901 0.934 -0.033 0.218
UNH 0.706 0.804 -0.098 0.039
PG 0.097 0.398 -0.301 0.004
JNJ 0.054 0.369 -0.315 0.002
XOM -0.246 0.169 -0.415 0.016
Adjustment formula: Adj Beta = (2/3) * Raw Beta + (1/3) * 1.0
Average raw beta: 0.879
Average adj beta: 0.919
What this tells us
The adjustment has asymmetric effects depending on which side of 1.0 the raw beta sits. High-beta stocks get pulled down: TSLA shrinks from 2.04 to 1.69. Low-beta stocks get pulled up: XOM’s negative beta (-0.25) becomes a modest positive (0.17). Near-1.0 betas barely change: AAPL moves from 0.984 to 0.989. The R-squared column reveals another dimension: JNJ and PG have near-zero R-squared values (0.002 and 0.004), meaning their raw betas are estimated from essentially no signal. The adjustment pushes these unreliable estimates toward 1.0, which is a safer prior than trusting a noisy regression. The Bayesian interpretation: the formula treats 1.0 as a prior and updates it with the data, with the 2/3 weight reflecting how much to trust the observed beta.
So what?
When constructing portfolios or hedging, use adjusted beta instead of raw beta. Raw beta overestimates the market sensitivity of volatile stocks and underestimates it for defensive stocks. For risk models that compute expected returns via CAPM (Expected Return = Rf + Beta × Market Premium), using raw betas produces forecasts that are too extreme in both directions. The Merrill Lynch adjustment is a one-line correction that improves out-of-sample prediction.
pip install xfinlink