Quantitative Analytics: Optimal Portfolio Allocation

From: https://lf0.com/post/portfolio-optimisation-model/portfolio-optimisation-r/

Introduction:

The literature in portfolio optimisation has been around for decades. In this post I cover a number of traditional portfolio optimisation models. The general aim is to select a portfolio of assets out of a set of all possible portfolios being considered with a defined objective function.

The data:

The data is collected using the tidyquant() package’s tq_get() function. I then convert the daily asset prices to daily log returns using the periodReturn function from the quantmod() package. Next I construct lists of 6 months worth of daily returns using the rolling_origin() function from the rsample() package. The objective is to compute on a rolling basis the 6 month mean returns mus and the 6 month covariance matrices Sigmas on the training sets (i.e. 6 months) and apply them on the test sets (i.e. 1 month later) – monthly rebalancing.

Just as with the returns data, the same is applied to the monthly prices data.

start_date <- "2013-01-01"
end_date <- "2017-08-31"
symbols <- c("AAPL", "ABBV", "A",  "APD", "AA", "CF", "NVDA", "HOG", "WMT", "AMZN"
            #,"MSFT", "F", "INTC", "ADBE", "AMG", "AKAM", "ALB", "ALK"
            )

portfolio_prices <- tq_get(
  symbols,
  from = start_date,
  to = end_date,
) %>% 
  select(symbol, date, adjusted)


portfolio_monthly_returns <- portfolio_prices %>% 
  group_by(symbol) %>% 
  tq_transmute(
    select = adjusted,
    mutate_fun = periodReturn,
    period = "daily",                              
    type = "log",
  ) %>% 
  pivot_wider(names_from = symbol, values_from = daily.returns) %>% 
  mutate(year_month = yearmonth(date)) %>% 
  nest(-year_month) %>% 
  rolling_origin(
    initial = 6,
    assess = 1,
    skip = 0,
    cumulative = FALSE)


portfolio_monthly_prices <- portfolio_prices %>%
  pivot_wider(names_from = symbol, values_from = adjusted) %>% 
  mutate(year_month = yearmonth(date)) %>% 
  nest(-year_month) %>% 
  rolling_origin(
    initial = 6,
    assess = 1,
    skip = 0,
    cumulative = FALSE)

ListNamesDates <- map(portfolio_monthly_returns$splits, ~assessment(.x) %>%
                        select(year_month)) %>%
  plyr::ldply(., data.frame) %>% 
  pull(year_month)

#########

# Goal is to define the mean and covariance matrix on the training sets and apply them on the test sets - monthly rebalancing

mus <- map(portfolio_monthly_returns$splits, ~ analysis(.x) %>% 
             unnest(data) %>%
             select(-year_month, -date) %>%
             colMeans) %>%
  setNames(c(ListNamesDates))

Sigmas <- map(portfolio_monthly_returns$splits, ~ analysis(.x) %>%
                unnest() %>%
                tk_xts(., date_var = date) %>%
                cov(.)) %>% 
  setNames(c(ListNamesDates))

Price and Returns data

The returns data for the first split looks like the following:

AAPLABBVAAPDAACFNVDAHOGWMTAMZN
0.0000000000.0000000000.0000000000.00000000000.0000000000.0000000000.00000000000.0000000000.00000000000.0000000000
-0.012702708-0.0082913310.003575412-0.00350024170.008859253-0.0047400370.0007860485-0.020819530-0.00637467480.0045367882
-0.028249939-0.0127133950.0195554110.01335153760.0207317970.0221520330.0324601827-0.0055298640.00377200980.0025886574
-0.0058994280.002033327-0.007259372-0.0009230752-0.017429792-0.003753345-0.02932282860.006958715-0.00960296060.0352948721
0.002687379-0.022004791-0.0080226220.00184517810.000000000-0.014769161-0.0221704307-0.0030639360.0027737202-0.0077780140
-0.0157522460.0056207920.0266496040.0133906716-0.0022001090.034376623-0.02267303630.038724890-0.0002916231-0.0001126237

The statistics

The Mus (mean returns) data looks like:

x
AAPL -0.0025241
ABBV 0.0014847
A 0.0002314
APD 0.0006546
AA -0.0010700
CF -0.0013681
NVDA 0.0008864
HOG 0.0008061
WMT 0.0006895
AMZN 0.0006147

The Sigmas (covariance matrix) data looks like:

AAPL ABBV A APD AA CF NVDA HOG WMT AMZN
AAPL 0.0004166 0.0000220 0.0000112 0.0000388 0.0000528 0.0000277 0.0000408 0.0000116 -0.0000038 -0.0000366
ABBV 0.0000220 0.0003128 0.0000490 0.0000393 0.0000137 0.0000472 0.0000511 0.0000732 0.0000258 0.0000295
A 0.0000112 0.0000490 0.0002061 0.0000720 0.0000741 0.0000885 0.0000930 0.0001175 0.0000371 0.0001139
APD 0.0000388 0.0000393 0.0000720 0.0000993 0.0000523 0.0000687 0.0000578 0.0000744 0.0000107 0.0000511
AA 0.0000528 0.0000137 0.0000741 0.0000523 0.0001485 0.0000874 0.0000685 0.0000674 -0.0000012 0.0000383
CF 0.0000277 0.0000472 0.0000885 0.0000687 0.0000874 0.0002271 0.0000706 0.0000900 -0.0000112 0.0000606
NVDA 0.0000408 0.0000511 0.0000930 0.0000578 0.0000685 0.0000706 0.0002092 0.0000706 0.0000127 0.0000853
HOG 0.0000116 0.0000732 0.0001175 0.0000744 0.0000674 0.0000900 0.0000706 0.0002393 0.0000214 0.0000895
WMT -0.0000038 0.0000258 0.0000371 0.0000107 -0.0000012 -0.0000112 0.0000127 0.0000214 0.0000682 0.0000236
AMZN -0.0000366 0.0000295 0.0001139 0.0000511 0.0000383 0.0000606 0.0000853 0.0000895 0.0000236 0.0003118