"""外供PE目标价重建及顺序驱动桥;非PE方法与口径错配不硬算。""" import json from decimal import Decimal as D old = {"symbol": "AAA", "year": 2027, "currency": "CNY", "basis": "diluted", "method": "PE", "target_horizon": "2027-12-31", "eps": D("1.00"), "multiple": D("20"), "reported_target": D("20.00")} new = {**old, "eps": D("1.20"), "multiple": D("22"), "reported_target": D("26.40")} def rebuild(row): if row["method"] != "PE": raise ValueError("unsupported_valuation_method") for field in ["eps", "multiple", "reported_target"]: if not row[field].is_finite(): raise ValueError("nonfinite_valuation_input:"+field) if row["eps"] <= 0 or row["multiple"] <= 0: raise ValueError("nonpositive_pe_inputs") computed = row["eps"]*row["multiple"] residual = row["reported_target"]-computed return computed, residual def bridge(before, after): for field in ["symbol", "year", "target_horizon", "currency", "basis"]: if before[field] != after[field]: raise ValueError("incompatible_"+field) old_target, old_residual = rebuild(before) new_target, new_residual = rebuild(after) earnings = (after["eps"]-before["eps"])*before["multiple"] multiple = after["eps"]*(after["multiple"]-before["multiple"]) assert earnings+multiple == new_target-old_target return {"old_computed": str(old_target), "new_computed": str(new_target), "earnings_first_effect": str(earnings), "multiple_second_effect": str(multiple), "change": str(new_target-old_target), "reported_residual": str(new_residual), "reproduced": abs(old_residual) <= D("0.01") and abs(new_residual) <= D("0.01")} result = bridge(old, new) assert result["earnings_first_effect"] == "4.00" and result["multiple_second_effect"] == "2.40" assert result["change"] == "6.40" and result["reproduced"] is True unmatched = bridge(old, {**new, "reported_target": D("27.00")}) assert unmatched["reported_residual"] == "0.60" and not unmatched["reproduced"] blocked = [] for invalid in [{**new, "method": "DCF"}, {**new, "year": 2028}, {**new, "currency": "HKD"}, {**new, "basis": "basic"}, {**new, "target_horizon": "2028-12-31"}]: try: bridge(old, invalid) except ValueError as exc: blocked.append(str(exc)) assert blocked == ["unsupported_valuation_method", "incompatible_year", "incompatible_currency", "incompatible_basis", "incompatible_target_horizon"] reverse_multiple_first = old["eps"]*(new["multiple"]-old["multiple"]) reverse_earnings_second = (new["eps"]-old["eps"])*new["multiple"] assert reverse_multiple_first == D("2.00") and reverse_earnings_second == D("4.40") interaction = (new["eps"]-old["eps"])*(new["multiple"]-old["multiple"]) assert interaction == D("0.40") for field in ["eps", "multiple", "reported_target"]: for token in ["NaN", "Infinity", "-Infinity"]: try: rebuild({**new, field: D(token)}) except ValueError as exc: assert str(exc) == "nonfinite_valuation_input:"+field else: raise AssertionError("非有限估值输入必须阻断") print(json.dumps({"bridge": result, "unmatched_reported_target": unmatched, "reverse_order_effects": [str(reverse_multiple_first), str(reverse_earnings_second)], "interaction": str(interaction), "blocked": blocked}, sort_keys=True))