Session 10 of 26 Part IV: Cost of Capital — Chapter 10 of 18
Part IV: Cost of Capital Chapter 10 of 18 Session 10 Python

Risk, Return & Cost of Equity

Estimate the return investors demand for bearing equity risk — the foundational input that drives every discount rate and every valuation.

Learning Objectives

10.1 Why the Cost of Equity Matters

The cost of equity is the rate of return that equity investors require to compensate them for the risk of holding a company's stock. It is not an accounting cost — the company writes no cheque for it. But it is a very real economic cost: if a company cannot earn at least its cost of equity on the capital shareholders have provided, it is destroying shareholder value, regardless of what its income statement says.

The cost of equity appears in every DCF valuation as a component of WACC. Getting it wrong by even 1–2 percentage points can swing a valuation by 15–30%. Yet there is no single "correct" cost of equity — it is an estimate, based on models, market data, and judgment. The goal is not precision but a well-reasoned, defensible estimate supported by evidence.

The Cost of Equity Is an Opportunity Cost
When an investor buys a share of TCS, they are choosing NOT to invest that money elsewhere — in a bank FD, a government bond, or another stock. The cost of equity is the return they could earn on the next-best investment of equivalent risk. If TCS cannot deliver that return, the investor's capital is misallocated, and the share price should fall until the expected return equals the required return.

10.2 The Capital Asset Pricing Model (CAPM)

The CAPM, developed by William Sharpe and John Lintner in the 1960s, remains the standard model for estimating the cost of equity in practice — despite its known limitations. It is simple, intuitive, and universally understood by practitioners.

Cost of Equity (Ke) = Rf + β × (Rm − Rf)

Where:

SymbolNameWhat It Represents
RfRisk-Free RateThe return on an investment with zero default risk — typically the 10-year government bond yield. For India, this is the 10-year G-Sec yield.
βBetaThe sensitivity of the stock's returns to market returns. A beta of 1.0 means the stock moves with the market. Beta of 1.5 means it amplifies market moves by 50%.
Rm − RfEquity Risk Premium (ERP)The additional return investors demand for bearing equity market risk instead of holding risk-free bonds. This is the most debated number in finance.

Each of these three inputs requires careful estimation. Let us tackle them one at a time.

10.3 The Risk-Free Rate (Rf) for Indian Companies

In developed markets, the 10-year government bond yield is the uncontroversial choice for the risk-free rate. For India, the 10-year Government Security (G-Sec) yield serves the same purpose — but with important caveats.

10.3.1 What Makes a Rate "Risk-Free"?

A true risk-free rate must satisfy two conditions: (1) zero default risk, and (2) no reinvestment risk when matched to the investment horizon. The 10-year G-Sec satisfies #1 (the Indian government has never defaulted on rupee-denominated debt). It approximately satisfies #2 for long-horizon equity valuation.

10.3.2 The Indian G-Sec Yield: Historical Context

The Indian 10-year yield has ranged from ~5.9% (2020, COVID low) to ~9.5% (2013, taper tantrum). As of mid-2026, it typically trades in the 6.5–7.2% range. This is significantly higher than US Treasuries (~4–5%), reflecting India's higher inflation and sovereign credit rating (BBB− / Baa3).

Critical Decision: Should you use the current spot G-Sec yield (which can be volatile) or a normalized long-term average? For DCF valuation, which is long-term by nature, most practitioners use a normalized risk-free rate — the average 10-year yield over the past 3–5 years, or a forward-looking estimate based on the RBI's inflation target (4%) plus a real rate of 2–3%. A common choice for Indian valuations is 6.5–7.0%.

10.3.3 Fetching the G-Sec Yield in Python

import yfinance as yf
import pandas as pd
import numpy as np

# Fetch the Indian 10-year G-Sec yield
# Yahoo Finance ticker: ^TNX for US 10Y; for India, use the RBI benchmark
# Alternative: use the iShares India Govt Bond ETF or direct yield source

# Method 1: RBI's 10-year benchmark via yfinance
gsec = yf.Ticker("0P0000OYFB.BO")  # Approximate; may need updating
# For reliable data, use the FRED database via pandas_datareader
# or manually input the current rate from RBI/FBIL website

# Method 2: Manual input (most reliable for Indian G-Sec)
# Source: https://www.rbi.org.in or https://www.fbil.org.in
current_10y_gsec = 6.85  # Example: current 10-year G-Sec yield in %

