pythonnumpymatrixportfoliosingular

Rebalancing portfolio creates a Singular Matrix


I am trying to create a minimum variance portfolio based on 1 year of data. I then want to rebalance the portfolio every month recomputing thus the covariance matrix. (my dataset starts in 1992 and finishes in 2017).

I did the following code which works when it is not in a loop. But when put in the loop the inverse of the covariance matrix is Singular. I don't understand why this problem arises since I reset every variable at the end of the loop.

### Importing the necessary libraries ###
import pandas as pd
import numpy as np
from numpy.linalg import inv

### Importing the dataset ###
df = pd.read_csv("UK_Returns.csv", sep = ";")
df.set_index('Date', inplace = True)

### Define varibales ###
stocks = df.shape[1]
returns = []
vol = []
weights_p =[]

### for loop to compute portfolio and rebalance every 30 days ###
for i in range (0,288):
  a = i*30
  b = i*30 + 252
  portfolio = df[a:b]
  mean_ret = ((1+portfolio.mean())**252)-1
  var_cov = portfolio.cov()*252
  inv_var_cov = inv(var_cov)
  doit = 0
  weights = np.dot(np.ones((1,stocks)),inv_var_cov)/(np.dot(np.ones((1,stocks)),np.dot(inv_var_cov,np.ones((stocks,1)))))
  ret = np.dot(weights, mean_ret)
  std = np.sqrt(np.dot(weights, np.dot(var_cov, weights.T)))
  returns.append(ret)
  vol.append(std)
  weights_p.append(weights)
  weights = []
  var_cov = np.zeros((stocks,stocks))
  inv_var_cov = np.zeros((stocks,stocks))
  i+=1

Does anyone has an idea to solve this issue?

The error it yields is the following:

---------------------------------------------------------------------------
LinAlgError                               Traceback (most recent call last)
<ipython-input-17-979efdd1f5b2> in <module>()
     21   mean_ret = ((1+portfolio.mean())**252)-1
     22   var_cov = portfolio.cov()*252
---> 23   inv_var_cov = inv(var_cov)
     24   doit = 0
     25   weights = np.dot(np.ones((1,stocks)),inv_var_cov)/(np.dot(np.ones((1,stocks)),np.dot(inv_var_cov,np.ones((stocks,1)))))

<__array_function__ internals> in inv(*args, **kwargs)

1 frames
/usr/local/lib/python3.6/dist-packages/numpy/linalg/linalg.py in _raise_linalgerror_singular(err, flag)
     95 
     96 def _raise_linalgerror_singular(err, flag):
---> 97     raise LinAlgError("Singular matrix")
     98 
     99 def _raise_linalgerror_nonposdef(err, flag):

LinAlgError: Singular matrix

Thank you so much for any help you can provide me with!

The data is shared in the following google drive: https://drive.google.com/file/d/1-Bw7cowZKCNU4JgNCitmblHVw73ORFKR/view?usp=sharing


Solution

  • It would be better to identify what is causing the singularity of the matrix but there are means of living with singular matrices.

    Try to use pseudoinverse by np.linalg.pinv(). It is guaranteed to always exist. See pinv

    Other way around it is avoid computing inverse matrix at all. Just find Least Squares solution of the system. See lstsq

    Just replace np.dot(X,inv_var_cov) with

    np.linalg.lstsq(var_conv, X, rcond=None)[0]