# Load packages
# Core
library(tidyverse)
library(tidyquant)
# Source function
source("../00_scripts/simulate_accumulation.R")
Revise the code below.
symbols <- c("SPY", "EFA", "IJS", "EEM", "AGG")
prices <- tq_get(x = symbols,
get = "stock.prices",
from = "2012-12-31",
to = "2022-12-31")
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] "AGG" "EEM" "EFA" "IJS" "SPY"
# weights
weights <- c(0.25, 0.25, 0.2, 0.2, 0.1)
weights
## [1] 0.25 0.25 0.20 0.20 0.10
w_tbl <- tibble(symbols, weights)
w_tbl
## # A tibble: 5 × 2
## symbols weights
## <chr> <dbl>
## 1 AGG 0.25
## 2 EEM 0.25
## 3 EFA 0.2
## 4 IJS 0.2
## 5 SPY 0.1
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: 120 × 2
## date returns
## <date> <dbl>
## 1 2013-01-31 0.0204
## 2 2013-02-28 -0.00239
## 3 2013-03-28 0.0121
## 4 2013-04-30 0.0174
## 5 2013-05-31 -0.0128
## 6 2013-06-28 -0.0247
## 7 2013-07-31 0.0321
## 8 2013-08-30 -0.0224
## 9 2013-09-30 0.0511
## 10 2013-10-31 0.0301
## # … with 110 more rows
# Get mean portfolio return
mean_port_return <- mean(portfolio_returns_tbl$returns)
mean_port_return
## [1] 0.003637758
# Get standard deviation of portfolio returns
stddev_port_return <- sd(portfolio_returns_tbl$returns)
stddev_port_return
## [1] 0.03421552
No need
# Create a vector of 1s as a starting point
sims <- 51
starts <- rep(100, sims) %>%
set_names(paste("sim", 1:sims))
starts
## sim 1 sim 2 sim 3 sim 4 sim 5 sim 6 sim 7 sim 8 sim 9 sim 10 sim 11
## 100 100 100 100 100 100 100 100 100 100 100
## sim 12 sim 13 sim 14 sim 15 sim 16 sim 17 sim 18 sim 19 sim 20 sim 21 sim 22
## 100 100 100 100 100 100 100 100 100 100 100
## sim 23 sim 24 sim 25 sim 26 sim 27 sim 28 sim 29 sim 30 sim 31 sim 32 sim 33
## 100 100 100 100 100 100 100 100 100 100 100
## sim 34 sim 35 sim 36 sim 37 sim 38 sim 39 sim 40 sim 41 sim 42 sim 43 sim 44
## 100 100 100 100 100 100 100 100 100 100 100
## sim 45 sim 46 sim 47 sim 48 sim 49 sim 50 sim 51
## 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())%>%
# Rename column names
set_names(c("month", names(starts))) %>%
# Transform to long form
pivot_longer(cols = -month, names_to = "sim", values_to = "growth")
monte_carlo_sim_51
## # A tibble: 12,291 × 3
## month sim growth
## <int> <chr> <dbl>
## 1 1 sim 1 100
## 2 1 sim 2 100
## 3 1 sim 3 100
## 4 1 sim 4 100
## 5 1 sim 5 100
## 6 1 sim 6 100
## 7 1 sim 7 100
## 8 1 sim 8 100
## 9 1 sim 9 100
## 10 1 sim 10 100
## # … with 12,281 more rows
# Find quantiles
monte_carlo_sim_51 %>%
group_by(sim) %>%
summarise(growth = last(growth)) %>%
ungroup() %>%
pull(growth) %>%
quantile(probs = c(0, 0.25, 0.5, 0.75, 1)) %>%
round(2)
## 0% 25% 50% 75% 100%
## 68.90 168.20 237.59 332.96 539.07
# Step 1: Summarize data into max, median and min if 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 539. 238. 68.9
# 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, color = 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")
Based on the results of the Monte Carlo’s 51 simulations, there would be a reasonable expectation that 100 dollars could grow to around 238 dollars in twenty years. In the best case scenario, the simulations had maximum growth on the original 100 dollar investment to reach $539. Alternatively, the worst-case projections were that the original investment could deteriorate to 68.9 dollars. I expanded the data’s time frame to ten years, so that both bear and bull market conditions would have an influence on the simulation results. As such, the forecasted growth of 138 dollars appears to be reasonable without acknowledging the simulations limitations. However, if we were to remove the assumed normal distribution of returns, the results would likely not be as profitable. Furthermore, while Monte Carlo simulations can be useful for estimating the likelihood of a gain or loss, these simulations use averages to predict what is most likely based on these averages. Averages can be insightful for quickly interpreting data, but if the data varies drastically between extremes, than this may lead to inaccuracies that will misrepresent real world circumstances and the investors expectations may be thrown off.