from __future__ import annotations
|
|
import hashlib
|
import importlib.util
|
import json
|
import sys
|
from pathlib import Path
|
from typing import Any
|
|
|
ROOT = Path(__file__).resolve().parents[2]
|
sys.path.insert(0, str(ROOT / "dev" / "ana-dev"))
|
sys.path.insert(0, str(ROOT / "dev" / "project-dev"))
|
BASE_PATH = ROOT / "ai-valuation-analyst" / "tools" / "generate_semiconductor_batch_20260804.py"
|
SPEC = importlib.util.spec_from_file_location("valuation_batch_base_for_ubtech", BASE_PATH)
|
if SPEC is None or SPEC.loader is None:
|
raise RuntimeError(f"cannot load {BASE_PATH}")
|
base = importlib.util.module_from_spec(SPEC)
|
sys.modules[SPEC.name] = base
|
SPEC.loader.exec_module(base)
|
|
AS_OF = "2026-08-04"
|
BATCH_ID = "BATCH-STOCK-VALUATION-20260805-003"
|
FX_DATE = "2026-08-03"
|
CNY_PER_HKD = 0.8612
|
CNY_TO_HKD = 1 / CNY_PER_HKD
|
SHARES = 503_401_373
|
PRICE = 86.95
|
RESULT_DIR = ROOT / "ana-data" / "result" / "股票估值" / "20260805_ubtech_robotics_valuation"
|
CASE_RAW = ROOT / "ana-data" / "cases" / "股票估值" / BATCH_ID / "raw" / "09880_HK"
|
REGISTRY = ROOT / "dev" / "ana-dev" / "stock_valuation_pipeline" / "source_registry.json"
|
|
|
def hkd(cny: float) -> float:
|
return cny * CNY_TO_HKD
|
|
|
def write_json(path: Path, value: Any) -> None:
|
path.parent.mkdir(parents=True, exist_ok=True)
|
path.write_text(json.dumps(value, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
|
|
|
def sha256(path: Path) -> str:
|
return hashlib.sha256(path.read_bytes()).hexdigest()
|
|
|
FORECASTS_RMB = [
|
{"institution": "大和证券(DAIWA)", "report_date": "2026-07-02", "profit": 349_000_000, "eps": 0.692, "rating": "买入"},
|
{"institution": "招商证券国际", "report_date": "2026-07-02", "profit": -304_000_000, "eps": -0.600, "rating": "买入"},
|
{"institution": "美国银行证券", "report_date": "2026-07-01", "profit": -181_000_000, "eps": -0.3603, "rating": "买入"},
|
{"institution": "摩根大通", "report_date": "2026-07-02", "profit": -402_000_000, "eps": -0.800, "rating": "增持"},
|
{"institution": "海通国际", "report_date": "2026-05-19", "profit": -131_000_000, "eps": -0.260, "rating": "优于大市"},
|
{"institution": "国泰君安国际", "report_date": "2026-04-20", "profit": -268_000_000, "eps": -0.589, "rating": "买入"},
|
{"institution": "花旗", "report_date": "2026-07-03", "profit": -288_000_000, "eps": -0.573, "rating": "买入"},
|
]
|
|
|
def source_register() -> dict[str, Any]:
|
return {
|
"batch_id": BATCH_ID,
|
"ticker": "09880.HK",
|
"as_of": AS_OF,
|
"currency_policy": {
|
"valuation_currency": "HKD",
|
"financial_reporting_currency": "CNY",
|
"cny_per_hkd": CNY_PER_HKD,
|
"fx_date": FX_DATE,
|
"reason": "估值日为2026-08-04;采用估值日前最近可核验的2026-08-03历史即期汇率。",
|
},
|
"market": {
|
"price_hkd": PRICE,
|
"price_date": AS_OF,
|
"ohlc_hkd": {"open": 86.40, "high": 87.15, "low": 85.00, "close": 86.95},
|
"volume": 3_721_852,
|
"amount_hkd": 321_395_280,
|
"shares": SHARES,
|
"shares_date": "2026-07-31",
|
},
|
"financials_rmb": {
|
"2025": {
|
"revenue": 2_000_999_000,
|
"attributable_profit": -703_191_000,
|
"cfo": -784_111_000,
|
"capex": 409_024_000,
|
"attributable_equity": 7_217_986_000,
|
"cash_available": 4_887_880_000,
|
"interest_bearing_debt": 1_123_000_000,
|
"minority_interest": 107_618_000,
|
"non_operating_financial_assets": 120_043_000,
|
},
|
"2024": {
|
"revenue": 1_305_361_000,
|
"attributable_profit": -1_123_590_000,
|
"cfo": -883_636_000,
|
"capex": 226_968_000,
|
},
|
},
|
"institutions_2026_rmb": FORECASTS_RMB,
|
"source_urls": {
|
"hkex_title_search": "https://www1.hkexnews.hk/search/titlesearch.xhtml?category=0&market=SEHK&stockId=1000208870",
|
"hkex_2025_annual_results": "https://www1.hkexnews.hk/listedco/listconews/sehk/2026/0331/2026033102607.pdf",
|
"hkex_2025_annual_report": "https://www.hkexnews.hk/listedco/listconews/sehk/2026/0414/2026041401168.pdf",
|
"hkex_2026_july_monthly_return": "https://www1.hkexnews.hk/listedco/listconews/sehk/2026/0803/2026080302180.pdf",
|
"eastmoney_hk_kline": "https://push2his.eastmoney.com/api/qt/stock/kline/get?secid=116.09880",
|
"eastmoney_hk_cashflow": "https://datacenter-web.eastmoney.com/api/data/v1/get?reportName=RPT_HKF10_FN_CASHFLOW_PC",
|
"etnet_consensus": "https://www.etnet.com.hk/www/eng/stocks/realtime/quote_profit.php?code=9880",
|
"kgi_report": "https://www.kgi.com.hk/en/-/media/files/kgishk/research-reports/investment-perspectives/2026/kgis-global-markets-weekly-kickstart_20260413.pdf",
|
"fx_history": "https://www.exchangerates.org.uk/HKD-CNY-spot-exchange-rates-history-2026.html",
|
},
|
"bounded_gaps": [
|
"港股没有A股式扣非归母净利润字段;主报告以归母亏损作为保守代理,不制造扣非数。",
|
"公开机构明细页给出7家2026年盈利预测;汇总均值由逐家数字复算,不把评级或目标价作为估值输入。",
|
"2026年上半年中报尚未披露;TTM采用最新已审计2025全年口径,不外推2026年中期利润。",
|
],
|
}
|
|
|
def build_snapshot() -> dict[str, Any]:
|
annual_2024 = {
|
"period_end": "2024-12-31",
|
"basis": "audited",
|
"revenue": hkd(1_305_361_000),
|
"attributable_profit": hkd(-1_123_590_000),
|
"deduct_profit": hkd(-1_123_590_000),
|
"cfo": hkd(-883_636_000),
|
"capex": hkd(226_968_000),
|
}
|
latest_2025 = {
|
"period_end": "2025-12-31",
|
"basis": "audited_latest_full_year",
|
"revenue": hkd(2_000_999_000),
|
"attributable_profit": hkd(-703_191_000),
|
"deduct_profit": hkd(-703_191_000),
|
"cfo": hkd(-784_111_000),
|
"capex": hkd(409_024_000),
|
}
|
prior_2024 = dict(annual_2024)
|
prior_2024["basis"] = "reported_comparative"
|
equity = hkd(7_217_986_000)
|
bvps = equity / SHARES
|
scenarios = [
|
{
|
"name": "悲观情景",
|
"role": "pessimistic",
|
"method": "pb",
|
"multiple_low": 2.0,
|
"multiple_high": 4.0,
|
"assumption": "人形机器人收入增速明显降档、亏损收窄慢于机构预期,现金消耗继续压低安全边际。",
|
},
|
{
|
"name": "基准情景",
|
"role": "base",
|
"method": "pb",
|
"multiple_low": 4.0,
|
"multiple_high": 6.0,
|
"assumption": "2026年收入接近33亿元人民币公开预测,归母亏损落在机构中位数附近并继续收窄,现金储备可支持研发与交付。",
|
},
|
{
|
"name": "乐观情景",
|
"role": "optimistic",
|
"method": "pb",
|
"multiple_low": 6.0,
|
"multiple_high": 9.0,
|
"assumption": "全尺寸人形机器人实现规模交付,毛利率和费用率同步改善,市场继续给予稀缺成长溢价。",
|
},
|
]
|
institutions = []
|
for item in FORECASTS_RMB:
|
institutions.append({
|
"institution": item["institution"],
|
"report_date": item["report_date"],
|
"include": True,
|
"core_assumption": f"ETNet公开明细;评级为{item['rating']}。盈利预测按{CNY_PER_HKD:.4f}人民币/港元换算,仅利润进入一致预期。",
|
"source_id": "SRC-ETNET-CONSENSUS",
|
"estimates": {"2026": {"profit": hkd(item["profit"]), "eps": hkd(item["eps"])}}
|
})
|
sources = [
|
{
|
"id": "SRC-HKEX-RESULTS-2025",
|
"source_type": "archived_primary",
|
"title": "优必选2025年度业绩公告",
|
"publish_date": "2026-03-31",
|
"period_end": "2025-12-31",
|
"url": "https://www1.hkexnews.hk/listedco/listconews/sehk/2026/0331/2026033102607.pdf",
|
"supports": [
|
"financials.annual", "financials.current_cumulative", "financials.prior_year_same_period",
|
"balance_sheet.equity", "balance_sheet.cash_available", "balance_sheet.interest_bearing_debt",
|
],
|
"revision_status": "current",
|
},
|
{
|
"id": "SRC-HKEX-ANNUAL-2025",
|
"source_type": "archived_primary",
|
"title": "优必选2025年度报告",
|
"publish_date": "2026-04-14",
|
"period_end": "2025-12-31",
|
"url": "https://www.hkexnews.hk/listedco/listconews/sehk/2026/0414/2026041401168.pdf",
|
"supports": ["financials.current_cumulative", "balance_sheet.equity", "financials.cashflow", "business.segments"],
|
"revision_status": "current",
|
},
|
{
|
"id": "SRC-HKEX-SHARES-202607",
|
"source_type": "archived_primary",
|
"title": "截至2026年7月31日证券变动月报表",
|
"publish_date": "2026-08-03",
|
"period_end": "2026-07-31",
|
"url": "https://www1.hkexnews.hk/listedco/listconews/sehk/2026/0803/2026080302180.pdf",
|
"supports": ["market.diluted_shares", "shares.full_circulation"],
|
"revision_status": "current",
|
},
|
{
|
"id": "SRC-EM-HK-KLINE-20260804",
|
"source_type": "quote_provider",
|
"title": "东方财富优必选2026-08-04未复权日K收盘价",
|
"publish_date": AS_OF,
|
"period_end": AS_OF,
|
"url": "https://push2his.eastmoney.com/api/qt/stock/kline/get?secid=116.09880",
|
"supports": ["market.price", "market.volume", "market.platform_market_cap"],
|
"revision_status": "current",
|
},
|
{
|
"id": "SRC-ETNET-CONSENSUS",
|
"source_type": "institution_aggregator",
|
"title": "ETNet优必选机构盈利预测明细",
|
"publish_date": AS_OF,
|
"period_end": AS_OF,
|
"url": "https://www.etnet.com.hk/www/eng/stocks/realtime/quote_profit.php?code=9880",
|
"supports": ["institutions"],
|
"revision_status": "current",
|
},
|
{
|
"id": "SRC-FX-HKD-CNY-20260803",
|
"source_type": "professional_database",
|
"title": "2026-08-03历史港元兑人民币即期汇率",
|
"publish_date": FX_DATE,
|
"period_end": FX_DATE,
|
"url": "https://www.exchangerates.org.uk/HKD-CNY-spot-exchange-rates-history-2026.html",
|
"supports": ["bulk_history"],
|
"revision_status": "current",
|
},
|
]
|
market_cap = PRICE * SHARES
|
return {
|
"snapshot_id": "SNAPSHOT-09880-20260804-V1",
|
"meta": {
|
"company": "优必选",
|
"code": "09880.HK",
|
"market": "香港联合交易所主板",
|
"as_of_date": AS_OF,
|
"currency": "HKD",
|
"report_period_end": "2025-12-31",
|
"latest_operating_info_date": "2026-04-14",
|
},
|
"market": {
|
"price": PRICE,
|
"price_type": "2026-08-04香港市场完整交易日未复权收盘价(港元)",
|
"price_timestamp": "2026-08-04T16:08:00+08:00",
|
"diluted_shares": SHARES,
|
"shares_date": "2026-07-31",
|
"platform_market_cap": None,
|
},
|
"financials": {
|
"annual": annual_2024,
|
"current_cumulative": latest_2025,
|
"prior_year_same_period": prior_2024,
|
},
|
"balance_sheet": {
|
"period_end": "2025-12-31",
|
"equity": equity,
|
"cash_available": hkd(4_887_880_000),
|
"non_operating_financial_assets": hkd(120_043_000),
|
"interest_bearing_debt": hkd(1_123_000_000),
|
"minority_interest": hkd(107_618_000),
|
},
|
"normalization": {
|
"adjustments": [{
|
"description": "港股法定报告未披露A股式扣非归母利润,以归母亏损作保守代理",
|
"amount": 0,
|
"basis": "不制造扣非数据;2025年最新已审计归母亏损直接作为归一化口径",
|
}]
|
},
|
"valuation": {
|
"scenarios": scenarios,
|
"reverse_pe_multiples": [20, 25, 30, 40, 50, 60, 75, 100],
|
"exit_pe_multiples": [20, 25, 30, 40, 50, 60, 75, 100],
|
"holding_period": {"years": 5, "required_return": 0.10, "cumulative_dividend_per_share": 0},
|
},
|
"institutions": {"coverage_status": "available", "forecasts": institutions},
|
"sources": sources,
|
"analysis": {
|
"company_type": "高成长但仍亏损的人形机器人平台公司",
|
"primary_model": "PB情景为主,PS、机构亏损收窄路径和现金消耗交叉验证;亏损状态不使用PE给方向性结论",
|
"cross_checks": ["2025年PB/PS", "2026年机构盈利预测", "KGI 2026年收入预测", "现金与经营现金流", "股本变动月报"],
|
"profit_sources": [
|
"2025年收入20.01亿元人民币,同比增长53.3%;其中全尺寸具身智能人形机器人约8.21亿元人民币,已成为最大收入来源。",
|
"其他机器人产品及服务约6.29亿元人民币、其他智能硬件约4.99亿元人民币,利润改善取决于机器人规模交付、产品毛利率和费用率,而非只看订单题材。",
|
"2025年归母仍亏损7.03亿元人民币;当前可衡量的是亏损收窄路径和现金安全垫,尚不能把收入增长直接等同于成熟利润。",
|
],
|
"profit_source_quality": [
|
"最新已审计2025年归母亏损7.03亿元人民币,较2024年归母亏损11.24亿元人民币收窄,但尚未跨过可持续盈利门槛。",
|
"2025年经营现金流约-7.84亿元人民币、资本开支约4.09亿元人民币,简化自由现金流仍显著为负;资产负债表因股权融资而较强。",
|
"7家公开机构对2026年归母利润预测从亏损4.02亿元人民币到盈利3.49亿元人民币,分歧很大,中位数为亏损2.68亿元人民币。",
|
],
|
"cashflow_notes": [
|
"2025年现金及现金等价物约48.88亿元人民币,可覆盖当前研发和交付投入,但高现金主要来自融资,不能替代经营自我造血。",
|
"企业价值计算按港元统一换算;采用2026-08-03的0.8612人民币/港元,汇率滞后一个自然日的影响小于财务预测分歧。",
|
],
|
"risks": [
|
"2026年机构盈利预测横跨盈亏两端,说明商业化节奏和费用收敛高度不确定。",
|
"当前约5.22倍PB、18.84倍2025年PS;按KGI 2026年33亿元人民币收入预测,前瞻PS仍约11.42倍,传统估值安全垫不高。",
|
"人形机器人订单到收入、收入到回款、回款到可持续利润之间存在较长验证链;交付不及预期会同时压低收入和估值倍数。",
|
"股权融资提高净资产与现金,也造成潜在摊薄;PB基准对融资时点和现金消耗敏感。",
|
],
|
"upgrade_triggers": [
|
"2026年收入达到或超过33亿元人民币,同时归母亏损接近机构中位数并且经营现金流明显改善。",
|
"全尺寸人形机器人持续规模交付,毛利率提升且应收、存货和合同资产没有失控。",
|
],
|
"downgrade_triggers": [
|
"收入增速低于基准路径、机构继续下修2026年盈利,或现金消耗显著超过当前预期。",
|
"新增融资导致明显摊薄,或者市场将成长PB从4—6倍压缩至2—4倍。",
|
],
|
"executive_conclusion": (
|
f"{PRICE:.2f}港元位于PB基准合理区间{bvps*4:.2f}—{bvps*6:.2f}港元内,判断为基本合理,"
|
"但属于高风险、高弹性的条件化合理;当前价格要求2026年收入高增长、亏损继续收窄和现金消耗受控同时兑现。"
|
),
|
"fx_rate_cny_per_hkd": CNY_PER_HKD,
|
"fx_date": FX_DATE,
|
"ttm_definition_note": "香港市场截至估值日没有2026年一季报;为保持固定TTM公式,年度锚点与上年同期均使用2024年,当前累计使用最新已审计2025全年,复算结果严格等于2025全年。",
|
"institution_provider_consolidation_2026_rmb": -268_000_000,
|
"institution_recomputed_mean_2026_rmb": sum(item["profit"] for item in FORECASTS_RMB) / len(FORECASTS_RMB),
|
"kgi_revenue_2026_rmb": 3_300_000_000,
|
"information_cutoff": "2026-08-04T23:59:59+08:00",
|
},
|
}
|
|
|
def main() -> None:
|
RESULT_DIR.mkdir(parents=True, exist_ok=True)
|
CASE_RAW.mkdir(parents=True, exist_ok=True)
|
register_path = CASE_RAW / "优必选公开数据登记_20260804.json"
|
write_json(register_path, source_register())
|
snapshot = build_snapshot()
|
snapshot_path = RESULT_DIR / "优必选估值快照_20260804.json"
|
write_json(snapshot_path, snapshot)
|
calc_dir = RESULT_DIR / "calculation"
|
run = base.run_pipeline(snapshot_path, calc_dir, REGISTRY)
|
results_path = calc_dir / "valuation_results.json"
|
results = json.loads(results_path.read_text(encoding="utf-8"))
|
report = (calc_dir / "valuation_report.md").read_text(encoding="utf-8")
|
report = report.replace("价格合理性评估(流水线生成底稿)", "价格合理性评估", 1)
|
report = report.replace(
|
"本文是研究计算底稿,不构成交易指令或收益承诺。",
|
"本文为按《股票价格合理性评估操作手册》形成的条件化研究结论,不构成交易指令或收益承诺。",
|
1,
|
)
|
report = report.replace("亿元", "亿港元").replace(" 元", " 港元").replace("使用元", "使用港元")
|
report = report.replace("亿港元人民币", "亿元人民币")
|
report = report.replace("| 最近年度 CFO |", "| 年度锚点 CFO(2024) |")
|
report = report.replace("| 最近年度资本开支 |", "| 年度锚点资本开支(2024) |")
|
report = report.replace("| 最近年度简化 FCF |", "| 年度锚点简化 FCF(2024) |")
|
report = report.replace("| 本期累计简化 FCF |", "| 最新已审计2025全年简化 FCF |")
|
ttm_note = snapshot["analysis"]["ttm_definition_note"]
|
report = report.replace("## 4. TTM 与归一化利润\n", f"## 4. TTM 与归一化利润\n\n> 港股TTM口径说明:{ttm_note}\n", 1)
|
formal_path = RESULT_DIR / "优必选价格合理性评估_20260804.md"
|
formal_path.write_text(report, encoding="utf-8")
|
evidence = {
|
"batch_id": BATCH_ID,
|
"ticker": "09880.HK",
|
"company": "优必选",
|
"as_of": AS_OF,
|
"information_cutoff": snapshot["analysis"]["information_cutoff"],
|
"raw_register": str(register_path.relative_to(ROOT)).replace("\\", "/"),
|
"raw_register_sha256": sha256(register_path),
|
"snapshot_sha256": sha256(snapshot_path),
|
"calculation_sha256": sha256(results_path),
|
"formal_report_sha256": sha256(formal_path),
|
"source_urls": source_register()["source_urls"],
|
"checks": {
|
"price_times_shares_hkd": PRICE * SHARES,
|
"result_market_cap_hkd": float(results["metrics"]["market_cap"]),
|
"shares_from_hkex_monthly_return": SHARES,
|
"cny_per_hkd": CNY_PER_HKD,
|
"institution_count": len(FORECASTS_RMB),
|
"qa": results["qa"],
|
},
|
"bounded_gaps": source_register()["bounded_gaps"],
|
}
|
write_json(RESULT_DIR / "source_evidence_manifest.json", evidence)
|
summary = {
|
"ticker": "09880.HK",
|
"company": "优必选",
|
"slug": "ubtech_robotics",
|
"price": PRICE,
|
"market_cap": float(results["metrics"]["market_cap"]),
|
"normalized_profit": float(results["metrics"]["normalized_profit"]),
|
"normalized_pe": None,
|
"pb": float(results["metrics"]["pb"]),
|
"ps": float(results["metrics"]["ps"]),
|
"consensus_count": len(FORECASTS_RMB),
|
"consensus_2026": float(results["institutions"]["summary"]["2026"]["profit_mean"]),
|
"consensus_median_2026": float(results["institutions"]["summary"]["2026"]["profit_median"]),
|
"forward_pe": None,
|
"base_low": float(results["scenarios"][1]["price_low"]),
|
"base_high": float(results["scenarios"][1]["price_high"]),
|
"optimistic_high": float(results["scenarios"][2]["price_high"]),
|
"label": "基本合理(高风险/高弹性)",
|
"qa": results["qa"]["status"],
|
"qa_errors": results["qa"]["error_count"],
|
"qa_warnings": results["qa"]["warning_count"],
|
"share_status": "HKEX_MONTHLY_RETURN_EXACT",
|
"currency": "HKD",
|
"formal_path": "20260805_ubtech_robotics_valuation/优必选价格合理性评估_20260804.md",
|
"run_status": run["status"],
|
}
|
write_json(RESULT_DIR / "summary_row.json", summary)
|
print(json.dumps(summary, ensure_ascii=False), flush=True)
|
|
|
if __name__ == "__main__":
|
main()
|