Overview

Indentifying stocks in portfolio as well as weight of each stock.

stocks <-  c("META","AAPL","MSFT","GOOG", "AMZN")
weights <-  c(0.4, 0.15, 0.1, 0.1, 0.25)

Using a for loop to pull and bind the closing prices of each stock using quantmod function “getSymbols”.

portfolioclose <-  NULL
for(stock in stocks) {
  portfolioclose <- cbind(portfolioclose,
                         getSymbols(stock, src = "yahoo", periodicity = 'daily', from = '2020-01-01', auto.assign = FALSE)[,4])
}
sp500price <- getSymbols("SPY", src = "yahoo", periodicity = 'daily', from = '2020-01-01', auto.assign = FALSE)[,4]

Utilize ROC (Rate of Change Function) to calculate returns of each individual stock as well as our benchmark.

portfolioreturns <-  na.omit(ROC(portfolioclose))
sp500returns <- na.omit(ROC(sp500price))
head(portfolioreturns)
##              META.Close   AAPL.Close   MSFT.Close    GOOG.Close   AMZN.Close
## 2020-01-03 -0.005305309 -0.009769603 -0.012529922 -0.0049193493 -0.012213314
## 2020-01-06  0.018658447  0.007936666  0.002581482  0.0243581503  0.014775871
## 2020-01-07  0.002161310 -0.004714140 -0.009159579 -0.0006242443  0.002089436
## 2020-01-08  0.010086962  0.015958275  0.015802857  0.0078495086 -0.007839287
## 2020-01-09  0.014209511  0.021018372  0.012415580  0.0109839096  0.004787695
## 2020-01-10 -0.001100034  0.002258152 -0.004637797  0.0069485075 -0.009455156
head(sp500returns)
##               SPY.Close
## 2020-01-03 -0.007601048
## 2020-01-06  0.003807793
## 2020-01-07 -0.002815738
## 2020-01-08  0.005315384
## 2020-01-09  0.006757764
## 2020-01-10 -0.002881854

Use Return.portfolio function to aggregate overall return of the portfolio after taking into account the weight of each stock.

pf_Return <- Return.portfolio(portfolioreturns, weights = weights)
head(pf_Return)
##            portfolio.returns
## 2020-01-03     -0.0083858197
## 2020-01-06      0.0150565118
## 2020-01-07     -0.0002748319
## 2020-01-08      0.0068135016
## 2020-01-09      0.0124065634
## 2020-01-10     -0.0021667063

Calculating Beta and Jensen’s Alpha of our returns.

CAPM.beta(pf_Return, sp500returns, 0.0382/252)
## [1] 1.179939
SimulatedReturn1 <- CAPM.jensenAlpha(pf_Return, sp500returns, 0.0382/252)
SimulatedReturn1
## [1] 0.002288992

Calendarize Returns for clarity.

Calendarized <- table.CalendarReturns(pf_Return)
Calendarized
##       Jan Feb  Mar  Apr  May  Jun  Jul  Aug  Sep  Oct  Nov  Dec
## 2020 -0.8 0.9 -0.1  3.6  0.6  2.4  5.1  0.7  0.4 -4.8 -0.3 -0.1
## 2021 -2.3 0.9  1.7 -0.9 -0.5 -0.5 -2.4  0.0 -0.5  0.2 -1.8 -1.4
## 2022  3.0 0.2 -2.1 -6.6  0.8 -2.0  3.6 -0.1 -1.8 -2.2  5.5 -0.1
## 2023  1.7 0.8  1.7 -0.4 -0.2  1.8 -0.4  0.6 -0.2  0.0 -0.6 -0.7
## 2024 -3.0 1.2 -0.7 -2.0 -0.2 -2.2  1.7 -0.7   NA   NA   NA   NA
##      portfolio.returns
## 2020               7.7
## 2021              -7.2
## 2022              -2.4
## 2023               4.0
## 2024              -5.9

Based on this simulation, having a portfolio of Meta weighted at 40%, Apple at a weight of 15%, Microsoft at a weight of 10%, Alphabet at a weight of 10%, and Amazon at a weight of 25% would have been slightly profitable, with a 0.22% return.

Plot Portfolio Returns and Benchmark for Visualization

chartSeries(portfolioclose, theme = "white") 

chartSeries(sp500price,theme = "white") 

Find Optimal Weights for Portfolio

portf  <- portfolio.spec(assets = colnames(portfolioreturns))

portf <- add.constraint(portf, type ="full_investment")
portf <- add.constraint(portf, type ="box", min = 0.10, max = 0.5)
portf <- add.objective(portf, type = "return", name = "mean")
portf <- add.objective(portf, type = "risk", name = "StdDev")

optimum <-  optimize.portfolio(
  portfolioreturns,
  portf,
  optimize_method = "ROI",
  trace = TRUE
  )
optimum
## ***********************************
## PortfolioAnalytics Optimization
## ***********************************
## 
## Call:
## optimize.portfolio(R = portfolioreturns, portfolio = portf, optimize_method = "ROI", 
##     trace = TRUE)
## 
## Optimal Weights:
## META.Close AAPL.Close MSFT.Close GOOG.Close AMZN.Close 
##        0.1        0.5        0.2        0.1        0.1 
## 
## Objective Measure:
##      mean 
## 0.0008426 
## 
## 
##  StdDev 
## 0.01869
chart.Weights(optimum)

He we used a simple mean variance optimization where we try to maximize our return while minimizing variance. Our constraints were a full investment (100% invested at all times), and weight restriction (minimum 10% of portfolio, maximum 50% of our portfolio).

Backtest New Weights to Measure Optimized Performance

weights2 = c(0.1, 0.5, 0.2, 0.1, 0.1)

pf_Return2 <- Return.portfolio(portfolioreturns, weights = weights2)
CAPM.beta(pf_Return2, sp500returns, 0.0382/252)
## [1] 1.172872
SimulatedReturn2 <- CAPM.jensenAlpha(pf_Return2, sp500returns, 0.0382/252)
SimulatedReturn2
## [1] 0.05421965

With this is simple mean variance optimization, we were able to increase our return by 5.19%.

Plot Returns of Initial Strategy, Optimized Strategy, and Benchmark S&P 500

overall <- cbind(pf_Return2, pf_Return, sp500returns)
charts.PerformanceSummary(overall, main = "Profit/Loss")