03 · 财务指标与估值¶

长期投资教程 · 第 3 章

免责声明:本教程为投资教育内容,所有分析与示例仅为方法演示,不构成任何投资建议。文中涉及的公司与数据仅用于教学举例,不代表推荐。市场有风险,决策需自负。


本章学什么 / 读完会什么¶

  • 掌握给公司「体检」的核心指标:ROE、毛利率/净利率、资产负债率、自由现金流(FCF);
  • 用杜邦分析把 ROE 拆成三块,看清一家公司「靠什么赚钱」;
  • 理解三大估值尺子 PE / PB / PEG,并用茅台真实价格 + 财报算出来;
  • 用一个可交互的简化 DCF 计算器,亲手改假设看「公司值多少钱」怎么变。

所有指标先讲「它在回答什么问题」,再给公式和代码。

In [1]:
import sys, os
sys.path.insert(0, os.path.abspath('.'))
import warnings; warnings.filterwarnings('ignore')
import numpy as np, pandas as pd
import matplotlib.pyplot as plt
import invest_data as D
FONT = D.setup_matplotlib()
np.random.seed(D.SEED)
print('中文字体:', FONT, '| 数据目录:', D.DATA_DIR)
中文字体: Noto Sans CJK SC | 数据目录: /data/docs/investing/long-term-investing/data

3.1 ROE:衡量「赚钱效率」的王牌指标¶

大白话:ROE(净资产收益率)= 净利润 ÷ 股东权益。它回答:股东每投入 1 块钱,公司一年能用它赚回几毛?

类比:你开店投入 100 万(净资产),一年净赚 20 万,ROE 就是 20%。同样投 100 万,A 店赚 20 万、B 店赚 5 万,显然 A 店「钱生钱」的本事强。

为什么巴菲特最看重 ROE:长期看,一只股票的年化回报会向它的 ROE 靠拢。长期高 ROE(>15%)且稳定,往往意味着有护城河。

看茅台的 ROE 历史:

In [2]:
ab = D.load_a_abstract("600519")
def yearly(metric):
    s = ab.loc[metric].dropna(); s = s[s.index.month == 12]
    return s[s.index.year >= 2018]
roe = yearly("净资产收益率(ROE)")

fig, ax = plt.subplots(figsize=(10, 5))
ax.bar([d.year for d in roe.index], roe.values, color="#c0392b", alpha=0.8)
ax.axhline(15, color="gray", ls="--", label="15% 优秀线")
for d, v in zip(roe.index, roe.values):
    ax.text(d.year, v+0.5, f"{v:.0f}", ha="center")
ax.set_title(f"贵州茅台 ROE(净资产收益率){D.source_tag(ab)}")
ax.set_xlabel("年份"); ax.set_ylabel("ROE %"); ax.legend()
plt.tight_layout(); plt.show()
print(f"茅台近年 ROE 常年在 {roe.min():.0f}%~{roe.max():.0f}% 之间,远超 15% 的优秀线。")
No description has been provided for this image
茅台近年 ROE 常年在 30%~36% 之间,远超 15% 的优秀线。

这张图在说什么:茅台 ROE 常年稳定在 30% 上下,远超「15% 优秀线」。这意味着股东的钱在茅台手里每年能滚出三成回报——这是顶级生意的标志。单看一年的高 ROE 不算数,要的是「长期且稳定」的高 ROE。

3.2 杜邦分析:把 ROE 拆开,看它靠什么撑起来¶

同样是 20% 的 ROE,有的公司靠高利润率(卖得贵,如茅台),有的靠高周转(薄利多销,如超市),有的靠高杠杆(借钱放大,如银行/地产)。杜邦分析就是这把「拆解刀」:

$$ROE = \underbrace{\frac{净利润}{营收}}_{净利率} \times \underbrace{\frac{营收}{总资产}}_{总资产周转率} \times \underbrace{\frac{总资产}{股东权益}}_{权益乘数(杠杆)}$$

  • 净利率高:产品赚钱、有定价权(消费、奢侈品)。
  • 周转率高:资产用得勤、薄利多销(零售、制造)。
  • 权益乘数高:靠借债放大,风险也放大(金融、地产)。

用茅台真实财报亲手拆一遍:

In [3]:
inc = D.load_a_report("600519", "income")
bal = D.load_a_report("600519", "balance")

def annual_val(df, col):
    s = df[df.index.month == 12][col].dropna()
    return s[s.index.year >= 2019]

