当前位置:首页>python>Python 模拟布朗运动

Python 模拟布朗运动

  • 2026-08-20 04:25:11
Python 模拟布朗运动
本文将演示如何使用 Python 编程语言,结合蒙特卡洛期权定价理论,模拟基于布朗运动的资产价格路径。

在本文中,我们将探讨布朗运动(Brownian Motion)的模拟方法——这是衍生品定价中最基础的概念之一。布朗运动是一种数学模型,用于模拟资产价格的行为,从而为期权合约的定价提供依据。

对某项资产上的期权进行定价的一种典型方法是:在期权存续期内,模拟大量随机的资产价格路径;在每条路径下计算该期权的收益;然后对所有路径下的期权价格取平均值,并将该平均值折现,从而得到最终的期权价格。这正是蒙特卡洛(Monte Carlo)方法的一个典型应用。

本文将专注于使用 Python 编程语言模拟布朗运动路径。我们将首先介绍“标准布朗运动”(Standard Brownian Motion),随后逐步增加布朗运动动态的复杂性。与 QuantStart 网站的所有文章一样,本文将提供完整的代码,以便读者能够完全复现下文所示的结果。

本文深受 Paul Glasserman 所著的《金融工程中的蒙特卡洛方法》(Monte Carlo Methods for Financial Engineering)[Glasserman, 2003] 一书的影响。该书详细阐述了相关理论基础,导出了下文所使用的离散化公式(本文将直接给出这些公式,而不进行推导)。

文章首先模拟所谓的“标准布朗运动”,即均值为零、方差为单位1的布朗运动路径。接着,我们将讨论如何在模拟中引入非零常数均值和非常数(但为常量)方差。在后续文章中,我们将进一步探讨均值和方差随时间变化的情形:首先考虑分段常数的均值与方差,之后再扩展到完全随时间变化的均值与方差情形。

注:如果您希望回顾布朗运动的数学定义,请参阅我们此前发表的相关文章。

标准布朗运动

以下公式引自 [Glasserman, 2003] 一书中的公式 (3.2)。该公式给出了在 n 个时间点(时间点不一定等间距)上生成一条(单条)布朗运动路径的递推关系。其核心含义是:在时刻 ti 的新布朗运动路径值,等于前一时刻 ti1 的路径值,加上时间间隔 Δti=titi1 的平方根与一个在时刻 ti 生成的标准正态分布随机样本的乘积。

然而,我们将利用 Python 的 NumPy 库所提供的向量化方法,同时生成 N 条路径。为此,我们将从标准正态分布中一次性抽取 N 个随机样本,然后利用上述递推关系,在向量化操作中并行地模拟这 N 条路径。

首先,我们需要导入后续分析所需的相关量化计算与可视化库,包括 Matplotlib、NumPy、Pandas 和 Seaborn:

import matplotlib.pyplot as pltimport numpy as npimport pandas as pdimport seaborn as sns

我们还需要设置一个随机种子值,以确保您生成的结果与我们的完全一致。为此,我们需要使用一个(伪)随机数生成器(RNG),此处使用的是 NumPy 提供的默认生成器。接着,必须提供一个整数作为种子值,以确保以下所有结果均可复现:

rng = np.random.default_rng(42)
下一步是确定路径数量以及每条路径的时间步数。我们设定了 N 条路径,每条路径包含 M 个时间步:
paths = 50points = 1000
由于这是标准布朗运动,该过程的漂移率(均值)为零,而波动率(标准差)为1:
mu, sigma = 0.01.0
下一步是从标准正态(高斯)分布中抽取所有必要的随机样本,并将它们存储在一个矩阵中,该矩阵的行数对应路径数量,列数对应时间点数量(即 N×M 个值)。为此,我们使用与上述相同的随机数生成器(RNG),因为它已被设定种子以确保结果可复现:
Z = rng.normal(mu, sigma, (paths, points))
下一步是确定模拟所覆盖的时间区间。我们将使用区间 [0,T]。此外,为本教程的简便起见,我们将采用等间距的时间步长,记为 Δt。为此,只需将区间长度除以时间点数量减一即可:
interval = [0.0, 1.0]dt = (interval[1] - interval[0]) / (points - 1)
为了在 Matplotlib 中绘制图形,需要创建一个“线性空间”坐标轴。以下代码将上述时间区间划分为指定数量的等间距点(包含区间的起始值和结束值),并将其存储在一个数组中,作为我们的“时间轴”:
t_axis = np.linspace(interval[0], interval[1], points)
以下代码实现了 [Glasserman, 2003] 中的递推公式(3.2)。我们首先创建一个大小为 N×M 的矩阵 W,用于存储布朗运动路径的结果,并将其初始化为全零。然后,我们遍历时间轴上的每个时间点。对于每个时间点,利用 NumPy 的向量化语法(W[:, real_idx]),将每条路径在该时刻的值设为前一时刻的值,加上时间步长 Δt 的平方根与矩阵 Z 中对应的标准正态随机样本的乘积:
W = np.zeros((paths, points))for idx in range(points - 1):    real_idx = idx + 1    W[:, real_idx] = W[:, real_idx - 1] + np.sqrt(dt) * Z[:, idx]
接着,我们可以使用 Matplotlib 将所有这些路径绘制在同一张图上。为此,我们使用 subplots 方法,它能让我们更精细地控制图形和坐标轴的配置。我们指定创建一个单行单列的子图,并以英寸为单位设置图形尺寸(默认分辨率为 100 dpi)。随后,我们遍历所有路径,将时间轴与矩阵 W 中对应的每一行(使用 NumPy 的向量化语法 W[path, :])进行绘图。最后,显示该图形:
fig, ax = plt.subplots(11, figsize=(128))for path in range(paths):    ax.plot(t_axis, W[path, :])ax.set_title("Standard Brownian Motion sample paths")ax.set_xlabel("Time")ax.set_ylabel("Asset Value")plt.show()
这将生成如下图像:

