Cai
8 days ago 2fbc2b9ee0dfcf211f57b04769b7694d539d7312
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
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
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()