DCF Fundamentals
The Core Principle¶
The Discounted Cash Flow (DCF) model values a firm (or project) as the present value of its expected future free cash flows:
where is the Free Cash Flow to the Firm in period , is the Weighted Average Cost of Capital, and is the terminal value — the value of all cash flows beyond the explicit forecast horizon.
Free Cash Flow to the Firm¶
| Component | Description |
|---|---|
| NOPAT — operating profit after tax | |
| Non-cash charge added back | |
| Investment in net working capital | |
| Capital expenditures (growth and maintenance) |
The Weighted Average Cost of Capital¶
where and are the target (not current) capital structure weights at market value, is the cost of equity, the pre-tax cost of debt, and the marginal tax rate.
Cost of Equity — CAPM¶
The equity beta measures the firm’s sensitivity to market risk. It should be estimated from comparable firms, unlevered, and re-levered to the target capital structure (Hamada equation):
Terminal Value¶
The terminal value typically represents 60–80% of the total DCF value — making it the most sensitive and most debated component.
Gordon Growth Model (perpetuity growth):
The long-run growth rate should not exceed the long-run nominal GDP growth rate — any higher and the firm eventually becomes the entire economy.
Exit multiple method:
Anchoring to a market multiple introduces circular reasoning (the multiple itself reflects DCF-based market prices) but provides a useful sanity check.
Python: A Simple DCF Model¶
import numpy as np
def dcf_valuation(fcff_base, growth_rates, terminal_growth, wacc, net_debt, shares):
"""
Simple DCF valuation.
Parameters
----------
fcff_base : float — Current year FCFF (year 0)
growth_rates : list — Explicit forecast period growth rates (one per year)
terminal_growth: float — Perpetuity growth rate after explicit period
wacc : float — Discount rate
net_debt : float — Net debt (Enterprise Value → Equity Value bridge)
shares : float — Shares outstanding
Returns
-------
dict with enterprise value, equity value, intrinsic price per share
"""
# Explicit forecast period
fcff = fcff_base
pv_fcff = 0.0
for t, g in enumerate(growth_rates, start=1):
fcff *= (1 + g)
pv_fcff += fcff / (1 + wacc) ** t
# Terminal value
T = len(growth_rates)
tv = fcff * (1 + terminal_growth) / (wacc - terminal_growth)
pv_tv = tv / (1 + wacc) ** T
enterprise_value = pv_fcff + pv_tv
equity_value = enterprise_value - net_debt
price_per_share = equity_value / shares
return {
"PV of explicit FCFFs": round(pv_fcff, 1),
"PV of Terminal Value": round(pv_tv, 1),
"Enterprise Value": round(enterprise_value, 1),
"Equity Value": round(equity_value, 1),
"Intrinsic Price": round(price_per_share, 2),
"TV % of EV": round(100 * pv_tv / enterprise_value, 1),
}
# Example: hypothetical industrial company
result = dcf_valuation(
fcff_base = 500, # €500m FCFF
growth_rates = [0.10, 0.09, 0.08, 0.07, 0.06], # 5-year explicit period
terminal_growth = 0.025, # 2.5% perpetuity growth
wacc = 0.09, # 9% WACC
net_debt = 800, # €800m net debt
shares = 200 # 200m shares
)
for k, v in result.items():
print(f" {k:30s}: {v}")Sensitivity Analysis¶
DCF outputs are highly sensitive to assumptions. A proper valuation always includes a sensitivity table showing how the intrinsic price varies with WACC and the terminal growth rate.
import pandas as pd
wacc_range = [0.07, 0.08, 0.09, 0.10, 0.11]
tg_range = [0.015, 0.020, 0.025, 0.030, 0.035]
table = pd.DataFrame(index=[f"g={g:.1%}" for g in tg_range],
columns=[f"WACC={w:.1%}" for w in wacc_range])
for g in tg_range:
for w in wacc_range:
res = dcf_valuation(
fcff_base=500, growth_rates=[0.10, 0.09, 0.08, 0.07, 0.06],
terminal_growth=g, wacc=w, net_debt=800, shares=200
)
table.loc[f"g={g:.1%}", f"WACC={w:.1%}"] = f"€{res['Intrinsic Price']}"
print(table.to_string())References¶
Damodaran, A. (2012). Investment Valuation (3rd ed.). Wiley Finance.
Koller, T., Goedhart, M., & Wessels, D. (2020). Valuation: Measuring and Managing the Value of Companies (7th ed.). McKinsey & Company / Wiley.