-
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add statistical risk model Rolling PCA
- Loading branch information
Showing
7 changed files
with
612 additions
and
135 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
from abc import ABC | ||
|
||
from numpy import ndarray | ||
|
||
|
||
class FactorRiskModel(ABC): | ||
""" | ||
Factor Risk Model. | ||
The model contains factor exposures, factors, and | ||
residual returns. | ||
""" | ||
|
||
def __init__(self): | ||
self._factor_exposures = None | ||
self._factors = None | ||
self._residual_returns = None | ||
|
||
@property | ||
def factor_exposures(self) -> ndarray: | ||
""" | ||
Return the factor exposures. | ||
Return | ||
------ | ||
ndarray | ||
Matrix in dimension (N, n) where N is the number of | ||
instruments and n is the number of components in PCA. | ||
""" | ||
return self._factor_exposures | ||
|
||
@property | ||
def factors(self) -> ndarray: | ||
""" | ||
Return the factors. | ||
Return | ||
------ | ||
ndarray | ||
Matrix in dimension (n, T) where n is the number of | ||
components in PCA and T is the number of time frames. | ||
""" | ||
return self._factors | ||
|
||
@property | ||
def residual_returns(self) -> ndarray: | ||
""" | ||
Return the residual returns. | ||
Return | ||
------ | ||
ndarray | ||
Matrix in dimension (N, T) where N is the number of | ||
instruments and T is the number of time frames. | ||
""" | ||
return self._residual_returns |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# flake8: noqa | ||
from .pca import PCA | ||
from .rolling_pca import RollingPCA |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
from typing import Optional, Union | ||
|
||
import numpy as np | ||
import pandas as pd | ||
|
||
from ..factor_risk_model import FactorRiskModel | ||
from .pca import PCA | ||
|
||
|
||
class RollingPCA(FactorRiskModel): | ||
def __init__( | ||
self, | ||
n_components: int, | ||
rolling_timeframe: int, | ||
demean: Optional[bool] = True, | ||
speedup: Optional[bool] = True, | ||
): | ||
""" | ||
Constructor. | ||
Parameters | ||
---------- | ||
n_components : int | ||
Number of components. | ||
rolling_timeframe: int | ||
Number of rolling time frames. | ||
demean : Optional[bool] | ||
Indicate whether to demean before fitting. Default is True. | ||
speedup: Optional[bool] | ||
Indicate whether to speed up the computation as much as possible. | ||
Default is True. | ||
""" | ||
super().__init__() | ||
self._n_components = n_components | ||
self._demean = demean | ||
self._rolling_timeframe = rolling_timeframe | ||
self._speedup = speedup | ||
self._model = PCA(n_components=n_components, demean=demean, speedup=speedup) | ||
|
||
def fit( | ||
self, | ||
X: Union[np.ndarray, pd.DataFrame], | ||
) -> object: | ||
""" | ||
Fit the returns into the risk model. | ||
Parameters | ||
---------- | ||
X: pandas.DataFrame or numpy.ndarray | ||
Instrument returns where the rows are the instruments | ||
and the columns are the date / time in ascending order. | ||
For example, if there are N instruments and T days of | ||
returns, the input is with the dimension of (N, T). | ||
Returns | ||
------- | ||
object | ||
The object itself. | ||
""" | ||
self._factor_exposures = {} | ||
self._factors = {} | ||
self._residual_returns = {} | ||
|
||
for index in range(0, X.shape[1]): | ||
start_index = index | ||
end_index = index + self._rolling_timeframe + 1 | ||
if end_index > X.shape[1]: | ||
break | ||
|
||
if isinstance(X, pd.DataFrame): | ||
X_input = X.iloc[:, start_index:end_index] | ||
index_name = X.columns[end_index - 1] | ||
elif isinstance(X, np.ndarray): | ||
X_input = X[:, start_index:end_index] | ||
index_name = end_index - 1 | ||
|
||
result = self._model.fit(X_input) | ||
self._factor_exposures[index_name] = result.factor_exposures | ||
self._factors[index_name] = result.factors | ||
self._residual_returns[index_name] = result.residual_returns | ||
|
||
return self |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.