From 6a305c73ae51254c9c8d7629b968720bc099ac6f Mon Sep 17 00:00:00 2001 From: Charles Young Date: Mon, 8 Mar 2021 19:08:55 +0800 Subject: [PATCH] Resolve https://github.com/microsoft/qlib/pull/280\#discussion_r589166529 --- qlib/model/riskmodel/base.py | 14 +++++++++----- qlib/model/riskmodel/poet.py | 2 +- qlib/model/riskmodel/shrink.py | 3 +-- qlib/model/riskmodel/structured.py | 16 ++++++---------- 4 files changed, 17 insertions(+), 18 deletions(-) diff --git a/qlib/model/riskmodel/base.py b/qlib/model/riskmodel/base.py index 89df80e8f..bb067e3d5 100644 --- a/qlib/model/riskmodel/base.py +++ b/qlib/model/riskmodel/base.py @@ -38,8 +38,11 @@ class RiskModel(BaseModel): self.scale_return = scale_return def predict( - self, X: Union[pd.Series, pd.DataFrame, np.ndarray], return_corr: bool = False, is_price: bool = True, - return_decomposed_components=False, + self, + X: Union[pd.Series, pd.DataFrame, np.ndarray], + return_corr: bool = False, + is_price: bool = True, + return_decomposed_components=False, ) -> Union[pd.DataFrame, np.ndarray, tuple]: """ Args: @@ -53,7 +56,7 @@ class RiskModel(BaseModel): pd.DataFrame or np.ndarray: estimated covariance (or correlation). """ assert ( - not return_corr or not return_decomposed_components + not return_corr or not return_decomposed_components ), "Can only return either correlation matrix or decomposed components." # transform input into 2D array @@ -84,8 +87,9 @@ class RiskModel(BaseModel): # return decomposed components if needed if return_decomposed_components: - assert 'return_decomposed_components' in inspect.getfullargspec(self._predict).args, \ - 'This risk model does not support return decomposed components of the covariance matrix ' + assert ( + "return_decomposed_components" in inspect.getfullargspec(self._predict).args + ), "This risk model does not support return decomposed components of the covariance matrix " F, cov_b, var_u = self._predict(X, return_decomposed_components=True) return F, cov_b, var_u diff --git a/qlib/model/riskmodel/poet.py b/qlib/model/riskmodel/poet.py index 8dbe89036..840384555 100644 --- a/qlib/model/riskmodel/poet.py +++ b/qlib/model/riskmodel/poet.py @@ -50,7 +50,7 @@ class POETCovEstimator(RiskModel): if self.num_factors > 0: Dd, V = np.linalg.eig(Y.T.dot(Y)) V = V[:, np.argsort(Dd)] - F = V[:, -self.num_factors:][:, ::-1] * np.sqrt(n) + F = V[:, -self.num_factors :][:, ::-1] * np.sqrt(n) LamPCA = Y.dot(F) / n uhat = np.asarray(Y - LamPCA.dot(F.T)) Lowrank = np.asarray(LamPCA.dot(LamPCA.T)) diff --git a/qlib/model/riskmodel/shrink.py b/qlib/model/riskmodel/shrink.py index 1298891fb..3cb2620d1 100644 --- a/qlib/model/riskmodel/shrink.py +++ b/qlib/model/riskmodel/shrink.py @@ -248,8 +248,7 @@ class ShrinkCovEstimator(RiskModel): roff1 = np.sum(v1 * cov_mkt[:, None].T) / var_mkt - np.sum(np.diag(v1) * cov_mkt) / var_mkt v3 = z.T.dot(z) / t - var_mkt * S roff3 = ( - np.sum(v3 * np.outer(cov_mkt, cov_mkt)) / var_mkt ** 2 - np.sum( - np.diag(v3) * cov_mkt ** 2) / var_mkt ** 2 + np.sum(v3 * np.outer(cov_mkt, cov_mkt)) / var_mkt ** 2 - np.sum(np.diag(v3) * cov_mkt ** 2) / var_mkt ** 2 ) roff = 2 * roff1 - roff3 rho = rdiag + roff diff --git a/qlib/model/riskmodel/structured.py b/qlib/model/riskmodel/structured.py index 39ff0166e..878503401 100644 --- a/qlib/model/riskmodel/structured.py +++ b/qlib/model/riskmodel/structured.py @@ -32,23 +32,19 @@ class StructuredCovEstimator(RiskModel): FACTOR_MODEL_FA = "fa" DEFAULT_NAN_OPTION = "fill" - def __init__( - self, - factor_model: str = "pca", - num_factors: int = 10, - **kwargs - ): + def __init__(self, factor_model: str = "pca", num_factors: int = 10, **kwargs): """ Args: factor_model (str): the latent factor models used to estimate the structured covariance (`pca`/`fa`). num_factors (int): number of components to keep. kwargs: see `RiskModel` for more information """ - if 'nan_option' in kwargs.keys(): - assert kwargs['nan_option'] in [self.DEFAULT_NAN_OPTION], \ - "nan_option={} is not supported".format(kwargs['nan_option']) + if "nan_option" in kwargs.keys(): + assert kwargs["nan_option"] in [self.DEFAULT_NAN_OPTION], "nan_option={} is not supported".format( + kwargs["nan_option"] + ) else: - kwargs['nan_option'] = self.DEFAULT_NAN_OPTION + kwargs["nan_option"] = self.DEFAULT_NAN_OPTION super().__init__(**kwargs)