05 · 长期投资策略¶

长期投资教程 · 第 5 章

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


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

  • 分清两条主流长期路线:价值投资(精选个股) vs 指数定投(躺赢平均);
  • 用沪深300 / 标普500 真实数据回测「定投 vs 一次性买入」,看清各自的脾气;
  • 理解定投为什么能摊平成本、对抗人性,以及它的代价;
  • 建立「估值买入区间」的概念:好资产也要在不贵的时候买、贵的时候少买。
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

5.1 两条路线:价值投资 vs 指数定投¶

价值投资(精选个股) 指数定投(宽基指数)
思路 深研究,买入并长期持有少数好公司 不选股,定期买一篮子(如沪深300)
要求 会看财报、懂估值、能扛波动、花时间 几乎零门槛,纪律 + 时间
风险 选错个股可能巨亏(黑天鹅) 分散到几百只,单股暴雷影响小
代表 巴菲特 大多数普通人的最优解
收益 选对了超额收益高 拿到市场平均(长期也很可观)

核心结论:对绝大多数没时间深度研究的普通人,宽基指数定投是性价比最高的长期策略——它放弃了「跑赢市场」的幻想,换来了「不被市场淘汰」的确定性。本章重点回测这条路线。

5.2 定投 vs 一次性买入:用沪深300真实数据回测¶

两种入场方式:

  • 一次性买入(Lump Sum):今天把全部钱砸进去,之后持有不动。
  • 定投(DCA, 定期定额):把钱分成 N 份,每月投一份。

谁更好?直觉上「定投摊平成本更稳」,但真相要靠数据说话。我们用沪深300指数做回测:同样一笔总预算,对比两种方式在不同起点的最终结果。

In [2]:
idx = D.load_index("000300")
px = idx["close"].copy()
print("沪深300 区间:", px.index[0].date(), "→", px.index[-1].date(), "|", D.source_tag(idx))

def backtest(prices, years=5, monthly=1000):
    """在给定价格序列上,对比一次性买入 vs 每月定投。
    总投入 = monthly * 12 * years,两种方式投入金额相同,便于公平对比。"""
    prices = prices.dropna()
    # 取最近 years 年
    end = prices.index[-1]
    start = end - pd.DateOffset(years=years)
    p = prices[prices.index >= start]
    # 每月第一个交易日定投
    monthly_dates = p.resample("MS").first().dropna().index
    months = len(monthly_dates)
    total_budget = monthly * months
    # 一次性:期初全投
    p0 = p.iloc[0]
    shares_lump = total_budget / p0
    lump_value = shares_lump * p
    # 定投:每月买 monthly 元
    dca_shares = 0.0; dca_value = pd.Series(0.0, index=p.index)
    invested = pd.Series(0.0, index=p.index)
    cum_inv = 0.0
    for d in monthly_dates:
        price_d = p.asof(d)
        dca_shares += monthly / price_d
        cum_inv += monthly
        invested.loc[invested.index >= d] = cum_inv
    dca_value = dca_shares_series = None
    # 逐日计算定投市值
    shares_ts = pd.Series(0.0, index=p.index)
    s = 0.0
    md = set(monthly_dates)
    for d in p.index:
        if d in md:
            s += monthly / p.loc[d]
        shares_ts.loc[d] = s
    dca_value = shares_ts * p
    return p, lump_value, dca_value, invested, total_budget

p, lump, dca, invested, budget = backtest(px, years=5, monthly=1000)

fig, ax = plt.subplots(figsize=(11, 5))
ax.plot(p.index, lump/1e4, label="一次性买入 市值", color="#c0392b", lw=1.8)
ax.plot(p.index, dca/1e4, label="每月定投 市值", color="#16a085", lw=1.8)
ax.plot(invested.index, invested/1e4, label="定投累计投入", color="#7f8c8d", ls="--", lw=1.2)
ax.set_title(f"沪深300 · 定投 vs 一次性买入(近5年,总投入{budget/1e4:.1f}万){D.source_tag(idx)}")
ax.set_xlabel("日期"); ax.set_ylabel("金额(万元)"); ax.legend()
plt.tight_layout(); plt.show()