rev = annual_val(inc, "营业总收入")
ni  = annual_val(inc, "净利润")
ta  = annual_val(bal, "资产总计")
eq  = annual_val(bal, "归属于母公司股东权益合计")

dupont = pd.DataFrame(index=[d.year for d in rev.index])
dupont["净利率%"] = (ni.values / rev.values * 100).round(1)
dupont["总资产周转率"] = (rev.values / ta.values).round(2)
dupont["权益乘数"] = (ta.values / eq.values).round(2)
dupont["ROE%(拆解还原)"] = (dupont["净利率%"]/100 * dupont["总资产周转率"] * dupont["权益乘数"] * 100).round(1)
print("贵州茅台 杜邦三因子拆解  数据来源:", D.source_tag(inc))
print(dupont.to_string())

fig, axes = plt.subplots(1, 3, figsize=(14, 4))
for ax, col, color in zip(axes, ["净利率%", "总资产周转率", "权益乘数"], ["#c0392b","#16a085","#e67e22"]):
    ax.bar(dupont.index, dupont[col], color=color, alpha=0.8)
    ax.set_title(col); ax.set_xlabel("年份")
plt.tight_layout(); plt.show()
贵州茅台 杜邦三因子拆解  数据来源: (真实数据·本地缓存)
      净利率%  总资产周转率  权益乘数  ROE%(拆解还原)
2019  49.5    0.49  1.35        32.7
2020  50.5    0.46  1.32        30.7
2021  50.9    0.43  1.35        29.5
2022  51.3    0.50  1.29        33.1
2023  51.5    0.55  1.26        35.7
2024  51.3    0.58  1.28        38.1
2025  49.6    0.57  1.24        35.1
No description has been provided for this image

这张图在说什么:茅台的 ROE 几乎完全由超高净利率(50%+)撑起来——卖得极贵、成本极低;总资产周转率不高(重资产、存货周期长),权益乘数也很低(几乎不借债)。结论:茅台是典型的「高毛利、低杠杆」白马,赚钱靠的是品牌定价权,而不是借债或走量。换成银行股,你会看到完全相反的画面:净利率一般、周转极低、权益乘数高达 10+。

3.3 自由现金流(FCF):公司能自由支配的真金白银¶

大白话:自由现金流 = 经营赚到的现金 − 维持和扩张生意必须花的钱(资本开支)。它是公司真正能拿去分红、回购、还债、再投资的钱。

类比:你月薪到手 2 万(经营现金流),但每月必须花 5 千买工具维持工作能力(资本开支),真正能自由花的是 1.5 万(FCF)。

公式(简化):FCF = 经营活动现金流净额 − 购建固定资产无形资产等支付的现金

利润可以「修饰」,但自由现金流很难长期造假。长期 FCF 为正且增长的公司,才是真正的现金奶牛。看茅台:

In [4]:
cf = D.load_a_report("600519", "cashflow")
ocf = annual_val(cf, "经营活动产生的现金流量净额")
capex = annual_val(cf, "购建固定资产、无形资产和其他长期资产所支付的现金")
fcf = (ocf - capex) / 1e8

fig, ax = plt.subplots(figsize=(10, 5))
yrs = [d.year for d in ocf.index]
ax.bar([y-0.2 for y in yrs], ocf.values/1e8, width=0.4, label="经营现金流", color="#16a085")
ax.bar([y+0.2 for y in yrs], fcf.values, width=0.4, label="自由现金流 FCF", color="#c0392b")
ax.set_title(f"茅台 经营现金流 与 自由现金流(亿元){D.source_tag(cf)}")
ax.set_xlabel("年份"); ax.set_ylabel("亿元"); ax.legend()
plt.tight_layout(); plt.show()
print("自由现金流(亿元):", dict(zip(yrs, fcf.round(0).astype(int).tolist())))
No description has been provided for this image
自由现金流(亿元): {2019: 421, 2020: 496, 2021: 606, 2022: 314, 2023: 640, 2024: 878, 2025: 584}

这张图在说什么:茅台的资本开支(经营现金流和 FCF 两根柱子的差额)很小——它不需要不断砸钱建厂就能赚钱,所以自由现金流几乎和经营现金流一样高、年年为正且巨大。这种「轻资本、高 FCF」的生意,是长期投资者梦寐以求的现金奶牛。反例是重资产行业(航空、面板),辛苦赚的钱大半要砸回设备,FCF 常年紧张甚至为负。

3.4 估值:好公司 ≠ 好股票,还要看「买得贵不贵」¶

再好的公司,买太贵也赚不到钱。估值就是回答「现在这个价,值不值」。三把常用尺子:

