用NumPy玩转蒙特卡洛模拟:手把手教你用随机数估算圆周率π和期权价格

张开发
2026/4/18 16:59:22 15 分钟阅读

分享文章

用NumPy玩转蒙特卡洛模拟:手把手教你用随机数估算圆周率π和期权价格
用NumPy玩转蒙特卡洛模拟手把手教你用随机数估算圆周率π和期权价格蒙特卡洛模拟就像一场数学魔术表演——通过随机撒点就能算出圆周率通过模拟股票走势就能预测期权价格。这种将概率游戏变成科学计算利器的技术正在金融工程、物理仿真等领域大放异彩。今天我们就用NumPy这把瑞士军刀带你亲自动手实现两个经典案例布丰投针实验估算π和欧式期权定价模拟。1. 蒙特卡洛方法的核心思想想象你在一间黑暗的房间里往墙上随机扔飞镖。虽然看不清靶心但如果你记录下所有飞镖的位置就能根据命中靶心的比例反推出靶心的大小——这就是蒙特卡洛模拟的精髓。这种方法得名于摩纳哥的赌城蒙特卡洛因为随机性是其核心特征。蒙特卡洛方法主要依赖三个关键要素随机数生成高质量的伪随机数决定了模拟的可靠性重复实验大数定律保证结果收敛到真实值结果统计通过概率统计方法提取有用信息在Python中NumPy的random模块提供了完善的随机数生成工具。我们最常用的两个函数是import numpy as np # 生成[0,1)均匀分布随机数 uniform_random np.random.rand(1000) # 生成标准正态分布随机数 normal_random np.random.randn(1000)提示虽然称为随机数但计算机生成的其实是伪随机数。对于大多数应用场景伪随机数已经足够随机了。2. 布丰投针实验用随机数计算π18世纪法国数学家布丰(Georges-Louis Leclerc)提出了一个惊人的发现通过随机投针可以估算圆周率π。这个实验成为蒙特卡洛方法最早的雏形之一。2.1 实验原理设想一组平行线间距为t。随机投下一根长度为l的针(l ≤ t)针与平行线相交的概率为P (2l)/(πt)通过大量实验统计相交频率就能反推出π的近似值。2.2 NumPy实现步骤我们用NumPy向量化运算高效模拟这个实验def estimate_pi(num_needles, needle_length1, line_spacing1): # 随机生成针中心位置(0到t/2之间) center_pos np.random.rand(num_needles) * (line_spacing/2) # 随机生成针角度(0到π/2之间) angles np.random.rand(num_needles) * (np.pi/2) # 计算针尖到最近平行线的距离 tip_distance (needle_length/2) * np.sin(angles) # 统计相交次数 crosses np.sum(center_pos tip_distance) # 估算π值 estimated_pi (2 * needle_length * num_needles) / (line_spacing * crosses) return estimated_pi让我们运行100万次投针实验np.random.seed(42) # 固定随机种子便于复现 pi_estimate estimate_pi(1_000_000) print(fπ的估计值为: {pi_estimate:.6f}, 误差: {abs(pi_estimate-np.pi)/np.pi*100:.4f}%)典型输出结果π的估计值为: 3.141631, 误差: 0.0012%2.3 结果可视化随着实验次数增加估算值会越来越接近真实π值实验次数π估计值相对误差(%)1,0003.1645570.729910,0003.1445440.0926100,0003.1410700.01661,000,0003.1416310.0012这个实验生动展示了如何用随机性解决确定性数学问题。虽然不如专业算法高效但体现了蒙特卡洛方法的普适性。3. 金融工程应用欧式期权定价蒙特卡洛模拟在金融衍生品定价中扮演着关键角色。我们以欧式看涨期权为例展示如何模拟股票价格路径来估算期权价值。3.1 布莱克-斯科尔斯模型基础欧式看涨期权赋予持有者在到期日以执行价K购买标的资产的权利。其理论价格可通过几何布朗运动模拟股票价格路径dS μSdt σSdW其中S股票价格μ预期收益率σ波动率dW维纳过程(随机项)3.2 NumPy实现步骤def european_call_option(S0, K, T, r, sigma, num_simulations100000): 蒙特卡洛模拟欧式看涨期权价格 参数: S0: 初始股价 K: 执行价 T: 到期时间(年) r: 无风险利率 sigma: 波动率 num_simulations: 模拟次数 # 生成随机路径(使用正态分布) rand_numbers np.random.randn(num_simulations) # 计算到期股价 ST S0 * np.exp((r - 0.5*sigma**2)*T sigma*np.sqrt(T)*rand_numbers) # 计算期权收益 payoffs np.maximum(ST - K, 0) # 贴现求现值 option_price np.exp(-r*T) * np.mean(payoffs) return option_price示例计算# 参数设置 S0 100 # 当前股价 K 105 # 执行价 T 1 # 1年到期 r 0.05 # 5%无风险利率 sigma 0.2 # 20%波动率 price european_call_option(S0, K, T, r, sigma) print(f欧式看涨期权价格估计值: {price:.4f})典型输出欧式看涨期权价格估计值: 8.02133.3 模拟结果分析影响期权价格的关键因素波动率波动越大期权价值越高时间价值到期时间越长期权价值越高价内外程度执行价与现价的差距我们可以用蒙特卡洛方法研究这些参数的影响# 研究波动率影响 volatilities np.linspace(0.1, 0.5, 10) prices [european_call_option(S0, K, T, r, vol) for vol in volatilities]将结果可视化波动率(σ)期权价格0.104.330.155.890.208.020.2510.210.3012.470.3514.720.4016.940.4519.130.5021.28注意实际金融应用中会采用更精细的模型和方差缩减技术但基本原理相同。4. 提升蒙特卡洛模拟精度的技巧虽然蒙特卡洛方法简单强大但要获得高精度结果需要注意以下几点4.1 控制随机数质量使用可靠的随机数生成器(np.random.default_rng()较新版本更推荐)设置随机种子保证结果可复现避免随机数序列相关性# 新版NumPy推荐方式 rng np.random.default_rng(seed42) uniform_random rng.random(1000) normal_random rng.standard_normal(1000)4.2 增加模拟次数根据大数定律误差与√N成反比误差 ∝ 1/√N要减少一半误差需要四倍模拟量。4.3 方差缩减技术对偶变量法同时使用U和1-U两组随机数控制变量法利用已知精确解的相似问题分层抽样将样本空间划分为均匀子区域以对偶变量法改进期权定价为例def european_call_antithetic(S0, K, T, r, sigma, num_simulations): # 生成两组对偶随机数 rand_numbers np.random.randn(num_simulations) antithetic -rand_numbers # 对偶变量 # 计算两组路径 ST1 S0 * np.exp((r - 0.5*sigma**2)*T sigma*np.sqrt(T)*rand_numbers) ST2 S0 * np.exp((r - 0.5*sigma**2)*T sigma*np.sqrt(T)*antithetic) # 计算两组收益 payoffs1 np.maximum(ST1 - K, 0) payoffs2 np.maximum(ST2 - K, 0) # 取平均值后贴现 option_price np.exp(-r*T) * np.mean(0.5*(payoffs1 payoffs2)) return option_price这种方法通常能将收敛速度提高2-4倍。5. 蒙特卡洛模拟的局限与替代方案虽然蒙特卡洛方法应用广泛但也存在一些不足计算成本高高精度需要大量模拟收敛速度慢误差仅以1/√N速度下降维度灾难高维问题效率急剧下降替代或补充方案包括拟蒙特卡洛使用低差异序列替代随机数PDE方法对某些问题更高效深度学习近年兴起的替代方法例如使用Sobol序列的拟蒙特卡洛实现from scipy.stats import qmc def european_call_quasi_mc(S0, K, T, r, sigma, num_simulations): # 生成Sobol序列 sampler qmc.Sobol(d1, scrambleTrue) u sampler.random(num_simulations) # 转换为正态分布 rand_numbers qmc.normal(u) # 计算股价路径 ST S0 * np.exp((r - 0.5*sigma**2)*T sigma*np.sqrt(T)*rand_numbers) # 计算期权价格 payoffs np.maximum(ST - K, 0) option_price np.exp(-r*T) * np.mean(payoffs) return option_price在实际项目中我通常会先用小规模测试比较不同方法的效率和精度再选择最适合当前问题的方案。对于简单问题标准蒙特卡洛通常已经足够对于高维复杂问题则需要考虑更高级的技术。

更多文章