WACC Calculation & Automation
Combine the cost of equity and cost of debt into the Weighted Average Cost of Capital — the discount rate that drives every DCF valuation — with fully automated Python computation.
Learning Objectives
- Understand the WACC formula and its role as the discount rate in DCF valuation
- Estimate the cost of debt using the yield-to-maturity approach and credit rating-based spreads
- Determine target capital structure weights — when to use market value vs book value
- Build a complete automated WACC pipeline in Python that integrates with Chapter 10's cost of equity
- Analyze WACC sensitivity to capital structure, tax rates, and market conditions
11.1 What Is WACC and Why Does It Matter?
The Weighted Average Cost of Capital (WACC) is the blended rate of return a company must earn on its invested capital to satisfy both its debt holders and its equity holders. It is the discount rate used in a DCF valuation to bring future free cash flows to the firm (FCFF) back to present value.
Where:
| Symbol | Name | Source (this course) |
|---|---|---|
| E / V | Equity weight | Market value of equity / (Market equity + Market debt) |
| Ke | Cost of equity | Chapter 10 — CAPM: Rf + β × ERP |
| D / V | Debt weight | Market value of debt / (Market equity + Market debt) |
| Kd | Pre-tax cost of debt | Yield-to-maturity on existing debt or credit spread + risk-free rate |
| (1 − T) | Tax shield | Interest is tax-deductible, reducing the effective cost of debt |
Two critical insights about WACC:
WACC Is the Firm's Hurdle Rate
Every investment the company makes must earn at least the WACC. Projects earning above WACC create value; projects earning below WACC destroy it. This is the same ROIC > WACC logic from Chapter 5, viewed from the cost-of-capital side.
WACC Matches FCFF
WACC is the discount rate for FCFF — cash flows available to ALL capital providers. The equity-only analog is the cost of equity (Ke), which discounts FCFE (cash flows to equity). Never discount FCFF with Ke or FCFE with WACC — that is a fundamental mismatch.
11.2 Estimating the Cost of Debt (Kd)
The cost of debt is the rate at which the company can borrow today, not the historical coupon rate on its existing debt. There are two standard approaches:
11.2.1 Approach 1: Yield-to-Maturity (YTM) on Traded Bonds
If the company has publicly traded bonds, the YTM is the best estimate of its current borrowing cost. For Indian companies with listed NCDs (Non-Convertible Debentures), the YTM can be observed from market prices.
11.2.2 Approach 2: Risk-Free Rate + Credit Spread
For most Indian companies — which rely on bank loans rather than public bonds — the cost of debt is estimated as:
The default spread depends on the company's credit rating. Indian companies are rated by CRISIL, ICRA, CARE, and India Ratings. Here are indicative spreads over the 10-year G-Sec:
| Credit Rating | Typical Spread (bp) | Kd (with Rf=6.75%) | Example Indian Companies |
|---|---|---|---|
| AAA | 50–80 bps | 7.25–7.55% | TCS, Infosys, HDFC Bank, Reliance (AAA-rated) |
| AA | 80–150 bps | 7.55–8.25% | Asian Paints, Titan, L&T, Maruti Suzuki |
| A | 150–250 bps | 8.25–9.25% | Mid-cap companies with moderate leverage |
| BBB | 250–400 bps | 9.25–10.75% | Higher-leverage mid-caps, cyclical companies |
| BB and below | 400–800+ bps | 10.75%+ | Distressed companies, highly leveraged firms |
| Unrated | 300–500 bps (estimated) | 9.75–11.75% | Many SMEs, startups |
11.2.3 Cost of Debt in Python
import pandas as pd
import numpy as np
def estimate_cost_of_debt(rf, ebit=None, interest_expense=None,
credit_rating=None, default_spread=None):
"""
Estimate the pre-tax cost of debt.
Three methods (in order of preference):
1. Direct credit rating + known spread
2. Synthetic rating from interest coverage ratio (ICR)
3. Explicit default spread provided by user
Parameters
----------
rf : float — risk-free rate (decimal)
ebit : float — EBIT (for synthetic rating)
interest_expense : float — interest expense (for synthetic rating)
credit_rating : str — known credit rating (AAA, AA, A, BBB, BB, B, etc.)
default_spread : float — explicit spread over Rf
Returns
-------
dict with cost of debt and methodology.
"""
# Mapping: Interest Coverage Ratio → Rating → Default Spread
icr_rating_map = [
(8.5, 'AAA', 0.0065),
(6.5, 'AA', 0.0100),
(4.5, 'A', 0.0180),
(3.0, 'BBB', 0.0300),
(2.0, 'BB', 0.0450),
(1.5, 'B', 0.0600),
(1.0, 'CCC', 0.0800),
(0.0, 'D', 0.1200),
]
if credit_rating:
# Find spread for given rating
for min_icr, rating, spread in icr_rating_map:
if rating == credit_rating:
default_spread = spread
break
method = f"Credit Rating ({credit_rating})"
elif default_spread is not None:
method = "User-provided spread"
elif ebit is not None and interest_expense is not None and interest_expense > 0:
icr = ebit / interest_expense
for min_icr, rating, spread in icr_rating_map:
if icr >= min_icr:
credit_rating = rating
default_spread = spread
break
method = f"Synthetic Rating (ICR = {icr:.1f} → {credit_rating})"
else:
# Fallback: assume BBB (typical Indian corporate)
default_spread = 0.03
credit_rating = 'BBB (assumed)'
method = "Default — BBB assumed (no data provided)"
kd_pre_tax = rf + default_spread
print(f"Cost of Debt Estimation:")
print(f" Method: {method}")
print(f" Risk-Free Rate: {rf*100:.2f}%")
print(f" Default Spread: {default_spread*100:.2f}%")
print(f" Kd (Pre-Tax): {kd_pre_tax*100:.2f}%")
return {
'kd_pre_tax': kd_pre_tax,
'default_spread': default_spread,
'credit_rating': credit_rating,
'method': method
}
# --- Examples ---
# AAA-rated company (TCS)
kd_tcs = estimate_cost_of_debt(rf=0.0675, credit_rating='AAA')
print()
# Synthetic rating (ICR-based)
kd_synthetic = estimate_cost_of_debt(rf=0.0675, ebit=5200, interest_expense=350)
print()
# Unrated — use default
kd_default = estimate_cost_of_debt(rf=0.0675)
11.3 Capital Structure Weights: Market Value vs Book Value
The WACC formula requires the proportion of debt and equity in the company's capital structure. There is an important choice here: book value weights or market value weights?
11.3.1 Why Market Value Weights Are Correct
WACC represents the opportunity cost of capital today, not the historical cost at which capital was raised. The market value of equity reflects current expectations about future cash flows. The book value of equity reflects historical accounting entries. For a company like Titan, with a P/B of 76x, book value weights would massively understate the equity proportion and produce a WACC that is far too low.
D = Market Value of Debt ≈ Book Value of Debt (for most Indian companies)
V = E + D
For debt, the market value is often close to the book value for Indian companies because most debt is bank loans (not traded bonds), and interest rates on floating-rate loans reset periodically. For companies with significant listed bonds, the market value should be used. In practice, book value of debt is an acceptable proxy for most Indian companies.
11.3.2 Target vs Current Capital Structure
Should you use the company's current capital structure or its target (long-run optimal) structure? For a mature company, the current structure is usually close to the target. Exceptions:
- Post-IPO: The company raised equity; D/E is temporarily low. Use target weights or industry-average weights.
- Post-acquisition: Debt was raised to fund the deal. Use the post-deal, steady-state capital structure.
- Turnaround: D/E is abnormally high due to losses eroding equity. Use target normalized weights.
def capital_structure_weights(market_cap, total_debt, cash=0,
use_net_debt=True, target_de_ratio=None):
"""
Calculate market-value-based capital structure weights.
Parameters
----------
market_cap : float — market capitalization (Rs. Cr)
total_debt : float — total debt on balance sheet
cash : float — cash and equivalents
use_net_debt : bool — if True, use Net Debt = Debt − Cash
target_de_ratio : float — if provided, override with target D/E
Returns
-------
dict with weights and net debt.
"""
if target_de_ratio is not None:
# Derive weights from target D/E
E_weight = 1 / (1 + target_de_ratio)
D_weight = target_de_ratio / (1 + target_de_ratio)
net_debt = total_debt - cash
print(f"Using TARGET capital structure: D/E = {target_de_ratio:.2f}")
else:
net_debt = (total_debt - cash) if use_net_debt else total_debt
enterprise_value = market_cap + net_debt
E_weight = market_cap / enterprise_value
D_weight = net_debt / enterprise_value
print(f"Using CURRENT market-value weights")
print(f" Market Cap: Rs. {market_cap:,.0f} Cr")
print(f" Net Debt: Rs. {net_debt:,.0f} Cr")
print(f" Enterprise Val: Rs. {market_cap + net_debt:,.0f} Cr")
print(f" Equity Weight: {E_weight*100:.1f}%")
print(f" Debt Weight: {D_weight*100:.1f}%")
return {
'equity_weight': E_weight,
'debt_weight': D_weight,
'net_debt': net_debt,
'enterprise_value': market_cap + net_debt,
'de_to_equity': net_debt / market_cap if market_cap > 0 else 0
}
# --- Example: Asian Paints ---
# Market Cap ~ Rs. 3,00,000 Cr, Debt ~ Rs. 4,800 Cr, Cash ~ Rs. 2,100 Cr
weights = capital_structure_weights(
market_cap=300000, total_debt=4800, cash=2100, use_net_debt=True
)
print(f"\n D/E Ratio: {weights['de_to_equity']:.3f}")
11.4 The Effective Tax Rate and the Debt Tax Shield
Interest on debt is tax-deductible, which creates a tax shield that reduces the effective cost of debt. This is why the WACC formula multiplies Kd by (1 − T). The tax shield is one of the two reasons debt is cheaper than equity (the other being seniority in the capital structure).
11.4.1 Which Tax Rate to Use?
| Rate Type | When to Use | Current India Value |
|---|---|---|
| Statutory tax rate | For companies that are consistently profitable and pay full taxes | 25.17% (25% base + surcharge + cess, new regime); 34.94% (old regime) |
| Effective tax rate | When the company's actual tax payments differ materially from the statutory rate (tax holidays, loss carry-forwards, MAT credits) | Varies — compute as Total Tax Expense / PBT from the income statement |
| Marginal tax rate | Theoretically correct — the rate at which the next rupee of interest deduction would be taxed. In practice, the statutory rate is used as a proxy. | ~25% for most Indian companies under the new regime |
For Indian valuations, 25% (new regime) is the standard choice for companies that have opted for the concessional tax regime under Section 115BAA of the Income Tax Act. Most large Indian companies have adopted this. Verify from the annual report's tax reconciliation note.
11.5 The Complete Automated WACC Pipeline
Now we combine everything — cost of equity (Chapter 10), cost of debt, capital structure weights, and tax rate — into a single automated WACC function:
def compute_wacc(ticker_symbol,
rf=None,
us_erp=0.05,
india_crp=0.0225,
tax_rate=0.25,
target_de=None,
use_blume=True,
credit_rating=None):
"""
Complete automated WACC computation for an Indian company.
Integrates:
- Cost of Equity (CAPM with India ERP) from Chapter 10
- Cost of Debt (credit rating or synthetic)
- Market-value capital structure weights
- Tax shield adjustment
Parameters
----------
ticker_symbol : str — NSE ticker
rf : float — risk-free rate (default: 6.75%)
us_erp : float — US implied ERP
india_crp : float — India country risk premium
tax_rate : float — effective/marginal tax rate
target_de : float — target D/E ratio (if None, uses current market weights)
use_blume : bool — apply Blume adjustment to beta
credit_rating : str — company's credit rating (if known)
Returns
-------
dict with complete WACC breakdown.
"""
import yfinance as yf
from scipy import stats
if rf is None:
rf = 0.0675
# --- 1. Fetch Company Data ---
ticker = yf.Ticker(ticker_symbol)
info = ticker.info
is_df = ticker.financials
bs_df = ticker.balance_sheet
def safe_get(df, candidates):
for c in ([candidates] if isinstance(candidates, str) else candidates):
if c in df.index:
return df.loc[c]
return None
# Market cap
mkt_cap = info.get('marketCap', None)
if mkt_cap is None:
# Estimate from share price × shares outstanding
price = info.get('currentPrice') or info.get('previousClose')
shares = info.get('sharesOutstanding')
if price and shares:
mkt_cap = price * shares
else:
raise ValueError(f"Cannot determine market cap for {ticker_symbol}")
mkt_cap_cr = mkt_cap / 1e7
# Balance sheet items
total_debt = 0
for key in ['Total Debt', 'Long Term Debt', 'Short Long Term Debt']:
val = safe_get(bs_df, key)
if val is not None:
total_debt = val.iloc[0] / 1e7
break
cash = safe_get(bs_df, ['Cash And Cash Equivalents',
'Cash Cash Equivalents And Short Term Investments'])
cash = cash.iloc[0] / 1e7 if cash is not None else 0
# For synthetic rating
ebit = safe_get(is_df, ['Operating Income', 'EBIT'])
ebit_val = ebit.iloc[0] / 1e7 if ebit is not None else None
interest = safe_get(is_df, ['Interest Expense', 'Interest Expense Non Operating'])
interest_val = interest.iloc[0] / 1e7 if interest is not None else None
# --- 2. Cost of Equity (from Chapter 10) ---
# Fetch price data for beta calculation
stock_prices = yf.download(ticker_symbol, period='5y', progress=False)['Adj Close']
market_prices = yf.download('^NSEI', period='5y', progress=False)['Adj Close']
stock_ret = stock_prices.resample('ME').last().pct_change().dropna()
market_ret = market_prices.resample('ME').last().pct_change().dropna()
common = stock_ret.index.intersection(market_ret.index)
rf_monthly = (1 + rf) ** (1/12) - 1
stock_excess = stock_ret[common] - rf_monthly
market_excess = market_ret[common] - rf_monthly
raw_beta, _, _, _, _ = stats.linregress(market_excess, stock_excess)
adjusted_beta = (2/3) * raw_beta + (1/3) * 1.0 if use_blume else raw_beta
india_erp = us_erp + india_crp
ke = rf + adjusted_beta * india_erp
# --- 3. Cost of Debt ---
kd_result = estimate_cost_of_debt(
rf=rf, ebit=ebit_val, interest_expense=interest_val,
credit_rating=credit_rating
)
kd_pre_tax = kd_result['kd_pre_tax']
kd_after_tax = kd_pre_tax * (1 - tax_rate)
# --- 4. Capital Structure Weights ---
if target_de is not None:
weights = capital_structure_weights(
mkt_cap_cr, total_debt, cash,
target_de_ratio=target_de
)
else:
weights = capital_structure_weights(
mkt_cap_cr, total_debt, cash
)
# --- 5. WACC Computation ---
wacc = weights['equity_weight'] * ke + weights['debt_weight'] * kd_after_tax
# --- 6. Display Results ---
print(f"\n{'='*60}")
print(f" WACC ANALYSIS: {info.get('longName', ticker_symbol)}")
print(f"{'='*60}")
print(f"\n COST OF EQUITY:")
print(f" Risk-Free Rate: {rf*100:.2f}%")
print(f" Raw Beta: {raw_beta:.2f}")
print(f" Adjusted Beta: {adjusted_beta:.2f}")
print(f" India ERP: {india_erp*100:.2f}%")
print(f" Cost of Equity (Ke): {ke*100:.2f}%")
print(f"\n COST OF DEBT:")
print(f" Rating: {kd_result['credit_rating']}")
print(f" Pre-Tax Kd: {kd_pre_tax*100:.2f}%")
print(f" Tax Rate: {tax_rate*100:.0f}%")
print(f" After-Tax Kd: {kd_after_tax*100:.2f}%")
print(f"\n CAPITAL STRUCTURE:")
print(f" Market Cap: Rs. {mkt_cap_cr:,.0f} Cr")
print(f" Net Debt: Rs. {weights['net_debt']:,.0f} Cr")
print(f" Equity Weight: {weights['equity_weight']*100:.1f}%")
print(f" Debt Weight: {weights['debt_weight']*100:.1f}%")
print(f" D/E Ratio: {weights['de_to_equity']:.2f}")
print(f"\n ═══════════════════════════════════════")
print(f" WACC: {wacc*100:.2f}%")
print(f" ═══════════════════════════════════════")
# --- 7. WACC Sensitivity ---
print(f"\n WACC Sensitivity (changing D/E ratio):")
for de_test in [0.0, 0.1, 0.2, 0.5, 1.0, 1.5, 2.0]:
e_w = 1 / (1 + de_test)
d_w = de_test / (1 + de_test)
# Relever beta for the new D/E
unlevered_b = raw_beta / (1 + (1 - tax_rate) * weights['de_to_equity'])
relevered_b = unlevered_b * (1 + (1 - tax_rate) * de_test)
relevered_b_adj = (2/3) * relevered_b + (1/3) if use_blume else relevered_b
ke_test = rf + relevered_b_adj * india_erp
wacc_test = e_w * ke_test + d_w * kd_pre_tax * (1 - tax_rate)
marker = ' ← current' if abs(de_test - weights['de_to_equity']) < 0.02 else ''
print(f" D/E = {de_test:.1f}: Ke = {ke_test*100:.2f}%, WACC = {wacc_test*100:.2f}%{marker}")
return {
'ticker': ticker_symbol,
'company': info.get('longName', ticker_symbol),
'rf': rf,
'raw_beta': raw_beta,
'adjusted_beta': adjusted_beta,
'india_erp': india_erp,
'ke': ke,
'kd_pre_tax': kd_pre_tax,
'kd_after_tax': kd_after_tax,
'tax_rate': tax_rate,
'equity_weight': weights['equity_weight'],
'debt_weight': weights['debt_weight'],
'de_to_equity': weights['de_to_equity'],
'wacc': wacc,
'credit_rating': kd_result['credit_rating'],
}
# --- Run WACC for multiple companies ---
# Note: requires internet connection for yfinance data
# Example 1: Low-leverage consumer company
wacc_ap = compute_wacc("ASIANPAINT.NS", credit_rating='AA')
print("\n" + "="*60)
# Example 2: Moderate leverage
wacc_reliance = compute_wacc("RELIANCE.NS", credit_rating='AAA')
print("\n" + "="*60)
# Example 3: High-growth IT (virtually debt-free)
wacc_tcs = compute_wacc("TCS.NS", credit_rating='AAA')
11.6 WACC Sensitivity: What Really Drives the Discount Rate?
WACC is a function of 6 inputs. A sensitivity analysis reveals which ones deserve the most attention:
def wacc_sensitivity_analysis(base_wacc_result, rf_range=None,
erp_range=None, de_range=None, tax_range=None):
"""
One-way sensitivity of WACC to each input parameter.
Returns a tornado-style DataFrame ranking inputs by their impact.
"""
base = base_wacc_result
if rf_range is None:
rf_range = np.linspace(0.06, 0.08, 5)
if erp_range is None:
erp_range = np.linspace(0.06, 0.085, 5)
if de_range is None:
de_range = np.linspace(0.0, 1.0, 5)
if tax_range is None:
tax_range = np.linspace(0.20, 0.30, 5)
def wacc_for_params(rf, erp, de, tax):
unlevered_b = base['raw_beta'] / (1 + (1 - base['tax_rate']) * base['de_to_equity'])
relevered_b = unlevered_b * (1 + (1 - tax) * de)
adj_b = (2/3) * relevered_b + (1/3)
ke = rf + adj_b * erp
e_w = 1 / (1 + de)
d_w = de / (1 + de)
return e_w * ke + d_w * base['kd_pre_tax'] * (1 - tax)
base_wacc = wacc_for_params(base['rf'], base['india_erp'],
base['de_to_equity'], base['tax_rate'])
sensitivities = {}
# Rf sensitivity
wacc_rf = [wacc_for_params(r, base['india_erp'], base['de_to_equity'], base['tax_rate'])
for r in rf_range]
sensitivities['Risk-Free Rate'] = (min(wacc_rf), max(wacc_rf))
# ERP sensitivity
wacc_erp = [wacc_for_params(base['rf'], e, base['de_to_equity'], base['tax_rate'])
for e in erp_range]
sensitivities['Equity Risk Premium'] = (min(wacc_erp), max(wacc_erp))
# D/E sensitivity
wacc_de = [wacc_for_params(base['rf'], base['india_erp'], d, base['tax_rate'])
for d in de_range]
sensitivities['D/E Ratio'] = (min(wacc_de), max(wacc_de))
# Tax rate sensitivity
wacc_tax = [wacc_for_params(base['rf'], base['india_erp'], base['de_to_equity'], t)
for t in tax_range]
sensitivities['Tax Rate'] = (min(wacc_tax), max(wacc_tax))
# Build tornado table
tornado = []
for param, (low, high) in sensitivities.items():
impact_low = low - base_wacc
impact_high = high - base_wacc
tornado.append({
'Parameter': param,
'Low WACC': f'{low*100:.2f}%',
'High WACC': f'{high*100:.2f}%',
'Downside Impact': f'{impact_low*100:+.2f}%',
'Upside Impact': f'{impact_high*100:+.2f}%',
'Range (bps)': abs(impact_high - impact_low) * 10000
})
tornado_df = pd.DataFrame(tornado).sort_values('Range (bps)', ascending=True)
print(f"Base WACC: {base_wacc*100:.2f}%")
print(f"\n=== WACC SENSITIVITY TORNADO ===")
print(tornado_df.to_string(index=False))
return tornado_df
# --- Run sensitivity ---
sensitivity = wacc_sensitivity_analysis(wacc_ap)
11.7 WACC for Unlisted Companies and Divisions
The WACC pipeline above assumes a listed company with observable market data. For unlisted companies, private companies, or individual business divisions, you need modifications:
| Challenge | Solution |
|---|---|
| No market cap | Use target D/E ratio (industry average or management guidance). Estimate equity value iteratively from the DCF itself — this creates a circular loop that converges with iteration. |
| No observable beta | Use bottom-up industry beta (Chapter 10, Section 10.5). Identify comparable listed companies, unlever their betas, take the median, relever to the target D/E. |
| No credit rating | Use synthetic rating from ICR, or estimate the cost of debt as Rf + industry-typical spread. |
| Divisional WACC | Different divisions have different risk profiles. Estimate a separate WACC for each division using industry-specific betas and capital structures. The conglomerate's overall WACC is the weighted average of divisional WACCs. |
| Startups | Startups have no debt (equity-only), no earnings (beta regression unreliable), and extreme growth. Use bottom-up beta from the industry. WACC ≈ Ke. As the startup matures, WACC should converge toward industry norms. |
def wacc_unlisted_company(industry_beta, target_de, rf=0.0675,
india_erp=0.0725, tax_rate=0.25,
credit_spread=0.025):
"""
WACC for an unlisted company or business division.
Uses bottom-up beta and target capital structure.
"""
# Relever industry beta to target D/E
unlevered_beta = industry_beta / (1 + (1 - tax_rate) * 0.15) # Assume avg peer D/E
relevered_beta = unlevered_beta * (1 + (1 - tax_rate) * target_de)
adjusted_beta = (2/3) * relevered_beta + (1/3)
ke = rf + adjusted_beta * india_erp
kd = rf + credit_spread
kd_after = kd * (1 - tax_rate)
e_weight = 1 / (1 + target_de)
d_weight = target_de / (1 + target_de)
wacc = e_weight * ke + d_weight * kd_after
print(f"Unlisted Company / Division WACC:")
print(f" Industry Beta (unlevered): {unlevered_beta:.2f}")
print(f" Relevered Beta (D/E={target_de}): {adjusted_beta:.2f}")
print(f" Ke: {ke*100:.2f}% | Kd: {kd_after*100:.2f}%")
print(f" WACC: {wacc*100:.2f}%")
return wacc
# Example: Unlisted paint manufacturing division
wacc_unlisted = wacc_unlisted_company(
industry_beta=0.65, # Median beta of Asian Paints, Berger, Indigo Paints
target_de=0.40, # Higher leverage than listed peers
credit_spread=0.025 # ~A rating equivalent
)
11.8 Indian WACC Benchmarks and Market Data
The following table provides indicative WACC ranges for key Indian sectors. These are benchmarks — your company-specific WACC should be computed using the pipeline above, not taken from this table.
| Sector | Typical D/E | Typical Beta | Indicative Ke | Indicative WACC |
|---|---|---|---|---|
| IT Services | 0.0–0.1 | 0.7–0.9 | 10.5–12.5% | 10.0–12.0% |
| Consumer Staples | 0.0–0.3 | 0.5–0.7 | 9.5–11.5% | 9.0–11.0% |
| Consumer Discretionary | 0.1–0.5 | 0.6–0.9 | 10.0–12.5% | 9.5–12.0% |
| Private Banks | N/A (use Ke only for FCFE) | 0.8–1.1 | 11.0–13.5% | 11.0–13.5% |
| Pharma | 0.1–0.6 | 0.5–0.8 | 10.0–12.0% | 9.5–11.5% |
| Automotive | 0.3–1.0 | 0.8–1.3 | 11.5–14.5% | 10.0–13.0% |
| Cement | 0.3–0.8 | 0.8–1.2 | 11.5–14.0% | 10.5–12.5% |
| Telecom | 1.0–3.0 | 0.9–1.4 | 12.5–16.0% | 9.0–11.5% |
| Infrastructure | 1.5–4.0 | 1.0–1.5 | 13.0–16.5% | 9.5–12.0% |
| Metals & Mining | 0.5–2.0 | 1.1–1.6 | 13.0–17.0% | 11.0–14.0% |
Hands-On Project: WACC Estimation for Your Capstone Company
Compute the complete WACC for your capstone company using the automated pipeline. Perform sensitivity analysis, benchmark against industry peers, and produce a defensible WACC estimate with a documented range. This WACC will be the discount rate in your DCF valuation in Chapter 14.
Steps
- Run the complete WACC pipeline using
compute_wacc()for your capstone company. Document every input and its source. - Verify the cost of debt: Check if the company has a published credit rating (CRISIL, ICRA, CARE). If not, compute the synthetic rating from its interest coverage ratio. Compare the two if both are available.
- Question the capital structure: Is the current D/E representative of the long-term target? If the company just completed a major acquisition, IPO, or buyback, consider using normalized weights.
- Run the WACC sensitivity analysis from Section 11.6. Identify which parameter drives the most WACC uncertainty.
- Benchmark against peers: Compute WACC for 3–5 comparable companies. Is your company's WACC an outlier? If so, why? (Different leverage? Different beta? Different credit rating?)
- Build the final WACC table with: Best estimate, Low estimate, High estimate, and the key assumptions behind each.
View Solution / Walkthrough
Complete WACC Analysis — Asian Paints (Illustrative)
# ================================================================
# CAPSTONE WACC ANALYSIS
# ================================================================
# --- 1. Run complete pipeline ---
wacc_result = compute_wacc(
"ASIANPAINT.NS",
rf=0.0675,
us_erp=0.05,
india_crp=0.0225,
tax_rate=0.25,
credit_rating='AA'
)
# --- 2. Verify cost of debt ---
print("\n--- COST OF DEBT VERIFICATION ---")
# Asian Paints is rated AA by CRISIL
# AA spread over G-Sec: ~100 bps
# Kd = 6.75% + 1.00% = 7.75%
# After-tax = 7.75% × (1 − 0.25) = 5.81%
# This matches the pipeline output
# --- 3. Capital structure check ---
print("\n--- CAPITAL STRUCTURE ANALYSIS ---")
# Asian Paints D/E ~ 0.01 (virtually debt-free)
# Question: is this the long-term target?
# Answer: Yes — consumer companies with strong cash flows rarely need debt
# The current structure IS the target structure
# --- 4. Sensitivity analysis ---
sensitivity = wacc_sensitivity_analysis(wacc_result)
# --- 5. Peer benchmarking ---
peers = ['BERGEPAINT.NS', 'INDIGOPNTS.NS', 'AKZOINDIA.NS']
peer_waccs = {}
for peer in peers:
try:
peer_waccs[peer] = compute_wacc(peer, credit_rating='AA')
except Exception as e:
print(f" {peer}: Error — {e}")
if peer_waccs:
print("\n--- PEER WACC COMPARISON ---")
for ticker, r in peer_waccs.items():
print(f" {ticker.replace('.NS',''):20s}: Ke={r['ke']*100:.2f}% "
f"WACC={r['wacc']*100:.2f}% D/E={r['de_to_equity']:.2f}")
# --- 6. Final WACC recommendation ---
print("\n" + "="*60)
print(" FINAL WACC RECOMMENDATION")
print("="*60)
base_wacc = wacc_result['wacc']
print(f"""
BEST ESTIMATE: {base_wacc*100:.2f}%
LOW ESTIMATE: {(base_wacc - 0.01)*100:.2f}%
HIGH ESTIMATE: {(base_wacc + 0.01)*100:.2f}%
KEY ASSUMPTIONS:
• Rf = 6.75% (normalized 10Y G-Sec)
• Beta = {wacc_result['adjusted_beta']:.2f} (Blume-adjusted, 5Y monthly vs Nifty)
• India ERP = {wacc_result['india_erp']*100:.2f}% (US 5.0% + CRP 2.25%)
• Kd = {wacc_result['kd_pre_tax']*100:.2f}% pre-tax ({wacc_result['credit_rating']} rating)
• D/E = {wacc_result['de_to_equity']:.2f} (market-value weights)
• Tax Rate = 25%
PRIMARY UNCERTAINTY: India ERP (±1% = ±{wacc_result['adjusted_beta']*100:.0f}bp on WACC)
SECONDARY: Beta estimation (R² of monthly regression)
""")
Key Takeaways
WACC = E/V × Ke + D/V × Kd × (1−T). It blends the cost of equity and after-tax cost of debt, weighted by market values. It is the discount rate for FCFF in a DCF valuation.
Use market value weights, not book value. Book value understates equity for high-P/B companies, producing a WACC that is too low. For Indian companies, book value of debt is an acceptable proxy.
The after-tax cost of debt = (Rf + Credit Spread) × (1 − T). If the company has no credit rating, use the synthetic rating from its interest coverage ratio (EBIT / Interest).
The tax shield (1−T) makes debt cheaper than equity. At a 25% tax rate, every rupee of interest costs only 75 paise after tax. But this benefit only exists if the company is profitable.
WACC is the bridge between forecasting (Ch 7–9) and DCF valuation (Ch 12–14). The FCFF from your integrated model, discounted at this WACC, produces the enterprise value of your capstone company.
Test Your Understanding
1. A company has a market cap of Rs. 10,000 Cr, debt of Rs. 2,000 Cr, cash of Rs. 500 Cr, Ke of 12%, pre-tax Kd of 8%, and a tax rate of 25%. What is its WACC?
2. Why is the market value of equity (not book value) used in WACC weights?
3. A company has EBIT of Rs. 500 Cr and interest expense of Rs. 40 Cr. Using the synthetic rating approach, what is its approximate credit rating?
4. Why does a reduction in the corporate tax rate (as India did in 2019) increase WACC for a highly leveraged company?
5. For an unlisted company, which approach correctly estimates WACC?