skfolio.descriptor.EWDownsideBeta#
- class skfolio.descriptor.EWDownsideBeta(half_life=60.0, min_acceptable_return=0.0, min_periods=None, eps=1e-12)[source]#
Exponentially weighted downside beta descriptor.
Measures the sensitivity of each asset to market downturns using lower partial co-moments. Unlike standard beta, which treats up-moves and down-moves symmetrically, downside beta captures how much an asset tends to drop when the market drops [1] [2].
The lower partial co-moment formulation is:
\[ \begin{aligned} D_i(t) &= \min(r_i(t) - \text{mar},\; 0) \\[0.75em] D_m(t) &= \min(r_m(t) - \text{mar},\; 0) \\[0.75em] \beta^{\text{down}}_i(t) &= \frac{\text{EWMA}(D_i \cdot D_m)} {\text{EWMA}(D_m^2)} \end{aligned} \]where \(\text{mar}\) is the minimum acceptable return threshold and the EWMA uses decay \(\lambda = \exp(-\ln(2) / \text{half\_life})\).
The EWMA is updated at every observation. Returns above
maradd zero downside co-moment for that observation, while previous downside co-moments still decay. This avoids freezing the estimator during calm periods, unlike a conditional estimator that updates only on down-market days.- Parameters:
- half_lifefloat, default=60.0
EWMA half-life in observations. Controls how fast old observations decay. The default of 60 trading days (~3 months) balances responsiveness and stability. Adjust for other frequencies (e.g.
half_life=12for weekly data).- min_acceptable_returnfloat, default=0.0
Threshold below which returns are considered “downside”. The default of
0.0defines downside as negative returns (losses).- min_periodsint, optional
Minimum number of market observations and valid asset returns required before computing downside betas. Until both counts reach this value, the asset’s output is NaN. This warm-up period avoids exposing early EWMA values before the downside beta estimate has sufficiently converged from its zero initialization. If
None, defaults to \(\lceil\text{half\_life}\rceil\), with a minimum of 1.- epsfloat, default=1e-12
Small constant for numerical stability in \(1 / \text{EWMA}(D_m^2)\).
- Attributes:
- n_assets_int
Number of assets seen during fitting.
- asset_names_ndarray of shape (n_assets,)
Asset names seen during fitting.
- downside_beta_ndarray of shape (n_assets,)
Last fitted downside beta value for each asset.
Methods
fit_transform(X[, y])Compute exponentially weighted downside betas.
Get metadata routing of this object.
get_params([deep])Get parameters for this estimator.
partial_fit_transform(X[, y])Update EWMA state and return downside betas for this batch.
set_params(**params)Set the parameters of this estimator.
Notes
The EWMA is initialized to zero (no bias correction). Since the initialization bias is identical across all assets at each time step, cross-sectional rankings are unaffected.
The market downside variance is updated at every observation. Asset co-moments are updated only for assets with valid (non-NaN) returns and each asset’s valid-observation count controls when its output starts. This avoids emitting initialized values for late-listed or sparsely observed assets. The
active_maskproperty ofAssetPaneldistinguishes holidays from delistings.Market returns are computed from the estimation universe (
estimation_maskofAssetPanel). If no estimable asset has both finite returns and finitemarket_capat an observation, the market return is undefined and aValueErroris raised.References
[1]“Downside risk” The Review of Financial Studies. Ang, A., Chen, J., & Xing, Y. (2006).
[2]“Systematic risk in emerging markets: the D-CAPM”. Emerging Markets Review. Estrada, J. (2002).
Examples
>>> from skfolio.datasets import make_synthetic_characteristics >>> from skfolio.descriptor import EWDownsideBeta >>> >>> X = make_synthetic_characteristics() >>> >>> # Standard downside beta (losses only) >>> descriptor = EWDownsideBeta() >>> downside_beta = descriptor.fit_transform(X) >>> >>> # Custom threshold >>> descriptor = EWDownsideBeta(min_acceptable_return=-0.01) >>> downside_beta = descriptor.fit_transform(X)
- fit_transform(X, y=None, **fit_params)[source]#
Compute exponentially weighted downside betas.
- Parameters:
- XAssetPanel
Input panel containing
returnsandmarket_cap.- yNone
Ignored. Present for compatibility with scikit-learn’s API.
- **fit_paramsdict
Additional fit parameters. Ignored.
- Returns:
- downside_betandarray of shape (n_observations, n_assets)
Downside beta for each observation and asset.
- get_metadata_routing()#
Get metadata routing of this object.
Please check User Guide on how the routing mechanism works.
- Returns:
- routingMetadataRequest
A
MetadataRequestencapsulating routing information.
- get_params(deep=True)#
Get parameters for this estimator.
- Parameters:
- deepbool, default=True
If True, will return the parameters for this estimator and contained subobjects that are estimators.
- Returns:
- paramsdict
Parameter names mapped to their values.
- partial_fit_transform(X, y=None, **fit_params)[source]#
Update EWMA state and return downside betas for this batch.
This method supports online updates by continuing from the current fitted state. Use
fit_transformto start from a clean state.- Parameters:
- XAssetPanel
Input panel containing
returnsandmarket_cap.- yNone
Ignored. Present for compatibility with scikit-learn’s API.
- **fit_paramsdict
Additional fit parameters. Ignored.
- Returns:
- downside_betandarray of shape (n_observations, n_assets)
Downside beta for each observation and asset.
- set_params(**params)#
Set the parameters of this estimator.
The method works on simple estimators as well as on nested objects (such as
Pipeline). The latter have parameters of the form<component>__<parameter>so that it’s possible to update each component of a nested object.- Parameters:
- **paramsdict
Estimator parameters.
- Returns:
- selfestimator instance
Estimator instance.