--- /data/files/bmw/stocklab-finalization-20260910-211846/app_engines_screening_executor.py.before +++ /data/files/bmw/stocklab-release-candidate-sl003-final-20260910-111453/app/engines/screening/executor.py @@ -14,6 +14,38 @@ "overall_score", "quality_score", "financial_health_score", "growth_score", "competitive_advantage_score", "valuation_score", "risk_score", } + +_PERCENTAGE_METRICS = { + "roic", + "roic_minus_wacc", + "revenue_growth_yoy", + "revenue_cagr_5y", + "eps_growth_yoy", + "fcf_growth_yoy", + "gross_margin", + "operating_margin", + "net_margin", + "fcf_margin", + "fcf_yield", + "dividend_yield", + "buyback_yield", + "shareholder_yield", + "roe", + "fcf_payout_ratio", +} + + +def _normalize_metric_threshold( + metric: str, + value: float | None, +) -> float | None: + """Convert public percentage-point thresholds to stored ratio values.""" + if value is None: + return None + if metric in _PERCENTAGE_METRICS: + return value / 100.0 + return value + _OP_MAP = { "gt": lambda col, v, v2: col > v, @@ -41,7 +73,9 @@ f"this build — see docs/SPEC_COVERAGE.md. Use relative='absolute' for now." ) m = Metric.__table__.alias(f"metric_{f.metric}") - condition = _OP_MAP[f.op](m.c.value, f.value, f.value2) + value = _normalize_metric_threshold(f.metric, f.value) + value2 = _normalize_metric_threshold(f.metric, f.value2) + condition = _OP_MAP[f.op](m.c.value, value, value2) return exists( select(1).select_from(m).where(m.c.security_id == Security.id, m.c.metric_key == f.metric, condition) )