"""合成CSV导入:显式类型与逐行拒绝。""" import csv import io import json from datetime import datetime from decimal import Decimal as D, InvalidOperation raw = """代码,日期,开盘,最高,最低,收盘,成交量,单位 AAA,2026/10/19,10,12,9,11,"1,200",shares AAA,2026/10/19,10,12,9,11,1200,shares BBB,2026/02/30,20,22,19,21,2000,shares CCC,2026/10/19,30,32,29,31,3,lots_unknown """ accepted, rejected, seen = [], [], set() for line, row in enumerate(csv.DictReader(io.StringIO(raw)), 2): try: day = datetime.strptime(row["日期"], "%Y/%m/%d").date().isoformat() key = (row["代码"], day) if key in seen: raise ValueError("duplicate_key") if row["单位"] != "shares": raise ValueError("unknown_volume_unit") prices = [D(row[k]) for k in ("开盘", "最高", "最低", "收盘")] if not all(value.is_finite() for value in prices): raise ValueError("non_finite_price") o, h, l, c = prices volume = int(row["成交量"].replace(",", "")) if not (0 < l <= min(o, c) <= max(o, c) <= h and volume >= 0): raise ValueError("invalid_bar") accepted.append({"symbol": key[0], "date": day, "open": str(o), "high": str(h), "low": str(l), "close": str(c), "volume": volume, "currency": "CNY", "adjustment": "raw"}) seen.add(key) except (ValueError, InvalidOperation, KeyError) as exc: rejected.append({"line": line, "reason": str(exc)}) assert len(accepted) == 1 and accepted[0]["volume"] == 1200 assert [r["line"] for r in rejected] == [3, 4, 5] assert len(accepted) + len(rejected) == 4 standardized = io.StringIO(newline="") writer = csv.DictWriter(standardized, fieldnames=list(accepted[0])) writer.writeheader() writer.writerows(accepted) standard_csv = standardized.getvalue() readback = list(csv.DictReader(io.StringIO(standard_csv))) assert len(readback) == 1 and int(readback[0]["volume"]) == 1200 assert readback[0]["date"] == "2026-10-19" print(json.dumps({"accepted": accepted, "rejected": rejected, "standard_csv": standard_csv}, ensure_ascii=True))