Coverage for src/pyhrp/covariance.py: 100%

14 statements  

« prev     ^ index     » next       coverage.py v7.14.3, created at 2026-07-17 14:01 +0000

1"""Covariance and correlation estimation from returns. 

2 

3This module isolates the second-moment estimators used by the HRP allocation 

4entry points: 

5- compute_cov: Covariance matrix from a DataFrame of returns 

6- compute_corr: Correlation matrix from a DataFrame of returns 

7- _returns: Simple returns from a DataFrame of prices 

8""" 

9 

10from __future__ import annotations 

11 

12import numpy as np 

13import polars as pl 

14 

15__all__ = ["compute_corr", "compute_cov"] 

16 

17 

18def compute_cov(df: pl.DataFrame) -> pl.DataFrame: 

19 """Compute covariance matrix from a DataFrame of returns.""" 

20 cols = df.columns 

21 cov = np.atleast_2d(np.cov(df.to_numpy().T)) 

22 return pl.DataFrame(dict(zip(cols, cov, strict=True))) 

23 

24 

25def compute_corr(df: pl.DataFrame) -> pl.DataFrame: 

26 """Compute correlation matrix from a DataFrame of returns.""" 

27 cols = df.columns 

28 corr = np.atleast_2d(np.corrcoef(df.to_numpy().T)) 

29 return pl.DataFrame(dict(zip(cols, corr, strict=True))) 

30 

31 

32def _returns(prices: pl.DataFrame) -> pl.DataFrame: 

33 """Compute simple returns from prices. 

34 

35 Drops leading all-null rows produced by pct_change and fills remaining 

36 nulls/NaNs (e.g. from missing prices) with zero returns. 

37 """ 

38 return ( 

39 prices.select(pl.all().pct_change()) 

40 .filter(pl.any_horizontal(pl.all().is_not_null())) 

41 .fill_null(0.0) 

42 .fill_nan(0.0) 

43 )