07 · 实战:完整分析一只股票¶

长期投资教程 · 第 7 章(终章)

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


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

这是总复习 + 实战。我们把前六章的工具串成一套「该不该长期持有」的分析框架, 并用它真刀真枪分析两家公司:贵州茅台(A股)和苹果(美股)。

分析五步走(对应前面章节):

  1. 生意懂不懂 —— 它靠什么赚钱(定性,第2章)
  2. 赚钱能力强不强 —— ROE / 毛利率 / 净利率(第3章)
  3. 财务健不健康 —— 负债率 / 经营现金流 vs 利润 / 自由现金流(第2-3章)
  4. 成长性如何 —— 营收/利润增速(第2-3章)
  5. 现在贵不贵 —— 估值分位 + 趋势(第3-5章)

⚠️ 重要:本章给的是分析框架和方法,最后的「评分」只是把客观指标量化呈现,绝不是买入/卖出建议。真实投资决策要结合宏观、行业、公司治理、你自己的风险偏好等无数因素。框架帮你思考,但替不了你做决定,更不构成投资建议。

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

7.1 搭一套通用的「体检」函数¶

先写两个分析函数:A股走 akshare 摘要表,美股走 yfinance 三表。它们都产出同一套指标,方便横向对比。

In [2]:
def analyze_a(symbol, name):
    """分析A股:返回最近年度的核心指标 dict。"""
    ab = D.load_a_abstract(symbol)
    price = D.load_a_price(symbol)
    inc = D.load_a_report(symbol, "income")
    cf = D.load_a_report(symbol, "cashflow")
    def y(metric):
        s = ab.loc[metric].dropna(); s = s[s.index.month == 12]; return s
    rev = y("营业总收入"); ni = y("归母净利润")
    roe = y("净资产收益率(ROE)"); gm = y("毛利率")
    nm = y("销售净利率") if "销售净利率" in ab.index else y("净利率")
    dr = y("资产负债率"); ocf = y("经营现金流量净额")
    # 自由现金流
    def ann(df, col):
        s = df[df.index.month == 12][col].dropna(); return s
    ocf_r = ann(cf, "经营活动产生的现金流量净额")
    capex = ann(cf, "购建固定资产、无形资产和其他长期资产所支付的现金")
    fcf = (ocf_r - capex)
    # 估值:PE 历史分位
    eps = ab.loc["基本每股收益"].dropna(); eps_a = eps[eps.index.month==12].sort_index()
    px = price["close"]
    eps_al = px.index.to_series().apply(lambda d: eps_a[eps_a.index<=d].iloc[-1] if len(eps_a[eps_a.index<=d]) else np.nan)
    pe_hist = (px/eps_al).dropna()
    return {
        "name": name, "market": "A股", "price": px.iloc[-1], "src": D.source_tag(price),
        "ROE": roe.iloc[-1], "毛利率": gm.iloc[-1], "净利率": nm.iloc[-1],
        "资产负债率": dr.iloc[-1], "营收增速": (rev.iloc[-1]/rev.iloc[-2]-1)*100,
        "利润增速": (ni.iloc[-1]/ni.iloc[-2]-1)*100,
        "现金流利润比": ocf.iloc[-1]/ni.iloc[-1],
        "FCF最新(亿)": fcf.iloc[-1]/1e8, "FCF为正年数": int((fcf.dropna().tail(5)>0).sum()),
        "FCF统计年数": int(len(fcf.dropna().tail(5))),
        "PE当前": pe_hist.iloc[-1], "PE分位%": (pe_hist<pe_hist.iloc[-1]).mean()*100,
        "price_series": px, "roe_series": roe, "rev_series": rev,
    }

def _pick(df, keys):
    for k in keys:
        for idx in df.index:
            if k.lower() == str(idx).lower():
                return df.loc[idx]
    for k in keys:
        for idx in df.index:
            if k.lower() in str(idx).lower():
                return df.loc[idx]
    return None

