#!/usr/bin/env python3 """甜蜜击球区 · 腾讯控股(00700.HK):股价 → 估值指标 投影表生成器 数据层定位:本脚本是 data/sweetspot/tencent_*.csv 的唯一生成入口(CSV 是运行时投影, 禁止手工编辑)。上游底稿是资料库节点「腾讯控股(00700.HK)甜蜜击球区检验」 (https://www.workbuddy.cn/space/d/Ey5NeiPls71FC12zn0ieSX,2026-09-17 版)。 与宁德那套(build_sweet_spot_catl.py)的两处口径差异,都是腾讯特有的: 1. 纵轴是 EV/EBIT,不是 PE。腾讯的「类现金」是 5,260 亿投资组合(股权、会波动), 只扣净现金(582 亿)几乎不改变倍数 —— 必须连投资组合一起扣,才是真实的经营资产价格。 2. 三情景是 EBIT(悲观 2,400 / 基准 2,585 / 乐观 2,900 亿元),不是归母净利。 分子分母成对:分母扣了投资组合,分子就不能含投资收益,所以用经营盈利口径。 计算基准(改这几个常量就能整表重算): 总股本 90.95 亿股 汇率 1 HKD = 0.86154 CNY(中国外汇交易中心 2026-09-17 中间价) 净现金 581.9 亿元 上市投资 4,872.0 亿元(公允价值) 非上市投资 387.9 亿元(账面) 非经营资产 5,841.8 亿元(= 净现金 + 上市 + 非上市,占市值 17.5%) TTM EBIT 2,585.43 亿元(= 2,415.62 − 1,176.70 + 1,346.51) 折旧情景 5 年直线 → 稳态 EBIT 2,247 亿元(占当前 EBIT 13.1%) 现价 426.8 港元(2026-09-17 收盘) 甜蜜区 8x 白送 / 10x 甜点 / 12x 上沿(巴菲特 10x 税前锚) 目标价 12x 上沿 470.5 / 10x 甜点 404.5 港元(基准 EBIT,不给增长) 用法: python3 scripts/build_sweet_spot_tencent.py """ from pathlib import Path SHARES = 90.95 # 亿股 FX = 0.86154 # 1 HKD = ? CNY NET_CASH = 581.9 # 亿元 LISTED = 4872.0 # 亿元(上市投资,公允价值) UNLISTED = 387.9 # 亿元(非上市投资,账面) NON_OP = NET_CASH + LISTED + UNLISTED # 5,841.8 亿元 EBIT = {"bear": 2400.0, "base": 2585.43, "bull": 2900.0} EBIT_DEP = 2247.0 # 5 年折旧情景下的稳态 EBIT(亿元) NOW = 426.8 # 港元 EXIT_MULT = {"high": 12.0, "mid": 10.0} # 三年后退出倍数(甜蜜区上沿 / 甜点) PRICE_BOTTOM = 240 # 港元,数据区下限 PRICE_TOP = 640 # 港元,数据区上限 OUT_DIR = Path(__file__).resolve().parent.parent / "data" / "sweetspot" # 数据点里必须出现的价位:甜蜜区标尺 5 档 + 现价。 # 它们要能被折线的数据标签命中(label.position 不接受函数,只能逐点覆盖 data)。 KEY_PRICES = ( 8 * EBIT["base"] + NON_OP, 9 * EBIT["base"] + NON_OP, 10 * EBIT["base"] + NON_OP, NOW * SHARES * FX, 12 * EBIT["base"] + NON_OP, ) KEY_PRICES = tuple(value / (SHARES * FX) for value in KEY_PRICES) def price_grid(top, step=20, keys=()): """等距网格 + 关键价位去重后升序,保证关键价位本身就是数据点(可被打标签)。""" prices = {float(p) for p in range(PRICE_BOTTOM, top + 1, step)} prices.update(round(float(k), 1) for k in keys) return sorted(prices) def price_to_hkd(value): """目标价公式:股价 =(目标倍数 × EBIT + 非经营资产)÷ 股本 ÷ 汇率。""" return value / (SHARES * FX) def mult_at(price, ebit, deduct=NON_OP): """EV/EBIT =(市值 − 扣除的非经营资产)÷ EBIT。deduct=0 即不扣任何资产。""" return (price * SHARES * FX - deduct) / ebit def main(): OUT_DIR.mkdir(parents=True, exist_ok=True) header = ( "# 由 scripts/build_sweet_spot_tencent.py 生成,请勿手工编辑。\n" "# 口径:总股本 90.95 亿股 · 汇率 0.86154 · 非经营资产 5,841.8 亿元" "(净现金 581.9 + 上市投资 4,872.0 + 非上市投资 387.9)· " "TTM EBIT 2,585.43 亿元 · 三情景 EBIT 2,400/2,585/2,900 亿元 · 现价 426.8 港元(2026-09-17)\n" "# 倍数与年化收益保留两位小数(与宁德两份表同精度;倍数一位会把 10.68x 与 10.7x 揉成一个读数)\n" ) # ---------- 1) 股价 → 倍数对照(图 1、图 2 共用) ---------- rows = price_grid(PRICE_TOP, 20, KEY_PRICES) lines = [ "price,market_cap,mult_bear,mult_base,mult_bull,mult_net_cash,mult_gross,non_op_pct" ] for px in rows: cap = px * SHARES * FX lines.append( ",".join([ f"{px:.2f}", f"{cap:.1f}", f"{mult_at(px, EBIT['bear']):.2f}", f"{mult_at(px, EBIT['base']):.2f}", f"{mult_at(px, EBIT['bull']):.2f}", f"{mult_at(px, EBIT['base'], NET_CASH):.2f}", f"{mult_at(px, EBIT['base'], 0):.2f}", f"{NON_OP / cap * 100:.1f}", ]) ) path = OUT_DIR / "tencent_price_ev.csv" path.write_text(header + "\n".join(lines) + "\n", encoding="utf-8") print(f"{path.relative_to(OUT_DIR.parent.parent)} {len(rows)} 行") # ---------- 2) 股价 → 三年退出试算(图 3) ---------- # 目标价三年不变(不给增长):退出在甜蜜区上沿 / 甜点 / 折旧后的上沿,年化只由买入价决定。 targets = { "cagr_12x": price_to_hkd(EXIT_MULT["high"] * EBIT["base"] + NON_OP), "cagr_10x": price_to_hkd(EXIT_MULT["mid"] * EBIT["base"] + NON_OP), "cagr_12x_dep": price_to_hkd(EXIT_MULT["high"] * EBIT_DEP + NON_OP), } rows = price_grid(PRICE_TOP, 20, KEY_PRICES) lines = ["price,market_cap,mult_base,cagr_12x,cagr_10x,cagr_12x_dep"] for px in rows: cap = px * SHARES * FX lines.append( ",".join([ f"{px:.2f}", f"{cap:.1f}", f"{mult_at(px, EBIT['base']):.2f}", *[f"{((value / px) ** (1 / 3) - 1) * 100:.2f}" for value in ( targets["cagr_12x"], targets["cagr_10x"], targets["cagr_12x_dep"], )], ]) ) path = OUT_DIR / "tencent_price_returns.csv" path.write_text(header + "\n".join(lines) + "\n", encoding="utf-8") print(f"{path.relative_to(OUT_DIR.parent.parent)} {len(rows)} 行") print("\n目标价(港元):" + " | ".join(f"{k} {v:.1f}" for k, v in targets.items())) print("现价倍数:" + " | ".join([ f"悲观 {mult_at(NOW, EBIT['bear']):.2f}x", f"基准 {mult_at(NOW, EBIT['base']):.2f}x", f"乐观 {mult_at(NOW, EBIT['bull']):.2f}x", f"只扣净现金 {mult_at(NOW, EBIT['base'], NET_CASH):.2f}x", f"不扣 {mult_at(NOW, EBIT['base'], 0):.2f}x", ])) if __name__ == "__main__": main()