Skip to content

Commit

Permalink
deprecate min cov det #294
Browse files Browse the repository at this point in the history
  • Loading branch information
robertmartin8 committed Feb 18, 2021
1 parent b20d510 commit 6ed1ded
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 28 deletions.
9 changes: 2 additions & 7 deletions docs/RiskModels.rst
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ covariance.

.. automodule:: pypfopt.risk_models

:exclude-members: min_cov_determinant

.. note::

For any of these methods, if you would prefer to pass returns (the default is prices),
Expand Down Expand Up @@ -94,13 +96,6 @@ covariance.
`blog post <https://reasonabledeviations.com/2018/08/15/exponential-covariance/>`_
on my academic website.

.. autofunction:: min_cov_determinant

The minimum covariance determinant (MCD) estimator is designed to be robust to
outliers and 'contaminated' data [3]_. An efficient estimator is implemented in the
:py:mod:`sklearn.covariance` module, which is based on the algorithm presented in
Rousseeuw (1999) [4]_.

.. autofunction:: cov_to_corr

.. autofunction:: corr_to_cov
Expand Down
16 changes: 9 additions & 7 deletions pypfopt/risk_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,10 @@ def fix_nonpositive_semidefinite(matrix, fix_method="spectral"):
else:
raise NotImplementedError("Method {} not implemented".format(fix_method))

if not _is_positive_semidefinite(fixed_matrix):
warnings.warn("Could not fix matrix. Please try a different risk model.")
if not _is_positive_semidefinite(fixed_matrix): # pragma: no cover
warnings.warn(
"Could not fix matrix. Please try a different risk model.", UserWarning
)

# Rebuild labels if provided
if isinstance(matrix, pd.DataFrame):
Expand All @@ -109,7 +111,6 @@ def risk_matrix(prices, method="sample_cov", **kwargs):
- ``sample_cov``
- ``semicovariance``
- ``exp_cov``
- ``min_cov_determinant``
- ``ledoit_wolf``
- ``ledoit_wolf_constant_variance``
- ``ledoit_wolf_single_factor``
Expand All @@ -127,8 +128,6 @@ def risk_matrix(prices, method="sample_cov", **kwargs):
return semicovariance(prices, **kwargs)
elif method == "exp_cov":
return exp_cov(prices, **kwargs)
elif method == "min_cov_determinant":
return min_cov_determinant(prices, **kwargs)
elif method == "ledoit_wolf" or method == "ledoit_wolf_constant_variance":
return CovarianceShrinkage(prices, **kwargs).ledoit_wolf()
elif method == "ledoit_wolf_single_factor":
Expand Down Expand Up @@ -290,6 +289,8 @@ def min_cov_determinant(
:return: annualised estimate of covariance matrix
:rtype: pd.DataFrame
"""
warnings.warn("min_cov_determinant is deprecated and will be removed in v1.5")

if not isinstance(prices, pd.DataFrame):
warnings.warn("data is not in a dataframe", RuntimeWarning)
prices = pd.DataFrame(prices)
Expand All @@ -306,7 +307,8 @@ def min_cov_determinant(
X = prices
else:
X = returns_from_prices(prices)
X = np.nan_to_num(X.values)
# X = np.nan_to_num(X.values)
X = X.dropna().values
raw_cov_array = sklearn.covariance.fast_mcd(X, random_state=random_state)[1]
cov = pd.DataFrame(raw_cov_array, index=assets, columns=assets) * frequency
return fix_nonpositive_semidefinite(cov, kwargs.get("fix_method", "spectral"))
Expand Down Expand Up @@ -377,7 +379,7 @@ def __init__(self, prices, returns_data=False, frequency=252):
from sklearn import covariance

self.covariance = covariance
except (ModuleNotFoundError, ImportError):
except (ModuleNotFoundError, ImportError): # pragma: no cover
raise ImportError("Please install scikit-learn via pip or poetry")

if not isinstance(prices, pd.DataFrame):
Expand Down
28 changes: 14 additions & 14 deletions tests/test_risk_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,19 +155,20 @@ def test_exp_cov_limits():
assert np.abs(S2 - sample_cov).max().max() < 1e-3


def test_min_cov_det():
df = get_data()
S = risk_models.min_cov_determinant(df, random_state=8)
assert S.shape == (20, 20)
assert S.index.equals(df.columns)
assert S.index.equals(S.columns)
assert S.notnull().all().all()
# assert risk_models._is_positive_semidefinite(S)
# Cover that it works on np.ndarray, with a warning
with pytest.warns(RuntimeWarning):
S2 = risk_models.min_cov_determinant(df.to_numpy(), random_state=8)
assert isinstance(S2, pd.DataFrame)
np.testing.assert_equal(S.to_numpy(), S2.to_numpy())
# def test_min_cov_det():
# df = get_data()
# S = risk_models.CovarianceShrinkage(df).ledoit_wolf()
# S = risk_models.min_cov_determinant(df, random_state=8)
# assert S.shape == (20, 20)
# assert S.index.equals(df.columns)
# assert S.index.equals(S.columns)
# assert S.notnull().all().all()
# # assert risk_models._is_positive_semidefinite(S)
# # Cover that it works on np.ndarray, with a warning
# with pytest.warns(RuntimeWarning):
# S2 = risk_models.min_cov_determinant(df.to_numpy(), random_state=8)
# assert isinstance(S2, pd.DataFrame)
# np.testing.assert_equal(S.to_numpy(), S2.to_numpy())


def test_cov_to_corr():
Expand Down Expand Up @@ -311,7 +312,6 @@ def test_risk_matrix_and_returns_data():
"sample_cov",
"semicovariance",
"exp_cov",
# FIXME: this fails "min_cov_determinant",
"ledoit_wolf",
"ledoit_wolf_constant_variance",
"ledoit_wolf_single_factor",
Expand Down

0 comments on commit 6ed1ded

Please sign in to comment.