# Load packages
# Core
library(tidyverse)
library(tidyquant)
Revise the code below.
symbols <- c("UNH", "LLY", "JNJ", "PFE", "MRK")
prices <- tq_get(x = symbols,
get = "stock.prices",
from = "2000-12-31",
to = "2025-06-11")
asset_returns_tbl <- prices %>%
group_by(symbol) %>%
tq_transmute(select = adjusted,
mutate_fun = periodReturn,
period = "monthly",
type = "log") %>%
slice(-1) %>%
ungroup() %>%
set_names(c("asset", "date", "returns"))
Revise the code for weights.
# symbols
symbols <- asset_returns_tbl %>% distinct(asset) %>% pull()
symbols
## [1] "JNJ" "LLY" "MRK" "PFE" "UNH"
# weights
weights <- c(0.3, 0.25, 0.20, 0.13, 0.12)
weights
## [1] 0.30 0.25 0.20 0.13 0.12
w_tbl <- tibble(symbols, weights)
w_tbl
## # A tibble: 5 × 2
## symbols weights
## <chr> <dbl>
## 1 JNJ 0.3
## 2 LLY 0.25
## 3 MRK 0.2
## 4 PFE 0.13
## 5 UNH 0.12
portfolio_returns_tbl <- asset_returns_tbl %>%
tq_portfolio(assets_col = asset,
returns_col = returns,
weights = w_tbl,
rebalance_on = "months",
col_rename = "returns")
portfolio_returns_tbl
## # A tibble: 293 × 2
## date returns
## <date> <dbl>
## 1 2001-02-28 0.0181
## 2 2001-03-30 -0.0633
## 3 2001-04-30 0.0746
## 4 2001-05-31 -0.0211
## 5 2001-06-29 -0.0516
## 6 2001-07-31 0.0677
## 7 2001-08-31 -0.0268
## 8 2001-09-28 0.0323
## 9 2001-10-31 -0.00428
## 10 2001-11-30 0.0495
## # ℹ 283 more rows
# Get mean portfolio return
mean_port_return <- mean(portfolio_returns_tbl$returns)
mean_port_return
## [1] 0.006613693
# Get standard deviation of portfolio returns
stddev_port_return <- sd(portfolio_returns_tbl$returns)
stddev_port_return
## [1] 0.04269281
# Construct a normal distribution
simulated_monthly_returns <- rnorm(120, mean_port_return, stddev_port_return)
simulated_monthly_returns
## [1] 0.0373071048 0.0695062937 0.0200155577 -0.0478303377 0.0308181215
## [6] 0.0051529833 0.0342871770 0.0648030275 -0.0266919465 -0.0066777267
## [11] 0.0757438211 0.0622701445 0.0568764512 0.0477924465 -0.0548640413
## [16] 0.0227610663 0.0969714675 0.0456995892 -0.0082245374 -0.0646131937
## [21] -0.0456965473 -0.0608850485 -0.0236562699 -0.0036044922 0.0462678215
## [26] -0.0367311819 -0.0533563860 -0.0914199847 -0.0269468421 0.0139145097
## [31] -0.0496054191 0.0632986104 -0.0037795271 0.0912453411 0.0122206671
## [36] 0.0106407704 -0.0186782318 0.0566637520 0.0290115146 0.0670794800
## [41] -0.0324800164 0.0558990673 -0.0094100537 0.0466126864 0.0226367651
## [46] 0.0566751210 0.0932165826 -0.0362111190 0.0166780299 0.0844173002
## [51] 0.0277568746 0.0241420683 0.0442178868 -0.0207610204 -0.0630135532
## [56] 0.0846165106 0.0592659988 0.0682518659 0.0646254276 0.0139034800
## [61] -0.0466900709 -0.0141614927 -0.0561805795 0.0260703844 -0.0262718658
## [66] -0.0826922755 -0.0184779044 0.0476726785 0.0062847757 0.1079801652
## [71] 0.0001456179 0.0272207866 -0.0330306801 0.0085659835 -0.0025796686
## [76] 0.0287747143 -0.0172585804 -0.0094856722 0.0443898430 -0.0053161342
## [81] -0.0539379055 -0.0017325324 0.0051797471 0.1089114825 -0.0013172914
## [86] 0.0947706009 0.0395205589 0.0673130124 -0.0007264524 0.0170994926
## [91] -0.0019303013 0.0283529078 0.0431703906 0.0310322667 -0.0322235845
## [96] 0.0157846263 -0.0474380193 0.1074461464 -0.0509222216 0.0051980217
## [101] -0.0369486463 -0.0436060159 0.0118111805 0.0738618023 -0.0075977076
## [106] -0.0029953136 0.0113654987 -0.0356535004 -0.0330746878 -0.0423341200
## [111] 0.0239360743 -0.1166659059 -0.0568957854 -0.0169779658 0.0192347750
## [116] 0.0314872233 -0.0461656389 0.0131866191 0.0354387678 0.0699062137
# Add a dollar
simulated_returns_add_1 <- tibble(returns = c(1, 1 + simulated_monthly_returns))
simulated_returns_add_1
## # A tibble: 121 × 1
## returns
## <dbl>
## 1 1
## 2 1.04
## 3 1.07
## 4 1.02
## 5 0.952
## 6 1.03
## 7 1.01
## 8 1.03
## 9 1.06
## 10 0.973
## # ℹ 111 more rows
# Calculate the cumulative growth of a dollar
simulated_growth <- simulated_returns_add_1 %>%
mutate(growth = accumulate(returns, function(x, y) x*y)) %>%
select(growth)
simulated_growth
## # A tibble: 121 × 1
## growth
## <dbl>
## 1 1
## 2 1.04
## 3 1.11
## 4 1.13
## 5 1.08
## 6 1.11
## 7 1.12
## 8 1.15
## 9 1.23
## 10 1.20
## # ℹ 111 more rows
# Check the compound annual growth rate
cagr <- ((simulated_growth$growth[nrow(simulated_growth)]^(1/10)) - 1) * 100
cagr
## [1] 11.76057
simulate_accumulation <- function(initial_value, N, mean_return, sd_return) {
# Add a dollar
simulated_returns_add_1 <- tibble(returns = c(initial_value, 1 + rnorm(N, mean_return, sd_return)))
# Calculate the cumulative growth of a dollar
simulated_growth <- simulated_returns_add_1 %>%
mutate(growth = accumulate(returns, function(x, y) x*y)) %>%
select(growth)
return(simulated_growth)
}
simulate_accumulation(initial_value = 100, N = 240, mean_return = 0.005, sd_return = 0.01) %>% tail()
## # A tibble: 6 × 1
## growth
## <dbl>
## 1 425.
## 2 436.
## 3 440.
## 4 440.
## 5 448.
## 6 450.
# Create a Vector of 1s as a Starting Point
sims <- 51
starts <- rep(100, sims) %>%
set_names(paste0("sim", 1:sims))
starts
## sim1 sim2 sim3 sim4 sim5 sim6 sim7 sim8 sim9 sim10 sim11 sim12 sim13
## 100 100 100 100 100 100 100 100 100 100 100 100 100
## sim14 sim15 sim16 sim17 sim18 sim19 sim20 sim21 sim22 sim23 sim24 sim25 sim26
## 100 100 100 100 100 100 100 100 100 100 100 100 100
## sim27 sim28 sim29 sim30 sim31 sim32 sim33 sim34 sim35 sim36 sim37 sim38 sim39
## 100 100 100 100 100 100 100 100 100 100 100 100 100
## sim40 sim41 sim42 sim43 sim44 sim45 sim46 sim47 sim48 sim49 sim50 sim51
## 100 100 100 100 100 100 100 100 100 100 100 100
# Simulate
# For Reproducible Research
set.seed(1234)
monte_carlo_sim_51 <- starts %>%
# Simulate
map_dfc(.x = .,
.f = ~simulate_accumulation(initial_value = .x,
N = 240,
mean_return = mean_port_return,
sd_return = stddev_port_return)) %>%
# Add Column Month
mutate(month = 1:nrow(.)) %>%
select(month, everything()) %>%
# Rearrange Column Names
set_names(c("month", names(starts))) %>%
# Transform to Long Form
pivot_longer(cols = -month, names_to = "sim", values_to = "growth")
# Find quantiles
monte_carlo_sim_51 %>%
group_by(sim) %>%
summarise(growth = last(growth)) %>%
ungroup() %>%
pull(growth) %>%
quantile(probs = c(0.3, 0.25, 0.20, 0.13, 0.12)) %>%
round(2)
## 30% 25% 20% 13% 12%
## 321.92 301.18 237.19 194.95 180.84
monte_carlo_sim_51 %>%
ggplot(aes(x = month, y = growth, colour = sim)) +
geom_line() +
theme(legend.position = "none") +
theme(plot.title = element_text(hjust = 0.5)) +
labs(title = "Simulating Growth of $100 Over 240 Months")
Line Plot With Max, Median, and Min
# Step 1 Summarize Data into Max, Median, and Min of Last Value
sim_summary <- monte_carlo_sim_51 %>%
group_by(sim) %>%
summarise(growth = last(growth)) %>%
ungroup() %>%
summarise(max = max(growth),
median = median(growth),
min = min(growth))
sim_summary
## # A tibble: 1 × 3
## max median min
## <dbl> <dbl> <dbl>
## 1 1281. 467. 99.1
# Step 2 Plot
monte_carlo_sim_51 %>%
# Filter for Max, Median, and Min Sim
group_by(sim) %>%
filter(last(growth) == sim_summary$max |
last(growth) == sim_summary$median |
last(growth) == sim_summary$min) %>%
ungroup() %>%
# Plot
ggplot(aes(x = month, y = growth, colour = sim)) +
geom_line() +
theme(legend.position = "none") +
theme(plot.title = element_text(hjust = 0.5)) +
theme(plot.subtitle = element_text(hjust = 0.5)) +
labs(title = "Simulating Growth of $100 Over 240 Months",
subtitle = "Maximum, Median, and Minimum Simulation")