library(tidyverse)
library(scales)
<- function(RF, ER_vector, CP_vector, G2, PV) {
solve_for_R
# Calculate cash flow vector
<- ER_vector * CP_vector
CF_vector
# Define the objective function
<- function(R) {
objective_function # This is effectively two-stage dividend discount model except the initial stage is explicated
# such that there exists no G1 and G2 refers to the subsequent period of growth
<- sum(CF_vector[1:5] / (1 + R)^(1:5)) + CF_vector[6] / ((R - G2) * (1 + R)^5)
PV_calculated return((PV - PV_calculated)^2)
}
# Use the optim function to minimize the objective function
<- optim(par = RF, fn = objective_function, method = "Brent", lower = -1, upper = 2)
result
return(result$par)
}
<- 0.04 # I have rounded his riskfree rate of 3.97% to 4.00%
RF <- c(217.8, 245.2, 273.7, 295.1, 308.9, 324.9) # A. Damodaran's earnings vector
ER_vector <- c(0.84, 0.82, 0.80, 0.78, 0.77, 0.77) # Cash payout ratios
CP_vector <- 0.04 # His model sets the stable growth equal to the RF rate
G2 <- 4600 # I rounded 4588.96 to 4,600
PV
<- solve_for_R(RF, ER_vector, CP_vector, G2, PV)
implied_equity <- implied_equity - RF
implied_ERP
# Number of simulations
<- 10000
n_simulations <- 0.10 # Arbitrarily suggesting that COV of 10% is tight
coeff_variation
# Assumed means and standard deviations for inputs
<- RF; sd_RF <- RF * coeff_variation
mean_RF <- ER_vector; sd_ER <- ER_vector * coeff_variation
mean_ER <- CP_vector; sd_CP <- CP_vector * coeff_variation
mean_CP <- G2; sd_G2 <- G2 * coeff_variation
mean_G2 <- PV; sd_PV <- PV * coeff_variation
mean_PV
# MC simulation
set.seed(379)
<- replicate(n_simulations,
R_values solve_for_R(
# RF = rnorm(1, mean_RF, sd_RF),
RF = RF,
ER_vector = rnorm(6, mean_ER, sd_ER),
CP_vector = rnorm(6, mean_CP, sd_CP),
G2 = rnorm(1, mean_G2, sd_G2),
PV = PV
)
)
# Histogram to visualize the distribution of R values
<- R_values[R_values > 0]
R_values <- R_values - RF
ERP_values <- mean(ERP_values)
ERP_values_mean <- as_data_frame(ERP_values)
ERP_values_df
%>% ggplot(aes(value)) +
ERP_values_df geom_histogram(color = "darkblue", fill = "lightblue") +
geom_vline(aes(xintercept = ERP_values_mean), color = "darkgreen", size = 1.5) +
scale_x_continuous(labels = percent_format(0.01)) +
labs(title = "Implied equity risk premium, ERP (n = 10,000 sims)",
subtitle = "Under tight assumption dispersion (CV = σ/μ =10%). Green vertical line is the mean.",
y = "Count") +
# xlab("X label") +
# ylab("Count") +
theme_classic() +
theme(axis.title = element_blank(),
axis.text = element_text(size = 12, face = "bold"))
The following implements the implied ERP approach in Professor Damodaran’s post on the The Price of Risk. My intention is to briefly explore its sensitivity to assumptions.
Quick check on the distribution:
library(moments)
skewness(ERP_values_df$value)
[1] 0.08903814
kurtosis(ERP_values_df$value)
[1] 2.997992
<- c(0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 0.75, 0.9, 0.95, 0.975, 0.99)
quantiles_v quantile(ERP_values_df$value, probs = quantiles_v)
1% 2.5% 5% 10% 25% 50% 75%
0.03041180 0.03248300 0.03433620 0.03649075 0.04004356 0.04410500 0.04832614
90% 95% 97.5% 99%
0.05209407 0.05447292 0.05638444 0.05881702
What is the relationship between the sustainable growth rate, G2, and the ERP?
<- seq(from = 0.02, to = 0.06, by = 0.001)
G2_values <- map_dbl(G2_values, function(G2) {
R_values solve_for_R(
RF = RF,
ER_vector = ER_vector,
CP_vector = CP_vector,
G2 = G2,
PV = PV
)
})
<- R_values - RF
ERP_values
<- tibble(
G_vs_ERP G2 = G2_values,
ERP = ERP_values
)
%>% ggplot(aes(x = G2, y = ERP)) +
G_vs_ERP geom_point() +
coord_cartesian(ylim = c(.02, .08)) +
labs(title = "Implied ERP as function of sustainable growth rate, G2",
subtitle = "Unlike prior/next visualization, predicted vectors are not randomized")
And just for fun, let’s add randomness to the earnings and cash payout vectors:
<- seq(from = 0.02, to = 0.06, by = 0.001)
G2_values
<- map(G2_values, function(G2) {
R_values replicate(30, {
solve_for_R(
RF = RF,
ER_vector = rnorm(6, mean_ER, sd_ER),
CP_vector = rnorm(6, mean_CP, sd_CP),
G2 = G2,
PV = PV
- RF # subtracting RF here inside replicat
)
})
})
<- tibble(
df G2 = G2_values,
ERP = R_values
%>% unnest()
)
<- lm(ERP ~ G2, data = df)
model_line <- summary(model_line)$r.squared
rsq <- sprintf("R^2 = %.2f", rsq)
label_R2
%>% ggplot(aes(x = G2, y = ERP)) +
df geom_point() +
coord_cartesian(ylim = c(.02, .08)) +
geom_smooth(method = "lm", se = TRUE, color = "blue") +
labs(title = "Restores 10% CV randomness to earnings and payout vectors") +
annotate("text", x=0.025, y=0.065, label=label_R2, fontface="bold", hjust=0)
# geom_text(aes(label = label_R2))