quantlab.portfolio.approximate.LowRankCovariance#

class quantlab.portfolio.approximate.LowRankCovariance(covered, exposures, factor_covariance, specific_variance)[source]#

Bases: object

Every bar’s covariance of a decision panel, in low-rank form: estimate_all’s result.

Bar k’s covariance over its covered symbols is B F B' + diag(D), with B = exposures[k], F = factor_covariance[k] (the identity when None) and D = specific_variance[k]; the dense [symbols, symbols] matrix is never built. A symbol a bar does not cover has zero exposures and specific variance there.

Attributes:
coverednp.ndarray

Booleans [bars, symbols]: the symbols each bar’s estimate covers.

exposuresnp.ndarray

[bars, symbols, k]: B per bar.

factor_covariancenp.ndarray or None

[bars, k, k]: F per bar, or None for the identity.

specific_variancenp.ndarray

[bars, symbols]: D per bar.

Examples

>>> covariance = LowRankCovariance(
...     covered=np.array([[True, True]]),
...     exposures=np.array([[[0.1], [0.2]]]),
...     factor_covariance=None,
...     specific_variance=np.array([[0.01, 0.02]]),
... )
>>> covariance.variance
array([[0.02, 0.06]])
>>> covariance.times(np.array([[1.0, 0.0]]))
array([[0.02, 0.02]])
scaled(factor)[source]#

Return the covariance with every entry multiplied by factor, the span scaling.

Examples

>>> covariance.scaled(5).variance
array([[0.1, 0.3]])
times(weights)[source]#

[bars, symbols]: each bar’s covariance times its row of weights.

Examples

>>> covariance.times(np.array([[1.0, 0.0]]))
array([[0.02, 0.02]])
property variance[source]#

[bars, symbols]: each covered symbol’s variance, the diagonal; 0 where not covered.

Computed once per covariance, by a batched matrix product (B F per bar) and a row sum, never a loop over the factor pairs.

Examples

>>> covariance.variance
array([[0.02, 0.06]])
with_volatility(volatility)[source]#

Return the covariance with each covered symbol’s volatility replaced, the correlations kept.

S Sigma S with S = diag(volatility / sqrt(variance)): the rows of B scaled by S and D by S^2. A symbol without a finite positive volatility is no longer covered, its row and specific variance zeroed.

Parameters:
volatilitynp.ndarray

[bars, symbols] volatilities.

Examples

>>> np.sqrt(covariance.with_volatility(np.array([[0.2, np.nan]])).variance).round(6)
array([[0.2, 0. ]])