estimators¶
Inputs to construction/optimization: expected returns, covariance, and factor models. Distinct from portpy.metrics.covariance, which decomposes realized risk for a given weight vector against a given matrix - this module produces the matrix itself.
Expected returns¶
expected_returns ¶
expected_returns(
y: DataFrame,
method: str = "mean_historical",
periods_per_year: int = TRADING_DAYS_PER_YEAR,
geometric: bool = False,
span: int | None = None,
benchmark: Series | None = None,
rf: float = 0.0,
prior: float | Series | None = None,
) -> pd.Series
Estimate an annualized expected-return vector.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
y
|
DataFrame
|
Per-asset periodic returns - the full multi-asset DataFrame (matches
|
required |
method
|
str
|
One of:
- "mean_historical": annualized historical mean return per asset
(arithmetic mean * periods_per_year by default; see |
'mean_historical'
|
periods_per_year
|
int
|
Periods per year, used to annualize. |
TRADING_DAYS_PER_YEAR
|
geometric
|
bool
|
"mean_historical" only - use CAGR-style geometric
annualization per asset instead of |
False
|
span
|
int | None
|
EWMA decay in periods, used by "ewma" (default 60 if omitted). |
None
|
benchmark
|
Series | None
|
Market/benchmark return series, required by "capm_implied". |
None
|
rf
|
float
|
Annual risk-free rate, used by "capm_implied". |
0.0
|
prior
|
float | Series | None
|
Optional shrinkage target for "james_stein" - a single annual
rate applied to every asset, or a per-asset Series. Defaults to
the equal-weighted grand mean of |
None
|
Returns:
| Type | Description |
|---|---|
Series
|
Annualized expected return per asset, indexed by |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Source code in src/portpy/models/estimators/expected_returns.py
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 | |
Covariance¶
covariance ¶
covariance(
y: DataFrame,
method: str = "sample",
span: int | None = None,
periods_per_year: int = TRADING_DAYS_PER_YEAR,
annualize: bool = True,
shrinkage_intensity: float = 0.2,
) -> pd.DataFrame
Estimate an (by default annualized) asset covariance matrix.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
y
|
DataFrame
|
Per-asset periodic returns - the full multi-asset DataFrame (matches
|
required |
method
|
str
|
One of:
- "sample": plain sample covariance ( |
'sample'
|
span
|
int | None
|
EWMA decay in periods, used by "ewma" (default 60 if omitted). |
None
|
periods_per_year
|
int
|
Periods per year, used when |
TRADING_DAYS_PER_YEAR
|
annualize
|
bool
|
If True (default), scale the matrix by |
True
|
shrinkage_intensity
|
float
|
Blend weight on the diagonal target for "shrinkage", in [0, 1] (0 = pure sample covariance, 1 = pure diagonal). |
0.2
|
Returns:
| Type | Description |
|---|---|
DataFrame
|
The (optionally annualized) covariance matrix, indexed and columned by asset. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Source code in src/portpy/models/estimators/covariance.py
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 | |
Factor models¶
factor_models ¶
Factor regressions: CAPM, Fama-French, and general linear/rolling factor models.
Replaces the old experimental metrics/regressions.py module. Everything here
is a thin, opinionated wrapper around statsmodels OLS - PortPy adds the
excess-return bookkeeping (rf, RF-column handling) and sensible defaults;
statsmodels does the actual estimation, so every RegressionResultsWrapper
returned here carries the full statsmodels API (.params, .rsquared,
.pvalues, .summary(), ...).
linear_regression ¶
OLS regression of y on x, with an intercept - the general building
block every other function here specializes.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
y
|
Series
|
Dependent variable (e.g. asset returns). |
required |
x
|
DataFrame
|
Independent variable(s) (e.g. one or more factor return series). |
required |
Returns:
| Type | Description |
|---|---|
RegressionResultsWrapper
|
A fitted |
RegressionResultsWrapper
|
|
Source code in src/portpy/models/estimators/factor_models.py
rolling_regression ¶
Rolling-window OLS of y on x - a rolling alpha and rolling factor
loading(s), via statsmodels.regression.rolling.RollingOLS.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
y
|
Series
|
Dependent variable (e.g. asset returns). |
required |
x
|
DataFrame
|
Independent variable(s), same length/index as |
required |
window
|
int
|
Rolling window size, in periods. |
required |
Returns:
| Type | Description |
|---|---|
DataFrame
|
A DataFrame indexed like |
DataFrame
|
intercept) plus one column per column of |
DataFrame
|
The first |
Source code in src/portpy/models/estimators/factor_models.py
capm ¶
capm(
y: Series,
benchmark: Series,
rf: float = DEFAULT_RISK_FREE_RATE,
periods_per_year: int = TRADING_DAYS_PER_YEAR,
) -> RegressionResultsWrapper
Single-factor CAPM regression: (y - rf) = alpha + beta * (benchmark - rf) + e.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
y
|
Series
|
Asset/portfolio return series. |
required |
benchmark
|
Series
|
Market/benchmark return series. |
required |
rf
|
float
|
Annual risk-free rate, de-annualized internally and subtracted
from both |
DEFAULT_RISK_FREE_RATE
|
periods_per_year
|
int
|
Periods per year, used to de-annualize |
TRADING_DAYS_PER_YEAR
|
Returns:
| Type | Description |
|---|---|
RegressionResultsWrapper
|
A fitted |
RegressionResultsWrapper
|
(periodic-scale) alpha, |
Source code in src/portpy/models/estimators/factor_models.py
fama_french ¶
Multi-factor Fama-French style regression of y on factors.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
y
|
Series
|
Asset/portfolio return series (raw, not pre-adjusted for rf - see the "RF" handling below). |
required |
factors
|
DataFrame
|
Factor return series as columns. If a column named "RF" is
present, it's treated as the risk-free rate: |
required |
version
|
int
|
3 or 5 validates that |
3
|
Returns:
| Type | Description |
|---|---|
RegressionResultsWrapper
|
A fitted |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Source code in src/portpy/models/estimators/factor_models.py
factor_attribution ¶
Decompose y's average per-period return into a contribution from each
factor (beta_i * mean(factor_i)) plus an unexplained "alpha" residual.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
y
|
Series
|
Asset/portfolio return series. |
required |
factor_returns
|
DataFrame
|
Factor return series as columns. |
required |
Returns:
| Type | Description |
|---|---|
DataFrame
|
A DataFrame indexed by factor name (plus "alpha"), with columns |
DataFrame
|
"beta" (NaN for the alpha row), "contribution" (return units), and |
DataFrame
|
"pct_of_total" (each contribution's share of |