"""声明的向后比例复权;拆股调价/调量,现金股利只调价。""" import json from decimal import Decimal as D raw = [("2026-10-19", D("100"), D("100")), ("2026-10-20", D("50"), D("200")), ("2026-10-21", D("49"), D("220")), ("2026-10-22", D("50"), D("240"))] events = [{"date": "2026-10-20", "split": D("2"), "dividend": D("0")}, {"date": "2026-10-21", "split": D("1"), "dividend": D("1")}] def factors(day): price_factor, volume_factor = D("1"), D("1") for event in events: if day >= event["date"]: continue split, dividend = event["split"], event["dividend"] if split <= 0: raise ValueError("invalid_split") price_factor /= split volume_factor *= split if dividend: previous = max((row for row in raw if row[0] < event["date"]), key=lambda row: row[0])[1] multiplier = (previous-dividend)/previous if not 0 < multiplier <= 1: raise ValueError("invalid_dividend_factor") price_factor *= multiplier return price_factor, volume_factor expected = {day: (price*factors(day)[0], volume*factors(day)[1]) for day, price, volume in raw} vendor = {"2026-10-19": (D("49"), D("200")), "2026-10-20": (D("49"), D("200")), "2026-10-21": (D("49"), D("220")), "2026-10-22": (D("50"), D("240"))} assert expected == vendor bad = {**vendor, "2026-10-19": (D("50"), D("200")), "2026-10-20": (D("49"), D("204"))} def discrepancies(observed, reference, tolerance=D("0.0001")): errors = {} for day in reference: fields = [field for index, field in enumerate(["close", "volume"]) if abs(observed[day][index]-reference[day][index]) > tolerance] if fields: errors[day] = fields return errors errors = discrepancies(bad, expected) assert errors == {"2026-10-19": ["close"], "2026-10-20": ["volume"]} assert discrepancies(vendor, expected) == {} rounded = {**vendor, "2026-10-19": (D("49.00005"), D("200"))} assert discrepancies(rounded, expected) == {} assert factors("2026-10-19") == (D("0.49"), D("2")) assert factors("2026-10-20") == (D("0.98"), D("1")) assert expected["2026-10-21"][0]/expected["2026-10-20"][0]-1 == 0 double_count = (D("49")+D("1"))/D("49")-1 assert double_count > 0 print(json.dumps({"expected": {d: [str(p), str(v)] for d, (p, v) in expected.items()}, "injected_errors": errors, "quarantined_dates": sorted(errors), "usable_bad_vendor_dates": sorted(set(expected)-set(errors)), "dividend_adjusted_return": "0", "double_counted_return": str(double_count)}, sort_keys=True))