跳转至

⚠️ 免责声明:本章仅为教育与研究方法展示,不构成任何投资建议。 所有回测结果来自历史数据,不代表未来表现。投资有风险,决策需独立判断。

第四课:蒙特卡洛模拟——100,000 种可能的未来

本章代码:code/lesson4_monte_carlo.py 运行方式:python lesson4_monte_carlo.py

4.0 策略概述

这是什么策略

前三课都在看历史。这一课看未来——不是预测,是穷举

蒙特卡洛模拟做的事:不问你"明年会发生什么",而是问"如果明年发生 100,000 种不同的事,结果会是什么分布?"你得到的不再是一个数字("沪深 300 明年涨 8.4%"),而是一个概率分布("沪深 300 明年有 5% 的概率跌破 2600,有 50% 的概率在 4162 左右,有 5% 的概率超过 6667")。

核心公式:几何布朗运动

金融学里最基础的模型之一:

S[t] = S[t-1] × exp( 漂移项 + 随机冲击项 )

漂移项 = (年化收益 - 0.5 × 波动率²) × 时间步长
随机冲击项 = 波动率 × √时间步长 × 标准正态随机数

用人话说:价格的变化 = 长期趋势(发动机)+ 随机波动(海浪)。

  • 发动机(漂移项):决定长期方向。如果年化收益是 8.4%,每天往上推一点点。
  • 海浪(随机冲击):决定短期颠簸。每天随机地往上或往下冲,幅度由波动率决定。

它回答什么问题

问题 白话
明年最坏能跌多少? 看 5% 分位——100,000 种未来里,只有 5% 比这更坏
明年大概能到多少? 看 50% 分位——一半未来比这高,一半比这低
亏 30% 以上的概率多大? 数一下 100,000 条路径里有多少条终点跌了 30%+

4.1 核心代码

只用了 5 行核心代码,跑 100,000 条路径:

import numpy as np

# 参数
S0 = 3779.5       # 沪深 300 当前价格
r = 0.084         # 年化收益 8.4%(来自第一课)
sigma = 0.308     # 年化波动 30.8%(来自第一课)
T = 1.0           # 模拟 1 年
M = 52            # 52 周
I = 100000        # 100,000 条路径

dt = T / M
S = np.zeros((M+1, I))
S[0] = S0

for t in range(1, M+1):
    Z = np.random.standard_normal(I)          # 100,000 个随机数
    S[t] = S[t-1] * np.exp(
        (r - 0.5*sigma**2) * dt               # 漂移:发动机
        + sigma * np.sqrt(dt) * Z             # 冲击:海浪
    )

这 5 行代码的本质:一个 for 循环,跑了 52 次(每周一次)。每次同时计算 100,000 个不同的未来。最终得到一个 (53 行, 100000 列) 的矩阵——53 个时间点,100,000 条人生。

为什么是 exp() 而不是直接加减

因为价格不能为负。用 exp() 保证了价格永远 > 0。这是几何布朗运动和简单随机游走的关键区别。


4.2 用真实数据跑一遍

用第一课算出来的沪深 300 参数(年化 8.4%,波动 30.8%),模拟结果:

100,000 条路径, 52 周, 沪深 300 当前 3780 点

5% 分位(最坏): 2,601 点 (-31%)
10% 分位:        2,882 点 (-24%)
50% 分位(中位): 4,162 点 (+10%)
90% 分位:        5,992 点 (+59%)
95% 分位(最好): 6,667 点 (+76%)

图 4-1:蒙特卡洛模拟结果。 左图:20 条样本路径(灰线)+ 90% 置信区间(蓝色阴影)。右图:100,000 个最终价格的分布直方图,五条红线标注 5%/10%/50%/90%/95% 分位。注意分布的右偏——大涨的可能性比大跌更大(因为漂移项是正的)。

图 4-1

这张图告诉你什么

不要问"明年涨还是跌"。 这个问题没有答案。正确的问题是:"明年有 90% 的概率落在 2600 到 6667 之间。我能承受 2600 吗?如果到了 6667 我会不会后悔卖早了?"

蒙特卡洛不做预测。它做风险映射——让你在做决策之前,看到完整的可能性空间。


