Portfolio Frontier not Working for large dataset

1.3k views Asked by At

I have a time series object with stock returns since 2012. The portfolioFrontier function works fine to create my efficiency frontier until I expand the data set beyond the number of months. For example, there are 39 months I am looking at, and everything works fine with 38 stocks. But once I add the 39th stock (and 40th, etc.), I get an error. The code and error are below.

dput :

returns <- new("timeSeries", .Data = structure(c(-0.0108, 0.005, -0.0059, 0.0067, -0.0069, -0.0275, 
0.0226, 0.0089, 0.0469, 0.0193, -5e-04, -0.03, -0.0483, 0.0251, 
0.013, 0.0202, 0.019, 0.015, 0.0091, 0.002, -0.014, 0.0046, 0.002, 
0.025, 0.008, 0.0177, -0.0023, 0.0023, -0.0217, 0.0045, 0.0117, 
0.0081, 0.0345, 0.0332, 0.0098, 0.0086, -0.0362, -0.0137, 0.0162, 
0.0276, 0.0749, 0.0691, 0.0275, -0.0278, -0.0442, 0.0226, -0.0136, 
0.0305, 0.0178, 0.0061, 0.0034, 0.0039, -0.0042, -0.0017, 0.0039, 
0.0083, -0.008, -0.0044, 7e-04, 0.0018, 0.008, -0.0057, 0.0044, 
0.0043, 0.012, 0.0134, 0.003, 0.0078, -0.0092, 0.0113, 0.0132, 
0.0168, 0.032, 0.037, 0.033, 0.017, -0.037, 0.027, 0.026, 0.018
), .Dim = c(8L, 10L), .Dimnames = list(NULL, c("Stock.A", "Stock.B", 
"Stock.C", "Stock.D", "Stock.E", "Stock.F", "Stock.G", "Stock.H", 
"Stock.I", "Stock.J")))
    , units = c("Stock.A", "Stock.B", "Stock.C", "Stock.D", "Stock.E",     "Stock.F", 
"Stock.G", "Stock.H", "Stock.I", "Stock.J")
    , positions = c(1327968000, 1330473600, 1333152000, 1335744000,     1338422400, 
1341014400, 1343692800, 1346371200)
    , format = "%Y-%m-%d"
    , FinCenter = "GMT"
    , recordIDs = structure(list(), .Names = character(0), row.names =     integer(0), class = "data.frame")
    , title = "Time Series Object"
        , documentation = "Tue Jun 23 13:48:36 2015"
    )

Code :

library(timeSeries)
library(fPortfolio)
# returns <- read.csv("Not Working Excel File.csv")
#lct <- Sys.getlocale("LC_TIME"); Sys.setlocale("LC_TIME", "C")
#returns[,1] = as.Date(as.character(returns[,1]),format="%d-%b-%y") 
#Sys.setlocale("LC_TIME", lct)
#returns = timeSeries(returns[,-1], charvec = returns[,1])
Frontier <- portfolioFrontier(returns)

Error:

Error in `colnames<-`(`*tmp*`, value = c("AAPL",  : 
  attempt to set 'colnames' on an object with less than two dimensions

How can I resolve this issue so that I can add how ever many stocks I want without adding dates?

Edit: Here is a snapshot of what the dataset looks like. https://i.stack.imgur.com/sPIRr.png So in this example with 8 months of data and only four stocks, the code I posted above works fine. But once I add 5 more stocks (9 total) I get the error listed above.

Changing the data frame to a matrix yields the same error. Adding more months allows me to add more stocks, but I don't want more months.

1

There are 1 answers

4
Vedda On BEST ANSWER

The Problem

The reason you are not able to add any more stocks without adding any more months (years) appears to be related to the problem of minimizing the mean-variance.

From Cochrane "Asset Pricing" page 81-83 :

Theorem: So long as the variance-covariance matrix of returns is non-singular, there is a mean-variance frontier.

The problem “choose a portfolio to minimize variance for a given mean” is then

min{w} w0 Σw s.t. w0

You would solve this using the Lagrangian Multiplier method as outlined in the book. However, what is interesting to take note of is the co-variance matrix of returns must be non-singular, which means the co-variance matrix must be Positive Definite. If the co-variance matrix you provide to calculate the frontier is singular, then a frontier will not exist.

An Example

dput :

returns <- new("timeSeries", .Data = structure(c(-0.0108, 0.005, -0.0059, 0.0067, -0.0069, -0.0275, 
    0.0226, 0.0089, 0.0469, 0.0193, -5e-04, -0.03, -0.0483, 0.0251, 
    0.013, 0.0202, 0.019, 0.015, 0.0091, 0.002, -0.014, 0.0046, 0.002, 
    0.025, 0.008, 0.0177, -0.0023, 0.0023, -0.0217, 0.0045, 0.0117, 
    0.0081, 0.0345, 0.0332, 0.0098, 0.0086, -0.0362, -0.0137, 0.0162, 
    0.0276, 0.0749, 0.0691, 0.0275, -0.0278, -0.0442, 0.0226, -0.0136, 
    0.0305, 0.0178, 0.0061, 0.0034, 0.0039, -0.0042, -0.0017, 0.0039, 
    0.0083, -0.008, -0.0044, 7e-04, 0.0018, 0.008, -0.0057, 0.0044, 
    0.0043, 0.012, 0.0134, 0.003, 0.0078, -0.0092, 0.0113, 0.0132, 
    0.0168, 0.032, 0.037, 0.033, 0.017, -0.037, 0.027, 0.026, 0.018
    ), .Dim = c(8L, 10L), .Dimnames = list(NULL, c("StockA", "StockB", 
    "StockC", "StockD", "StockE", "StockF", "StockG", "StockH", 
    "StockI", "StockJ")))
        , units = c("StockA", "StockB", "StockC", "StockD", "StockE", "StockF", 
    "StockG", "StockH", "StockI", "StockJ")
        , positions = c(1327968000, 1330473600, 1333152000, 1335744000, 1338422400, 
    1341014400, 1343692800, 1346371200)
        , format = "%Y-%m-%d"
        , FinCenter = "GMT"
        , recordIDs = structure(list(), .Names = character(0), row.names =     integer(0), class = "data.frame")
        , title = "Time Series Object"
            , documentation = "Tue Jun 23 13:48:36 2015"
        )

Code Block 1 :

# Load Matrix Checks 
library(matrixcalc)

# Get dimensions and check if positive definite
dim(returns)
is.positive.definite(cov(returns))

### Results ###
# > dim(returns)
#   [1]  8 10
# > is.positive.definite(cov(returns))
#   [1] FALSE

As you can see, the covariance matrix is not positive definite and if you try to use portfolioFrontier() it will throw an error.

> portfolioFrontier(returns)
Error in `colnames<-`(`*tmp*`, value = c("StockA", "StockB", "StockC",  : 
  attempt to set 'colnames' on an object with less than two dimensions

Code Block 2:

# Remove first three columns to fit n (obs) > m (stocks)
returns <- returns[,4:10]
dim(returns)

#Check if positive definite
is.positive.definite(cov(returns))

### Results ###
# > dim(returns)
# [1] 8 7
# > is.positive.definite(cov(returns))
# [1] TRUE

Now check portfolioFrontier()

Output :

Title:
 MV Portfolio Frontier 
 Estimator:         covEstimator 
 Solver:            solveRquadprog 
 Optimize:          minRisk 
 Constraints:       LongOnly 
 Portfolio Points:  5 of 50 

Portfolio Weights:
   StockD StockE StockF StockG StockH StockI StockJ
1  0.0000 0.0000 0.0000 0.0000 1.0000 0.0000 0.0000
13 0.0000 0.0000 0.0000 0.1452 0.5016 0.2566 0.0966
25 0.0000 0.0000 0.0000 0.0000 0.1345 0.6738 0.1917
37 0.0000 0.0000 0.0000 0.0000 0.0000 0.4758 0.5242
50 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 1.0000

Covariance Risk Budgets:
    StockD  StockE  StockF  StockG  StockH  StockI  StockJ
1   0.0000  0.0000  0.0000  0.0000  1.0000  0.0000  0.0000
13  0.0000  0.0000  0.0000  0.1417 -0.0570  0.4871  0.4282
25  0.0000  0.0000  0.0000  0.0000 -0.0455  0.5865  0.4589
37  0.0000  0.0000  0.0000  0.0000  0.0000  0.2196  0.7804
50  0.0000  0.0000  0.0000  0.0000  0.0000  0.0000  1.0000

Target Returns and Risks:
     mean    Cov   CVaR    VaR
1  0.0001 0.0056 0.0080 0.0080
13 0.0048 0.0037 0.0025 0.0025
25 0.0094 0.0092 0.0122 0.0122
37 0.0141 0.0158 0.0238 0.0238
50 0.0191 0.0237 0.0370 0.0370

Seems to be working now. So lets plot the Efficient Frontier :

portfolio <- portfolioFrontier(returns)
plot(portfolio)

enter image description here