#' Simulate Portfolios
#'
#' Simulate random portfolios and calculate risk, return and sharpe ratio
#' @param prices Data frame of daily asset prices
#' @param n_portfolios Number of portfolios to be simulated
#' @param risk_measure Default standard deviation. Other possible value-at-risk and expected shortfall
#' @param method Either historical or normal distribution method if the risk measure is either value-at-risk or expected shortfall then
#' @param significance Significance level for value-at-risk and expected shortfall. Deafult set to 0.05
#' @param risk_free Risk free interest rate to calculate sharpe ratio
#' @param plot If TRUE plot portfolios
#'
#' @return Portfolios with minimum risk and max sharpe ratio.
#' @export
#'
#' @examples
#' portfolio_simulations(close_prices, 1e3, risk_measure = 'standard deviation')
#' portfolio_simulations(close_prices, 1e3, risk_measure = 'value-at-risk', method = 'historical')
#' portfolio_simulations(close_prices, 1e3, risk_measure = 'value-at-risk', method = 'normal')
#' portfolio_simulations(close_prices, 1e3, risk_measure = 'expected shortfall', method = 'historical')
#' portfolio_simulations(close_prices, 1e3, risk_measure = 'expected shortfall', method = 'normal')
portfolio_simulations <- function(prices
,n_portfolios = 1e3
,risk_measure = c('standard deviation'
,'value-at-risk'
,'expected shortfall')
,method = c('historical', 'normal')
,significance = 0.05
,risk_free = 0.01
,plot = TRUE) {
results <- list()
returns <- as.data.frame(
sapply(
as.data.frame(
sapply(dplyr::select(prices, where(is.numeric))
,log))
,diff
)
)
# Calculate annualized asset parameters
returns_mean <- (colMeans(returns) + 1)^252 - 1
returns_cov <- cov(returns)*252
returns_std <- sqrt(diag(returns_cov))
# Initialize weights and df for portfolio parameters ##
weights <- matrix(nrow = n_portfolios
,ncol = dim(returns)[2])
portfolios <- data.frame(return = rep(0, n_portfolios)
,risk = rep(0, n_portfolios)
,sharpe = rep(0, n_portfolios))
# Simulation
for (i in 1:n_portfolios) {
random_weights <- runif(ncol(returns))
random_weights <- random_weights / sum(random_weights)
weights[i,] <- random_weights
p_returns <- portfolio_returns(prices, random_weights)
portfolios$return[i] <- random_weights %*% returns_mean
portfolios$risk[i] <- switch(
risk_measure
,`standard deviation` = sqrt(t(random_weights) %*% (returns_cov %*% random_weights))
,`value-at-risk` = -value_at_risk(p_returns
,method = method
,significance = significance
,plot = FALSE)$VaR
,`expected shortfall` = -value_at_risk(p_returns
,method = method
,significance = significance
,plot = FALSE)$ES
)
portfolios$sharpe[i] <- (portfolios$return[i] - risk_free) / portfolios$risk[i]
}
max_sharpe <- round(100 * weights[which.max(portfolios$sharpe),], 2)
names(max_sharpe) <- names(returns)
results$max_sharpe <- max_sharpe
min_risk <- round(100 * weights[which.min(portfolios$risk),], 2)
names(min_risk) <- names(returns)
results$min_risk <- min_risk
if (plot == TRUE) {
ggplot(portfolios) +
geom_point(aes(x = risk
,y = return
,color = sharpe)) +
theme_bw() +
labs(x = risk_measure
,y = 'expected returns'
,title = paste0('Simulation of ', n_portfolios, ' portfolios'))
}
return(results)
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.