def analyze_us(ticker, name):
    """分析美股:用 yfinance 三表。"""
    inc = D.load_us_stmt(ticker, "income")
    bal = D.load_us_stmt(ticker, "balance")
    cf = D.load_us_stmt(ticker, "cashflow")
    price = D.load_us_price(ticker)
    rev = _pick(inc, ["Total Revenue"])
    ni  = _pick(inc, ["Net Income"])
    gp  = _pick(inc, ["Gross Profit"])
    eq  = _pick(bal, ["Stockholders Equity"])
    ocf = _pick(cf, ["Operating Cash Flow"])
    fcf = _pick(cf, ["Free Cash Flow"])
    roe = (ni / eq * 100)
    gm = (gp / rev * 100); nm = (ni / rev * 100)
    px = price["close"]
    return {
        "name": name, "market": "美股", "price": px.iloc[-1], "src": D.source_tag(price),
        "ROE": roe.iloc[-1], "毛利率": gm.iloc[-1], "净利率": nm.iloc[-1],
        "资产负债率": np.nan,   # yfinance 口径需另算,这里聚焦现金流与盈利
        "营收增速": (rev.iloc[-1]/rev.iloc[-2]-1)*100,
        "利润增速": (ni.iloc[-1]/ni.iloc[-2]-1)*100,
        "现金流利润比": ocf.iloc[-1]/ni.iloc[-1],
        "FCF最新(亿)": fcf.iloc[-1]/1e8, "FCF为正年数": int((fcf.dropna()>0).sum()),
        "FCF统计年数": int(len(fcf.dropna())),
        "PE当前": np.nan, "PE分位%": np.nan,
        "price_series": px, "roe_series": roe, "rev_series": rev,
    }

print("分析函数就绪")
分析函数就绪

7.2 分析对象一:贵州茅台(A股)¶

茅台的生意:高端白酒龙头。靠极强的品牌力和稀缺性获得定价权,几乎是「印钞机」型生意——这是我们在第2、3章已经验证过的。现在跑一遍完整体检:

In [3]:
mt = analyze_a("600519", "贵州茅台")
print(f"【{mt['name']}】{mt['market']}  当前股价 {mt['price']:.1f} 元  {mt['src']}\n")
print(f"  盈利能力:  ROE {mt['ROE']:.1f}% | 毛利率 {mt['毛利率']:.1f}% | 净利率 {mt['净利率']:.1f}%")
print(f"  财务健康:  资产负债率 {mt['资产负债率']:.1f}% | 经营现金流/净利润 {mt['现金流利润比']:.2f}")
print(f"  自由现金流: 最新 {mt['FCF最新(亿)']:.0f} 亿 | 近年为正 {mt['FCF为正年数']}/{mt['FCF统计年数']} 年")
print(f"  成长性:    营收增速 {mt['营收增速']:.1f}% | 利润增速 {mt['利润增速']:.1f}%")
print(f"  估值:      PE {mt['PE当前']:.0f}x,处于近几年 {mt['PE分位%']:.0f}% 分位")
【贵州茅台】A股  当前股价 1215.0 元  (真实数据·本地缓存)

  盈利能力:  ROE 32.5% | 毛利率 91.2% | 净利率 50.5%
  财务健康:  资产负债率 16.4% | 经营现金流/净利润 0.75
  自由现金流: 最新 584 亿 | 近年为正 5/5 年
  成长性:    营收增速 -1.2% | 利润增速 -4.5%
  估值:      PE 19x,处于近几年 0% 分位

7.3 分析对象二:苹果(美股)¶

苹果的生意:消费电子 + 服务生态。靠 iPhone 硬件 + App Store/服务的高粘性生态赚钱,品牌溢价 + 用户锁定构成护城河。跑体检:

