Skip to main content
added 380 characters in body
Source Link
rbm
  • 3.3k
  • 2
  • 19
  • 29

OK, had a look at the data, and it's OK. The problem is, as the error says, that the covariance matrix is not a positive definite. A quick test confirms that (BTW - I'm using packages matrixcalc and Matrix):

library(tseries) prices <- read.csv2("20153Q.csv",header=TRUE,dec=".") n <- nrow(prices) returns <- (prices[2:n,])/(prices[1:(n-1),])-1 portfolio.optim(as.matrix(returns), shorts=FALSE,riskless=FALSE) # cov(X) not a positive definitive # check matrixcalc::is.positive.definite(cov(returns)) 

gets

> matrixcalc::is.positive.definite(cov(returns)) [1] FALSE 

What you can do is adjust the covariance matrix to its nearest positive definite matrix by using Matrix::nearPD

returns.nearest.PD <- Matrix::nearPD(cov(returns))$mat returns.nearest.PD <- as.matrix(returns.nearest.PD) 

which will then allow you to using portfolio.optim by explicitly specifying the covmat:

(po <- portfolio.optim(as.matrix(returns), covmat = returns.nearest.PD, shorts=FALSE,riskless=FALSE)) 

which works without error:

> sum(po$pw) [1] 1 

and you can confirm that it has weights for each symbol:

> length(po$pw) [1] 99 

EDIT Just to be sure, the adjusted covariance matrix is very close to the original covariance matrix, the diffs are miniscule:

> # the matrices are really close > sum((abs(returns.nearest.PD - cov(returns)) > 0.000000001)==TRUE) [1] 0 > # the matrices are really close > sum((abs(returns.nearest.PD - cov(returns)) > 0.0000000001)==TRUE) [1] 74 

OK, had a look at the data, and it's OK. The problem is, as the error says, that the covariance matrix is not a positive definite. A quick test confirms that (BTW - I'm using packages matrixcalc and Matrix):

library(tseries) prices <- read.csv2("20153Q.csv",header=TRUE,dec=".") n <- nrow(prices) returns <- (prices[2:n,])/(prices[1:(n-1),])-1 portfolio.optim(as.matrix(returns), shorts=FALSE,riskless=FALSE) # cov(X) not a positive definitive # check matrixcalc::is.positive.definite(cov(returns)) 

gets

> matrixcalc::is.positive.definite(cov(returns)) [1] FALSE 

What you can do is adjust the covariance matrix to its nearest positive definite matrix by using Matrix::nearPD

returns.nearest.PD <- Matrix::nearPD(cov(returns))$mat returns.nearest.PD <- as.matrix(returns.nearest.PD) 

which will then allow you to using portfolio.optim by explicitly specifying the covmat:

(po <- portfolio.optim(as.matrix(returns), covmat = returns.nearest.PD, shorts=FALSE,riskless=FALSE)) 

which works without error:

> sum(po$pw) [1] 1 

and you can confirm that it has weights for each symbol:

> length(po$pw) [1] 99 

OK, had a look at the data, and it's OK. The problem is, as the error says, that the covariance matrix is not a positive definite. A quick test confirms that (BTW - I'm using packages matrixcalc and Matrix):

library(tseries) prices <- read.csv2("20153Q.csv",header=TRUE,dec=".") n <- nrow(prices) returns <- (prices[2:n,])/(prices[1:(n-1),])-1 portfolio.optim(as.matrix(returns), shorts=FALSE,riskless=FALSE) # cov(X) not a positive definitive # check matrixcalc::is.positive.definite(cov(returns)) 

gets

> matrixcalc::is.positive.definite(cov(returns)) [1] FALSE 

What you can do is adjust the covariance matrix to its nearest positive definite matrix by using Matrix::nearPD

returns.nearest.PD <- Matrix::nearPD(cov(returns))$mat returns.nearest.PD <- as.matrix(returns.nearest.PD) 

which will then allow you to using portfolio.optim by explicitly specifying the covmat:

(po <- portfolio.optim(as.matrix(returns), covmat = returns.nearest.PD, shorts=FALSE,riskless=FALSE)) 

which works without error:

> sum(po$pw) [1] 1 

and you can confirm that it has weights for each symbol:

> length(po$pw) [1] 99 

EDIT Just to be sure, the adjusted covariance matrix is very close to the original covariance matrix, the diffs are miniscule:

> # the matrices are really close > sum((abs(returns.nearest.PD - cov(returns)) > 0.000000001)==TRUE) [1] 0 > # the matrices are really close > sum((abs(returns.nearest.PD - cov(returns)) > 0.0000000001)==TRUE) [1] 74 
Source Link
rbm
  • 3.3k
  • 2
  • 19
  • 29

OK, had a look at the data, and it's OK. The problem is, as the error says, that the covariance matrix is not a positive definite. A quick test confirms that (BTW - I'm using packages matrixcalc and Matrix):

library(tseries) prices <- read.csv2("20153Q.csv",header=TRUE,dec=".") n <- nrow(prices) returns <- (prices[2:n,])/(prices[1:(n-1),])-1 portfolio.optim(as.matrix(returns), shorts=FALSE,riskless=FALSE) # cov(X) not a positive definitive # check matrixcalc::is.positive.definite(cov(returns)) 

gets

> matrixcalc::is.positive.definite(cov(returns)) [1] FALSE 

What you can do is adjust the covariance matrix to its nearest positive definite matrix by using Matrix::nearPD

returns.nearest.PD <- Matrix::nearPD(cov(returns))$mat returns.nearest.PD <- as.matrix(returns.nearest.PD) 

which will then allow you to using portfolio.optim by explicitly specifying the covmat:

(po <- portfolio.optim(as.matrix(returns), covmat = returns.nearest.PD, shorts=FALSE,riskless=FALSE)) 

which works without error:

> sum(po$pw) [1] 1 

and you can confirm that it has weights for each symbol:

> length(po$pw) [1] 99