# Normalized rate (3-year average proxy)
normalized_rf = 6.75  # Based on 2023-2026 average

print(f"Current 10Y G-Sec Yield: {current_10y_gsec}%")
print(f"Normalized Risk-Free Rate: {normalized_rf}%")
print(f"\nUsing normalized rate ({normalized_rf}%) for long-term DCF valuation.")
📝
Data Note: Unlike US Treasury yields, Indian G-Sec yields are not easily accessible via yfinance. The most reliable sources are the RBI Database on Indian Economy (dbie.rbi.org.in), the FBIL website (fbil.org.in), or TradingView. For this course, we enter the rate manually from the latest available data. In a production valuation, always cite your source and date.

10.4 Estimating Beta: The Stock's Market Sensitivity

Beta (β) measures how a stock's returns move relative to the market. A stock with a beta of 1.2 tends to rise 1.2% when the market rises 1% and fall 1.2% when the market falls 1%. Beta captures systematic risk — the risk that cannot be diversified away by holding a portfolio.

10.4.1 The Regression Approach

Beta is estimated by regressing the stock's historical returns against the market's returns. The slope of the regression line is the beta.

Rstock − Rf = α + β × (Rmarket − Rf) + ε
import yfinance as yf
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from scipy import stats
import seaborn as sns

def calculate_beta(ticker_symbol, market_index="^NSEI", period="5y", rf=0.0675):
    """
    Calculate a stock's beta using historical price data.

    Parameters
    ----------
    ticker_symbol : str — stock ticker (e.g., 'RELIANCE.NS')
    market_index : str — market index ticker (default: Nifty 50)
    period : str — historical period for regression
    rf : float — annual risk-free rate (for excess return calculation)

    Returns
    -------
    dict with beta, alpha, R², and confidence interval.
    """
    # Download price data
    stock = yf.download(ticker_symbol, period=period, progress=False)
    market = yf.download(market_index, period=period, progress=False)

    # Use Adjusted Close prices
    stock_prices = stock['Adj Close']
    market_prices = market['Adj Close']

    # Calculate monthly returns (more stable than daily for beta)
    stock_returns = stock_prices.resample('ME').last().pct_change().dropna()
    market_returns = market_prices.resample('ME').last().pct_change().dropna()

    # Align the dates
    common_dates = stock_returns.index.intersection(market_returns.index)
    stock_returns = stock_returns[common_dates]
    market_returns = market_returns[common_dates]

    # Convert annual rf to monthly
    rf_monthly = (1 + rf) ** (1/12) - 1

    # Excess returns
    stock_excess = stock_returns - rf_monthly
    market_excess = market_returns - rf_monthly

    # Linear regression: stock_excess = alpha + beta * market_excess
    slope, intercept, r_value, p_value, std_err = stats.linregress(
        market_excess, stock_excess
    )

    beta = slope
    alpha = intercept * 12  # Annualize
    r_squared = r_value ** 2

    # 95% confidence interval for beta
    n = len(stock_excess)
    beta_se = std_err
    beta_ci_low = beta - 1.96 * beta_se
    beta_ci_high = beta + 1.96 * beta_se

    # --- Plot ---
    fig, axes = plt.subplots(1, 2, figsize=(16, 6))

    # Regression scatter
    ax = axes[0]
    ax.scatter(market_excess * 100, stock_excess * 100, alpha=0.5,
              color='#6c8cff', edgecolors='white', s=40)
    x_range = np.linspace(market_excess.min(), market_excess.max(), 100)
    ax.plot(x_range * 100, (intercept + slope * x_range) * 100,
            color='#e0556a', linewidth=2, label=f'β = {beta:.2f}')
    ax.set_xlabel('Market Excess Return (%)')
    ax.set_ylabel('Stock Excess Return (%)')
    ax.set_title(f'{ticker_symbol} — Beta Regression', fontweight='bold')
    ax.legend(fontsize=10)
    ax.grid(True, alpha=0.3)

    # Rolling beta (1-year window)
    ax = axes[1]
    window = 12  # 12 months
    rolling_betas = []
    rolling_dates = []
    for i in range(window, len(stock_excess)):
        s = stock_excess.iloc[i-window:i]
        m = market_excess.iloc[i-window:i]
        b, _, _, _, _ = stats.linregress(m, s)
        rolling_betas.append(b)
        rolling_dates.append(stock_excess.index[i])

    ax.plot(rolling_dates, rolling_betas, color='#6c8cff', linewidth=2)
    ax.axhline(y=beta, color='#e0556a', linestyle='--', linewidth=1.5,
              label=f'Full-period β = {beta:.2f}')
    ax.fill_between(rolling_dates, beta_ci_low, beta_ci_high,
                    alpha=0.12, color='#6c8cff', label='95% CI')
    ax.set_xlabel('Date')
    ax.set_ylabel('Rolling 1-Year Beta')
    ax.set_title('Beta Stability Over Time', fontweight='bold')
    ax.legend(fontsize=9)
    ax.grid(True, alpha=0.3)

    plt.suptitle(f'Beta Analysis — {ticker_symbol} vs Nifty 50',
                 fontsize=14, fontweight='bold', y=1.02)
    plt.tight_layout()
    plt.show()

    return {
        'beta': round(beta, 3),
        'alpha_annual': round(alpha * 100, 2),
        'r_squared': round(r_squared, 3),
        'p_value': round(p_value, 4),
        'beta_ci_95': (round(beta_ci_low, 3), round(beta_ci_high, 3)),
        'observations': n,
        'period': period
    }


