- import numpy as np
- import matplotlib.pyplot as plt
- def monte_carlo_simulation(
- S0: float,
- mu: float,
- sigma: float,
- T: float,
- n_sim: int,
- n_steps: int
- ) -> np.ndarray:
- """
- 使用几何布朗运动(GBM)对资产价格进行蒙特卡洛模拟。
- 参数
- ----------
- S0 : float
- 初始资产价格。
- mu : float
- 年化预期收益率(无风险利率或历史漂移率)。
- sigma : float
- 年化波动率。
- T : float
- 模拟期限(年)。
- n_sim : int
- 模拟路径数量。
- n_steps : int
- 每条路径的时间步数。
- 返回
- -------
- paths : np.ndarray, shape (n_sim, n_steps + 1)
- 模拟价格矩阵,每一行是一条路径,每一列是一个时间点。
- """
- dt = T / n_steps
- # 布朗运动的漂移项修正(伊藤引理)
- drift = (mu - 0.5 * sigma ** 2) * dt
- # 随机冲击的标准差
- vol = sigma * np.sqrt(dt)
- # 生成标准正态随机数 (n_sim, n_steps)
- Z = np.random.standard_normal((n_sim, n_steps))
- # 对数收益率
- log_returns = drift + vol * Z
- # 累积对数收益率
- log_returns_cum = np.cumsum(log_returns, axis=1)
- # 将初始价格添加到第一列,构建完整路径
- paths = np.zeros((n_sim, n_steps + 1))
- paths[:, 0] = S0
- paths[:, 1:] = S0 * np.exp(log_returns_cum)
- return paths
- # --------------
- # 示例使用与可视化
- # --------------
- if __name__ == "__main__":
- # 参数设置
- S0 = 100 # 初始价格
- mu = 0.05 # 预期收益率 5%
- sigma = 0.2 # 波动率 20%
- T = 1.0 # 模拟1年
- n_sim = 1000 # 1000条路径
- n_steps = 252 # 252个交易日
- # 运行模拟
- price_paths = monte_carlo_simulation(S0, mu, sigma, T, n_sim, n_steps)
- # 期末价格统计
- final_prices = price_paths[:, -1]
- print(f"期末价格均值: {final_prices.mean():.2f}")
- print(f"期末价格标准差: {final_prices.std():.2f}")
- print(f"5% VaR (历史法): {S0 - np.percentile(final_prices, 5):.2f}")
- # 可视化部分路径
- plt.figure(figsize=(10, 6))
- plt.plot(price_paths.T[:, :100], alpha=0.1, color='blue')
- plt.axhline(y=S0, linestyle='--', color='red', alpha=0.5, label='Initial Price')
- plt.title("Monte Carlo Simulation of Asset Prices (GBM)")
- plt.xlabel("Time Steps")
- plt.ylabel("Price")
- plt.legend()
- plt.show()
- # 期末价格分布直方图
- plt.figure(figsize=(8, 5))
- plt.hist(final_prices, bins=50, alpha=0.7, color='skyblue', edgecolor='black')
- plt.axvline(x=S0, linestyle='--', color='red', label='Initial Price')
- plt.title("Distribution of Final Prices")
- plt.xlabel("Price")
- plt.ylabel("Frequency")
- plt.legend()
- plt.show()
复制代码
|