In [4]:
ap = analyze_us("AAPL", "苹果")
print(f"【{ap['name']}】{ap['market']}  当前股价 ${ap['price']:.1f}  {ap['src']}\n")
print(f"  盈利能力:  ROE {ap['ROE']:.1f}% | 毛利率 {ap['毛利率']:.1f}% | 净利率 {ap['净利率']:.1f}%")
print(f"  财务健康:  经营现金流/净利润 {ap['现金流利润比']:.2f}")
print(f"  自由现金流: 最新 {ap['FCF最新(亿)']:.0f} 亿美元 | 近年为正 {ap['FCF为正年数']}/{ap['FCF统计年数']} 年")
print(f"  成长性:    营收增速 {ap['营收增速']:.1f}% | 利润增速 {ap['利润增速']:.1f}%")
print("  注:苹果 ROE 极高部分源于大额回购缩减了净资产分母,需结合负债结构理解。")
【苹果】美股  当前股价 $298.0  (真实数据·本地缓存)

  盈利能力:  ROE 151.9% | 毛利率 46.9% | 净利率 26.9%
  财务健康:  经营现金流/净利润 1.00
  自由现金流: 最新 988 亿美元 | 近年为正 4/4 年
  成长性:    营收增速 6.4% | 利润增速 19.5%
  注:苹果 ROE 极高部分源于大额回购缩减了净资产分母,需结合负债结构理解。

7.4 横向对比 + 雷达图¶

把两家公司的核心维度画成雷达图,直观对比「体格」。我们把几个指标统一归一化到 0~100 分(仅为可视化对比,非绝对评分):

In [5]:
def score_card(a):
    """把原始指标映射到0~100直观分(阈值为教学设定,非投资标准)。"""
    def clip(x, lo, hi): return max(0, min(100, (x-lo)/(hi-lo)*100))
    return {
        "盈利能力(ROE)": clip(a["ROE"], 5, 35),
        "毛利率": clip(a["毛利率"], 20, 90),
        "现金含量": clip(a["现金流利润比"]*100, 60, 130),
        "成长性": clip(a["利润增速"], -10, 40),
        "FCF稳健": (a["FCF为正年数"]/max(a["FCF统计年数"],1))*100,
    }

sc_mt = score_card(mt); sc_ap = score_card(ap)
dims = list(sc_mt.keys())
ang = np.linspace(0, 2*np.pi, len(dims), endpoint=False).tolist(); ang += ang[:1]

fig, ax = plt.subplots(figsize=(7,7), subplot_kw=dict(polar=True))
for sc, name, color in [(sc_mt,"贵州茅台","#c0392b"), (sc_ap,"苹果","#2c3e50")]:
    vals = [sc[d] for d in dims]; vals += vals[:1]
    ax.plot(ang, vals, lw=2, label=name, color=color)
    ax.fill(ang, vals, alpha=0.12, color=color)
ax.set_xticks(ang[:-1]); ax.set_xticklabels(dims)
ax.set_ylim(0,100); ax.set_title("茅台 vs 苹果 · 多维体检雷达图(归一化分,仅作对比)")
ax.legend(loc="upper right", bbox_to_anchor=(1.25,1.1))
plt.tight_layout(); plt.show()

cmp = pd.DataFrame({"贵州茅台": sc_mt, "苹果": sc_ap}).round(0)
print(cmp.to_string())
No description has been provided for this image
            贵州茅台     苹果
盈利能力(ROE)   92.0  100.0
毛利率        100.0   38.0
现金含量        21.0   56.0
成长性         11.0   59.0
FCF稳健      100.0  100.0

这张图在说什么:雷达图覆盖面积越大、越饱满,说明这家公司在这几个维度上整体越强。茅台和苹果都是各自市场的顶级公司,盈利能力、现金含量都很突出,但「形状」不同——这正反映了不同生意模式的特点(高毛利稳健型 vs 高 ROE 强生态型)。注意:这里的归一化评分阈值是教学设定,不同行业不能简单套用同一把尺子。

7.5 趋势与估值快照:现在是什么位置¶

最后看「市场先生」当前给的报价处在什么位置——把价格走势和(A股的)估值分位放一起。好公司 + 不贵的价格 = 长期投资者真正想要的组合。