# --- Calculate beta for key Indian stocks ---
stocks_to_analyze = ['RELIANCE.NS', 'TCS.NS', 'ASIANPAINT.NS', 'TATASTEEL.NS']

for ticker in stocks_to_analyze:
    result = calculate_beta(ticker)
    print(f"\n{ticker}: β = {result['beta']:.2f} "
          f"(95% CI: {result['beta_ci_95'][0]:.2f} – {result['beta_ci_95'][1]:.2f}) | "
          f"R² = {result['r_squared']:.2f} | "
          f"n = {result['observations']} months")

10.4.2 Interpreting Beta Values

Beta RangeInterpretationTypical Indian Examples
< 0.5Defensive — low sensitivity to market movementsNestle India, HUL, Power Grid (regulated utility)
0.5 – 0.8Moderately defensiveITC, Asian Paints, Sun Pharma
0.8 – 1.2Market-like riskInfosys, HDFC Bank, Reliance
1.2 – 1.5Above-average sensitivityTata Motors, ICICI Bank, Larsen & Toubro
> 1.5High-beta — amplifies market movementsTata Steel, Hindalco, real estate stocks, PSU banks

10.4.3 Adjusting Raw Beta: The Blume Adjustment

Raw historical betas have a statistical tendency to regress toward 1.0 over time. A stock with a measured beta of 1.8 today is likely to have a beta closer to 1.0 in the future. The Blume adjustment corrects for this:

Adjusted Beta = (2/3) × Raw Beta + (1/3) × 1.0
def blume_adjusted_beta(raw_beta):
    """Apply the Blume adjustment to correct for beta's mean-reversion tendency."""
    return (2/3) * raw_beta + (1/3) * 1.0

# Example
raw_betas = {'TCS': 0.72, 'Asian Paints': 0.65, 'Tata Steel': 1.45, 'Reliance': 1.05}
print("Beta Adjustment:")
for name, raw in raw_betas.items():
    adjusted = blume_adjusted_beta(raw)
    print(f"  {name}: Raw β = {raw:.2f} → Adjusted β = {adjusted:.2f}")
💡
Pro Tip: For unlisted companies or divisions, you cannot calculate beta from stock prices. Instead, use the bottom-up (industry) beta approach: identify a set of comparable listed companies, unlever their betas to remove the effect of their individual capital structures, take the median, and re-lever using the target company's debt-to-equity ratio. We cover this in Section 10.5.

10.5 Levered vs Unlevered Beta

The beta we calculated above is a levered beta — it reflects both the company's business risk and its financial risk from debt. To compare companies with different capital structures, or to estimate beta for an unlisted company, we must separate these two risks.

10.5.1 Unlevering and Relevering Beta

βUnlevered = βLevered / (1 + (1 − Tax Rate) × (Debt / Equity))

βRelevered = βUnlevered × (1 + (1 − Tax Rate) × (Target D/E))
def unlever_beta(levered_beta, debt, equity, tax_rate=0.25):
    """Remove the effect of financial leverage from beta."""
    return levered_beta / (1 + (1 - tax_rate) * (debt / equity))

def relever_beta(unlevered_beta, target_de, tax_rate=0.25):
    """Apply target capital structure to unlevered beta."""
    return unlevered_beta * (1 + (1 - tax_rate) * target_de)

