Skip to content
All library documents

Missing Covariances Cause NaN Portfolio Volatility Calculations

Article Quant Q&A · Author: Mysterio

Summary

The document diagnoses why a portfolio volatility calculation can return NaN values when constructing an efficient frontier from many stocks. Its explanation is that the return data may contain missing observations, causing some pairwise entries in the covariance matrix to be undefined. Multiplying portfolio weights by a matrix containing NaN values propagates those values into the resulting calculation.

A small dataframe example shows two series with limited overlapping observations: their individual variances can be computed, while their cross-covariance remains undefined. The practical lesson is to inspect the return panel and covariance matrix for missing values before interpreting portfolio output. The post explains the source of the NaNs but does not prescribe a method for handling them. Choices such as aligning dates, excluding assets, or estimating missing relationships require care because each changes the data or covariance assumptions underlying portfolio risk.

Key ideas

  • Missing or insufficiently overlapping return observations can produce undefined covariance entries.
  • NaN values propagate through matrix multiplication and arithmetic.
  • Inspect the covariance matrix when portfolio volatility outputs are NaN.
  • Handling missing data requires an explicit choice that can affect estimated portfolio risk.

Tags

Full text
# Why am I getting 'NaN' for as the output for a porfolio of 505 assets?


# Why am I getting 'NaN' for as the output for a porfolio of 505 assets?












In an attempt to construct the efficient frontier curve for a portfolio made up of all the stocks in the s&p index, I have run into some strange error for the calculations of the volatility of this portfolio. Here's the piece of the python code with the error:

```
tickers = ['A'..........# all the tickers of the s&p listed companies]

adj_close = pd.DataFrame()  # an empty variable that will house

adj_close = web.get_data_yahoo(tickers, start='2017-5-25', end='2017-6-25')['Adj Close']

returns = (adj_close / adj_close.shift(1)) - 1

pf_returns = []
pf_volatility = []

num_assets = len(tickers)

cov_matrix = returns.cov() * 20

for x in range(100):
    weights = np.random.random(num_assets) #random set of floats that matches the number of assets
    weights /= np.sum(weights)             #sum of weights = 1
    pf_returns.append(np.sum(weights * returns.mean() * 20))
    pf_volatility.append(np.dot(weights.T, np.dot(cov_matrix, weights)) * 0.5)

pf_returns = np.array(pf_returns)
pf_volatility = np.array(pf_volatility)

port = pd.DataFrame({'Returns': pf_returns, 'Volatility': pf_volatility})
print(port)
```

Here's the output:

```
   Returns  Volatility
0   0.014793         NaN
1   0.013081         NaN
2   0.013250         NaN
3   0.010461         NaN
4   0.010808         NaN
5   0.011683         NaN
6   0.011159         NaN
7   0.012093         NaN
8   0.010168         NaN
9   0.013329         NaN
10  0.012290         NaN
11  0.011616         NaN
12  0.011767         NaN
13  0.011151         NaN
14  0.011238         NaN
15  0.010688         NaN
16  0.011548         NaN
17  0.010132         NaN
18  0.010191         NaN
19  0.012638         NaN
20  0.010190         NaN
21  0.013640         NaN
22  0.014704         NaN
23  0.012479         NaN
24  0.011054         NaN
25  0.011495         NaN
26  0.012228         NaN
27  0.008502         NaN
28  0.012055         NaN
29  0.013000         NaN
..       ...         ...
70  0.010414         NaN
71  0.012023         NaN
72  0.011955         NaN
73  0.012560         NaN
74  0.014966         NaN
75  0.011383         NaN
76  0.012452         NaN
77  0.010191         NaN
78  0.011512         NaN
79  0.014761         NaN
80  0.011228         NaN
81  0.013632         NaN
82  0.011403         NaN
83  0.011184         NaN
84  0.013233         NaN
85  0.015004         NaN
86  0.012597         NaN
87  0.012751         NaN
88  0.012068         NaN
89  0.009325         NaN
90  0.012346         NaN
91  0.010205         NaN
92  0.010199         NaN
93  0.014781         NaN
94  0.011009         NaN
95  0.011710         NaN
96  0.010670         NaN
97  0.013398         NaN
98  0.012641         NaN
99  0.011366         NaN

[100 rows x 2 columns]
```

How can correct my volatility code?. Thanks in advance.

## Answer by Matthew Gunn (score 1, accepted)

https://quant.stackexchange.com/a/35294

You probably have NaN values in your covariance matrix. NaN is a special floating point value that's often used to denote missing observations.

Example: If you have a dataframe $y$ with two series that don't overlap in time more than 1 period, the covariance between the two series is going to be undefined (which the cov function returns as NaN).

```
x = pd.DataFrame([[1, np.NaN],[2,3],[np.NaN,4]])
x.cov()
```

Dataframe x is

```
     0    1
0  1.0  NaN
1  2.0  3.0
2  NaN  4.0
```

and x.cov() is

```
     0    1
0  0.5  NaN
1  NaN  0.5
```

Notice the NaN value in the covariance matrix. Note that NaN times a number returns NaN and NaN plus a number returns NaN.

Shown in full with attribution under the source's licence. Licence: CC BY-SA 4.0 (Stack Exchange)

This summary was written by Stratmill's research agent from the original; it is not a copy of the source.