You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

蒙特卡洛模拟R代码生成的收益图出现直线异常求助

蒙特卡洛模拟投资组合收益出现直线异常问题

我刚接触蒙特卡洛模拟,用R写了基础代码模拟指定投资组合的收益,但部分模拟收益在图表里始终是直线。已经减少模拟次数方便观察,调整其他参数后问题依旧,其余输出符合随机特性。代码和效果图如下:

library(quantmod)
library(ggplot2)
maxDate<- "2000-01-01"
tickers<-c("MSFT", "AAPL", "BRK-B")
getSymbols(tickers, from=maxDate)
Port.p<-na.omit(merge(Cl(AAPL),Cl(MSFT),Cl(`BRK-B`)))
Port.r<-ROC(Port.p, type = "discrete")[-1,]
stock_Price<- as.matrix(Port.p[,1:3])
stock_Returns <- as.matrix(Port.r[,1:3])

mc_rep = 50 # Number of Sims
training_days = 200 
portfolio_Weights = c(0.5,0.3,0.2)

coVarMat = cov(stock_Returns)
miu = colMeans(stock_Returns)
Miu = matrix(rep(miu, training_days), nrow = 3)
portfolio_Returns_m = matrix(0, training_days, mc_rep)

set.seed(2000)
for (i in 1:mc_rep) {
  Z = matrix ( rnorm( dim(stock_Returns)[2] * training_days ), ncol = training_days )
  L = t( chol(coVarMat) )
  daily_Returns = Miu + L %*% Z  
  portfolio_Returns_200 = cumprod( portfolio_Weights %*% daily_Returns + 1 )
  portfolio_Returns_m[,i] = portfolio_Returns_200;
}
x_axis = rep(1:training_days, mc_rep)
y_axis = as.vector(portfolio_Returns_m-1)
plot_data = data.frame(x_axis, y_axis)
ggplot(data = plot_data, aes(x = x_axis, y = y_axis)) + geom_path(col = 'red', size = 0.1) +
  xlab('Days') + ylab('Portfolio Returns') + 
  ggtitle('Simulated Portfolio Returns in 200 days')+
  theme_bw() +
  theme(plot.title = element_text(hjust = 0.5))

模拟收益异常图表


问题根源

绘图时未对不同模拟路径进行分组,导致ggplot将所有模拟的点按x轴顺序直接连接,跨路径的连线形成了看似直线的异常效果,并非模拟结果本身是直线。

修正后的代码

library(quantmod)
library(ggplot2)
maxDate<- "2000-01-01"
tickers<-c("MSFT", "AAPL", "BRK-B")
getSymbols(tickers, from=maxDate)
Port.p<-na.omit(merge(Cl(AAPL),Cl(MSFT),Cl(`BRK-B`)))
Port.r<-ROC(Port.p, type = "discrete")[-1,]
stock_Returns <- as.matrix(Port.r[,1:3])

mc_rep = 50 # Number of Sims
training_days = 200 
portfolio_Weights = c(0.5,0.3,0.2)

coVarMat = cov(stock_Returns)
miu = colMeans(stock_Returns)
# 简化均值矩阵的创建逻辑
Miu = matrix(miu, nrow = 3, ncol = training_days)
portfolio_Returns_m = matrix(0, training_days, mc_rep)

set.seed(2000)
for (i in 1:mc_rep) {
  Z = matrix(rnorm(3 * training_days), nrow = 3, ncol = training_days)
  L = t(chol(coVarMat))
  daily_Returns = Miu + L %*% Z  
  portfolio_Returns_200 = cumprod(portfolio_Weights %*% daily_Returns + 1)
  portfolio_Returns_m[,i] = portfolio_Returns_200;
}

# 关键修改:添加模拟路径分组变量
plot_data = data.frame(
  x_axis = rep(1:training_days, mc_rep),
  y_axis = as.vector(portfolio_Returns_m - 1),
  simulation = rep(1:mc_rep, each = training_days) # 标记每条路径所属的模拟次数
)

ggplot(data = plot_data, aes(x = x_axis, y = y_axis, group = simulation)) + 
  geom_path(col = 'red', size = 0.1) +
  xlab('Days') + ylab('Portfolio Returns') + 
  ggtitle('Simulated Portfolio Returns in 200 days')+
  theme_bw() +
  theme(plot.title = element_text(hjust = 0.5))

修正说明

  1. 添加分组变量:在plot_data中加入simulation列,标记每个点所属的模拟路径,确保ggplot为每条路径单独连线,避免跨路径连接。
  2. 简化均值矩阵创建:用matrix(miu, nrow=3, ncol=training_days)替代原代码,逻辑更清晰。
  3. 优化代码注释:调整随机数矩阵的生成注释,提升代码可读性。

修改后所有模拟路径会独立绘制,不会再出现异常直线。

内容的提问来源于stack exchange,提问作者Quantmax

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 18:31:07