def bottom_up_beta(peer_betas, peer_de_ratios, target_de, tax_rate=0.25):
    """
    Calculate bottom-up beta for a target company using peer data.

    Parameters
    ----------
    peer_betas : list of levered betas for comparable companies
    peer_de_ratios : list of D/E ratios for the same companies
    target_de : target company's D/E ratio
    tax_rate : marginal tax rate

    Returns
    -------
    Estimated levered beta for the target company.
    """
    # Unlever each peer's beta
    unlevered_betas = []
    for beta, de in zip(peer_betas, peer_de_ratios):
        unlevered = unlever_beta(beta, de, 1.0, tax_rate)
        unlevered_betas.append(unlevered)

    # Median unlevered beta (more robust than mean)
    median_unlevered = np.median(unlevered_betas)

    # Relever using target D/E
    target_beta = relever_beta(median_unlevered, target_de, tax_rate)

    return {
        'unlevered_betas': unlevered_betas,
        'median_unlevered': round(median_unlevered, 3),
        'target_levered_beta': round(target_beta, 3),
        'peers_used': len(peer_betas)
    }


# --- Example: Bottom-up beta for an unlisted paint company ---
paint_peers_betas = [0.65, 0.72, 0.58]  # Asian Paints, Berger, Indigo Paints
paint_peers_de = [0.15, 0.22, 0.08]      # Their D/E ratios
target_de_ratio = 0.40                     # Unlisted company has more debt

result = bottom_up_beta(paint_peers_betas, paint_peers_de, target_de_ratio)
print(f"Bottom-Up Beta Estimation:")
print(f"  Peer unlevered betas: {[round(b,3) for b in result['unlevered_betas']]}")
print(f"  Median unlevered beta: {result['median_unlevered']}")
print(f"  Target levered beta (D/E={target_de_ratio}): {result['target_levered_beta']}")

10.6 The Equity Risk Premium (ERP)

The Equity Risk Premium is the most consequential and most debated number in corporate finance. It is the additional return investors demand for investing in equities as a class rather than risk-free bonds. A 1% change in the ERP changes the cost of equity by 1% × beta — and can swing a DCF valuation by 15–25%.

10.6.1 Two Approaches to Estimating ERP

ApproachMethodTypical Result
Historical (ex-post)Compute the average excess return of equities over risk-free bonds over a long period (30–100 years)US: ~4.5–6.5% (geometric mean). India: ~6–8% over G-Sec, but data quality and period matter enormously.
Implied (ex-ante / forward-looking)Back out the ERP from current market prices and expected cash flows using a DCF model applied to the entire market indexUS: ~4–5%. India: ~5–7%. This is Damodaran's preferred approach — it reflects current market conditions, not historical averages.

10.6.2 The India-Specific Challenge

Indian equities have a shorter history of reliable data than US equities. The Nifty 50 index started in 1996, giving us ~30 years of data — not the 100 years available for the S&P 500. Moreover, the Indian market has undergone structural transformation (liberalization in 1991, electronic trading, FII participation, SEBI reforms) that makes pre-2000 data of questionable relevance.

For Indian valuations, the standard practice is:

ERPIndia = ERPUS (Implied) + Country Risk PremiumIndia

Where the Country Risk Premium (CRP) for India is typically 1.5–3.0%, estimated from either the sovereign credit default swap (CDS) spread or the relative volatility of Indian vs US equity markets.

def estimate_erp_india(us_erp=0.05, country_risk_premium=0.0225):
    """
    Estimate the Equity Risk Premium for India.

    Parameters
    ----------
    us_erp : float — US implied ERP (Damodaran's estimate, typically 4.5–5.5%)
    country_risk_premium : float — India CRP (typically 1.5–3.0%)

    Returns
    -------
    dict with ERP components.
    """
    india_erp = us_erp + country_risk_premium

    print(f"ERP Estimation for India:")
    print(f"  US Implied ERP:      {us_erp*100:.1f}%")
    print(f"  + India CRP:         {country_risk_premium*100:.1f}%")
    print(f"  = India ERP:         {india_erp*100:.1f}%")
    print(f"\n  Source: US ERP from Damodaran (pages.stern.nyu.edu/~adamodar/)")
    print(f"         CRP based on India's sovereign rating (BBB-/Baa3)")

    return {
        'us_erp': us_erp,
        'crp': country_risk_premium,
        'india_erp': india_erp
    }

