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()