Skip to content

Commit 8dd382b

Browse files
committed
Generate warning when the matrix is ill-defined and the regularization term is added to fix it.
1 parent fd3e55b commit 8dd382b

File tree

2 files changed

+9
-7
lines changed

2 files changed

+9
-7
lines changed

src/riskparityportfolio/sca.py

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import numpy as np
2+
import warnings
23
from tqdm import tqdm
34

45
try:
@@ -251,12 +252,11 @@ def iterate(self, verbose=True):
251252
w_hat = quadprog.solve_qp(Q, -q, C=self.CCmat, b=self.bvec, meq=self.meq)[0]
252253
except ValueError as e:
253254
if str(e) == "matrix G is not positive definite":
254-
# Add a small positive value to the diagonal of Q to make it positive definite
255-
if verbose:
256-
print(" Matrix Q is not positive definite: adding regularization term and then calling QP solver again.")
257-
#eigvals = np.linalg.eigvals(Q)
258-
#print(" - before regularization: cond. number = {:,.0f}".format(max(eigvals) / min(eigvals)))
259-
#print(" - after regularization: cond. number = {:,.0f}".format(max(eigvals + np.trace(Q)/1e7) / min(eigvals + np.trace(Q)/1e7)))
255+
warnings.warn(
256+
"Matrix Q is not positive definite: adding regularization term and then calling QP solver again.")
257+
# eigvals = np.linalg.eigvals(Q)
258+
# print(" - before regularization: cond. number = {:,.0f}".format(max(eigvals) / min(eigvals)))
259+
# print(" - after regularization: cond. number = {:,.0f}".format(max(eigvals + np.trace(Q)/1e7) / min(eigvals + np.trace(Q)/1e7)))
260260
Q += np.eye(Q.shape[0]) * np.trace(Q)/1e7
261261
w_hat = quadprog.solve_qp(Q, -q, C=self.CCmat, b=self.bvec, meq=self.meq)[0]
262262
else:

src/riskparityportfolio/tests/test_modern_rpp.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import numpy as np
22
import riskparityportfolio as rpp
3+
import pytest
34
import pdb
45

56
def test_on_tricky_example():
@@ -49,7 +50,8 @@ def test_singularity_issues_with_G_matrix():
4950
Sigma = U @ U.T # singular covariance matrix
5051

5152
my_portfolio = rpp.RiskParityPortfolio(Sigma, budget=b)
52-
my_portfolio.design(verbose=False, tau=1e-10) # <-- force ill-conditioned matrix
53+
with pytest.warns(UserWarning, match="Matrix Q is not positive definite: adding regularization term and then calling QP solver again."):
54+
my_portfolio.design(verbose=False, tau=1e-12) # <-- force ill-conditioned matrix
5355
w_ref = my_portfolio.weights
5456

5557
my_portfolio = rpp.RiskParityPortfolio(Sigma, budget=b)

0 commit comments

Comments
 (0)