# --- Example ---
erp = estimate_erp_india(us_erp=0.05, country_risk_premium=0.0225)

# Compare against direct historical estimate
# Nifty 50 CAGR (1996–2026): ~11.5%
# Average 10Y G-Sec (same period): ~7.5%
# Historical ERP ≈ 11.5% − 7.5% = 4.0%
# But this is arithmetic mean, backward-looking, and covers a period of declining rates.
# The forward-looking (implied) ERP is generally preferred for DCF.
🌎
Real World — Damodaran's ERP Updates: Professor Aswath Damodaran publishes monthly updates of the US implied ERP and country risk premiums for 150+ countries at pages.stern.nyu.edu/~adamodar/. As of early 2026, the US implied ERP is approximately 4.5–5.5%, and India's CRP is 1.5–2.5% depending on the estimation method. Always check the latest data before finalizing your valuation — ERP estimates change with market conditions.

10.7 The Complete Cost of Equity Pipeline

Now we assemble all three components into a single function that estimates the cost of equity for any Indian company:

def estimate_cost_of_equity(ticker_symbol,
                             rf=None,
                             us_erp=0.05,
                             india_crp=0.0225,
                             use_blume=True,
                             market_index="^NSEI",
                             period="5y"):
    """
    Complete cost of equity estimation for an Indian company.

    Parameters
    ----------
    ticker_symbol : str — NSE ticker (e.g., 'RELIANCE.NS')
    rf : float — risk-free rate (if None, defaults to 6.75%)
    us_erp : float — US implied equity risk premium
    india_crp : float — India country risk premium
    use_blume : bool — apply Blume adjustment to raw beta
    market_index : str — market index for beta regression
    period : str — historical period for beta

    Returns
    -------
    dict with full cost of equity breakdown.
    """
    if rf is None:
        rf = 0.0675  # Default: normalized Indian 10Y G-Sec

    # 1. Calculate raw beta
    beta_result = calculate_beta(ticker_symbol, market_index, period, rf)
    raw_beta = beta_result['beta']

    # 2. Adjust beta (Blume)
    adjusted_beta = blume_adjusted_beta(raw_beta) if use_blume else raw_beta

    # 3. ERP
    india_erp = us_erp + india_crp

    # 4. Cost of Equity
    ke = rf + adjusted_beta * india_erp

    # 5. Display
    print(f"\n{'='*55}")
    print(f"  COST OF EQUITY: {ticker_symbol}")
    print(f"{'='*55}")
    print(f"  Risk-Free Rate (Rf):       {rf*100:.2f}%")
    print(f"  Raw Beta:                  {raw_beta:.2f}")
    print(f"  Adjusted Beta (Blume):     {adjusted_beta:.2f}")
    print(f"  India ERP (Rm − Rf):       {india_erp*100:.2f}%")
    print(f"    └ US Implied ERP:        {us_erp*100:.2f}%")
    print(f"    └ India CRP:             {india_crp*100:.2f}%")
    print(f"  ─────────────────────────")
    print(f"  COST OF EQUITY (Ke):       {ke*100:.2f}%")
    print(f"{'='*55}")

    # 6. Sensitivity: Ke at different ERP and beta assumptions
    print(f"\n  Sensitivity — Ke at varying ERP assumptions:")
    for erp_test in [0.06, 0.065, 0.07, 0.075, 0.08, 0.085]:
        ke_test = rf + adjusted_beta * erp_test
        print(f"    ERP = {erp_test*100:.1f}% → Ke = {ke_test*100:.2f}%")

    return {
        'ticker': ticker_symbol,
        'rf': rf,
        'raw_beta': raw_beta,
        'adjusted_beta': adjusted_beta,
        'us_erp': us_erp,
        'india_crp': india_crp,
        'india_erp': india_erp,
        'cost_of_equity': ke,
        'beta_details': beta_result
    }


# --- Estimate cost of equity for key Indian companies ---
companies = ['TCS.NS', 'RELIANCE.NS', 'ASIANPAINT.NS', 'TATASTEEL.NS']
ke_results = {}

for ticker in companies:
    ke_results[ticker] = estimate_cost_of_equity(ticker)
    print()  # spacing

# Comparison table
print("\n=== COST OF EQUITY COMPARISON ===")
for ticker, r in ke_results.items():
    print(f"  {ticker.replace('.NS',''):20s}: β = {r['adjusted_beta']:.2f}, "
          f"Ke = {r['cost_of_equity']*100:.2f}%")

