Source code for skfolio.descriptor._growth._earnings_change_to_price

"""Earnings change to price descriptor."""

# Copyright (c) 2023-2026
# Author: Hugo Delatte <hugo.delatte@skfoliolabs.com>
# SPDX-License-Identifier: BSD-3-Clause

from __future__ import annotations

from skfolio.descriptor._growth._base._change_to_scale import ChangeToScale


[docs] class EarningsChangeToPrice(ChangeToScale): r"""Lagged earnings change divided by current market capitalization. Computes the change in trailing twelve-month net income over a fixed lag, divided by current market capitalization: .. math:: \text{earnings\_change\_to\_price}(t) = \frac{\text{net\_income\_ttm}(t) - \text{net\_income\_ttm}(t - \text{lag})} {\text{market\_cap}(t)} The first `lag` observations are NaN because no lagged history is available. NaNs are allowed as missing observations and propagate when the current, lagged or market-cap value is missing. Non-missing `net_income_ttm` values must be finite. Non-missing `market_cap` values must be finite and strictly positive. This descriptor captures earnings momentum: whether a firm's profitability is improving or deteriorating relative to its market value [1]_. A positive value indicates earnings improvement and a negative value indicates deterioration. Unlike :class:`GrowthRate`, which computes `x(t) / x(t-lag) - 1`, this formulation is well-defined when earnings are negative. A standard growth rate with a negative base produces sign-inverted rankings, making it unsuitable for earnings. By normalizing the level change with market capitalization, the sign of the output reflects the direction of change. This is a convenience subclass of :class:`ChangeToScale` with `field="net_income_ttm"` and `scale_field="market_cap"`. This descriptor uses aggregate quantities (net income and market capitalization). The per-share equivalent is: .. math:: \frac{\text{eps\_ttm}(t) - \text{eps\_ttm}(t - \text{lag})} {\text{adj\_close}(t)} The aggregate form is preferred for consistency with the other value descriptors and to avoid split-adjustment mismatches. Parameters ---------- lag : int, default=252 Number of observations to look back. The interpretation depends on the data frequency: `lag=12` means 1 year for monthly data, `lag=252` for daily data, `lag=4` for quarterly data. Attributes ---------- n_assets_ : int Number of assets seen during fitting. asset_names_ : ndarray of shape (n_assets,) Asset names seen during fitting. change_to_scale_ : ndarray of shape (n_assets,) Last earnings change to price value for each asset. References ---------- .. [1] Fama, E. F., & French, K. R. (2006). "Profitability, investment and average returns." *Journal of Financial Economics*, 82(3), 491-518. See Also -------- ChangeToScale : Generic change-to-scale descriptor. GrowthRate : Simple growth rate for positive-definite characteristics. EarningsToPrice : Level of trailing earnings to price (value signal). Examples -------- >>> from skfolio.datasets import make_synthetic_characteristics >>> from skfolio.descriptor import EarningsChangeToPrice >>> >>> X = make_synthetic_characteristics() >>> >>> descriptor = EarningsChangeToPrice(lag=252) >>> earnings_change_to_price = descriptor.fit_transform(X) """ def __init__(self, lag: int = 252): super().__init__(field="net_income_ttm", scale_field="market_cap", lag=lag)