BusinessMath Quarterly Series
16 min read
Part 18 of 12-Week BusinessMath Series
Stock valuation is both art and science. How much is a share of Apple worth? Tesla? Your local bank? Getting it wrong is expensive:
Spreadsheet valuation is tedious and error-prone when modeling multiple scenarios and methods.
BusinessMath provides five complementary equity valuation approaches: Gordon Growth DDM, Two-Stage DDM, H-Model, FCFE, Enterprise Value Bridge, and Residual Income. Use multiple methods and triangulate to a range.
Start with the simplest model for stable, dividend-paying companies:
import BusinessMath
import Foundation
// Mature utility company
// - Current dividend: $2.50/share
// - Growth: 4% annually (stable)
// - Required return: 9% (cost of equity)
let utilityStock = GordonGrowthModel(
dividendPerShare: 2.50,
growthRate: 0.04,
requiredReturn: 0.09
)
let intrinsicValue = utilityStock.valuePerShare()
print("Gordon Growth Model Valuation")
print("==============================")
print("Current Dividend: $2.50")
print("Growth Rate: 4.0%")
print("Required Return: 9.0%")
print("Intrinsic Value: \(intrinsicValue.currency(2))")
// Compare to market price
let marketPrice = 48.00
let assessment = intrinsicValue > marketPrice ? "UNDERVALUED" : "OVERVALUED"
let difference = abs((intrinsicValue / marketPrice) - 1.0)
print("\nMarket Price: \(marketPrice.currency())")
print("Assessment: \(assessment) by \(difference.percent(1))")
Output:
Gordon Growth Model Valuation
==============================
Current Dividend: $2.50
Growth Rate: 4.0%
Required Return: 9.0%
Intrinsic Value: $50.00
Market Price: $48.00
Assessment: UNDERVALUED by 4.2%
The formula: Value = D₁ / (r - g) where D₁ = next dividend, r = required return, g = growth rate.
The limitation: Only works for stable, mature companies with predictable dividend growth. Not suitable for growth stocks.
For companies transitioning from high growth to maturity:
// Technology company: High growth → Maturity
// - Current dividend: $1.00/share
// - High growth: 20% for 5 years
// - Stable growth: 5% thereafter
// - Required return: 12% (higher risk)
let techStock = TwoStageDDM(
currentDividend: 1.00,
highGrowthRate: 0.20,
highGrowthPeriods: 5,
stableGrowthRate: 0.05,
requiredReturn: 0.12
)
let techValue = techStock.valuePerShare()
print("\nTwo-Stage DDM Valuation")
print("========================")
print("Current Dividend: $1.00")
print("High Growth: 20% for 5 years")
print("Stable Growth: 5% thereafter")
print("Required Return: 12%")
print("Intrinsic Value: \(techValue.currency(2))")
// Break down components
let highGrowthValue = techStock.highGrowthPhaseValue()
let terminalValue = techStock.terminalValue()
print("\nValue Decomposition:")
print(" High Growth Phase: \(highGrowthValue.currency())")
print(" Terminal Value (PV): \(terminalValue.currency())")
print(" Total: \((highGrowthValue + terminalValue).currency())")
Output:
Two-Stage DDM Valuation
========================
Current Dividend: $1.00
High Growth: 20% for 5 years
Stable Growth: 5% thereafter
Required Return: 12%
Intrinsic Value: $27.36
Value Decomposition:
High Growth Phase: $6.18
Terminal Value (PV): $21.18
Total: $27.36
The insight: 77% of value comes from the terminal phase, not the high-growth years! This is common in two-stage models—most value is in perpetuity.
When growth declines linearly (not abruptly):
// Emerging market company
// - Current dividend: $2.00
// - Initial growth: 15% (current)
// - Terminal growth: 5% (mature)
// - Half-life: 8 years (time to decline)
// - Required return: 11%
let emergingStock = HModel(
currentDividend: 2.00,
initialGrowthRate: 0.15,
terminalGrowthRate: 0.05,
halfLife: 8,
requiredReturn: 0.11
)
let emergingValue = emergingStock.valuePerShare()
print("\nH-Model Valuation")
print("==================")
print("Current Dividend: $2.00")
print("Growth: 15% declining to 5% over 8 years")
print("Required Return: 11%")
print("Intrinsic Value: \(emergingValue.currency(2))")
Output:
H-Model Valuation
==================
Current Dividend: $2.00
Growth: 15% declining to 5% over 8 years
Required Return: 11%
Intrinsic Value: $61.67
The formula: Value = [D₀ × (1 + gₗ)] / (r - gₗ) + [D₀ × H × (gₛ - gₗ)] / (r - gₗ)
The use case: More realistic than two-stage for companies where growth fades gradually (most real-world scenarios).
For companies that don’t pay dividends (like growth tech companies):
// High-growth tech company (no dividends)
let periods = [
Period.year(2024),
Period.year(2025),
Period.year(2026)
]
// Operating cash flow (growing 20%)
let operatingCF = TimeSeries(
periods: periods,
values: [500.0, 600.0, 720.0] // Millions
)
// Capital expenditures (also growing 20%)
let capEx = TimeSeries(
periods: periods,
values: [100.0, 120.0, 144.0] // Millions
)
let fcfeModel = FCFEModel(
operatingCashFlow: operatingCF,
capitalExpenditures: capEx,
netBorrowing: nil, // No debt changes
costOfEquity: 0.12,
terminalGrowthRate: 0.05
)
// Total equity value
let totalEquityValue = fcfeModel.equityValue()
// Value per share (100M shares outstanding)
let sharesOutstanding = 100.0
let fcfeSharePrice = fcfeModel.valuePerShare(sharesOutstanding: sharesOutstanding)
print("\nFCFE Model Valuation")
print("====================")
print("Total Equity Value: \(totalEquityValue.currency(0))M")
print("Shares Outstanding: \(sharesOutstanding.number(0))M")
print("Value Per Share: \(fcfeSharePrice.currency(2))")
// Show FCFE breakdown
let fcfeValues = fcfeModel.fcfe()
print("\nProjected FCFE:")
for (period, value) in zip(fcfeValues.periods, fcfeValues.valuesArray) {
print(" \(period.label): \(value.currency(0))M")
}
Output:
FCFE Model Valuation
====================
Total Equity Value: $7,300M
Shares Outstanding: 100M
Value Per Share: $73.00
Projected FCFE:
2024: $400M
2025: $480M
2026: $576M
The power: FCFE captures all cash available to equity holders, regardless of dividend policy. Superior to DDM for growth companies.
When you start with firm-wide cash flows (FCFF), bridge to equity value:
// Step 1: Calculate Enterprise Value from FCFF
let fcffPeriods = [
Period.year(2024),
Period.year(2025),
Period.year(2026)
]
let fcff = TimeSeries(
periods: fcffPeriods,
values: [150.0, 165.0, 181.5] // Growing 10% (millions)
)
let enterpriseValue = enterpriseValueFromFCFF(
freeCashFlowToFirm: fcff,
wacc: 0.09,
terminalGrowthRate: 0.03
)
print("\nEnterprise Value Bridge")
print("========================")
print("Enterprise Value: \(enterpriseValue.currency(0))M")
// Step 2: Bridge to Equity Value
let bridge = EnterpriseValueBridge(
enterpriseValue: enterpriseValue,
totalDebt: 500.0, // Total debt outstanding
cash: 100.0, // Cash and equivalents
nonOperatingAssets: 50.0, // Marketable securities
minorityInterest: 20.0, // Minority shareholders
preferredStock: 30.0 // Preferred equity
)
let breakdown = bridge.breakdown()
print("\nBridge to Equity:")
print(" Enterprise Value: \(breakdown.enterpriseValue.currency(0))M")
print(" - Net Debt: \(breakdown.netDebt.currency(0))M")
print(" + Non-Op Assets: \(breakdown.nonOperatingAssets.currency(0))M")
print(" - Minority Interest: \(breakdown.minorityInterest.currency(0))M")
print(" - Preferred Stock: \(breakdown.preferredStock.currency(0))M")
print(" " + String(repeating: "=", count: 30))
print(" Common Equity Value: \(breakdown.equityValue.currency(0))M")
let bridgeSharePrice = bridge.valuePerShare(sharesOutstanding: 100.0)
print("\nValue Per Share: \(bridgeSharePrice.currency(2))")
Output:
Enterprise Value Bridge
========================
Enterprise Value: $2,823M
Bridge to Equity:
Enterprise Value: $2,823M
- Net Debt: $400M
+ Non-Op Assets: $50M
- Minority Interest: $20M
- Preferred Stock: $30M
==============================
Common Equity Value: $2,423M
Value Per Share: $24.23
The process: EV → Subtract debt → Add non-op assets → Subtract other claims = Equity Value
The critical insight: Enterprise Value is what an acquirer pays to buy the whole company. Equity value is what common shareholders receive.
For banks and financial institutions where book value is meaningful:
// Regional bank
let riPeriods = [
Period.year(2024),
Period.year(2025),
Period.year(2026)
]
// Projected earnings (5% growth)
let netIncome = TimeSeries(
periods: riPeriods,
values: [120.0, 126.0, 132.3] // Millions
)
// Book value of equity (grows with retained earnings)
let bookValue = TimeSeries(
periods: riPeriods,
values: [1000.0, 1050.0, 1102.5] // Millions
)
let riModel = ResidualIncomeModel(
currentBookValue: 1000.0,
netIncome: netIncome,
bookValue: bookValue,
costOfEquity: 0.10,
terminalGrowthRate: 0.03
)
let riEquityValue = riModel.equityValue()
let riSharePrice = riModel.valuePerShare(sharesOutstanding: 100.0)
print("\nResidual Income Model")
print("======================")
print("Current Book Value: \(riModel.currentBookValue.currency(0))M")
print("Equity Value: \(riEquityValue.currency(0))M")
print("Value Per Share: \(riSharePrice.currency(2))")
print("Book Value Per Share: \((riModel.currentBookValue / 100.0).currency(2))")
let priceToBooksRatio = riSharePrice / (riModel.currentBookValue / 100.0)
print("\nPrice-to-Book Ratio: \(priceToBooksRatio.number(2))x")
// Show residual income (economic profit)
let residualIncome = riModel.residualIncome()
print("\nResidual Income (Economic Profit):")
for (period, ri) in zip(residualIncome.periods, residualIncome.valuesArray) {
let verdict = ri > 0 ? "creating value" : "destroying value"
print(" \(period.label): \(ri.currency(1))M (\(verdict))")
}
// ROE analysis
let roe = riModel.returnOnEquity()
print("\nReturn on Equity (ROE):")
for (period, roeValue) in zip(roe.periods, roe.valuesArray) {
let spread = roeValue - riModel.costOfEquity
print(" \(period.label): \(roeValue.percent(1)) (spread over cost of equity: \(spread.percent(1)))")
}
Output:
Residual Income Model
======================
Current Book Value: $1,000M
Equity Value: $1,296M
Value Per Share: $12.96
Book Value Per Share: $10.00
Price-to-Book Ratio: 1.30x
Residual Income (Economic Profit):
2024: $20.0M (creating value)
2025: $21.0M (creating value)
2026: $22.1M (creating value)
Return on Equity (ROE):
2024: 12.0% (spread over cost of equity: 2.0%)
2025: 12.0% (spread over cost of equity: 2.0%)
2026: 12.0% (spread over cost of equity: 2.0%)
The formula: Equity Value = Book Value + PV(Residual Income)
Residual Income = Net Income - (Cost of Equity × Beginning Book Value)
The insight: The bank trades at 1.25x book because ROE (12%) exceeds cost of equity (10%). The 2% spread creates positive residual income and a premium valuation.
In practice, use multiple methods and triangulate:
print("\n" + String(repeating: "=", count: 50))
print("COMPREHENSIVE VALUATION SUMMARY")
print(String(repeating: "=", count: 50))
struct ValuationSummary {
let method: String
let value: Double
let confidence: String
let bestFor: String
}
let valuations = [
ValuationSummary(
method: "Gordon Growth DDM",
value: 50.00,
confidence: "High",
bestFor: "Mature dividend payers"
),
ValuationSummary(
method: "Two-Stage DDM",
value: 27.36,
confidence: "Medium",
bestFor: "Growth-to-maturity transition"
),
ValuationSummary(
method: "H-Model",
value: 48.33,
confidence: "Medium",
bestFor: "Declining growth scenarios"
),
ValuationSummary(
method: "FCFE Model",
value: 74.56,
confidence: "High",
bestFor: "All companies with CF data"
),
ValuationSummary(
method: "EV Bridge",
value: 21.00,
confidence: "High",
bestFor: "Firm-level DCF to equity"
),
ValuationSummary(
method: "Residual Income",
value: 12.45,
confidence: "High",
bestFor: "Financial institutions"
)
]
print("\nMethod | Value | Confidence | Best For")
print("----------------------|----------|------------|------------------------")
for v in valuations {
print("\(v.method.padding(toLength: 21, withPad: " ", startingAt: 0)) | \(v.value.currency(2).padding(toLength: 8, withPad: " ", startingAt: 0)) | \(v.confidence.padding(toLength: 10, withPad: " ", startingAt: 0)) | \(v.bestFor)")
}
// Calculate valuation range
let values = valuations.map { $0.value }
let minValue = values.min()!
let maxValue = values.max()!
let medianValue = values.sorted()[values.count / 2]
print("\nValuation Range:")
print(" Low: \(minValue.currency(2))")
print(" Median: \(medianValue.currency(2))")
print(" High: \(maxValue.currency(2))")
print(" Spread: \((maxValue - minValue).currency(2)) (\(((maxValue - minValue) / medianValue).percent()))")
Output:
==================================================
COMPREHENSIVE VALUATION SUMMARY
==================================================
Method | Value | Confidence | Best For
----------------------|----------|------------|------------------------
Gordon Growth DDM | $50.00 | High | Mature dividend payers
Two-Stage DDM | $27.36 | Medium | Growth-to-maturity transition
H-Model | $48.33 | Medium | Declining growth scenarios
FCFE Model | $74.56 | High | All companies with CF data
EV Bridge | $21.00 | High | Firm-level DCF to equity
Residual Income | $12.45 | High | Financial institutions
Valuation Range:
Low: $12.45
Median: $48.33
High: $74.56
Spread: $62.11 (128.51%)
The reality: Different models give vastly different values depending on company type and assumptions. This is why equity valuation is art + science.
The approach: Weight models based on company characteristics, cross-check assumptions, establish a range.
import BusinessMath
import Foundation
// MARK: - Gordon Growth Model
// Mature utility company
// - Current dividend: $2.50/share
// - Growth: 4% annually (stable)
// - Required return: 9% (cost of equity)
let utilityStock = GordonGrowthModel(
dividendPerShare: 2.50,
growthRate: 0.04,
requiredReturn: 0.09
)
let intrinsicValue = utilityStock.valuePerShare()
print("Gordon Growth Model Valuation")
print("==============================")
print("Current Dividend: $2.50")
print("Growth Rate: 4.0%")
print("Required Return: 9.0%")
print("Intrinsic Value: \(intrinsicValue.currency(2))")
// Compare to market price
let marketPrice = 48.00
let assessment = intrinsicValue > marketPrice ? "UNDERVALUED" : "OVERVALUED"
let difference = abs((intrinsicValue / marketPrice) - 1.0)
print("\nMarket Price: \(marketPrice.currency())")
print("Assessment: \(assessment) by \(difference.percent(1))")
// MARK: - Two-Stage Growth Model
// Technology company: High growth → Maturity
// - Current dividend: $1.00/share
// - High growth: 20% for 5 years
// - Stable growth: 5% thereafter
// - Required return: 12% (higher risk)
let techStock = TwoStageDDM(
currentDividend: 1.00,
highGrowthRate: 0.20,
highGrowthPeriods: 5,
stableGrowthRate: 0.05,
requiredReturn: 0.12
)
let techValue = techStock.valuePerShare()
print("\nTwo-Stage DDM Valuation")
print("========================")
print("Current Dividend: $1.00")
print("High Growth: 20% for 5 years")
print("Stable Growth: 5% thereafter")
print("Required Return: 12%")
print("Intrinsic Value: \(techValue.currency(2))")
// Break down components
let highGrowthValue = techStock.highGrowthPhaseValue()
let terminalValue = techStock.terminalValue()
print("\nValue Decomposition:")
print(" High Growth Phase: \(highGrowthValue.currency())")
print(" Terminal Value (PV): \(terminalValue.currency())")
print(" Total: \((highGrowthValue + terminalValue).currency())")
// MARK: - H-Model (Declining Growth)
// Emerging market company
// - Current dividend: $2.00
// - Initial growth: 15% (current)
// - Terminal growth: 5% (mature)
// - Half-life: 8 years (time to decline)
// - Required return: 11%
let emergingStock = HModel(
currentDividend: 2.00,
initialGrowthRate: 0.15,
terminalGrowthRate: 0.05,
halfLife: 8,
requiredReturn: 0.11
)
let emergingValue = emergingStock.valuePerShare()
print("\nH-Model Valuation")
print("==================")
print("Current Dividend: $2.00")
print("Growth: 15% declining to 5% over 8 years")
print("Required Return: 11%")
print("Intrinsic Value: \(emergingValue.currency(2))")
// MARK: - Free Cash Flow to Equity (FCFE)
// High-growth tech company (no dividends)
let periods = [
Period.year(2024),
Period.year(2025),
Period.year(2026)
]
// Operating cash flow (growing 20%)
let operatingCF = TimeSeries(
periods: periods,
values: [500.0, 600.0, 720.0] // Millions
)
// Capital expenditures (also growing 20%)
let capEx = TimeSeries(
periods: periods,
values: [100.0, 120.0, 144.0] // Millions
)
let fcfeModel = FCFEModel(
operatingCashFlow: operatingCF,
capitalExpenditures: capEx,
netBorrowing: nil, // No debt changes
costOfEquity: 0.12,
terminalGrowthRate: 0.05
)
// Total equity value
let totalEquityValue = fcfeModel.equityValue()
// Value per share (100M shares outstanding)
let sharesOutstanding = 100.0
let fcfeSharePrice = fcfeModel.valuePerShare(sharesOutstanding: sharesOutstanding)
print("\nFCFE Model Valuation")
print("====================")
print("Total Equity Value: \(totalEquityValue.currency(0))M")
print("Shares Outstanding: \(sharesOutstanding.number(0))M")
print("Value Per Share: \(fcfeSharePrice.currency(2))")
// Show FCFE breakdown
let fcfeValues = fcfeModel.fcfe()
print("\nProjected FCFE:")
for (period, value) in zip(fcfeValues.periods, fcfeValues.valuesArray) {
print(" \(period.label): \(value.currency(0))M")
}
// MARK: - Enterprise Value Bridge
// Step 1: Calculate Enterprise Value from FCFF
let fcffPeriods = [
Period.year(2024),
Period.year(2025),
Period.year(2026)
]
let fcff = TimeSeries(
periods: fcffPeriods,
values: [150.0, 165.0, 181.5] // Growing 10% (millions)
)
let enterpriseValue = enterpriseValueFromFCFF(
freeCashFlowToFirm: fcff,
wacc: 0.09,
terminalGrowthRate: 0.03
)
print("\nEnterprise Value Bridge")
print("========================")
print("Enterprise Value: \(enterpriseValue.currency(0))M")
// Step 2: Bridge to Equity Value
let bridge = EnterpriseValueBridge(
enterpriseValue: enterpriseValue,
totalDebt: 500.0, // Total debt outstanding
cash: 100.0, // Cash and equivalents
nonOperatingAssets: 50.0, // Marketable securities
minorityInterest: 20.0, // Minority shareholders
preferredStock: 30.0 // Preferred equity
)
let breakdown = bridge.breakdown()
print("\nBridge to Equity:")
print(" Enterprise Value: \(breakdown.enterpriseValue.currency(0))M")
print(" - Net Debt: \(breakdown.netDebt.currency(0))M")
print(" + Non-Op Assets: \(breakdown.nonOperatingAssets.currency(0))M")
print(" - Minority Interest: \(breakdown.minorityInterest.currency(0))M")
print(" - Preferred Stock: \(breakdown.preferredStock.currency(0))M")
print(" " + String(repeating: "=", count: 30))
print(" Common Equity Value: \(breakdown.equityValue.currency(0))M")
let bridgeSharePrice = bridge.valuePerShare(sharesOutstanding: 100.0)
print("\nValue Per Share: \(bridgeSharePrice.currency(2))")
// MARK: - Residual Income Model
// Regional bank
let riPeriods = [
Period.year(2024),
Period.year(2025),
Period.year(2026)
]
// Projected earnings (5% growth)
let netIncome = TimeSeries(
periods: riPeriods,
values: [120.0, 126.0, 132.3] // Millions
)
// Book value of equity (grows with retained earnings)
let bookValue = TimeSeries(
periods: riPeriods,
values: [1000.0, 1050.0, 1102.5] // Millions
)
let riModel = ResidualIncomeModel(
currentBookValue: 1000.0,
netIncome: netIncome,
bookValue: bookValue,
costOfEquity: 0.10,
terminalGrowthRate: 0.03
)
let riEquityValue = riModel.equityValue()
let riSharePrice = riModel.valuePerShare(sharesOutstanding: 100.0)
print("\nResidual Income Model")
print("======================")
print("Current Book Value: \(riModel.currentBookValue.currency(0))M")
print("Equity Value: \(riEquityValue.currency(0))M")
print("Value Per Share: \(riSharePrice.currency(2))")
print("Book Value Per Share: \((riModel.currentBookValue / 100.0).currency(2))")
let priceToBooksRatio = riSharePrice / (riModel.currentBookValue / 100.0)
print("\nPrice-to-Book Ratio: \(priceToBooksRatio.number(2))x")
// Show residual income (economic profit)
let residualIncome = riModel.residualIncome()
print("\nResidual Income (Economic Profit):")
for (period, ri) in zip(residualIncome.periods, residualIncome.valuesArray) {
let verdict = ri > 0 ? "creating value" : "destroying value"
print(" \(period.label): \(ri.currency(1))M (\(verdict))")
}
// ROE analysis
let roe = riModel.returnOnEquity()
print("\nReturn on Equity (ROE):")
for (period, roeValue) in zip(roe.periods, roe.valuesArray) {
let spread = roeValue - riModel.costOfEquity
print(" \(period.label): \(roeValue.percent(1)) (spread over cost of equity: \(spread.percent(1)))")
}
// MARK: - Multi-Model Valuation Summary
print("\n" + String(repeating: "=", count: 50))
print("COMPREHENSIVE VALUATION SUMMARY")
print(String(repeating: "=", count: 50))
struct ValuationSummary {
let method: String
let value: Double
let confidence: String
let bestFor: String
}
let valuations = [
ValuationSummary(
method: "Gordon Growth DDM",
value: 50.00,
confidence: "High",
bestFor: "Mature dividend payers"
),
ValuationSummary(
method: "Two-Stage DDM",
value: 27.36,
confidence: "Medium",
bestFor: "Growth-to-maturity transition"
),
ValuationSummary(
method: "H-Model",
value: 48.33,
confidence: "Medium",
bestFor: "Declining growth scenarios"
),
ValuationSummary(
method: "FCFE Model",
value: 74.56,
confidence: "High",
bestFor: "All companies with CF data"
),
ValuationSummary(
method: "EV Bridge",
value: 21.00,
confidence: "High",
bestFor: "Firm-level DCF to equity"
),
ValuationSummary(
method: "Residual Income",
value: 12.45,
confidence: "High",
bestFor: "Financial institutions"
)
]
print("\nMethod | Value | Confidence | Best For")
print("----------------------|----------|------------|------------------------")
for v in valuations {
print("\(v.method.padding(toLength: 21, withPad: " ", startingAt: 0)) | \(v.value.currency(2).padding(toLength: 8, withPad: " ", startingAt: 0)) | \(v.confidence.padding(toLength: 10, withPad: " ", startingAt: 0)) | \(v.bestFor)")
}
// Calculate valuation range
let values = valuations.map { $0.value }
let minValue = values.min()!
let maxValue = values.max()!
let medianValue = values.sorted()[values.count / 2]
print("\nValuation Range:")
print(" Low: \(minValue.currency(2))")
print(" Median: \(medianValue.currency(2))")
print(" High: \(maxValue.currency(2))")
print(" Spread: \((maxValue - minValue).currency(2)) (\(((maxValue - minValue) / medianValue).percent()))")
→ Full API Reference: BusinessMath Docs – 3.9 Equity Valuation
Modifications to try:
Every equity analyst, portfolio manager, and investment banker uses these models:
Equity research use case: “Value Tesla using FCFE. Assume 25% revenue CAGR for 5 years, then 8% perpetual growth. Cost of equity 12%. Compare to current market price.”
BusinessMath makes these valuations programmatic, scenario-testable, and portfolio-wide.
★ Insight ─────────────────────────────────────
Why Do Valuations Vary So Much Across Methods?
In our example, valuations ranged from $12.45 to $74.56 (6x difference!). Why?
Each model captures different aspects:
Which is “right”? Depends on the company:
The lesson: No single model is universally correct. Use multiple methods, understand their assumptions, and triangulate to a range.
─────────────────────────────────────────────────
The biggest design challenge was modeling growth transitions. Real companies don’t go from 20% growth to 5% growth overnight (two-stage assumption), but they also don’t decline linearly forever (H-Model assumption).
We considered implementing a three-stage model (high growth → declining growth → stable), but decided against it because:
The principle: Provide flexible primitives rather than complex all-in-one models.
Related Methodology: Documentation as Design (Week 2) - We wrote tutorial examples first to ensure APIs were learnable before implementing.
Coming up tomorrow: Bond Valuation - Pricing fixed income, credit spreads, callable bonds, and option-adjusted spreads.
Next week: Monte Carlo simulation and scenario analysis for risk modeling.
Series Progress:
Tagged with: businessmath, swift, equity-valuation, ddm, fcfe, residual-income, stock-valuation