4.3 这个策略的致命缺陷

缺陷一:输入参数来自历史

年化 8.4%、波动 30.8%——这两个数字来自过去 26 年的数据。如果未来 26 年和过去 26 年不一样(一定不一样),模拟结果就是错的。

缺陷二:假设独立同分布

随机数 Z 每天都是独立抽取的。这意味着模型假设:今天的涨跌和昨天无关,明天的涨跌和今天无关。但真实市场不是这样的——暴跌之后往往接着暴跌(波动聚集),上涨之后往往接着上涨(趋势持续性)。

缺陷三:假设波动率恒定

波动率在 2008 年(金融危机)和 2015 年(A 股泡沫)和 2020 年(新冠)完全不同。模型用一个固定的 30.8% 来覆盖所有情况——这相当于用年平均气温来预测明天的天气。


4.4 那为什么还要用它

因为它强迫你思考"最坏情况"。 在投资中,大多数人只思考"最好的情况"("如果涨到 6000 点我就赚多少")。蒙特卡洛强迫你同时看到两端——最好的 5% 和最坏的 5%。

举个例子:如果你经营一家工厂,把"股价"替换成"原材料价格",把"波动率"替换成"价格波动"——跑出来的结果能告诉你:在最坏的 5% 情景下,你下季度的原材料成本会涨到多少。这个数字直接决定了你需要预留多少现金。

蒙特卡洛的价值不在股市——在你需要对一个未知的未来做财务规划的任何地方。


4.5 这一课教了你什么

  1. 蒙特卡洛不预测——它穷举。100,000 种未来,每种都同样可能。
  2. 核心公式只有 5 行:漂移(发动机)+ 冲击(海浪)。
  3. 沪深300 一年后:90% 的概率在 2671—6008 之间(5% 概率跌破 2671,5% 概率超过 6008)。实际数值随随机种子和参数估计变化——重要的是"范围"和"形状",不是具体数字。
  4. 三个致命缺陷:参数来自历史、假设独立、假设波动恒定。
  5. 真正的价值在迁移——把股票换成你所在行业的任何时间序列数据,蒙特卡洛就从"股价模拟"变成了"业务风险量化工具"。

4.6 课堂问答

问:蒙特卡洛的参数(年化收益、波动率)从哪来?

本课的代码直接从 data/index_updated.csv 里沪深300 的 8683 天真实日收益率估计——年化收益 ≈ 8.3%,年化波动 ≈ 24.7%。这就是蒙特卡洛的第一个死穴:参数来自历史,而未来不一定重复历史。如果你把参数换成 2008 年的波动率,结果会完全不同。

问:100,000 条路径够吗?结果会不会不稳定?

够。本课代码固定了随机种子(seed=42),任何人跑出来都是同一组数字。去掉种子你会看到结果在小范围内波动——这正是蒙特卡洛的第二个特性:它是概率分布,不是精确答案。要验证收敛性,你可以把路径数从 100,000 改成 10,000 或 1,000,000,观察分位数是否稳定。

问:蒙特卡洛能预测股市吗?

不能。它做的是"给定当前参数,未来一年的可能分布"。它不知道明天的新闻、后天的政策。它的价值恰恰在于此:它把'不确定'变成了'可量化的不确定'——最坏 5% 情景亏 30%,这句话比"股市有风险"有用一百倍,而且它能迁移到任何有历史数据的业务变量上。


动手练习(第 4 课)

  1. 入门:路径数收敛性。把 I(路径数)从 100,000 改成 10,000 和 1,000,000, 比较 VaR 95% 的变化。100,000 条路径够吗?多少条开始稳定?
  2. 进阶:改变时间跨度。把 T 从 1 年改成 3 年,90% 区间怎么变宽? 把结果换算成"3 年最坏 5% 情景亏多少"——这个数字对长期持有者才是真问题。
  3. 挑战:业务迁移报告。把 s0/r/sigma 换成你行业的数据(成本、销量、汇率), 写一页纸的"最坏 5% 情景"报告:你的业务明年最坏会怎样?需要预留多少现金?

下节预告: 前四课都在自己产生信号。第五课换一个角度——如果别人给你信号,你怎么判断这些信号靠不靠谱?