feat: 增加宁德时代图表
This commit is contained in:
@@ -0,0 +1,108 @@
|
||||
#!/usr/bin/env python3
|
||||
"""甜蜜击球区 · 宁德时代(300750):股价 → 估值指标 投影表生成器
|
||||
|
||||
数据层定位:本脚本是 data/sweetspot/*.csv 的唯一生成入口(CSV 是运行时投影,
|
||||
禁止手工编辑)。上游底稿是资料库节点「宁德时代_股价PE对照表」
|
||||
(https://www.workbuddy.cn/space/d/EsAWMaLKt4ECKPDvESKKvT,2026-09-15 版)。
|
||||
|
||||
计算基准(改这几个常量就能整表重算):
|
||||
总股本 46.27 亿股
|
||||
净现金 2,263.8 亿元 (每股 48.93 元)
|
||||
2026E 归母 悲观 900 / 中性 964 / 乐观 1,000 亿元(65 家机构一致预期)
|
||||
分红率 50%(2023–2025 年实际值)
|
||||
现价 316.21 元(2026-09-15 收盘)
|
||||
2028E 目标 1,400 亿 × 20x → 605 元(老唐法三年后合理估值,用于试算年化收益)
|
||||
无风险利率 1.68%(10 年期国债,仅用于股息率倍数的脚注说明)
|
||||
|
||||
精度例外:PE 与股息率保留两位小数。CLAUDE.md 默认一位,但 PE 一位会把
|
||||
15.18x 与 15.2x 揉成同一个读数,而「现价到底落在哪个区间」正是这张表要回答的
|
||||
问题(买入区上沿 15.5x 与合理区下沿贴得极近),故按行业惯例取两位。
|
||||
|
||||
用法:
|
||||
python3 scripts/build_sweet_spot_catl.py
|
||||
"""
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
SHARES = 46.27 # 亿股
|
||||
NET_CASH = 2263.8 # 亿元
|
||||
NOW = 316.21 # 元
|
||||
PAYOUT = 0.50
|
||||
NI = {"bear": 900.0, "base": 964.0, "bull": 1000.0}
|
||||
TARGET_2028 = 605.0 # 元(2028E 1,400 亿 × 20x ÷ 46.27 亿股)
|
||||
|
||||
OUT_DIR = Path(__file__).resolve().parent.parent / "data" / "sweetspot"
|
||||
|
||||
|
||||
def price_grid(top, step=20, keys=()):
|
||||
"""等距网格 + 关键价位去重后升序,保证关键价位本身就是数据点(可被打标签)。"""
|
||||
prices = {float(p) for p in range(220, top + 1, step)}
|
||||
prices.update(float(k) for k in keys)
|
||||
return sorted(prices)
|
||||
|
||||
|
||||
def pct(value):
|
||||
return value * 100
|
||||
|
||||
|
||||
def main():
|
||||
OUT_DIR.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
header = (
|
||||
"# 由 scripts/build_sweet_spot_catl.py 生成,请勿手工编辑。\n"
|
||||
"# 口径:总股本 46.27 亿股 · 净现金 2,263.8 亿元(每股 48.93 元)· "
|
||||
"2026E 归母 900/964/1,000 亿元 · 分红率 50% · 现价 316.21 元(2026-09-15)\n"
|
||||
"# PE 与股息率保留两位小数(见脚本 docstring 的精度例外说明)\n"
|
||||
)
|
||||
|
||||
# ---------- 1) 股价 → PE 对照(图 1、图 2 共用) ----------
|
||||
rows = price_grid(700, 20, (265, 290, 303, NOW, 378, 605, 617))
|
||||
lines = [
|
||||
"price,market_cap,pe_bear,pe_base,pe_bull,pe_ex_cash,dividend_yield,net_cash_pct"
|
||||
]
|
||||
for px in rows:
|
||||
cap = px * SHARES
|
||||
lines.append(
|
||||
",".join([
|
||||
f"{px:.2f}",
|
||||
f"{cap:.1f}",
|
||||
f"{cap / NI['bear']:.2f}",
|
||||
f"{cap / NI['base']:.2f}",
|
||||
f"{cap / NI['bull']:.2f}",
|
||||
f"{(cap - NET_CASH) / NI['base']:.2f}",
|
||||
f"{pct(NI['base'] * PAYOUT / cap):.2f}",
|
||||
f"{pct(NET_CASH / cap):.1f}",
|
||||
])
|
||||
)
|
||||
path = OUT_DIR / "catl_price_pe.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) ----------
|
||||
rows = price_grid(620, 20, (265, 290, 303, NOW, 378, 450, TARGET_2028))
|
||||
lines = [
|
||||
"price,market_cap,pe_base,dividend_yield,cagr_price,cagr_total"
|
||||
]
|
||||
for px in rows:
|
||||
cap = px * SHARES
|
||||
dy = NI["base"] * PAYOUT / cap
|
||||
cagr = (TARGET_2028 / px) ** (1 / 3) - 1
|
||||
# 总收益按 (1 + 价差年化) × (1 + 股息率) − 1:股息以买入价口径年年复投,
|
||||
# 与资料库试算器的「未含分红」口径并列展示,两者差额即分红的贡献。
|
||||
lines.append(
|
||||
",".join([
|
||||
f"{px:.2f}",
|
||||
f"{cap:.1f}",
|
||||
f"{cap / NI['base']:.2f}",
|
||||
f"{pct(dy):.2f}",
|
||||
f"{pct(cagr):.1f}",
|
||||
f"{pct((1 + cagr) * (1 + dy) - 1):.1f}",
|
||||
])
|
||||
)
|
||||
path = OUT_DIR / "catl_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)} 行")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user