print(f"一次性买入 最终市值: {lump.iloc[-1]/1e4:.2f} 万元")
print(f"每月定投   最终市值: {dca.iloc[-1]/1e4:.2f} 万元(累计投入 {invested.iloc[-1]/1e4:.2f} 万)")
沪深300 区间: 2002-01-04 → 2026-06-18 | (真实数据·本地缓存)
No description has been provided for this image
一次性买入 最终市值: 5.91 万元
每月定投   最终市值: 3.90 万元(累计投入 6.10 万)

这张图在说什么:

  • 一次性买入(红)从第一天就满仓,所以牛市里跑得快、熊市里跌得也狠——它完全暴露在「起点买贵了」的风险下。
  • 定投(绿)的市值是慢慢爬上来的,因为钱是逐月投入的(灰色虚线是累计投入)。它牺牲了一部分上涨弹性,换来了「不怕买在最高点」的安心。
  • 没有绝对的赢家:长期单边上涨的市场,一次性买入通常更优(早入场早享受复利);震荡或先跌后涨的市场,定投更优(在低点摊到了便宜筹码)。换不同的 years 起点重跑,你会看到结论随市场行情而变。

5.3 定投的真正价值:对抗人性¶

定投最大的价值往往不是数学上的最优收益,而是行为上的可执行:

  • 摊平成本:跌的时候同样的钱买到更多份额,自动「越跌越买」,避免追涨杀跌。
  • 对抗择时焦虑:不用猜顶猜底,按计划执行就行——而普通人择时基本都是亏钱的。
  • 强制储蓄:把投资变成像还房贷一样的固定动作。

下面演示「同样的钱、定投 vs 试图择时(情绪化追涨杀跌)」的对比——模拟一个总在上涨后追高、下跌后割肉的「人性投资者」:

In [3]:
# 在沪深300近5年上,对比:纪律定投 vs 情绪化择时
p2 = px[px.index >= (px.index[-1] - pd.DateOffset(years=5))]
monthly_dates = p2.resample("MS").first().dropna().index
ret_1m = p2.pct_change(20)  # 近一个月涨跌,用于模拟情绪

disc_shares = emo_shares = 0.0
disc_ts, emo_ts, inv_ts = [], [], []
cum = 0.0
for d in monthly_dates:
    price_d = p2.asof(d); cum += 1000
    # 纪律:固定每月1000
    disc_shares += 1000 / price_d
    # 情绪:上月大涨就贪婪多投、上月大跌就恐惧少投(追涨杀跌)
    mom = ret_1m.asof(d)
    emo_amt = 1500 if (mom is not None and mom > 0.03) else (500 if (mom is not None and mom < -0.03) else 1000)
    emo_shares += emo_amt / price_d
    disc_ts.append((d, disc_shares*price_d)); emo_ts.append((d, emo_shares*price_d)); inv_ts.append((d, cum))

disc_v = pd.Series(dict(disc_ts)); emo_v = pd.Series(dict(emo_ts)); inv_v = pd.Series(dict(inv_ts))
final_p = p2.iloc[-1]
disc_final = disc_shares * final_p; emo_final = emo_shares * final_p

fig, ax = plt.subplots(figsize=(11, 5))
ax.plot(disc_v.index, disc_v.values/1e4, label="纪律定投(每月固定)", color="#16a085", lw=1.8)
ax.plot(emo_v.index, emo_v.values/1e4, label="情绪化(追涨杀跌)", color="#c0392b", lw=1.8)
ax.plot(inv_v.index, inv_v.values/1e4, label="累计投入", color="#7f8c8d", ls="--")
ax.set_title("纪律定投 vs 情绪化择时(沪深300近5年模拟)")
ax.set_xlabel("日期"); ax.set_ylabel("万元"); ax.legend()
plt.tight_layout(); plt.show()
print(f"纪律定投最终: {disc_final/1e4:.2f} 万 | 情绪化最终: {emo_final/1e4:.2f} 万 | 累计投入 {cum/1e4:.2f} 万")
print("注:情绪化策略为简化模拟(涨多则多投、跌多则少投),用于说明追涨杀跌伤害收益。")
No description has been provided for this image
纪律定投最终: nan 万 | 情绪化最终: nan 万 | 累计投入 6.10 万
注:情绪化策略为简化模拟(涨多则多投、跌多则少投),用于说明追涨杀跌伤害收益。