10.8 Practical Issues and Common Mistakes

10.8.1 Which Risk-Free Rate?

The risk-free rate must match the currency and duration of your cash flows. If your FCFF is in Indian rupees, use the Indian G-Sec yield — not the US Treasury. If you use the US Treasury rate and your cash flows are in rupees, you are implicitly assuming zero currency risk, which is wrong.

10.8.2 Beta Estimation Period and Frequency

ChoiceRecommendationReason
Period3–5 yearsLong enough for statistical reliability; short enough to reflect current business mix
FrequencyMonthly returnsDaily data contains noise and microstructure biases; weekly or monthly is cleaner. Monthly is standard in practice.
Market IndexNifty 50 or BSE SensexBroad, liquid, representative. Use the Nifty 500 for a broader market proxy if available.
AdjustmentYes — Blume or VasicekRaw beta mean-reverts. Adjusted betas produce better future forecasts.

10.8.3 The CAPM Is Not Perfect — But It Is What We Have

The CAPM has well-known limitations: it assumes markets are efficient, investors are rational, and beta captures all relevant risk. Multi-factor models (Fama-French three-factor, Carhart four-factor) add size, value, and momentum factors that improve explanatory power. But for practical valuation, the CAPM remains the standard because:

📝
For Small/Mid-Cap Indian Companies: Consider adding a size premium of 1–4% to the CAPM-derived cost of equity. Duff & Phelps (now Kroll) publishes annual size premium studies. Small-cap Indian stocks have historically earned a premium of 2–6% over large-caps, though this varies by period and methodology. This is an advanced adjustment — for the core DCF in this course, the standard CAPM with India ERP is sufficient.

Hands-On Project: Cost of Equity Analysis for Your Capstone Company

Estimate the cost of equity for your capstone company using the complete pipeline. Calculate raw and adjusted beta, research the current risk-free rate and ERP, and produce a sensitivity table showing how Ke changes under different ERP and beta assumptions.

Steps

  1. Find the current 10-year G-Sec yield. Check RBI (rbi.org.in), FBIL (fbil.org.in), or a financial news source. Record the date and source.
  2. Calculate beta for your capstone company using the calculate_beta() function. Examine the R² — if it is below 0.15, the beta estimate is noisy and should be supplemented with a bottom-up industry beta.
  3. Check Damodaran's latest ERP data at pages.stern.nyu.edu/~adamodar/. Record the US implied ERP and India CRP. If the website is inaccessible, use 5.0% US ERP and 2.25% India CRP as reasonable defaults.
  4. Compute the cost of equity using estimate_cost_of_equity(). Document your assumptions.
  5. Calculate bottom-up beta for your company using 3–5 comparable firms. Compare it to the regression beta. If they differ significantly (more than 0.2), investigate why — has the company's business mix changed? Is the peer group appropriate?
  6. Build a sensitivity table: Ke for beta ranging from 0.6 to 1.8 and ERP ranging from 5% to 9%. Identify the range of plausible Ke values.
  7. Write a 200-word note: What is your best estimate of Ke, what is the range of plausible values, and what is the single biggest source of uncertainty in your estimate?
View Solution / Walkthrough

Illustrative Output: Asian Paints

# ================================================================
# COST OF EQUITY ANALYSIS — Asian Paints
# ================================================================

# Step 1: Current G-Sec Yield (as of analysis date)
rf = 0.0685  # 6.85% — 10Y Indian G-Sec, source: RBI/FBIL

# Step 2: Calculate Beta
beta_result = calculate_beta("ASIANPAINT.NS", period="5y")
raw_beta = beta_result['beta']  # Typically 0.55–0.70 for Asian Paints
print(f"Raw Beta: {raw_beta:.2f} (R² = {beta_result['r_squared']:.2f})")

# Step 3: Bottom-up beta check
paint_peers_betas = [0.65, 0.72, 0.58, 0.70]
paint_peers_de = [0.15, 0.22, 0.08, 0.30]
bottom_up = bottom_up_beta(paint_peers_betas, paint_peers_de,
                           target_de=0.12)  # Asian Paints' actual D/E
print(f"Bottom-up Beta: {bottom_up['target_levered_beta']:.2f}")

# Step 4: ERP
us_erp = 0.05
india_crp = 0.0225
india_erp = us_erp + india_crp

