| | |
| | | "retained_base_low": item["base_low"], |
| | | "retained_base_high": item["base_high"], |
| | | } |
| | | write_json(out_dir / "估值快照.json", gap_snapshot) |
| | | write_json(out_dir / f"{safe_name(item['company'])}估值快照_当前.json", gap_snapshot) |
| | | calc_dir = out_dir / "calculation" |
| | | calc_dir.mkdir(parents=True, exist_ok=True) |
| | | for stale_name in ("valuation_results.json", "valuation_report.md", "run_manifest.json"): |
| | | stale_path = calc_dir / stale_name |
| | | if stale_path.exists(): |
| | | stale_path.unlink() |
| | | formal_path = out_dir / f"{safe_name(item['company'])}价格合理性评估.md" |
| | | formal_path = out_dir / f"{safe_name(item['company'])}价格合理性评估_当前.md" |
| | | formal_path.write_text( |
| | | "\n".join( |
| | | [ |
| | |
| | | ttm_attr = annual["attributable_profit"] + current["attributable_profit"] - prior["attributable_profit"] |
| | | ttm_deduct = annual["deduct_profit"] + current["deduct_profit"] - prior["deduct_profit"] |
| | | ttm_revenue = annual["revenue"] + current["revenue"] - prior["revenue"] |
| | | shares = item.get("static_total_shares") or number(selected.get("current_main") or {}, "TOTAL_SHARE") or float(old["market"]["diluted_shares"]) |
| | | # Latest statutory report equity units take precedence over the older |
| | | # instrument-static snapshot. This matters after bonus issues, splits, |
| | | # conversions and other H1 capital changes. |
| | | reported_shares = number(selected.get("current_main") or {}, "TOTAL_SHARE") |
| | | shares = reported_shares or item.get("static_total_shares") or float(old["market"]["diluted_shares"]) |
| | | shares = float(shares) |
| | | if shares < 1_000_000 and float(old["market"]["diluted_shares"]) > 10_000_000: |
| | | shares *= 10000 |
| | | shares_date = current_end if reported_shares else PRICE_DATE |
| | | price = item.get("close") or float(old["market"]["price"]) |
| | | notice_date = str(selected["current_income"].get("NOTICE_DATE") or selected["current_income"].get("UPDATE_DATE"))[:10] |
| | | included, excluded = included_forecasts(raw, notice_date, current["attributable_profit"], shares) |
| | |
| | | }, |
| | | "market": { |
| | | "price": price, "price_type": "前复权完整交易日收盘价", "price_timestamp": f"{PRICE_DATE}T15:00:00+08:00", |
| | | "diluted_shares": shares, "shares_date": PRICE_DATE, "platform_market_cap": price * shares, |
| | | "diluted_shares": shares, "shares_date": shares_date, "platform_market_cap": price * shares, |
| | | }, |
| | | "financials": financials, |
| | | "balance_sheet": bal, |
| | |
| | | } |
| | | out_dir = CURRENT_ROOT / ticker |
| | | out_dir.mkdir(parents=True, exist_ok=True) |
| | | snapshot_path = out_dir / "估值快照.json" |
| | | snapshot_path = out_dir / f"{safe_name(item['company'])}估值快照_当前.json" |
| | | write_json(snapshot_path, snapshot) |
| | | calc_dir = out_dir / "calculation" |
| | | if method == "pb" and bal["equity"] <= 0: |
| | |
| | | stale_path = calc_dir / stale_name |
| | | if stale_path.exists(): |
| | | stale_path.unlink() |
| | | formal_path = out_dir / f"{safe_name(item['company'])}价格合理性评估.md" |
| | | formal_path = out_dir / f"{safe_name(item['company'])}价格合理性评估_当前.md" |
| | | formal_path.write_text( |
| | | "\n".join( |
| | | [ |
| | |
| | | ) |
| | | formal = calc_text.replace("\n## 1. 结论先行", intro + "\n## 1. 结论先行", 1) |
| | | formal = formal.replace("价格合理性评估(流水线生成底稿)", "当前价格合理性评估", 1) |
| | | formal_path = out_dir / f"{safe_name(item['company'])}价格合理性评估.md" |
| | | formal_path = out_dir / f"{safe_name(item['company'])}价格合理性评估_当前.md" |
| | | formal_path.write_text("\n".join(line.rstrip() for line in formal.splitlines()) + "\n", encoding="utf-8") |
| | | evidence = { |
| | | "batch_id": BATCH_ID, "ticker": ticker, "company": item["company"], "as_of": AS_OF, |