"""简化季度盈利驱动模型:实际替换和有证据的未来假设分别形成桥。""" import copy import json from decimal import Decimal as D, InvalidOperation def finite(value): try: number = D(str(value)) except (InvalidOperation, ValueError, TypeError) as exc: raise ValueError("invalid_numeric_input") from exc if not number.is_finite(): raise ValueError("nonfinite_model_driver") return number def profit(row): if any(row.get(key) is None for key in ["revenue", "margin", "finance", "tax"]): return None rev, margin, finance, tax = [finite(row[key]) for key in ["revenue", "margin", "finance", "tax"]] if rev < 0 or not (0 <= margin <= 1 and 0 <= tax <= 1): raise ValueError("driver_out_of_domain") return (rev*margin-finance)*(1-tax) def eps(model, shares="100"): denominator = finite(shares) if denominator <= 0: raise ValueError("invalid_share_assumption") profits = [profit(model[q]) for q in [1, 2, 3, 4]] return None if any(p is None for p in profits) else sum(profits)/denominator def update(model, actual, revisions): if actual.get("source_id") is None or actual.get("quarter") != 1: raise ValueError("unverified_actual_scope") after_actual = copy.deepcopy(model) after_actual[1] = {key: actual.get(key) for key in ["revenue", "margin", "finance", "tax"]} after_actual[1].update(status="actual", source_id=actual["source_id"]) profit(after_actual[1]) revised = copy.deepcopy(after_actual) changes, rejected = [], [] for change in revisions: quarter, field = change["quarter"], change["field"] if quarter not in [2, 3, 4] or field not in ["revenue", "margin", "finance", "tax"]: raise ValueError("unsupported_revision") if not change.get("source_id"): rejected.append({"quarter": quarter, "field": field, "reason": "missing_revision_evidence"}) continue new = finite(change["value"]) changes.append({**change, "before": str(revised[quarter][field])}) revised[quarter][field] = str(new) revised[quarter].setdefault("driver_sources", {})[field] = change["source_id"] profit(revised[quarter]) before, replaced, after = eps(model), eps(after_actual), eps(revised) return {"old_eps": before, "actual_only_eps": replaced, "new_eps": after, "actual_effect": None if replaced is None or before is None else replaced-before, "assumption_effect": None if after is None or replaced is None else after-replaced, "changes": changes, "rejected": rejected, "model": revised} old = {q: {"revenue": "100", "margin": "0.20", "finance": "0", "tax": "0.25", "status": "assumed"} for q in [1, 2, 3, 4]} snapshot = copy.deepcopy(old) actual = {"quarter": 1, "revenue": "120", "margin": "0.18", "finance": "0", "tax": "0.25", "source_id": "filing:AAA:Q1"} revisions = [{"quarter": 2, "field": "revenue", "value": "110", "source_id": "orders:AAA:review-1"}, {"quarter": 2, "field": "margin", "value": "0.19", "source_id": "costs:AAA:review-1"}, {"quarter": 3, "field": "margin", "value": "0.30", "source_id": None}] result = update(old, actual, revisions) assert [result[k] for k in ["old_eps", "actual_only_eps", "new_eps", "actual_effect", "assumption_effect"]] == list(map(D, ["0.60", "0.612", "0.61875", "0.012", "0.00675"])) assert result["model"][3]["margin"] == "0.20" and old == snapshot assert len(result["rejected"]) == 1 and len(result["changes"]) == 2 unknown = update(old, {**actual, "tax": None}, revisions) assert unknown["new_eps"] is None and unknown["actual_effect"] is None for token in ["NaN", "Infinity", "-Infinity"]: try: update(old, {**actual, "revenue": token}, revisions) except ValueError: assert old == snapshot else: raise AssertionError("非有限驱动必须拒绝") print(json.dumps({"bridge": {k: v for k, v in result.items() if k != "model"}, "missing_actual_tax_eps": unknown["new_eps"], "unchanged_q3": result["model"][3]}, default=str, sort_keys=True))