可以明显看出,在接近 T(模拟结束时刻)时,大部分路径的取值集中在零附近,落在 [1,1] 区间内,而少数路径则表现出更极端的终值。这正是标准布朗运动所预期的行为。

然而,我们可以通过对所生成的 N 条样本路径的终值分布进行量化分析,使这一观察更加严谨。为此,我们可以使用核密度估计(Kernel Density Estimate, KDE),这是一种从有限样本数据中估计连续概率分布的方法。我们将使用 Seaborn 统计可视化库来实现这一点。

第一步是创建一个 Pandas DataFrame(包含单列),其中存储所有样本路径在终点时刻的取值:

final_values = pd.DataFrame({'final_values': W[:, -1]})
然后,我们可以使用 Seaborn 对这些终值进行核密度估计(KDE)并绘制其分布图:
fig, ax = plt.subplots(11, figsize=(128))sns.kdeplot(data=final_values, x='final_values', fill=True, ax=ax)ax.set_title("Kernel Density Estimate of asset path final value distribution")ax.set_ylim(0.00.325)ax.set_xlabel('Final Values of Asset Paths')plt.show()
这将生成如下图像:
如图所示,该分布看起来与标准正态分布(即均值为零、标准差为1)颇为相似。然而,我们也可以直接计算该分布的样本均值和样本标准差:
print(final_values.mean(), final_values.std())
这将产生如下输出:
(final_values   -0.011699 dtype: float64, final_values    1.251382 dtype: float64)

所得均值为 -0.01,接近于零;标准差为 1.25,也相当接近于 1。如果模拟的路径数量进一步增加,根据大数定律,这些统计量将趋近于标准正态分布的理论值(即均值为 0,标准差为 1)。

在下一节中,我们将允许采样路径具有非零均值和非单位标准差。

具有常数漂移率与波动率的布朗运动

下一个递推关系式引自 [Glasserman, 2003] 中的公式 (3.3)。它是对前述公式的改进,在原有基础上增加了一项 μΔt,并将最后一项乘以 σ。正是这两个修改使得布朗运动路径可以具有非零均值(由 μ 控制)和非单位标准差(由 σ 控制):

上一节中的大部分代码和已计算的变量都可以直接复用,包括(已设定随机种子的)标准正态随机样本矩阵 Z。现在需要设置新的漂移率 μc 和波动率 σc,我们分别将其设为 5 和 2:
mu_c, sigma_c = 5.02.0
以下代码实现了 [Glasserman, 2003] 中的公式 (3.3)。注意其中新增了 mu_c * dt 项,并在后一项中加入了 sigma_c * ...。由于我们仍然使用固定长度的时间步长,因此依然可以使用常量 Δt(即 dt):
X = np.zeros((paths, points))for idx in range(points - 1):    real_idx = idx + 1    X[:, real_idx] = X[:, real_idx - 1] + mu_c * dt + sigma_c * np.sqrt(dt) * Z[:, idx]
与标准布朗运动类似,我们可以绘制所生成的样本路径集合:
fig, ax = plt.subplots(11, figsize=(128))for path in range(paths):    ax.plot(t_axis, X[path, :])ax.set_title("Constant mean and standard deviation Brownian Motion sample paths")ax.set_xlabel("Time")ax.set_ylabel("Asset Value")plt.show()
这将生成如下图像:

注意这些路径呈现出向均值 5 的正向漂移趋势,且其离散程度(波动幅度)相比标准布朗运动明显增大。通过调整 μc 和 σc 的取值,也可以生成具有不同动态特征的路径。

下一步计划

在本系列的下一篇文章中,我们将放宽均值和标准差为常数的假设,转而引入随时间变化的均值和标准差,以构建更复杂的资产价格动态模型。在后续文章中,我们还将探讨多维布朗运动、“布朗桥”(Brownian Bridge)以及几何布朗运动(Geometric Brownian Motion)。

最新文章

随机文章