指标 公式 大白话 适用
PE 市盈率 股价 / 每股收益 按当前盈利,回本要几年 盈利稳定的公司
PB 市净率 股价 / 每股净资产 花几倍于净资产的价买 重资产/银行/周期
PEG PE / 盈利增速 把成长性也算进去,<1 通常算便宜 成长股

用茅台当前真实股价 + 最新财报每股数据,算出真实的 PE/PB:

In [5]:
price = D.load_a_price("600519")
last_price = price["close"].iloc[-1]
last_date = price.index[-1].date()

# 用最近四个季度 TTM 每股收益更准;这里用最新年报基本EPS近似 + 每股净资产
eps_ser = ab.loc["基本每股收益"].dropna()
eps_ttm = eps_ser[eps_ser.index.month == 12].iloc[-1]   # 最新完整年报 EPS
bvps = ab.loc["每股净资产"].dropna().iloc[-1] if "每股净资产" in ab.index else np.nan

pe = last_price / eps_ttm
pb = last_price / bvps
# 盈利增速(最近两年归母净利润)
ni_y = yearly("归母净利润")
growth = (ni_y.iloc[-1] / ni_y.iloc[-2] - 1) * 100
peg = pe / growth

print(f"茅台 当前股价 ({last_date}): {last_price:.1f} 元   {D.source_tag(price)}")
print(f"最新年报 EPS: {eps_ttm:.2f} 元 | 每股净资产: {bvps:.2f} 元")
print(f"PE(市盈率)  ≈ {pe:.1f} 倍   → 按当前盈利约 {pe:.0f} 年回本")
print(f"PB(市净率)  ≈ {pb:.1f} 倍")
print(f"净利润增速 ≈ {growth:.1f}%  → PEG ≈ {peg:.2f}")
茅台 当前股价 (2026-06-18): 1215.0 元   (真实数据·本地缓存)
最新年报 EPS: 65.66 元 | 每股净资产: 216.32 元
PE(市盈率)  ≈ 18.5 倍   → 按当前盈利约 19 年回本
PB(市净率)  ≈ 5.6 倍
净利润增速 ≈ -4.5%  → PEG ≈ -4.08

3.4.1 把估值放进历史区间看¶

绝对的 PE 数字没意义,要和它自己的历史比——现在是贵还是便宜?我们用「股价 ÷ 每股收益」算出茅台过去几年的 PE 走廊:

In [6]:
# 用每个交易日股价 / 最近年报EPS 估算 PE 历史走廊(近似:EPS 用阶梯式年报值)
eps_annual = eps_ser[eps_ser.index.month == 12].sort_index()
px = price["close"].copy()
# 对每个交易日匹配「最近已披露的年报EPS」
eps_aligned = pd.Series(index=px.index, dtype=float)
for dt in px.index:
    valid = eps_annual[eps_annual.index <= dt]
    eps_aligned[dt] = valid.iloc[-1] if len(valid) else np.nan
pe_hist = (px / eps_aligned).dropna()

fig, ax = plt.subplots(figsize=(11, 5))
ax.plot(pe_hist.index, pe_hist.values, color="#2c3e50", lw=1.2)
for q, c, lbl in [(0.2,"#27ae60","低估20%分位"),(0.5,"#f39c12","中位"),(0.8,"#c0392b","高估80%分位")]:
    ax.axhline(pe_hist.quantile(q), color=c, ls="--", lw=1, label=f"{lbl}={pe_hist.quantile(q):.0f}x")
ax.scatter([pe_hist.index[-1]],[pe_hist.iloc[-1]], color="red", zorder=5, s=60)
ax.set_title(f"茅台 PE 历史走廊(近似){D.source_tag(price)}")
ax.set_xlabel("日期"); ax.set_ylabel("PE 倍数"); ax.legend()
plt.tight_layout(); plt.show()
pct = (pe_hist < pe_hist.iloc[-1]).mean()*100
print(f"当前 PE ≈ {pe_hist.iloc[-1]:.0f}x,处于近几年 {pct:.0f}% 分位(越低越便宜)。")
No description has been provided for this image
当前 PE ≈ 19x,处于近几年 0% 分位(越低越便宜)。

这张图在说什么:把当前 PE 放到自己的历史分位里看,比孤立地说「30 倍贵不贵」有用得多。靠近下沿(低分位)= 相对便宜,靠近上沿(高分位)= 相对贵。这是「估值买入区间」思路的雏形(第 5 章细讲)。注意:这里 EPS 用阶梯式年报值近似,季度切换处会有跳变,仅作教学示意。

