aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--components/valuation.py9
-rw-r--r--services/valuation_service.py19
2 files changed, 23 insertions, 5 deletions
diff --git a/components/valuation.py b/components/valuation.py
index 24405d6..4e2d003 100644
--- a/components/valuation.py
+++ b/components/valuation.py
@@ -30,6 +30,7 @@ from services.valuation_service import (
run_ev_revenue,
run_price_to_book,
compute_historical_growth_rate,
+ compute_raw_historical_growth_rate,
)
from utils.formatters import fmt_ratio, fmt_pct, fmt_large, fmt_currency
@@ -337,6 +338,7 @@ def _build_model_context(ticker: str) -> dict:
base_fcf = _coerce_float(get_free_cash_flow_ttm(ticker))
hist_growth = compute_historical_growth_rate(fcf_series) if len(fcf_series) >= 2 else None
+ hist_growth_raw = compute_raw_historical_growth_rate(fcf_series) if len(fcf_series) >= 2 else None
ebitda = _coerce_float(ratios_data.get("ebitdaTTM"))
revenue_ttm = _coerce_float(get_revenue_ttm(ticker))
if revenue_ttm is None or revenue_ttm <= 0:
@@ -435,6 +437,7 @@ def _build_model_context(ticker: str) -> dict:
"fcf_series": fcf_series,
"base_fcf": base_fcf,
"hist_growth": hist_growth,
+ "hist_growth_raw": hist_growth_raw,
"ebitda": ebitda,
"revenue_ttm": revenue_ttm,
"book_value_per_share": book_value_per_share,
@@ -473,7 +476,9 @@ def _render_dcf_model(ctx: dict):
st.markdown("**Discounted Cash Flow (DCF)**")
hist_growth = ctx["hist_growth"]
+ hist_growth_raw = ctx["hist_growth_raw"]
hist_growth_pct = hist_growth * 100 if hist_growth is not None else 5.0
+ hist_growth_raw_pct = hist_growth_raw * 100 if hist_growth_raw is not None else hist_growth_pct
slider_default = float(max(-20.0, min(30.0, hist_growth_pct)))
st.caption(
@@ -515,11 +520,11 @@ def _render_dcf_model(ctx: dict):
max_value=30.0,
value=round(slider_default, 1),
step=0.5,
- help=f"Historical median: {hist_growth_pct:.1f}%. Drag to override.",
+ help=f"Historical median: {hist_growth_raw_pct:.1f}%. Drag to override.",
key=f"dcf_growth_{ctx['ticker']}",
)
- st.caption(f"Historical FCF growth (median): **{hist_growth_pct:.1f}%**")
+ st.caption(f"Historical FCF growth (median): **{hist_growth_raw_pct:.1f}%**")
result = run_dcf(
fcf_series=ctx["fcf_series"],
diff --git a/services/valuation_service.py b/services/valuation_service.py
index 1230aa5..0b8dfde 100644
--- a/services/valuation_service.py
+++ b/services/valuation_service.py
@@ -12,9 +12,9 @@ def _cap_growth(value: float) -> float:
return max(GROWTH_FLOOR, min(GROWTH_CAP, float(value)))
-def compute_historical_growth_rate(fcf_series: pd.Series) -> float | None:
+def _compute_median_historical_growth_rate(fcf_series: pd.Series) -> float | None:
"""
- Return a capped median YoY FCF growth rate from historical data.
+ Return the raw median YoY FCF growth rate from historical data.
Notes:
- skips periods with near-zero prior FCF
@@ -40,7 +40,20 @@ def compute_historical_growth_rate(fcf_series: pd.Series) -> float | None:
if not growth_rates:
return None
- return _cap_growth(float(np.median(growth_rates)))
+ return float(np.median(growth_rates))
+
+
+def compute_historical_growth_rate(fcf_series: pd.Series) -> float | None:
+ """Return a capped median YoY FCF growth rate from historical data."""
+ raw_growth = _compute_median_historical_growth_rate(fcf_series)
+ if raw_growth is None:
+ return None
+ return _cap_growth(raw_growth)
+
+
+def compute_raw_historical_growth_rate(fcf_series: pd.Series) -> float | None:
+ """Return the uncapped median YoY FCF growth rate from historical data."""
+ return _compute_median_historical_growth_rate(fcf_series)
def run_dcf(