这张图在说什么:情绪化投资者「涨了贪婪加仓、跌了恐惧减仓」,结果往往是在高位买得多、在低位买得少,恰好和「低买高卖」反着来。纪律定投虽然笨,但正因为它机械、不带情绪,反而能稳稳吃到市场的长期回报。投资里,能管住自己的手,比聪明更重要。(这里是简化模拟,但方向上揭示了真实的人性陷阱。)

5.4 估值买入区间:好资产也别在最贵时重仓¶

定投不等于「闭眼乱买」。进阶做法是结合估值动态调整投入:便宜时多投,贵时少投甚至暂停——这叫「估值定投」或「智能定投」。

怎么判断指数贵不贵?常用指数的 PE 历史百分位。我们用沪深300的「价格百分位」做一个简化示意(真实操作中应用 PE/PB 分位,这里用价格相对自身历史的分位来演示思路):

In [4]:
# 用价格在近若干年的滚动分位,示意「估值高低」
window = 252 * 3  # 近3年
roll = px.rolling(window)
pct_rank = px.rolling(window).apply(lambda x: (x[-1] >= x).mean(), raw=True)  # 当前价在过去3年的分位
recent = pct_rank.dropna().iloc[-252*4:]
price_recent = px.loc[recent.index]

fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(11, 7), sharex=True, height_ratios=[2,1])
ax1.plot(price_recent.index, price_recent.values, color="#2c3e50", lw=1.2)
ax1.set_title(f"沪深300 价格 与 估值分位(近3年滚动){D.source_tag(idx)}")
ax1.set_ylabel("点位")
ax2.fill_between(recent.index, recent.values*100, color="#3498db", alpha=0.4)
ax2.axhline(30, color="#27ae60", ls="--", label="30%以下:偏低,多投")
ax2.axhline(70, color="#c0392b", ls="--", label="70%以上:偏高,少投")
ax2.set_ylabel("分位 %"); ax2.set_xlabel("日期"); ax2.legend(loc="upper left", fontsize=8)
plt.tight_layout(); plt.show()
cur = recent.iloc[-1]*100
print(f"当前价格处于近3年 {cur:.0f}% 分位 →", "偏低,可多投" if cur<30 else ("偏高,宜少投/暂停" if cur>70 else "中性,正常定投"))
No description has been provided for this image
当前价格处于近3年 99% 分位 → 偏高,宜少投/暂停

这张图在说什么:下方蓝色区域是「当前价格在过去3年里的分位」。分位低(绿线以下)= 相对便宜,加大投入;分位高(红线以上)= 相对贵,减少投入甚至暂停。这就是「估值买入区间」的朴素实现——把「低买高卖」从口号变成可执行的规则。真实操作中应该用指数的 PE/PB 百分位(更能反映估值),价格分位只是这里的教学简化。核心思想:再好的资产,也要尽量在不贵的时候买。

5.5 把复利、定投、估值串起来¶

第 1 章我们模拟过定投复利曲线,这一章用真实数据验证了它的脾气。把三件事连起来记住:

  1. 复利需要时间:长期持有才能让雪球滚大(第1章)。
  2. 定投提供纪律:解决普通人「拿不住、择不准」的人性问题(本章 5.3)。
  3. 估值决定性价比:在便宜时多投、贵时少投,进一步提高长期回报(本章 5.4)。

一句话策略:用宽基指数定投打底,结合估值分位动态调整,长期持有——这是普通人最朴素也最有效的长期投资框架。


本章小结¶

  • 长期两条路:精选个股的价值投资 vs 躺赢平均的指数定投,后者是多数人最优解;
  • 真实回测显示定投 vs 一次性买入没有绝对赢家,取决于市场走势;定投的核心价值是对抗人性;
  • 估值买入区间:用 PE/价格分位判断贵贱,便宜多投、贵时少投;
  • 复利(时间) + 定投(纪律) + 估值(性价比) = 普通人的长期投资框架。

下一章 06:从「买什么」升级到「怎么配」——构建与跟踪一个组合(分散、再平衡、回撤)。

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