3.5 简化 DCF 计算器:自己动手给公司估值¶

大白话:DCF(现金流折现)的思想很简单——一家公司值多少钱 = 它未来能赚的所有自由现金流,按一个折现率折回到今天的总和。

类比:明年的 100 块,没有今天的 100 块值钱(因为今天的钱能拿去钱生钱)。折现率就是「打几折」的那个折扣。

下面是一个可交互的简化 DCF:改 g1(前期增速)、g_terminal(永续增速)、discount(折现率)这几个假设,看估值怎么变。这恰恰是 DCF 的精髓——估值对假设极其敏感,所谓「精确的错误」。

In [7]:
def simple_dcf(fcf0, g1=0.10, years=10, g_terminal=0.03, discount=0.09, shares=None):
    """两阶段 DCF:前 years 年按 g1 增长,之后永续按 g_terminal。
    返回企业内在价值(亿元);若给 shares(亿股)则同时返回每股内在价值。"""
    pv = 0.0
    fcf = fcf0
    for t in range(1, years + 1):
        fcf *= (1 + g1)
        pv += fcf / (1 + discount) ** t
    # 永续价值(戈登增长模型)
    fcf_next = fcf * (1 + g_terminal)
    terminal = fcf_next / (discount - g_terminal)
    pv += terminal / (1 + discount) ** years
    per_share = pv / shares if shares else None
    return pv, per_share

# 用茅台最新自由现金流做起点(亿元)
fcf0 = float(fcf.iloc[-1])         # 最新年度 FCF(亿元)
shares = ab.loc["归母净利润"].dropna().iloc[-1] / eps_ttm / 1e8  # 估算总股本(亿股)= 净利润/EPS
print(f"DCF 起点:最新 FCF ≈ {fcf0:.0f} 亿元,估算总股本 ≈ {shares:.2f} 亿股\n")

print(f"{'前期增速 g1':>10} {'折现率':>8} {'永续增速':>8} {'内在价值(亿)':>12} {'每股内在价值':>12}")
for g1 in [0.06, 0.10, 0.14]:
    for disc in [0.08, 0.10]:
        val, ps = simple_dcf(fcf0, g1=g1, discount=disc, g_terminal=0.03, shares=shares)
        print(f"{g1*100:>9.0f}% {disc*100:>7.0f}% {3:>7.0f}% {val:>12.0f} {ps:>12.0f}")
print(f"\n对比:当前市价 {last_price:.0f} 元/股。内在价值 > 市价 → 偏低估;< 市价 → 偏高估。")
DCF 起点:最新 FCF ≈ 584 亿元,估算总股本 ≈ 4.15 亿股

   前期增速 g1      折现率     永续增速      内在价值(亿)       每股内在价值
        6%       8%       3%        15255         3677
        6%      10%       3%        10723         2584
       10%       8%       3%        20921         5042
       10%      10%       3%        14432         3478
       14%       8%       3%        28613         6896
       14%      10%       3%        19426         4682

对比:当前市价 1215 元/股。内在价值 > 市价 → 偏低估;< 市价 → 偏高估。

这张表在说什么:

  • 同样一家茅台,仅仅把「前期增速」从 6% 调到 14%、把折现率从 8% 调到 10%,算出的每股内在价值能差出一大截。这就是 DCF 的双刃剑:逻辑严密,但对假设极度敏感。
  • 正确用法不是算出一个「精确数字」当真理,而是:①倒推市价隐含了多乐观的假设;②做敏感性分析(像上面这张表),看在「合理假设区间」里公司大概值多少;③留足安全边际(只在内在价值明显高于市价时买)。
  • 动手改改 simple_dcf 的参数,体会「估值是一门艺术,不是精确科学」。

本章小结¶

  • ROE 是赚钱效率王牌,长期高且稳(>15%)才算优秀;
  • 杜邦分析把 ROE 拆成 净利率 × 周转率 × 杠杆,看清公司靠什么赚钱;
  • 自由现金流(FCF) 是真正能自由支配的钱,长期为正且增长才是现金奶牛;
  • PE/PB/PEG 是估值尺子,要和历史分位比;
  • DCF 思想清晰但对假设极敏感,用来做敏感性分析 + 留安全边际,而非求精确解。

下一章 04:换个视角,学看 K 线和技术面——以及为什么它对长期投资者只是「辅助」。

免责声明:本教程为投资教育内容,所有分析与示例仅为方法演示,不构成任何投资建议。文中涉及的公司与数据仅用于教学举例,不代表推荐。市场有风险,决策需自负。