Cai
18 hours ago cd6bfbea57c2437c00f808317f896aacb2ad2440
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()