diff options
| author | Openclaw <openclaw@mail.tylerhoang.xyz> | 2026-04-01 23:32:01 -0700 |
|---|---|---|
| committer | Openclaw <openclaw@mail.tylerhoang.xyz> | 2026-04-01 23:32:01 -0700 |
| commit | 3806bd3b4d69917f3f5312acfa57bc4ee2886a49 (patch) | |
| tree | 7fca5c5c8aacc5365d2db33e40da2e251e3c67b0 /services/fmp_service.py | |
| parent | 96b27f1d00ae8110273de973053c3d6bfc4f3662 (diff) | |
Harden valuation edge cases
Diffstat (limited to 'services/fmp_service.py')
| -rw-r--r-- | services/fmp_service.py | 39 |
1 files changed, 37 insertions, 2 deletions
diff --git a/services/fmp_service.py b/services/fmp_service.py index 1e5ea42..82a9c4c 100644 --- a/services/fmp_service.py +++ b/services/fmp_service.py @@ -33,6 +33,11 @@ def get_key_ratios(ticker: str) -> dict: All ratios are self-computed via compute_ttm_ratios() — no FMP calls. Forward P/E and dividend fallbacks come from yfinance's info dict. + + For edge cases, trailing P/E prefers the vendor-supplied value from the + info dict when the self-computed statement-based figure is missing or + materially inconsistent. This avoids obviously bad P/E outputs on tickers + with restatements, near-zero earnings, or statement mapping quirks. """ ticker = ticker.upper() merged = {"symbol": ticker} @@ -44,13 +49,43 @@ def get_key_ratios(ticker: str) -> dict: # Forward P/E requires analyst estimates — can't compute from statements info = get_company_info(ticker) if info: + trailing_pe_info = info.get("trailingPE") + trailing_pe_computed = merged.get("peRatioTTM") + + if trailing_pe_info is not None: + try: + vendor_pe = float(trailing_pe_info) + except (TypeError, ValueError): + vendor_pe = None + + try: + computed_pe = float(trailing_pe_computed) if trailing_pe_computed is not None else None + except (TypeError, ValueError): + computed_pe = None + + if vendor_pe is not None and vendor_pe > 0: + if computed_pe is None or computed_pe <= 0: + merged["peRatioTTM"] = vendor_pe + else: + # If the two values are wildly different, trust the vendor + # trailing P/E. This prevents edge-case display bugs where a + # malformed TTM net income makes P/E look duplicated/wrong. + ratio_gap = max(vendor_pe, computed_pe) / max(min(vendor_pe, computed_pe), 1e-9) + if ratio_gap > 2.0: + merged["peRatioTTM"] = vendor_pe + if info.get("forwardPE") is not None: merged["forwardPE"] = info["forwardPE"] # Fallback: dividends from info dict when cash-flow data is missing if merged.get("dividendYieldTTM") is None and info.get("dividendYield") is not None: merged["dividendYieldTTM"] = info["dividendYield"] - if merged.get("dividendPayoutRatioTTM") is None and info.get("payoutRatio") is not None: - merged["dividendPayoutRatioTTM"] = info["payoutRatio"] + payout_ratio_info = info.get("payoutRatio") + if ( + merged.get("dividendPayoutRatioTTM") is None + and payout_ratio_info is not None + and float(payout_ratio_info) > 0 + ): + merged["dividendPayoutRatioTTM"] = payout_ratio_info return merged if len(merged) > 1 else {} |
