This notebook illustrates the concepts in the Exam 7 reading P&C Insurance Company Valuation by Richard Goldfarb, which relates to learning objectives B1 to B3 of the syllabus. These concepts are illustrated by reproducing the examples in the paper; however, due to rounding not all numbers will match exactly. The following packages are used in this notebook:
easypackages::packages("data.table", "DT", "ggplot2")
options(scipen = 999)
Suppose that \(n\) is the final year of the forecast period. Then the terminal value \(T\) can be calculated as \[ T = \sum_{i \geq 1} \frac{D_n (1+g)^i}{(1+k)^i} = D_n \frac{1+g}{1+k}\frac{1}{1 - \frac{1+g}{1+k}} = \frac{D_{n+1}}{k-g} \] Then the present value of all dividends is \[ \sum_{1\leq i \leq n} \frac{D_i}{(1+k)^i} + \frac{T}{(1+k)^n} \] The overall mechanic will be illustrated using the projections in the following example, followed by a discussion of the assumptions underlying the method:
goldfarb.ddm = fread("./goldfarb_ddm.csv")
datatable(goldfarb.ddm)
We will make the following assumptions:
The first step is to calculate the projected dividend in each year. Based on the company’s dividend policy, we can calculate these projections as follows:
goldfarb.ddm[,net_income_after_tax := GAAP_Net_income_before_tax - Corporate_income_tax]
goldfarb.ddm[,expected_dividend := 0.5 * net_income_after_tax]
datatable(goldfarb.ddm)
We’ll calculate the terminal value using an R function, with the assumed growth rate as an input. This will facilitate sensitivity testing on the growth rate assumption.
terminal.value = function(growth.rate, discount.rate, final.dividend) {
return(final.dividend * (1 + growth.rate) / (discount.rate - growth.rate))
}
With the assumptions given, we can calculate the terminal value as follows:
final.dividend = goldfarb.ddm[Year == 2009, expected_dividend]
terminal.value(growth.rate = 0.05, discount.rate = 0.0895, final.dividend = final.dividend)
## [1] 161367.7
To perform sensitivity testing on the terminal value, first create a dataset containing the range of assumptions to be tested. This can be visualized using the “geom_raster” function in the ggplot package.
discount.range = 0.090 + 0:40*0.001
growth.range = 0.04 + 0:40*0.001
TV.sensitivity.test = as.data.table(merge(discount.range, growth.range))
colnames(TV.sensitivity.test) = c("discount.rate", "growth.rate")
TV.sensitivity.test$terminal.value = apply(TV.sensitivity.test, 1, function(y) terminal.value(growth.rate = y['growth.rate'], discount.rate = y['discount.rate'], final.dividend = final.dividend))
ggplot(data = TV.sensitivity.test, aes(x = discount.rate, y = growth.rate, fill = terminal.value)) + geom_raster() + labs(title = "Terminal Value Projections - Sensitivity Analysis")
## Warning in plyr::split_indices(scale_id, n): '.Random.seed' is not an
## integer vector but of type 'NULL', so ignored
Notice that the most extreme values occur in the upper left corner, where the discount rate is close to the growth rate. This is not surprising given that the value \(k-g\) appears in the denominator of the terminal value calculation. Let’s zoom in on the areas where the discount rate is above 0.1, and the growth rate is below 0.07:
ggplot(data = TV.sensitivity.test[discount.rate > 0.1 & growth.rate < 0.07], aes(x = discount.rate, y = growth.rate, fill = terminal.value)) + geom_raster() + labs(title = "Terminal Value Projections - Sensitivity Analysis")
An additional consideration is that there is likely correlation between the two assumptions: high growth rates are associated with higher discount rates. Because of this, the top left and bottom right corners of this table, where the values are most extreme, are the more unlikely regions for the terminal value.
Next, discount the dividends during the projection period, and add the discounted value of the terminal value:
ddm.valuation.details = function(dataset, discount.rate) {
first.year = min(dataset$Year)
last.year = max(dataset$Year)
pv.dividends = apply(dataset, 1, function(x){x['expected_dividend']} / ((1 + discount.rate)^(x['Year'] - first.year + 1)))
discount.factor = apply(dataset, 1, function(x){1 / (1 + discount.rate)^(x['Year'] - first.year + 1)})
return(as.data.table(cbind(dataset$Year, discount.factor, pv.dividends)))
}
The projection is based on years 2005 and later:
datatable(ddm.valuation.details(goldfarb.ddm[Year >= 2005], 0.0895))
Finally, we sum the present value of the dividends and add the present value of the terminal value:
ddm.valuation = function(dataset, discount.rate, growth.rate) {
total.pv.dividends = sum(ddm.valuation.details(dataset, discount.rate)$pv.dividends)
first.year = min(dataset$Year)
last.year = max(dataset$Year)
final.dividend = dataset[Year == last.year, expected_dividend]
pv.terminal.value = terminal.value(growth.rate = growth.rate, discount.rate = discount.rate, final.dividend = final.dividend) / (1 + discount.rate)^(last.year - first.year + 1)
return (total.pv.dividends + pv.terminal.value)
}
ddm.valuation(goldfarb.ddm[Year >= 2005], 0.0895, 0.05)
## [1] 126434.9
Note that the present value of the terminal value in this case is
terminal.value(growth.rate = 0.05, discount.rate = 0.0895, final.dividend = 6070) / (1 + 0.0895)^5
## [1] 105110.2
This represents a significant fraction of the value of the company, indicating that this method is particularly sensitive to the selection of assumptions underlying the terminal value. Earlier, we performed sensitivity testing on the terminal value; we can perform similar tests on the equity value as well.
EV.sensitivity.test = as.data.table(merge(discount.range, growth.range))
colnames(EV.sensitivity.test) = c("discount.rate", "growth.rate")
EV.sensitivity.test$equity.value = apply(EV.sensitivity.test, 1, function(y) ddm.valuation(goldfarb.ddm[Year >= 2005], discount.rate = y['discount.rate'], growth.rate = y['growth.rate']))
ggplot(data = EV.sensitivity.test, aes(x = discount.rate, y = growth.rate, fill = equity.value)) + geom_raster() + labs(title = "Equity Value Estimates - Sensitivity Analysis")
Let’s zoom in on the areas where the discount rate is above 0.1, and the growth rate is below 0.07:
ggplot(data = EV.sensitivity.test[discount.rate > 0.1 & growth.rate < 0.07], aes(x = discount.rate, y = growth.rate, fill = equity.value)) + geom_raster() + labs(title = "Equity Value Estimates - Sensitivity Analysis")
The method requires assumptions about the following.
A simple R function can be used to calculate the CAPM discount rate:
CAPM.discount = function(risk.free.rate, beta, equity.risk.premium) {
return(risk.free.rate + beta * equity.risk.premium)
}
Using the values in Goldfarb’s paper, we obtain the discount rate used in the examples above:
CAPM.discount(risk.free.rate = 0.0433, beta = 0.84, equity.risk.premium = 0.0550)
## [1] 0.0895
We can use this function as one of the inputs to the DDM valuation function to obtain the results:
ddm.valuation(goldfarb.ddm[Year >= 2005], discount.rate = CAPM.discount(risk.free.rate = 0.0433, beta = 0.84, equity.risk.premium = 0.0550), growth.rate = 0.05)
## [1] 126434.9
By combining the functions in this way, we can now perform sensitivity testing on the final equity value relative to changes in \(\beta\) and the equity risk premium, keeping the dividend growth rate and risk-free rate fixed:
beta.range = 0.70 + 0:40*0.01
equity.risk.range = 0.04 + 0:40*0.001
CAPM.sensitivity.test = as.data.table(merge(beta.range, equity.risk.range))
colnames(CAPM.sensitivity.test) = c("beta", "equity.risk")
CAPM.sensitivity.test$equity.value = apply(CAPM.sensitivity.test, 1, function(y) { ddm.valuation(goldfarb.ddm[Year >= 2005], discount.rate = CAPM.discount(risk.free.rate = 0.0433, beta = y['beta'], equity.risk.premium = y['equity.risk']), growth.rate = 0.05)})
ggplot(data = CAPM.sensitivity.test, aes(x = beta, y = equity.risk, fill = equity.value)) + geom_raster() + labs(title = "Equity Value Projections - Sensitivity Analysis")
Alternatively, FCFE can be calculated as the difference between the minimum capital required and ending GAAP equity before dividends for the year.
The FCFE method can be illustrated using the following dataset. Sensitivity testing can also be performed on these results, but it is not significantly different from the approach illustrated for the DDM method, so I will omit it for simplicity.
goldfarb.fcfe = fread("./goldfarb_fcfe.csv")
datatable(goldfarb.fcfe)
First, derive the required capital investment and FCFE in each year:
goldfarb.fcfe[, reinvested.capital := Minimum_capital - GAAP_equity_start]
goldfarb.fcfe[, FCFE := GAAP_net_income - reinvested.capital]
datatable(goldfarb.fcfe)
First, we will calculate the growth rate, reinvestment rate, and ROE in each year. We calculate it in two ways: as the ratio of successive values of FCFE, and as the product of ROE and the reinvestment rate. Note that due to cancellation of net income in the numerator and denominator, the second calculation is equal to the ratio of reinvested capital to starting GAAP equity.
goldfarb.fcfe[, growth_rate := as.double(FCFE)/as.double(shift(FCFE, type = "lag")) -1]
goldfarb.fcfe[, ROE := GAAP_net_income / GAAP_equity_start]
goldfarb.fcfe[, reinvestment_rate := reinvested.capital / GAAP_net_income]
goldfarb.fcfe[, horizon_growth_rate := ROE * reinvestment_rate]
goldfarb.fcfe[, horizon_growth_rate_2 := reinvested.capital / GAAP_equity_start]
datatable(goldfarb.fcfe[, .(Year, growth_rate, horizon_growth_rate, horizon_growth_rate_2)])
The growth rate beyond the forecast horizon is:
perpetual.growth.rate = goldfarb.fcfe[Year == 2009, horizon_growth_rate]
perpetual.growth.rate
## [1] 0.03943736
Using the same discount rate as in the DDM example, undiscounted terminal value is:
final.FCFE = goldfarb.fcfe[Year == 2009, FCFE]
discount.rate = 0.0895
terminal.value.FCFE = final.FCFE * (1 + perpetual.growth.rate) / (discount.rate - perpetual.growth.rate)
terminal.value.FCFE
## [1] 293564.3
At present value, the terminal value is:
TV.discount = 1/(1+discount.rate)^5
PV.terminal.value.FCFE = terminal.value.FCFE * TV.discount
PV.terminal.value.FCFE
## [1] 191234.9
Note that the growth and discount rate assumptions can be combined into a single assumption that the terminal value is a fixed multiple of the final projected FCFE, namely,
(1 + discount.rate) / (discount.rate - perpetual.growth.rate)
## [1] 21.76273
Finally, discount the projected FCFE values to present:
goldfarb.fcfe[, discount_factor := 1 / (1 + discount.rate)^(Year - 2004)]
goldfarb.fcfe[, PV_FCFE := FCFE * discount_factor]
datatable(goldfarb.fcfe[, .(Year, FCFE, discount_factor, PV_FCFE)])
The total value of the company is therefore:
PV.terminal.value.FCFE + goldfarb.fcfe[, sum(PV_FCFE)]
## [1] 241887.6
This technique can be illustated using the same data underlying the FCFE example, and the same required rate of return.
goldfarb.ae = fread("./goldfarb_fcfe.csv")
k = 0.0895
goldfarb.ae[, normal_earnings := GAAP_equity_start * k]
goldfarb.ae[, abnormal_earnings := GAAP_net_income - normal_earnings]
goldfarb.ae[, PV_abnormal_earnings := abnormal_earnings / (1 + k)^(Year - 2004)]
datatable(goldfarb.ae)
In a simple case, we can assume that there are no abnormal earnings beyond the forecast period. In this case, the valuation is
goldfarb.ae[Year == 2005, GAAP_equity_start] + goldfarb.ae[, sum(PV_abnormal_earnings)]
## [1] 133546.5
One approach to calculating the terminal value is to assume that the abnormal earnings persist in perputuity, at the same level (growth rate of 0). In this case, the terminal value is:
terminal.value.AE = goldfarb.ae[Year == 2009, abnormal_earnings] / (k - 0)
terminal.value.AE
## [1] 89499.79
In this case, the present value of the equity is
goldfarb.ae[Year == 2005, GAAP_equity_start] + goldfarb.ae[, sum(PV_abnormal_earnings)] + terminal.value.AE / (1 + k)^5
## [1] 191848.8
For reasons discussed above, this is not a reasonable result since we do not expect abnormal earnings to persist in perpetuity.
Although not mentioned in Goldfarb’s paper, an easy-to-implement assumption is that the abnormal earnings will decay exponentially beyond the forecast period. For example, if we assume that abnormal earnings will decay by 20% per year, then the terminal value is:
decay.factor = 0.2
terminal.value.AE = goldfarb.ae[Year == 2009, abnormal_earnings] * (1-decay.factor) / (k + decay.factor)
terminal.value.AE
## [1] 22135.35
In this case, the present value of the equity is
goldfarb.ae[Year == 2005, GAAP_equity_start] + goldfarb.ae[, sum(PV_abnormal_earnings)] + terminal.value.AE / (1 + k)^5
## [1] 147966
Goldfarb suggests an assumption that the abnormal earnings decay linearly over a horizon of \(n\) years. Below, this approach is illustrated for \(n=5\), and then as a sensitivity test, the terminal value is calculated for a range of \(n\) from 1 to 20.
linear.decay.table = function(initial.AE, decay.duration, discount.rate) {
horizon.year = 1:decay.duration
result.table = as.data.table(horizon.year)
result.table[, AE := initial.AE * (decay.duration - horizon.year + 1) / (decay.duration + 1)]
result.table[, PV_AE := AE / (1 + discount.rate)^horizon.year]
return (result.table)
}
datatable(linear.decay.table(initial.AE = goldfarb.ae[Year == 2009, abnormal_earnings], decay.duration = 5, discount.rate = k))
We can calculate the terminal value as the sum of the present value of the abnormal earnings under this projection:
linear.decay.TV = function(initial.AE, decay.duration, discount.rate) {
AE.table = linear.decay.table(initial.AE, decay.duration, discount.rate)
return(AE.table[,sum(PV_AE)])
}
linear.decay.TV(initial.AE = goldfarb.ae[Year == 2009, abnormal_earnings], decay.duration = 5, discount.rate = k)
## [1] 16487.31
Finally, let’s calculate it under each value of \(n\) between 1 and 20, and plot the results.
AE.duration.assumption = 1:20
AE.TV.sensitivity = as.data.table(AE.duration.assumption)
AE.TV.sensitivity$terminal.value = apply(AE.TV.sensitivity, 1, function(x){linear.decay.TV(initial.AE = goldfarb.ae[Year == 2009, abnormal_earnings], decay.duration = x['AE.duration.assumption'], discount.rate = k)})
ggplot(data = AE.TV.sensitivity, aes(x = AE.duration.assumption, y = terminal.value)) + geom_line() + labs(title = "Sensitivity Test: Terminal Value under Linear Decay Assumption")
Then the total value of the firm is \[ P = \frac{dE}{k-g}. \] Dividing by \(E\), we get the following: \[ \frac{P}{E} = \frac{d}{k-g} \] In other words, the P-E ratio summarizes the combined effect of three assumptions: discount rate, growth rate, dividend payout rate, into a single number. Alternately, since the plowback ratio is equal to \(1-d\), we can express this in terms of the assumed ROE rather than growth rate, using \[ g = (1-d)\mathrm{ROE} \] We can visualize the effect that different assumptions about the dividend payout ratio and discount rate have on the P-E ratio, assuming a constant ROE of 15%:
discount.rate = 0.1 + 1:50*0.001
dividend.payout = 0.4 + 1:40*0.005
assumption.table = as.data.table(merge(discount.rate, dividend.payout))
colnames(assumption.table) = c("discount.rate", "dividend.payout")
PE.ratio = function(discount.rate, dividend.payout, ROE) {
return(dividend.payout/(discount.rate - (1 - dividend.payout) * ROE))
}
assumption.table$PE.ratio = apply(assumption.table, 1, function(x){PE.ratio(discount.rate = x['discount.rate'], dividend.payout = x['dividend.payout'], ROE = 0.15)})
ggplot(data = assumption.table, aes(x = discount.rate, y = dividend.payout, fill = PE.ratio)) + geom_raster() + labs(title = "PE Ratio - Sensitivity Analysis")
Notice that the PE ratio is constant when the discount rate is equal to ROE:
assumption.table[discount.rate > 0.1495, PE.ratio]
## [1] 6.666667 6.666667 6.666667 6.666667 6.666667 6.666667 6.666667
## [8] 6.666667 6.666667 6.666667 6.666667 6.666667 6.666667 6.666667
## [15] 6.666667 6.666667 6.666667 6.666667 6.666667 6.666667 6.666667
## [22] 6.666667 6.666667 6.666667 6.666667 6.666667 6.666667 6.666667
## [29] 6.666667 6.666667 6.666667 6.666667 6.666667 6.666667 6.666667
## [36] 6.666667 6.666667 6.666667 6.666667 6.666667
This is consistent with the philosophy underlying the abnormral earnings approach, that the growth rate does not affect the value of the firm if it does not generate earnings in excess of the discount rate.
Then we have: \[ P = B + \sum_{i\geq 1}\frac{AE_i}{(1+k)^i} = B + \sum_{i\geq 1} \frac{(\mathrm{ROE}-k) B}{(1+k)^i} \] Incorporating the growth rate in book value, this becomes \[ P = B + \sum_{i\geq 1}\frac{(\mathrm{ROE}-k)B(1+g)^{i-1}}{(1+k)^i} \] Simplifying the geometric series, \[ P = B + (\mathrm{ROE} - k)B\frac{1}{1+k}\frac{1}{1 - \frac{1+g}{1+k}} = B + \frac{(\mathrm{ROE} - k)B}{k-g} \] Therefore, the price-to-book value ratio is \[ \frac{P}{B} = 1 + \frac{\mathrm{ROE}-k}{k-g} \] We can visualize the relationship between fundamentals and the P-B ratio as follows:
discount.rate = 0.1 + 1:50*0.001
growth.rate = 1:40*0.001
assumption.table = as.data.table(merge(discount.rate, growth.rate))
colnames(assumption.table) = c("discount.rate", "growth.rate")
PB.ratio = function(discount.rate, growth.rate, ROE) {
return(1 + (ROE - discount.rate)/(discount.rate - growth.rate))
}
assumption.table$PB.ratio = apply(assumption.table, 1, function(x){PB.ratio(discount.rate = x['discount.rate'], growth.rate = x['growth.rate'], ROE = 0.15)})
ggplot(data = assumption.table, aes(x = discount.rate, y = growth.rate, fill = PB.ratio)) + geom_raster() + labs(title = "P-BV Ratio - Sensitivity Analysis")
As before, the growth rate has no impact on the valuation of the firm if the expected ROE is equal to the discount rate. It fact, it clearly demonstrates that growth adds nothing to the book value unless earnings are in excess of the required rate of return.
assumption.table[discount.rate > 0.1495, PB.ratio]
## [1] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
## [36] 1 1 1 1 1
To illustrate this approach, import the data for the peers and the company whose valuation is being calculated:
RV.peers <- fread("./Goldfarb_RV_peers.csv")
RV.subject <- fread("./Goldfarb_RV_subject.csv")
datatable(RV.peers)
We need the average ratios for each of the pure play lines. Note that the P-E ratio may be missing if earnings were negative, so it is important to remove missing values when calculating the mean.
pure.play.averages = RV.peers[Line != "Diversified", .(avg_PE = mean(`P-E`, na.rm = TRUE), avg_PBV = mean(`P-BV`)), by = Line]
datatable(pure.play.averages)
Join the firm-specific financial measures:
firm.with.pp.averages = merge(RV.subject, pure.play.averages, by = "Line")
Calculate the valuation, by line, using both the P-E and P-BV ratios:
firm.with.pp.averages[, PE_valuation := Earnings * avg_PE]
firm.with.pp.averages[, PBV_valuation := Book_Value * avg_PBV]
firm.with.pp.averages[, avg_valuation := (PE_valuation + PBV_valuation) / 2]
datatable(firm.with.pp.averages)
We can now determine the total firm valuation by adding the results by line:
total.firm.valuation = firm.with.pp.averages[, sum(avg_valuation)]
total.firm.valuation
## [1] 36024.56
To compare against diversified firms, first calculate average ratios for these firms:
diversified.averages = RV.peers[Line == "Diversified", .(avg_PE = mean(`P-E`, na.rm = TRUE), avg_PBV = mean(`P-BV`)), by = "Line"]
datatable(diversified.averages)
We sum the subject companye financial results before applying the ratios.
firm.total = RV.subject[, .(total_earnings = sum(Earnings), total_BV = sum(Book_Value), Line = "Diversified")]
Join as before, then calculate the average valuation using the P-E and P-BV methods:
firm.with.diversified.averages = merge(firm.total, diversified.averages, by = "Line")
firm.with.diversified.averages[, PE_valuation := total_earnings * avg_PE]
firm.with.diversified.averages[, PBV_valuation := total_BV * avg_PBV]
firm.with.diversified.averages[, avg_valuation := (PE_valuation + PBV_valuation) / 2]
datatable(firm.with.diversified.averages)
To understand how equity can be valued as a call option, assume that the firm has a debt \(D\) that must be repaid at time \(T\). Let \(V_T\) denote the value of the firm at time \(T\). Then the value of the firm to the equityholders at time \(T\) is \[ E_T = \max(V_T-D, 0) \] This is the same as the value of a call option with a strike price of \(D\). However, this approach is not generally used for insurance companies, since the notion of debt is not well-defined due to the existince of policy liabilities, and there is no single expiration time for all of the insurer’s debt.
Options can be used as a way to price managerial flexibility to abandon, expand, contract, defer, or extend projects. This approach is only valid when there is the possibility that assets could be purchased at less than their fair value, and the firm has exclusive access to the opportunity at a fixed price. (A future opportunity to purchase assests at market prices has no value.) Goldfarb provides an example in which an insurance company is presented with a new business opportunity, with the following characteristics:This can be valued as a European call option, expiring in 3 years, with a current asset value of $500M and a strike price of $500M. The value of this option can be calculated using the Black-Scholes formula:
A = 500000000
I = 500000000
sigma = 0.2
T = 3
r = 0.0455
d1 = (log(A/I) + T * (r + sigma^2/2)) / sqrt(T) / sigma
d2 = d1 - sigma * sqrt(T)
option.value = A * pnorm(d1) - I * exp(-r*T) * pnorm(d2)
option.value
## [1] 101141917
Therefore, we can add $101.1M to the value of the firm to reflect the value attributed to the flexibility associated with this project. Potential drawbacks to this approach include: