Source code for orion_finance_sdk_py.stats.covariance
"""skfolio-backed covariance and correlation estimators."""
from __future__ import annotations
import numpy as np
import pandas as pd
from skfolio.measures import correlation as skfolio_correlation
from skfolio.moments import EmpiricalCovariance, LedoitWolf
from orion_finance_sdk_py.stats.series import ReturnSeries
def _overlapping_returns(rs: ReturnSeries | pd.DataFrame) -> pd.DataFrame:
"""Contiguous daily returns with rows that are complete across assets."""
frame = rs.returns if isinstance(rs, ReturnSeries) else rs
overlap = frame.dropna(how="any")
if overlap.empty:
raise ValueError("no overlapping contiguous daily returns")
return overlap
def _labeled_square(matrix: np.ndarray, columns: pd.Index) -> pd.DataFrame:
"""Wrap a square numpy matrix with asset labels."""
return pd.DataFrame(matrix, index=columns, columns=columns)
[docs]
def sample(rs: ReturnSeries | pd.DataFrame) -> pd.DataFrame:
"""Sample covariance via skfolio ``EmpiricalCovariance`` (``ddof=1``)."""
overlap = _overlapping_returns(rs)
model = EmpiricalCovariance(ddof=1)
model.fit(overlap)
return _labeled_square(np.asarray(model.covariance_), overlap.columns)
[docs]
def ledoit_wolf(rs: ReturnSeries | pd.DataFrame) -> pd.DataFrame:
"""Ledoit–Wolf shrunk covariance via skfolio ``LedoitWolf``."""
overlap = _overlapping_returns(rs)
model = LedoitWolf()
model.fit(overlap)
return _labeled_square(np.asarray(model.covariance_), overlap.columns)
[docs]
def correlation(rs: ReturnSeries | pd.DataFrame) -> pd.DataFrame:
"""Correlation of overlapping contiguous daily returns (skfolio)."""
overlap = _overlapping_returns(rs)
matrix = np.asarray(skfolio_correlation(overlap.to_numpy(dtype=float)))
return _labeled_square(matrix, overlap.columns)