# Step 5: Compute Ke
adjusted_beta = blume_adjusted_beta(raw_beta)
ke = rf + adjusted_beta * india_erp
print(f"\nCost of Equity: {ke*100:.2f}%")

# Step 6: Sensitivity Table
print("\n=== Ke SENSITIVITY TABLE ===")
betas = [0.6, 0.7, 0.8, 0.9, 1.0]
erps = [0.06, 0.065, 0.07, 0.075, 0.08]
print(f"{'Beta \\ ERP':<10}", end="")
for erp in erps:
    print(f"{erp*100:.1f}%".rjust(8), end="")
print()

for b in betas:
    print(f"{b:<10}", end="")
    for erp in erps:
        ke_val = rf + b * erp
        print(f"{ke_val*100:.2f}%".rjust(8), end="")
    print()

# Step 7: Visualization
fig, ax = plt.subplots(figsize=(10, 6))
for erp in erps:
    ke_values = [rf + b * erp for b in np.linspace(0.4, 1.6, 100)]
    ax.plot(np.linspace(0.4, 1.6, 100), [k*100 for k in ke_values],
            linewidth=1.5, label=f'ERP = {erp*100:.1f}%')
ax.scatter([adjusted_beta], [ke*100], s=200, color='#e0556a', zorder=10,
           edgecolors='white', linewidth=2)
ax.annotate(f'Best Estimate\nβ={adjusted_beta:.2f}, Ke={ke*100:.1f}%',
           (adjusted_beta, ke*100),
           textcoords="offset points", xytext=(15, -15), fontsize=10,
           fontweight='bold', color='#e0556a')
ax.set_xlabel('Beta')
ax.set_ylabel('Cost of Equity (%)')
ax.set_title('Cost of Equity Sensitivity: Beta vs ERP', fontweight='bold')
ax.legend()
ax.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()

Sample Note (200 words): My best estimate for Asian Paints' cost of equity is 11.50%, based on the CAPM with a normalized risk-free rate of 6.85% (current 10Y G-Sec), a Blume-adjusted beta of 0.63 (derived from 5-year monthly returns vs Nifty 50, R² = 0.21), and an India ERP of 7.25% (US implied ERP of 5.0% + India CRP of 2.25%). The low beta reflects Asian Paints' defensive characteristics — stable demand, strong brand, and low financial leverage. The plausible range for Ke is 10.5–13.0%, driven primarily by uncertainty in the ERP. A ±1% change in the ERP (±100bp) moves Ke by ~63bp given the low beta. The single largest source of uncertainty is the India country risk premium, which is difficult to estimate precisely and varies with global risk appetite. The regression beta's modest R² introduces additional uncertainty — the bottom-up industry beta (0.58) is slightly lower than the regression beta, suggesting the regression may be capturing some idiosyncratic volatility rather than pure systematic risk. For the DCF valuation, I will use 11.5% as the base case and test sensitivity at 10.5% and 12.5%.

Key Takeaways

1

The CAPM remains the standard despite its limitations: Ke = Rf + β × ERP. Each of the three inputs requires careful estimation; none can be taken off-the-shelf.

2

Beta is estimated via regression, then adjusted. Use monthly returns over 3–5 years. Apply the Blume adjustment to correct for mean-reversion. For unlisted companies, use the bottom-up (industry) method.

3

The India ERP = US ERP + Country Risk Premium. The US implied ERP (~5%) is the global benchmark. Add 1.5–3% for India's sovereign risk. Total India ERP is typically 6.5–8%.

4

Use the Indian G-Sec yield for Rf when valuing Indian rupee cash flows. Never use the US Treasury rate for rupee-denominated DCF — you would ignore currency and sovereign risk.

5

The cost of equity is an estimate, not a fact. Always present it with a sensitivity range. In Chapter 11, we combine Ke with the cost of debt to compute WACC — the discount rate for your DCF.

Test Your Understanding

1. A stock has a raw beta of 1.35 calculated from 5 years of monthly returns. Using the Blume adjustment, what is the adjusted beta?

2. Why is the bottom-up (industry) beta approach preferred for unlisted companies?

3. Why must the Indian ERP include a Country Risk Premium above the US ERP?

4. You compute a stock's beta with daily returns and get 0.95, then recompute with monthly returns and get 0.78. Which should you use for cost of equity estimation and why?

5. A company has a levered beta of 1.40 with a D/E ratio of 0.80 and a tax rate of 25%. What is its unlevered beta?