1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
| from __future__ import annotations
|
| import json
| import os
| import subprocess
| import sys
| from concurrent.futures import ThreadPoolExecutor, as_completed
| from pathlib import Path
|
|
| ROOT = Path(__file__).resolve().parents[2]
| AS_OF = "2026-08-04"
| OUT = ROOT / "ai-valuation-analyst" / "tmp" / "valuation_batch_20260805_004"
| CACHE = ROOT / "ai-valuation-analyst" / "tmp" / "v2_cache"
| TICKERS = [
| "000063.SZ", "000066.SZ", "000426.SZ", "000547.SZ", "000657.SZ",
| "000807.SZ", "000963.SZ", "000977.SZ", "001296.SZ", "002156.SZ",
| "002185.SZ", "002281.SZ", "002294.SZ", "002384.SZ", "002463.SZ",
| "002738.SZ", "002773.SZ", "002792.SZ", "002859.SZ", "002916.SZ",
| "003009.SZ", "300285.SZ", "300357.SZ", "300373.SZ", "300408.SZ",
| "300455.SZ", "300456.SZ", "300762.SZ", "301583.SZ", "600111.SH",
| "600118.SH", "600183.SH", "600276.SH", "600343.SH", "600378.SH",
| "600487.SH", "600549.SH", "600584.SH", "600699.SH", "600877.SH",
| "601127.SH", "601698.SH", "601869.SH", "601958.SH", "603019.SH",
| "603239.SH", "603596.SH", "603799.SH", "603893.SH", "603993.SH",
| "688166.SH", "688180.SH", "688192.SH", "688202.SH", "688278.SH",
| "688336.SH", "688506.SH", "688521.SH",
| ]
|
|
| def fetch(ticker: str) -> dict[str, object]:
| target = OUT / f"v2_{ticker.replace('.', '_')}"
| env = os.environ.copy()
| env["PYTHONPATH"] = str(ROOT / "dev" / "project-dev")
| proc = subprocess.run(
| [
| sys.executable,
| "-m",
| "stock_valuation_pipeline_v2",
| "--ticker",
| ticker,
| "--as-of",
| AS_OF,
| "--cache-dir",
| str(CACHE),
| "--output-dir",
| str(target),
| ],
| cwd=ROOT,
| env=env,
| capture_output=True,
| text=True,
| encoding="utf-8",
| errors="replace",
| timeout=120,
| )
| return {
| "ticker": ticker,
| "returncode": proc.returncode,
| "stdout": proc.stdout.strip().splitlines()[-1] if proc.stdout.strip() else "",
| "stderr": proc.stderr.strip()[-500:],
| }
|
|
| def main() -> None:
| if hasattr(sys.stdout, "reconfigure"):
| sys.stdout.reconfigure(encoding="utf-8", errors="replace")
| OUT.mkdir(parents=True, exist_ok=True)
| rows = []
| with ThreadPoolExecutor(max_workers=12) as pool:
| pending = {pool.submit(fetch, ticker): ticker for ticker in TICKERS}
| for future in as_completed(pending):
| try:
| rows.append(future.result())
| except Exception as exc: # noqa: BLE001 - batch boundary must retain every failure
| rows.append({"ticker": pending[future], "returncode": 99, "error": repr(exc)})
| rows.sort(key=lambda item: str(item["ticker"]))
| print(json.dumps({"count": len(rows), "items": rows}, ensure_ascii=False))
|
|
| if __name__ == "__main__":
| main()
|
|