In [6]:
fig, axes = plt.subplots(1, 2, figsize=(13, 5))
# 茅台:价格 + 年线
mtpx = mt["price_series"].iloc[-750:]
ma250 = mtpx.rolling(250).mean()
axes[0].plot(mtpx.index, mtpx.values, color="#c0392b", lw=1.2, label="茅台收盘")
axes[0].plot(ma250.index, ma250.values, color="gray", lw=1.5, label="MA250(年线)")
axes[0].set_title(f"茅台 价格 vs 年线  (PE分位 {mt['PE分位%']:.0f}%)"); axes[0].legend()
# 苹果:价格 + 年线
appx = ap["price_series"].iloc[-750:]
ma250b = appx.rolling(250).mean()
axes[1].plot(appx.index, appx.values, color="#2c3e50", lw=1.2, label="苹果收盘")
axes[1].plot(ma250b.index, ma250b.values, color="gray", lw=1.5, label="MA250(年线)")
axes[1].set_title("苹果 价格 vs 年线"); axes[1].legend()
plt.tight_layout(); plt.show()
print(f"茅台:价格 {'在年线上方(长期偏多)' if mtpx.iloc[-1]>ma250.iloc[-1] else '在年线下方(长期偏弱)'},PE 分位 {mt['PE分位%']:.0f}%")
print(f"苹果:价格 {'在年线上方(长期偏多)' if appx.iloc[-1]>ma250b.iloc[-1] else '在年线下方(长期偏弱)'}")
No description has been provided for this image
茅台:价格 在年线下方(长期偏弱),PE 分位 0%
苹果:价格 在年线上方(长期偏多)

这张图在说什么:把第4章学的年线趋势和第3章学的估值分位合在一起看——价格相对年线的位置告诉你长期趋势方向,估值分位告诉你贵贱。理想的长期买点是「好公司 + 估值分位低 + 趋势没破坏」;要警惕的是「估值分位很高 + 增速放缓」。但这些都只是参考信号,不是机械的买卖指令。

7.6 「该不该长期持有」分析框架(总结)¶

把全部串起来,一只股票值不值得长期持有,依次问自己五个问题:

步骤 问题 看什么(章节) 红旗信号
① 生意 它靠什么赚钱?护城河在哪? 定性理解(第2章) 看不懂的生意、护城河被侵蚀
② 盈利 赚钱效率高吗? ROE>15%、高毛利净利(第3章) ROE 长期低或剧烈波动
③ 健康 财务稳吗?赚的是真钱吗? 负债率、经营现金流≥净利润、FCF为正(第2-3章) 高利润低现金流、负债飙升
④ 成长 还能增长吗? 营收/利润增速(第2-3章) 增速持续转负
⑤ 估值 现在买贵不贵? PE/PB 分位、年线趋势(第3-5章) 估值历史高位 + 增速放缓

用法:①是前提(看不懂就不碰);②③④判断「是不是好公司」;⑤判断「是不是好价格」。好公司 + 好价格 + 长期持有 + 适当分散(第6章)= 长期投资的朴素答案。

再次强调(也是整套教程的结尾):


🔚 教程结语与免责声明¶

恭喜你走完了从入门到精通的全程!你现在拥有了一套可复用的分析框架:会读三张表、会算关键指标、会做简化估值、会看 K 线趋势、懂定投与组合。把本章的 analyze_a / analyze_us 换成任何你感兴趣的股票代码,就能跑一遍属于你自己的分析。

但请永远记住三件事:

  1. 框架不是水晶球。所有指标都是「后视镜」,反映过去,不保证未来。真实世界还有宏观、政策、行业变迁、黑天鹅、公司治理等无数变量。
  2. 认知决定收益。别人推荐的「好股票」不是你的,只有自己研究透、看得懂、拿得住的,才是你的。
  3. 活下来最重要。分散、仓位、不上杠杆、不借钱炒股——先保证不出局,复利才有机会发酵。

免责声明:本教程为投资教育内容,所有分析、指标、评分与示例仅为方法演示,使用的真实公司数据仅用于教学举例,不构成任何投资建议,也不代表对任何证券的推荐。投资有风险,过往业绩不预示未来表现,任何决策请基于你自己的独立判断并自行承担后果。

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

—— 教程完 ——