"""合成保存筛选重跑与字段归因。""" import json old = {"AAA": {"price": 18, "eps": 1, "revision": "v1"}, "BBB": {"price": 24, "eps": 1, "revision": "v1"}, "CCC": {"price": 15, "eps": 1, "revision": "v1"}, "DDD": {"price": 21, "eps": 1, "revision": "v1"}, "FFF": {"price": 10, "eps": 1, "revision": "v1"}} new = {"AAA": {"price": 22, "eps": 1, "revision": "v1"}, "BBB": {"price": 24, "eps": 1.5, "revision": "v2", "event": "correction"}, "DDD": {"price": 19, "eps": 1, "revision": "v1"}, "EEE": {"price": 17, "eps": 1, "revision": "v1"}, "FFF": {"price": 10, "eps": 1, "revision": "v1"}} def run(snapshot): return {s for s, r in snapshot.items() if r["eps"] > 0 and r["price"] / r["eps"] < 20} before, after = run(old), run(new) changes = {} for symbol in sorted(before ^ after): if symbol not in old or symbol not in new: cause = "universe" else: fields = [f for f in ("price", "eps") if old[symbol][f] != new[symbol][f]] cause = "+".join(fields) if "eps" in fields: cause += ":" + new[symbol].get("event", "unresolved") changes[symbol] = cause assert run(old) == before assert before == {"AAA", "CCC", "FFF"} assert after == {"BBB", "DDD", "EEE", "FFF"} assert changes == {"AAA": "price", "BBB": "eps:correction", "CCC": "universe", "DDD": "price", "EEE": "universe"} assert old["BBB"]["revision"] != new["BBB"]["revision"] print(json.dumps({"added": sorted(after-before), "removed": sorted(before-after), "retained": sorted(before & after), "causes": changes}, sort_keys=True))