This report aims to apply a robust statistical framework to a standard portfolio optimization problem. Traditional methods of estimating expected returns (mean) and volatility (stanard deviation) are straightforward and easy to interpret. However, sample estimates are arguably inaccurate in estimating the center and (magnitiude of) dispersion due to extreme observations (outliers), nonstationarity, and nonconstant conditional volatility (etc.). Yet, since the inception of modern portfolio theory in the 1950’s (see Markowitz(1952,1959)), several statistical methods have been developed to derive more accurate measures of the properties of investment portfolios.
A common reoccuring theme ```{r setup, include=FALSE} knitr::opts_chunk$set(echo = TRUE) in this report is the issue of efficiently trading off expected return and risk. Modern portfolio theory addresses two principles: investors want to maximize expected return while minimizing risk, which can be defined as standard deviation of returns although it is defined differently in alternative settings. The allocation of capital into different assets of varying risk & expected returns is the issue moder portfolio theory has worked to solve. This report applies some of the methodologies developed to create optimal efficient mean-variance portfolios.
First, an exploratory data analysis (EDA) framework is applied to a basked of stocks and indexes, followed by computations of robust sample portfolio statistics. These parameters will then be assessed by a standard resampling with replacement or bootstrap method. Once the portfolio’s statistics have been estimated, optimal portfolios are derived. The CAPM model is applied to estimate individual stock, as well as portfolio, betas and expected returns. Lastly, the Treynor-Black model of constructing efficient active portfolios is applied and analyzed against relaive indexes and other portfolios.
This report focuses on five stocks to build an efficient and optimal mean-variance (MV) portfolio. The five stocks include BlackRock (Financial), IBM (Technology), Costco Wholesale (Consumer Defensive), Royal Gold (Basic Materials), and Alexandria Real Estate Equities (Real Estate). The SPDR S&P 500 ETF (SPY) is also loaded in for performance comparison.
The quantmod package is loaded in and used to download the data of RGLD, ARE, BLK, IBM, COST, and SPY. The historical sample period for this analysis runs from December 2013 to December 2018 on a monthly frequency.
library(quantmod)
library(timeSeries)
library(fPortfolio)
fin_6310 <- new.env() # Create new environment to store compuations
tickers <- c('RGLD', 'BLK', 'ARE', 'IBM', 'COST', 'SPY')
stock_prices_data <- getSymbols.yahoo(Symbols = tickers, env = fin_6310, return.class = 'xts',
index.class = 'Date', from = '2013-12-01',
to = '2018-12-31', periodicity = 'monthly')
close_prices <- cbind(fin_6310$ARE$ARE.Adjusted, fin_6310$BLK$BLK.Adjusted, fin_6310$COST$COST.Adjusted,
fin_6310$IBM$IBM.Adjusted, fin_6310$RGLD$RGLD.Adjusted, fin_6310$SPY$SPY.Adjusted)
returns_stocks <- removeNA(diff(log(close_prices)))
summary(timeSeries(returns_stocks))
## ARE.Adjusted BLK.Adjusted COST.Adjusted
## Min. :-0.12365 Min. :-0.129378 Min. :-0.12456
## 1st Qu.:-0.01321 1st Qu.:-0.024885 1st Qu.:-0.01994
## Median : 0.01517 Median : 0.007054 Median : 0.01180
## Mean : 0.01265 Mean : 0.005614 Mean : 0.01108
## 3rd Qu.: 0.03205 3rd Qu.: 0.038545 3rd Qu.: 0.04701
## Max. : 0.13818 Max. : 0.168233 Max. : 0.13537
## IBM.Adjusted RGLD.Adjusted SPY.Adjusted
## Min. :-0.270005 Min. :-0.285733 Min. :-0.097991
## 1st Qu.:-0.033346 1st Qu.:-0.081818 1st Qu.:-0.008220
## Median :-0.004016 Median : 0.006333 Median : 0.010242
## Mean :-0.005130 Mean : 0.011520 Mean : 0.006686
## 3rd Qu.: 0.039412 3rd Qu.: 0.077662 3rd Qu.: 0.027124
## Max. : 0.154992 Max. : 0.448803 Max. : 0.091427
Clearly IBM and RGLD display leptokurtic and asymmetric properties due to realized outliers. The tails of the distributions are heavier, i.e. the probability of realized returns are higher in the tail of the distribution than assumed by the normal distribution. The distribution make result from instances of nonconstant volatility or volatility clustering, a common trait of financial time series.
Refer to the correlation plot. BLK and the SPY index show a strong sample pearson correlation (0.806), whereas RGLD and SPY are nearly uncorrelated. This is no surprise considering basic materials are considered a relatively low volatitle, “safe haven” asset. Other pairwise dependencies between the assets show varying levels of magnitude, though no pair shows a negative relationship.
In portfolio management, a significant source of risk to a fund’s AUM (assets under management) is covariance (correlation) risk. Moreso, assets that exhibit tail dependencies are far more risky. When anlayzing the correlation plot, extreme observations in the lower-left and upper-right corners are examples of mutually shared extreme observations. Therefore, if company’s in the same industry are exposed to the same macroeconomic risk factor, there losses could in fact be correlated, resulting in twice as much downside risk if both were held in a portfolio of assets.
When markets begin to realize cumulative downward pressure in prices, stocks that exhibit pairwise dependencies in the left tail put the fund at risk of realizing significant losses. That’s why the covariance (standardized correlation) matrix is an important and fundamental property in portfolio managment and analysis. Similarly, solving optimization problems requires the covariance matrix to be estimated with reasonable accuracy.
library(dygraphs)
library(PerformanceAnalytics)
# Compute Price Weighted Index
Price_Weights <- close_prices[,1:5] / rowSums(close_prices[,1:5])
Price_Weighted_Index <- rowSums(returns_stocks[,1:5] * Price_Weights)
# Track a $10K investment in the index
Price_Weighted_Index[1] <- 10000
for (i in 2:length(Price_Weighted_Index)) {
Price_Weighted_Index[i] <- Price_Weighted_Index[i-1] + (Price_Weighted_Index[i] * Price_Weighted_Index[i-1])
}
fin_6310$PW_Index <- Price_Weighted_Index
# Compute the SPY index of a similar $10K investment.
fin_6310$SPY_Index <- returns_stocks$SPY.Adjusted
fin_6310$SPY_Index[1,] <- 10000
SPY_Index <- as.numeric(fin_6310$SPY_Index)
for (i in 2:length(SPY_Index)) {
SPY_Index[i] <- SPY_Index[i-1] + (SPY_Index[i] * SPY_Index[i-1])
}
fin_6310$SPY_Index <- SPY_Index
# Combine the two index investments and plot
index_frame <- fin_6310$SPY$SPY.Adjusted[-1,]
index_frame$SPY_Index <- SPY_Index
index_frame$PW_Index <- Price_Weighted_Index
index_frame <- index_frame[,-1]
dygraph(index_frame, main = "Performance of $10K Investment in SPY and Price-Weighred Index")
An investment of 10,000 USD in each respective index over the historical period 2013-12-01 to 2018-12-01 yield similar returns. The SPY Index produeces a holding period return (HPR) of 49.10% (gain of 4,914.00 USD), equivalent to 8.32% annualized. Similarly, the price-weighted index of the five stocks yields a 49.5% HPR (gain of 4,948 USD) or 8.40$ annualized. Although the price-weighted index performed slightly better than the SPY, this does not provide credence to the assumption that this allocation strategy is efficient. An investment strategy that allocates capital as a function of relative prices of positions in a portfolio does not consider other important risk factors, namely correlation / covariance risk.
Diving deeper into this question of omptimal capital allocations, we explore the multivariate relationships between the assets and the indexes. Note that the correlation and sample statistics have been recalculated in order to factor in the return series for the price-weighted and SPY index. In this analysis, the risk-free rate is assumed constant at 2.4% per annum. Alternative risk-free rates can be used (N period swap LIBOR rate) and can be adjusted to fluctuate over the historical period.
# Optimality
# Redo statistics to compute pairwise dependencies including the indexes
optimal_frame <- cbind(returns_stocks, Price_Weighted_Index)
cor(optimal_frame)
## ARE.Adjusted BLK.Adjusted COST.Adjusted IBM.Adjusted
## ARE.Adjusted 1.0000000 0.38423547 0.4671280 0.19471566
## BLK.Adjusted 0.3842355 1.00000000 0.4092315 0.46017650
## COST.Adjusted 0.4671280 0.40923150 1.0000000 0.21436433
## IBM.Adjusted 0.1947157 0.46017650 0.2143643 1.00000000
## RGLD.Adjusted 0.2255852 0.03993880 -0.1194586 0.11260851
## SPY.Adjusted 0.5017873 0.80974324 0.6066141 0.51908269
## Price_Weighted_Index -0.1072876 0.03853751 0.1262040 0.03130322
## RGLD.Adjusted SPY.Adjusted Price_Weighted_Index
## ARE.Adjusted 0.22558516 0.50178731 -0.10728761
## BLK.Adjusted 0.03993880 0.80974324 0.03853751
## COST.Adjusted -0.11945861 0.60661406 0.12620399
## IBM.Adjusted 0.11260851 0.51908269 0.03130322
## RGLD.Adjusted 1.00000000 0.05357762 -0.05944126
## SPY.Adjusted 0.05357762 1.00000000 0.08165528
## Price_Weighted_Index -0.05944126 0.08165528 1.00000000
sample_stats <- summary(timeSeries(optimal_frame))
risk_free_rate <- 0.024/12
# Calcualte sample estimate Sharpe ratio
SharpeRatio(optimal_frame[,1:5], Rf = risk_free_rate)
## ARE.Adjusted BLK.Adjusted COST.Adjusted
## StdDev Sharpe (Rf=0.2%, p=95%): 0.2164134 0.06636072 0.18801383
## VaR Sharpe (Rf=0.2%, p=95%): 0.1599743 0.04435991 0.12776139
## ES Sharpe (Rf=0.2%, p=95%): 0.1152572 0.03419241 0.09618951
## IBM.Adjusted RGLD.Adjusted
## StdDev Sharpe (Rf=0.2%, p=95%): -0.11537236 0.07572259
## VaR Sharpe (Rf=0.2%, p=95%): -0.05947206 0.05624665
## ES Sharpe (Rf=0.2%, p=95%): -0.03328101 0.04599394
# Alternative Manual calculation
Sharpe_storage <- matrix(0, nrow = 1, ncol = 5)
colnames(Sharpe_storage) <- colnames(optimal_frame[,1:5])
rownames(Sharpe_storage) <- "Sample Estimated Sharpe Ratio"
for (i in 1:ncol(Sharpe_storage)) {
Sharpe_storage[1,i] <- (mean(optimal_frame[,i]) - risk_free_rate) / sd(optimal_frame[,i])
}
print(Sharpe_storage)
## ARE.Adjusted BLK.Adjusted COST.Adjusted
## Sample Estimated Sharpe Ratio 0.2164134 0.06636072 0.1880138
## IBM.Adjusted RGLD.Adjusted
## Sample Estimated Sharpe Ratio -0.1153724 0.07572259
# Assess optimality in addition / withdrawal of capital budget in respective stocks
stock_PWindex_corr <- cor(optimal_frame)[7,1:5]
stock_PWindex_corr <- as.matrix(stock_PWindex_corr)
colnames(stock_PWindex_corr) <- "Sample Correlationwith P-W Index"
optimal_allocation <- matrix(0, nrow = 1, ncol = 5)
colnames(optimal_allocation) <- colnames(optimal_frame[,1:5])
rownames(optimal_allocation) <- "Optimality Condition"
# Calculate Sharpe ratio of PW Index
pw_sharpe <- (mean(optimal_frame$Price_Weighted_Index) - risk_free_rate) / sd(optimal_frame$Price_Weighted_Index)
for (i in 1:length(optimal_allocation)) {
if(Sharpe_storage[1,i] > (pw_sharpe*stock_PWindex_corr[i])) {
optimal_allocation[i] <- 1
} else {
optimal_allocation[i] <- 0}
}
print(optimal_allocation)
## ARE.Adjusted BLK.Adjusted COST.Adjusted IBM.Adjusted
## Optimality Condition 1 0 0 0
## RGLD.Adjusted
## Optimality Condition 1
Let 1 indicate that the sample estimate of a stock’s Sharpe ratio is greater than the product of the price-weighted index Sharpe ratio and the correlation between the respective stock and price-weighted index over the sample period. 0 indicates the absense of optimality, i.e. allocation additional capital to the asset within the price-weighted portfolio would reduce risk-adjusted excess expected returns. In this case, Alexandria Real Estate Equities (ARE), Costco Wholesale (COST), and Royal Gold (RGLD) are optimal assets that have higher risk-adjusted returns after factoring in covariance risk with the price-weighted portfolio. This indicates that allocating additional capitalto ARE, COST, or RGLD, would improve the risk-adjust performacne of the price-weighted portfolio as meausred by the Sharpe ratio.
Note that there are limitations to this analysis. The data comes from one sample period and should be cross-validated would out of sample historical data. Outliers that skew the sample estimates can be adjusted or removed from the data set to refine the accuracy of the sample statistics of central tendency and dispersion. It may be interesting to evaluate optimality as a function of alternative perofrmance metrics other than the Sharpe ratio, like the Sortion, Infromation, and or Treynor ration. This analysis can also be automated one a rolling window to simulate the changing risk-return characteristics of the stocks and indexes.
In this section, optimal portfolio construction is implemented to calculate a set of optimal portfolio with varying investor constraints. The fPortfolio package, developed by RMetrics, is used to solve the quadratic programming problem of solving for an efficient set of weights subject to linear constraints. The constraints specified make assumptions about the investor’s suitability and investment objectives, as well as the regulatory restrictions of an investment company. In other words, this anlaysis assumes an investor requires a target monthly return on an investment. The investment strategy of management is subject to long-only constraints, i.e. no short trades.
First, a feasible set of portfolios that are mean-variance efficient are specified and computed. These results are then plotted along the efficient frontier. Through the help of the array of functions in the fPortfolio package, the covariance relationships and variance contributions to overall portfolio variability can be interpreted with relative ease.
This procedure is completed twice to compare the differences in portfolio parameter estimates between the sample covariance estimator and a minimum covariance determinant estimator (Rousseeuw, 1985, 1999).
## $center
## ARE.Adjusted BLK.Adjusted COST.Adjusted IBM.Adjusted RGLD.Adjusted
## 0.010449111 0.004769500 0.009775280 0.001634568 0.006301630
##
## $cov
## ARE.Adjusted BLK.Adjusted COST.Adjusted IBM.Adjusted
## ARE.Adjusted 0.0022309896 0.0007733485 0.0009581651 0.0008052218
## BLK.Adjusted 0.0007733485 0.0023037972 0.0007795494 0.0011768230
## COST.Adjusted 0.0009581651 0.0007795494 0.0022691957 0.0006885592
## IBM.Adjusted 0.0008052218 0.0011768230 0.0006885592 0.0023148695
## RGLD.Adjusted 0.0018245029 0.0003916823 -0.0005285667 0.0001160195
## RGLD.Adjusted
## ARE.Adjusted 0.0018245029
## BLK.Adjusted 0.0003916823
## COST.Adjusted -0.0005285667
## IBM.Adjusted 0.0001160195
## RGLD.Adjusted 0.0128573528
##
## $cor
## ARE.Adjusted BLK.Adjusted COST.Adjusted IBM.Adjusted
## ARE.Adjusted 1.0000000 0.34111778 0.42584897 0.35432641
## BLK.Adjusted 0.3411178 1.00000000 0.34094596 0.50959572
## COST.Adjusted 0.4258490 0.34094596 1.00000000 0.30042914
## IBM.Adjusted 0.3543264 0.50959572 0.30042914 1.00000000
## RGLD.Adjusted 0.3406591 0.07196744 -0.09785613 0.02126631
## RGLD.Adjusted
## ARE.Adjusted 0.34065912
## BLK.Adjusted 0.07196744
## COST.Adjusted -0.09785613
## IBM.Adjusted 0.02126631
## RGLD.Adjusted 1.00000000
##
## $quantile
## [1] 13.66848
##
## $outliers
## 2014-10-01 2015-10-01 2016-02-01 2018-10-01
## 10 22 26 58
##
## $series
## GMT
## ARE.Adjusted BLK.Adjusted COST.Adjusted IBM.Adjusted
## 2014-10-01 0.1279368915 0.038216319 0.062256844 -0.14382648
## 2015-10-01 0.0669526767 0.168232635 0.089590672 -0.03431317
## 2016-02-01 -0.0002526822 -0.007345839 -0.007238958 0.04879410
## 2018-10-01 -0.0210840913 -0.129377537 -0.026969889 -0.27000543
## RGLD.Adjusted
## 2014-10-01 -0.127784352
## 2015-10-01 0.022893688
## 2016-02-01 0.448802801
## 2018-10-01 -0.005595858
##
## Model List:
## Type: MV
## Optimize: minRisk
## Estimator: CovMcdEstimator
## Params: alpha = 0.05
##
## Portfolio List:
## Target Weights: NULL
## Target Return: NULL
## Target Risk: NULL
## Risk-Free Rate: 0
## Number of Frontier Points: 50
##
## Optim List:
## Solver: solveRquadprog
## Objective: portfolioObjective portfolioReturn portfolioRisk
## Options: meq = 2
## Trace: FALSE
##
## Title:
## MV Feasible Portfolio
## Estimator: covEstimator
## Solver: solveRquadprog
## Optimize: minRisk
## Constraints: LongOnly
##
## Portfolio Weights:
## ARE.Adjusted BLK.Adjusted COST.Adjusted IBM.Adjusted RGLD.Adjusted
## 0.2 0.2 0.2 0.2 0.2
##
## Covariance Risk Budgets:
## ARE.Adjusted BLK.Adjusted COST.Adjusted IBM.Adjusted RGLD.Adjusted
## 0.1523 0.1604 0.1032 0.1739 0.4101
##
## Target Returns and Risks:
## mean Cov CVaR VaR
## 0.0071 0.0415 0.0898 0.0659
##
## Description:
## Wed Nov 13 02:16:11 2019 by user: NOAH HARNESS
##
## Title:
## MV Feasible Portfolio
## Estimator: CovMcdEstimator
## Solver: solveRquadprog
## Optimize: minRisk
## Constraints: LongOnly
##
## Portfolio Weights:
## ARE.Adjusted BLK.Adjusted COST.Adjusted IBM.Adjusted RGLD.Adjusted
## 0.2 0.2 0.2 0.2 0.2
##
## Covariance Risk Budgets:
## ARE.Adjusted BLK.Adjusted COST.Adjusted IBM.Adjusted RGLD.Adjusted
## 0.1523 0.1604 0.1032 0.1739 0.4101
##
## Target Returns and Risks:
## mean mu Cov Sigma CVaR VaR
## 0.0071 0.0071 0.0415 0.0330 0.0898 0.0659
##
## Description:
## Wed Nov 13 02:16:11 2019 by user: NOAH HARNESS
##
## Title:
## MV Portfolio Frontier
## Estimator: CovMcdEstimator
## Solver: solveRquadprog
## Optimize: minRisk
## Constraints: LongOnly
## Portfolio Points: 5 of 19
##
## Portfolio Weights:
## ARE.Adjusted BLK.Adjusted COST.Adjusted IBM.Adjusted RGLD.Adjusted
## 1 0.0000 0.0784 0.0000 0.9160 0.0056
## 5 0.0761 0.1008 0.0978 0.6859 0.0394
## 10 0.3431 0.0433 0.1168 0.4429 0.0539
## 14 0.5557 0.0000 0.1316 0.2475 0.0652
## 19 1.0000 0.0000 0.0000 0.0000 0.0000
##
## Covariance Risk Budgets:
## ARE.Adjusted BLK.Adjusted COST.Adjusted IBM.Adjusted RGLD.Adjusted
## 1 0.0000 0.0375 0.0000 0.9610 0.0015
## 5 0.0277 0.0666 0.0345 0.8497 0.0215
## 10 0.2809 0.0346 0.0673 0.5631 0.0541
## 14 0.6107 0.0000 0.0866 0.2228 0.0800
## 19 1.0000 0.0000 0.0000 0.0000 0.0000
##
## Target Returns and Risks:
## mean mu Cov Sigma CVaR VaR
## 1 -0.0042 -0.0042 0.0588 0.0440 0.1612 0.0966
## 5 -0.0005 -0.0005 0.0485 0.0340 0.1284 0.0840
## 10 0.0042 0.0042 0.0405 0.0257 0.1046 0.0702
## 14 0.0080 0.0080 0.0397 0.0248 0.0884 0.0680
## 19 0.0126 0.0126 0.0492 0.0336 0.0925 0.0765
##
## Description:
## Wed Nov 13 02:16:11 2019 by user: NOAH HARNESS
##
## Title:
## MV Portfolio Frontier
## Estimator: covEstimator
## Solver: solveRquadprog
## Optimize: minRisk
## Constraints: LongOnly
## Portfolio Points: 5 of 19
##
## Portfolio Weights:
## ARE.Adjusted BLK.Adjusted COST.Adjusted IBM.Adjusted RGLD.Adjusted
## 1 0.0000 0.0867 0.0002 0.9130 0.0000
## 5 0.0071 0.1249 0.1721 0.6707 0.0251
## 10 0.1430 0.1292 0.2839 0.3945 0.0494
## 14 0.2517 0.1327 0.3733 0.1735 0.0688
## 19 1.0000 0.0000 0.0000 0.0000 0.0000
##
## Covariance Risk Budgets:
## ARE.Adjusted BLK.Adjusted COST.Adjusted IBM.Adjusted RGLD.Adjusted
## 1 0.0000 0.0420 0.0000 0.9580 0.0000
## 5 0.0023 0.0861 0.0705 0.8313 0.0097
## 10 0.1023 0.1232 0.2181 0.5192 0.0372
## 14 0.2537 0.1321 0.3754 0.1695 0.0692
## 19 1.0000 0.0000 0.0000 0.0000 0.0000
##
## Target Returns and Risks:
## mean Cov CVaR VaR
## 1 -0.0042 0.0588 0.1605 0.0958
## 5 -0.0005 0.0483 0.1259 0.0833
## 10 0.0042 0.0391 0.1029 0.0799
## 14 0.0080 0.0367 0.0854 0.0798
## 19 0.0126 0.0492 0.0925 0.0765
##
## Description:
## Wed Nov 13 02:16:12 2019 by user: NOAH HARNESS
##
## Title:
## MV Tangency Portfolio
## Estimator: covEstimator
## Solver: solveRquadprog
## Optimize: minRisk
## Constraints: LongOnly
##
## Portfolio Weights:
## ARE.Adjusted BLK.Adjusted COST.Adjusted IBM.Adjusted RGLD.Adjusted
## 0.4832 0.0000 0.4394 0.0000 0.0774
##
## Covariance Risk Budgets:
## ARE.Adjusted BLK.Adjusted COST.Adjusted IBM.Adjusted RGLD.Adjusted
## 0.5210 0.0000 0.4043 0.0000 0.0746
##
## Target Returns and Risks:
## mean Cov CVaR VaR
## 0.0119 0.0405 0.0802 0.0560
##
## Description:
## Wed Nov 13 02:16:12 2019 by user: NOAH HARNESS
##
## Title:
## MV Tangency Portfolio
## Estimator: CovMcdEstimator
## Solver: solveRquadprog
## Optimize: minRisk
## Constraints: LongOnly
##
## Portfolio Weights:
## ARE.Adjusted BLK.Adjusted COST.Adjusted IBM.Adjusted RGLD.Adjusted
## 0.8045 0.0000 0.1242 0.0000 0.0713
##
## Covariance Risk Budgets:
## ARE.Adjusted BLK.Adjusted COST.Adjusted IBM.Adjusted RGLD.Adjusted
## 0.8564 0.0000 0.0685 0.0000 0.0751
##
## Target Returns and Risks:
## mean mu Cov Sigma CVaR VaR
## 0.0124 0.0124 0.0453 0.0311 0.0843 0.0645
##
## Description:
## Wed Nov 13 02:16:12 2019 by user: NOAH HARNESS
##
## Title:
## MV Efficient Portfolio
## Estimator: covEstimator
## Solver: solveRquadprog
## Optimize: minRisk
## Constraints: LongOnly
##
## Portfolio Weights:
## ARE.Adjusted BLK.Adjusted COST.Adjusted IBM.Adjusted RGLD.Adjusted
## 0.2278 0.1319 0.3537 0.2220 0.0646
##
## Covariance Risk Budgets:
## ARE.Adjusted BLK.Adjusted COST.Adjusted IBM.Adjusted RGLD.Adjusted
## 0.2190 0.1333 0.3439 0.2411 0.0626
##
## Target Returns and Risks:
## mean Cov CVaR VaR
## 0.0071 0.0368 0.0892 0.0798
##
## Description:
## Wed Nov 13 02:16:12 2019 by user: NOAH HARNESS
##
## Title:
## MV Efficient Portfolio
## Estimator: CovMcdEstimator
## Solver: solveRquadprog
## Optimize: minRisk
## Constraints: LongOnly
##
## Portfolio Weights:
## ARE.Adjusted BLK.Adjusted COST.Adjusted IBM.Adjusted RGLD.Adjusted
## 0.5099 0.0074 0.1286 0.2911 0.0629
##
## Covariance Risk Budgets:
## ARE.Adjusted BLK.Adjusted COST.Adjusted IBM.Adjusted RGLD.Adjusted
## 0.5409 0.0055 0.0842 0.2935 0.0759
##
## Target Returns and Risks:
## mean mu Cov Sigma CVaR VaR
## 0.0071 0.0071 0.0394 0.0245 0.0920 0.0684
##
## Description:
## Wed Nov 13 02:16:12 2019 by user: NOAH HARNESS
A sample covariance estimator can be thought of as a multivariate statistic capturing the dependencies or variability among all the possible relationships between the random variables in the data set. Several alternative, more robust methods have been developed to estimate the covariance strucutre with more accuracy and long-run stability. The idea is that, while outliers have a very low probability of occuring, they can skew the data and inflate the covariance estimates. In this report, the minimum covariance determinant (MCD) approach is applied to constructing optimal portfolios.
Developed Rousseeuw & Van Driessen, the MCD aims to estimate the location (mean) and scale (sigma) parameters of highly-dimensional data by making assumptions of what data is in fact ‘good’ data. Outliers that deviate from the clustering patters in the scatter plot matrix are considered bad data and are left out of the location and scale paramter estimates. This process seeks to minimize the determinant (scalar) of the covariance matrix. The following code estimates the parameters of various optimal portfolios for a traditional sample mean-variance optimal portfolio, and a robust MCD mean-variance optimal portfolio.
The optimal portfolio used for this analysis is the sample mean-variance tangent portfolio, which is computed below. The expected monthly return is 0.0119 (1.19%) with a variance of 4.05%. The weights of this portfolio involve allocation 48.32% in ARE, 43.94% in COST, and 7.74% in RGLD.
weights_optimal <- c(0.4832, 0, 0.43942, 0, 0.07738)
weights_optimal <- as.matrix(weights_optimal)
optimal_portfolio_returns <- stockdata %*% weights_optimal
fin_6310$Optimal_Portfolio <- optimal_portfolio_returns
fin_6310$Optimal_Portfolio[1,] <- 10000
fin_6310$Optimal_Portfolio[1] <- 10000
for (i in 2:nrow(index_frame)) {
index_frame$Optim_Portf[i] <- index_frame$Optim_Portf[i-1] +
(optimal_portfolio_returns[i] *
index_frame$Optim_Portf[i-1])
}
dygraph(index_frame, main = "Performance of $10K Investment in the Optimal Tangent Portfolio")
Compared to the price-weighted and SPY indexes, the optimal portfolio outperformed with an annualized yield of 13.18%, equivalent to a gain of 8,569 USD or a HPR of 85.69%. Taking the sample mean and standard deviation of the optimal portfolio, the assumed expected return and volatility are 1.19% (0.01187) and 4.05% (0.04046), respectively. The charts above provide interesting insight into the dynamic changes in portfolio allocaitons and risk exposure as target returns change. More important, concentration risk becomes increasingly concerning for management as the reuqired target return increases. Often constraints are put in place on allocations and risk contributions of certain assets, and it is possible to set such linear constraints in the fPortfolio package. It is left to the reader to investigate such dynamic allocation strategies. One final not before moving on, this optimization “engine” assumes the weights remain fixed over the historical period. This is a dubious and risky assumption to make. Dynamic Asset Allocation Algorithms (AAA) are frequently used by invesment management companies to adjust weights that can place a cap on risk exposure while still maintaining a degree of efficiency.
Though not exhaustive, the CAPM single-factor model is a good and often standard starting place to estimate the expected returns of assets. The model assumes that the expected (excess) return of a stock is a function of its sensitivity (beta-risk) to the perofrmance of the broader market index. Often the S&P 500 is taken to replicate this broad market of all available investments. This model, and the following analysis, are approximations of risk-return characteristics of assets and subject to change over time. In other words, a stock’s estimated beta and expected return change over time. Knowing this, it important to simulate the CAPM over a rolling-window and to cross-validate sample assumptions with realized out-of-sample data.
# CAPM Estimations
attach(as.data.frame(returns_stocks))
# ARE Sample Beta
Beta_ARE <- cov(ARE.Adjusted,SPY.Adjusted) / var(SPY.Adjusted)
# BLK Sample Beta
Beta_BLK <- cov(BLK.Adjusted,SPY.Adjusted) / var(SPY.Adjusted)
# COST Sample Beta
Beta_COST <- cov(COST.Adjusted,SPY.Adjusted) / var(SPY.Adjusted)
# IBM Sample Beta
Beta_IBM <- cov(IBM.Adjusted,SPY.Adjusted) / var(SPY.Adjusted)
# RGLD Sample Beta
Beta_RGLD <- cov(RGLD.Adjusted,SPY.Adjusted) / var(SPY.Adjusted)
# OPTIM Sample Beta
Beta_Optim <- cov(optimal_portfolio_returns, SPY.Adjusted) / var(SPY.Adjusted)
BetaMatrix <- c(Beta_ARE, Beta_BLK, Beta_COST, Beta_IBM, Beta_RGLD, Beta_Optim)
BetaMatrix <- as.matrix(BetaMatrix)
rownames(BetaMatrix) <- c( colnames(returns_stocks[,1:5]), "OPTIM")
colnames(BetaMatrix) <- "Estimated Sample Beta"
show(BetaMatrix)
## Estimated Sample Beta
## ARE.Adjusted 0.7611590
## BLK.Adjusted 1.3597895
## COST.Adjusted 0.9038647
## IBM.Adjusted 0.9893088
## RGLD.Adjusted 0.2077270
## OPTIM 0.7810422
Optim_Exp_Ret <- risk_free_rate + Beta_Optim*(cov.rob(SPY.Adjusted)[['center']] - risk_free_rate)
show(Optim_Exp_Ret)
## [,1]
## [1,] 0.008607863
robust_estimates <- covMcdEstimator(timeSeries(returns_stocks))
robust_mu <- robust_estimates$mu
robust_covariances <- robust_estimates$Sigma[,6]
robust_optim_mu <- covMcdEstimator(timeSeries(cbind(optimal_portfolio_returns,
returns_stocks$SPY.Adjusted)))$mu[1]
robust_optim_covariance <- covMcdEstimator(timeSeries(cbind(optimal_portfolio_returns,
returns_stocks$SPY.Adjusted)))$Sigma
# ARE ROBUST BETA
Beta_Rb_ARE <- robust_covariances[1] / robust_covariances[6]
# BLK ROBUST BETA
Beta_Rb_BLK <- robust_covariances[2] / robust_covariances[6]
# COST ROBUST BETA
Beta_Rb_COST <- robust_covariances[3] / robust_covariances[6]
# IBM ROBUST BETA
Beta_Rb_IBM <- robust_covariances[4] / robust_covariances[6]
# RGLD ROBUST BETA
Beta_Rb_RGLD <- robust_covariances[5] / robust_covariances[6]
# OPTIM ROBUST BETA
Beta_Rb_Optim <- robust_optim_covariance[2,1] / robust_covariances[6]
Robust_BetaMatrix <- c(Beta_Rb_ARE, Beta_Rb_BLK, Beta_Rb_COST, Beta_Rb_IBM, Beta_Rb_RGLD,
Beta_Rb_Optim)
Robust_BetaMatrix <- as.matrix(Robust_BetaMatrix)
rownames(Robust_BetaMatrix) <- c( colnames(returns_stocks[,1:5]), "OPTIM")
colnames(Robust_BetaMatrix) <- "Est. Robust MCD Sample Beta"
show(Robust_BetaMatrix)
## Est. Robust MCD Sample Beta
## ARE.Adjusted 0.4059066
## BLK.Adjusted 1.4878515
## COST.Adjusted 0.9194632
## IBM.Adjusted 0.2757408
## RGLD.Adjusted 0.7068072
## OPTIM 0.3937939
Optim_Robust_Exp_Ret <- risk_free_rate + Beta_Rb_Optim*(robust_mu[6] - risk_free_rate)
show(Optim_Exp_Ret)
## [,1]
## [1,] 0.008607863
Above the SPY index is approximated as the broader market index, an assumption investor’s in this context are willing to live with. The SPY’s historical returns are used to calculate the sample beta coefficients for each stock, as well as the beta and expected return of the optimal portfolio. The differnece between the expected return derived from the optimal portfolio and from the CAPM is likely due to a number of factors, including, but not limited to, estimation error of sample statistics or the limitations of a single-factor model in estimating expected returns. An alternative method is to use the covariance estimates derived from a robust covariance function.
In this section, the Treynor-Black model is applied to construct an optimal weighting strategy for our five stocks. The monthly returns of this active portfolio are derived. Note: the sample mean (average) of the SPY (market) index is assumed expected market return.
## Alpha Robust Est.
## ARE.Adjusted 0.008743045
## BLK.Adjusted -0.003358178
## COST.Adjusted 0.004775800
## IBM.Adjusted -0.008422325
## RGLD.Adjusted 0.006208155
## ARE.Adjusted BLK.Adjusted COST.Adjusted IBM.Adjusted RGLD.Adjusted
## 0.0007358897 0.0021588053 0.0022051173 0.0020836995 0.0143901847
## [,1]
## ARE.Adjusted 1.33786047
## BLK.Adjusted -0.17516652
## COST.Adjusted 0.24387950
## IBM.Adjusted -0.45515339
## RGLD.Adjusted 0.04857995
The Treynor Black outperforms the other portfolios by a wide margin, with a HPR of 345.28% (3.4528), a gain of 34,528 USD or 34.81% annualized over the five year period. The robust expected returs of the four portfolios and indexes is listed below.
index_est <- covMcdEstimator(timeSeries(cbind(returns_stocks$SPY.Adjusted,Treynor_Black, Price_Weighted_Index,
optimal_portfolio_returns)))
index_est_mu <- index_est$mu
show(index_est_mu)
## SPY.Adjusted Treynor_Black
## 6.685820e-03 2.153191e-02
## Price_Weighted_Index optimal_portfolio_returns
## 1.345220e+04 1.187215e-02
The alphas are computed below. The SPY, at no surprise, has an alpha of 0. The price-weighted portfolio follows with an alpha of 0.007183. The optimal max tangent portfolio yields an alpha of 0.011872. Lastly, the Treynor-Black portfolio produces the highest alpha of 0.036412 (3.6412%) per month!
The Sharpe ratios are computed as well. SPY, Treynor-Black, price-weighted, and optimal portfolios produced a risk-adjusted excess return of 0.1581, 1/315, 0.1665, and 0.3506.
# CAPM and Alpha Calculations of the 4 portfolios
alpha_spy <- 0
alpha_Treynor_Black <- (index_est_mu[[2]] - risk_free_rate) - (index_est$Sigma[[1,2]]/index_est$Sigma[[1]])*
(index_est_mu[[1]]-risk_free_rate)
alpha_PW <-(index_est_mu[[3]] - risk_free_rate) - (index_est$Sigma[[1,3]]/index_est$Sigma[[1]])*
(index_est_mu[[1]]-risk_free_rate)
alpha_Optim <- (index_est_mu[[4]] - risk_free_rate) - (index_est$Sigma[[1,4]]/index_est$Sigma[[1]])*
(index_est_mu[[1]]-risk_free_rate)
Alphas <- cbind(alpha_spy, alpha_Treynor_Black, alpha_PW, alpha_Optim)
show(Alphas)
## alpha_spy alpha_Treynor_Black alpha_PW alpha_Optim
## [1,] 0 0.01590014 13326.73 0.005724547
Sharpe_SPY <- (index_est_mu[[1]] - risk_free_rate) / sqrt(index_est$Sigma[[1]])
Sharpe_Treynor_Black <- (index_est_mu[[2]] - risk_free_rate) / sqrt(index_est$Sigma[[2]])
Sharpe_PW <- (index_est_mu[[3]] - risk_free_rate) / sqrt(index_est$Sigma[[3]])
Sharpe_Optim <- (index_est_mu[[4]] - risk_free_rate) / sqrt(index_est$Sigma[[4]])
Sharpes <- cbind(Sharpe_SPY, Sharpe_Treynor_Black, Sharpe_PW, Sharpe_Optim)
show(Sharpes)
## Sharpe_SPY Sharpe_Treynor_Black Sharpe_PW Sharpe_Optim
## [1,] 0.1911888 0.9052219 3354.361 0.4281369