一、引言

本次作业基于给定的股票历史数据,运用投资组合理论对资产配置进行实证分析。根据学号后四位(4437),选取了对应的四只股票作为研究对象,分别为:华岭股份(430139.BJ)、微创光电(430198.BJ)、辰光医疗(430300.BJ)、乐创技术(430425.BJ)。
  作业要求:
  1. 求最小风险权重并画出对应直方图
  2. 求最大收益组合的权重并画出对应直方图
  3. 求夏普比率最大的组合权重并画出对应直方图
  4. 做投资组合优化并画出有效前沿
  根据以上要求,我采用了以下工具包:

library(PerformanceAnalytics)
library(quantmod)
library(xts)
library(dygraphs)
library(tibble)
library(tidyr)
library(ggplot2)
library(plotly)
library(timetk)
library(forcats)
library(readxl)
library(dplyr)
library(scales)

二、数据说明

本次使用的数据来源于课程提供的股票历史价格Excel文件,其中:第4行为变量名称,第1列为时间(格式为yyyy/mm/dd,其余列为各股票收盘价格。
  在数据处理过程中,主要进行了数据读取与清洗、转换为时间序列数据(xts格式)、去除缺失值等工作,以下为数据处理代码:

# 读取数据,跳过前4行,第5行开始是数据
data_raw <- read_excel("E:/wangwenyang/data.xls", sheet = "Sheet1", skip = 4, col_names = FALSE)
# 查看数据结构
cat("数据维度:", dim(data_raw), "\n")
# 处理日期(第一列)
dates_char <- as.character(data_raw[[1]])
dates <- as.Date(dates_char, format = "%Y-%m-%d")
dates_posix <- as.POSIXct(dates)
cat("日期范围:", format(min(dates), "%Y-%m-%d"), "至", format(max(dates), "%Y-%m-%d"), "\n")
cat("观测天数:", length(dates), "\n")
# 提取价格数据(第4,5,6,8列)
price_cols <- data_raw[, c(4, 5, 6, 8)]
price_matrix <- as.matrix(price_cols)
mode(price_matrix) <- "numeric"
# 创建xts对象,使用英文列名
price <- xts(price_matrix, order.by = dates_posix)
colnames(price) <- c("Hualing", "Weichuang", "Chenguang", "Lechuang")
# 移除缺失值
price <- na.omit(price)
cat("最终数据范围:", format(start(price)), "至", format(end(price)), "\n")
cat("最终观测数量:", nrow(price), "\n")
# 查看前几行(为了验证数据读取是否正确,输出数据基本信息如下:)
head(price)

2.1 股票价格走势

下图展示了四只股票在样本期间内的价格变化情况,可以观察到不同股票的价格整体上呈现下降态势,而具体的波动特征存在明显差异。

# 创建中文显示的数据用于绘图
price_cn <- price
colnames(price_cn) <- c("华岭股份", "微创光电", "辰光医疗", "乐创技术")

dygraph(price_cn) %>%
  dyOptions(colors = c("#1f77b4", "#ff7f0e", "#2ca02c", "#d62728")) %>%
  dyLegend(show = "always", width = 400) %>%
  dyRangeSelector() %>%
  dyAxis("y", label = "价格") %>%
  dyAxis("x", label = "日期")

为了更精确地衡量各股票的跌幅,下表统计了从样本期初(2022年1月4日)到样本期末(2023年4月14日)各股票的价格变化情况。

# 计算样本期初到期末的价格变化率
price_start <- as.numeric(price_cn[1, ])
price_end <- as.numeric(price_cn[nrow(price_cn), ])
price_change <- (price_end - price_start) / price_start
# 创建价格变化率表格
price_change_table <- data.frame(
  股票 = c("华岭股份", "微创光电", "辰光医疗", "乐创技术"),
  期初价格 = round(price_start, 2),
  期末价格 = round(price_end, 2),
  涨跌幅 = paste0(round(price_change * 100, 2), "%")
)
knitr::kable(price_change_table, caption = "表:样本期初至期末各股票价格变化", align = "c")
表:样本期初至期末各股票价格变化
股票 期初价格 期末价格 涨跌幅
华岭股份 20.26 10.48 -48.27%
微创光电 9.70 4.66 -51.96%
辰光医疗 8.86 6.00 -32.28%
乐创技术 24.50 12.65 -48.37%

2.2 收益率走势

为了更准确地衡量资产收益及风险的表现,本文采用对数收益率进行分析。收益率序列能够更好地反映资产的波动性特征,下图展示了四只股票在样本期间内的对数收益率走势。

# 计算对数日收益率
rt_daily <- na.omit(Return.calculate(price, method = "log"))
# 收益率走势图
rt_cn <- rt_daily
colnames(rt_cn) <- c("华岭股份", "微创光电", "辰光医疗", "乐创技术")
dygraph(rt_cn) %>%
  dyOptions(colors = c("#1f77b4", "#ff7f0e", "#2ca02c", "#d62728")) %>%
  dyLegend(show = "always", width = 400) %>%
  dyRangeSelector() %>%
  dyAxis("y", label = "对数收益率")

图中可见四只股票的对数收益率均表现出显著的波动聚集性,其中乐创技术与华岭股份的极端波动幅度更大,乐创技术更是出现大幅正负双向跳升,体现出较高的收益风险;而辰光医疗波动相对更为温和,四只股票的差异化波动特征进一步印证了各标的自身的风险收益属性差异。

三、统计量计算

为了更精确地刻画各股票的收益与风险特征,本文进一步计算其平均收益率、协方差矩阵以及标准差等统计指标。

# 日平均收益率
mean_ret_daily <- colMeans(rt_daily)
cat("\n=== 日平均收益率 ===\n")
## 
## === 日平均收益率 ===
print(round(mean_ret_daily, 6))
##   Hualing Weichuang Chenguang  Lechuang 
## -0.002133 -0.002373 -0.001261 -0.002139
# 年化平均收益率 (252个交易日)
mean_ret_annual <- mean_ret_daily * 252
cat("\n=== 年化平均收益率 ===\n")
## 
## === 年化平均收益率 ===
names(mean_ret_annual) <- c("华岭股份", "微创光电", "辰光医疗", "乐创技术")
print(round(mean_ret_annual, 4))
## 华岭股份 微创光电 辰光医疗 乐创技术 
##  -0.5376  -0.5979  -0.3179  -0.5391
# 协方差矩阵 (年化)
cov_mat <- cov(rt_daily) * 252
cat("\n=== 年化协方差矩阵 ===\n")
## 
## === 年化协方差矩阵 ===
colnames(cov_mat) <- c("华岭", "微创", "辰光", "乐创")
rownames(cov_mat) <- c("华岭", "微创", "辰光", "乐创")
print(round(cov_mat, 4))
##        华岭    微创   辰光    乐创
## 华岭 0.1414  0.0222 0.0105  0.0154
## 微创 0.0222  0.0667 0.0228 -0.0150
## 辰光 0.0105  0.0228 0.0950  0.0018
## 乐创 0.0154 -0.0150 0.0018  0.5691
# 年化标准差(风险)
std_annual <- sqrt(diag(cov_mat))
names(std_annual) <- c("华岭股份", "微创光电", "辰光医疗", "乐创技术")
cat("\n=== 年化标准差(风险)===\n")
## 
## === 年化标准差(风险)===
print(round(std_annual, 4))
## 华岭股份 微创光电 辰光医疗 乐创技术 
##   0.3760   0.2582   0.3083   0.7544

根据上述统计结果,四只股票在样本期间均呈现负收益,年化收益率在-31.79%至-59.79%之间。其中辰光医疗的年化收益率为-31.79%,亏损幅度最小;微创光电的年化收益率为-59.79%,亏损幅度最大;华岭股份和乐创技术分别为-53.76%和-53.91%,亏损程度相近。从风险角度来看,乐创技术的年化标准差高达75.44%,波动最为剧烈;微创光电的年化标准差为25.82%,波动相对最平稳;华岭股份和辰光医疗分别为37.60%和30.83%,居于中间水平。值得注意的是,乐创技术虽然风险最高,但其亏损幅度并非最大,而微创光电风险最低却遭受了最大的亏损,说明在样本期间内风险与收益之间并未呈现出严格的正相关关系。从协方差矩阵来看,华岭股份与乐创技术之间存在微弱的负相关关系(协方差为-0.0150),这为投资组合的风险分散提供了一定的空间。总体而言,四只股票在风险和收益维度上表现出明显的差异性,通过合理的权重配置有望在组合层面实现风险的优化管理。

四、蒙特卡洛模拟

为了寻找最优投资组合,本文采用蒙特卡洛模拟方法,通过随机生成大量投资组合权重,并计算其对应的收益与风险,从而构建有效前沿。

4.1 模拟设置

本次模拟的参数设置如下:随机种子设为4437以保证结果的可重复性,模拟生成10000个随机投资组合,每个组合包含四只股票,权重通过runif()函数随机生成并归一化处理,确保各资产权重之和为1(即全部资金用于投资)。无风险利率假设为0%,以简化计算。组合收益的计算方式为:首先计算各资产日收益率的加权平均值,然后进行年化处理——即(加权平均日收益率 + 1)^252 - 1。组合风险的计算则基于现代投资组合理论的核心公式:σ_p = sqrt(w^T Σ w),其中w为权重向量,Σ为年化协方差矩阵。夏普比率则定义为组合收益除以组合风险(由于无风险利率为0),模拟在R语言中通过for循环实现,每生成1000个组合输出一次进度提示。

4.2 执行模拟

set.seed(4437)  # 设置随机种子
tick <- c("Hualing", "Weichuang", "Chenguang", "Lechuang")
num_port <- 10000
# 存储矩阵和向量
all_wts <- matrix(nrow = num_port, ncol = 4)
port_returns <- vector('numeric', length = num_port)
port_risk <- vector('numeric', length = num_port)
sharpe_ratio <- vector('numeric', length = num_port)
cat("\n开始蒙特卡洛模拟...\n")
## 
## 开始蒙特卡洛模拟...
for (i in 1:num_port) {
  # 随机生成权重
  wts <- runif(4)
  wts <- wts / sum(wts)
  all_wts[i, ] <- wts
  
  # 组合收益(年化)
  port_ret <- sum(wts * mean_ret_daily)
  port_ret <- ((port_ret + 1)^252) - 1
  port_returns[i] <- port_ret
  # 组合风险
  port_sd <- sqrt(t(wts) %*% (cov_mat %*% wts))
  port_risk[i] <- port_sd
  # 夏普比率(假设无风险利率=0)
  sharpe_ratio[i] <- port_ret / port_sd
  # 显示进度
  if(i %% 1000 == 0) cat("已完成", i, "个组合\n")
}
## 已完成 1000 个组合
## 已完成 2000 个组合
## 已完成 3000 个组合
## 已完成 4000 个组合
## 已完成 5000 个组合
## 已完成 6000 个组合
## 已完成 7000 个组合
## 已完成 8000 个组合
## 已完成 9000 个组合
## 已完成 10000 个组合
# 创建结果数据表
portfolio_values <- tibble(
  Hualing = all_wts[,1],
  Weichuang = all_wts[,2],
  Chenguang = all_wts[,3],
  Lechuang = all_wts[,4],
  Return = port_returns,
  Risk = port_risk,
  SharpeRatio = sharpe_ratio
)
cat("\n模拟完成!生成了", nrow(portfolio_values), "个随机组合\n")
## 
## 模拟完成!生成了 10000 个随机组合

五、最优投资组合分析

在完成蒙特卡洛模拟后,可以从所有随机生成的投资组合中筛选出不同优化目标下的最优组合,包括最小风险组合、最大收益组合以及最大夏普比率组合,不同组合代表了不同的投资偏好和风险承受能力,投资者可以根据自身情况选择适合自己的配置方案。

5.1 最小风险组合

最小风险组合是指在所有投资组合中具有最低波动率(标准差)的组合,该组合强调风险最小化,适用于风险厌恶型投资者。

# 找出最小风险组合
min_var <- portfolio_values[which.min(portfolio_values$Risk), ]
cat("\n=== 最小风险组合 ===\n")
## 
## === 最小风险组合 ===
cat("年化风险:", round(min_var$Risk, 4), "\n")
## 年化风险: 0.1996
cat("年化收益:", round(min_var$Return, 4), "\n")
## 年化收益: -0.393
cat("夏普比率:", round(min_var$SharpeRatio, 4), "\n")
## 夏普比率: -1.9691
cat("\n权重分配:\n")
## 
## 权重分配:
min_weights <- round(c(min_var$Hualing, min_var$Weichuang, min_var$Chenguang, min_var$Lechuang), 4)
names(min_weights) <- c("华岭股份", "微创光电", "辰光医疗", "乐创技术")
print(min_weights)
## 华岭股份 微创光电 辰光医疗 乐创技术 
##   0.1727   0.4505   0.3012   0.0757
# 最小风险组合权重直方图
p1 <- data.frame(
  Asset = c("华岭股份", "微创光电", "辰光医疗", "乐创技术"),
  Weights = min_weights
) %>%
  mutate(Asset = factor(Asset, levels = Asset[order(Weights)])) %>%
  ggplot(aes(x = Asset, y = Weights, fill = Asset)) +
  geom_bar(stat = 'identity') +
  theme_minimal() +
  labs(x = '资产', y = '权重', title = "最小风险组合权重") +
  scale_y_continuous(labels = scales::percent, limits = c(0, 1)) +
  geom_text(aes(label = paste0(round(Weights * 100, 1), "%")), 
            vjust = -0.5, size = 4) +
  theme(legend.position = "bottom")

ggplotly(p1) %>% layout(title = "最小风险组合权重分配")

最终我们发现最小风险组合的权重分配是:华岭股份 0.1727 微创光电 0.4505 辰光医疗 0.3012 乐创技术 0.0757。

5.2 最大收益组合

最大收益组合是指在所有投资组合中年化收益率最高的组合,强调收益最大化。

# 找出最大收益组合
max_return <- portfolio_values[which.max(portfolio_values$Return), ]
cat("\n=== 最大收益组合 ===\n")
## 
## === 最大收益组合 ===
cat("年化收益:", round(max_return$Return, 4), "\n")
## 年化收益: -0.2903
cat("年化风险:", round(max_return$Risk, 4), "\n")
## 年化风险: 0.2807
cat("夏普比率:", round(max_return$SharpeRatio, 4), "\n")
## 夏普比率: -1.0342
cat("\n权重分配:\n")
## 
## 权重分配:
max_weights <- round(c(max_return$Hualing, max_return$Weichuang, max_return$Chenguang, max_return$Lechuang), 4)
names(max_weights) <- c("华岭股份", "微创光电", "辰光医疗", "乐创技术")
print(max_weights)
## 华岭股份 微创光电 辰光医疗 乐创技术 
##   0.0463   0.0108   0.8906   0.0523
# 最大收益组合权重直方图
p2 <- data.frame(
  Asset = c("华岭股份", "微创光电", "辰光医疗", "乐创技术"),
  Weights = max_weights
) %>%
  mutate(Asset = factor(Asset, levels = Asset[order(Weights)])) %>%
  ggplot(aes(x = Asset, y = Weights, fill = Asset)) +
  geom_bar(stat = 'identity') +
  theme_minimal() +
  labs(x = '资产', y = '权重', title = "最大收益组合权重") +
  scale_y_continuous(labels = scales::percent, limits = c(0, 1)) +
  geom_text(aes(label = paste0(round(Weights * 100, 1), "%")), 
            vjust = -0.5, size = 4) +
  theme(legend.position = "bottom")

ggplotly(p2) %>% layout(title = "最大收益组合权重分配")

最终我们发现最大收益组合的权重分配是:华岭股份 0.0463 微创光电 0.0108 辰光医疗 0.8906 乐创技术 0.0523。

5.3 最大夏普比率组合

最大夏普比率组合是指单位风险下收益最高的投资组合,是风险与收益权衡的最优解。

# 找出最大夏普比率组合
max_sr <- portfolio_values[which.max(portfolio_values$SharpeRatio), ]
cat("\n=== 最大夏普比率组合 ===\n")
## 
## === 最大夏普比率组合 ===
cat("夏普比率:", round(max_sr$SharpeRatio, 4), "\n")
## 夏普比率: -0.5894
cat("年化收益:", round(max_sr$Return, 4), "\n")
## 年化收益: -0.4156
cat("年化风险:", round(max_sr$Risk, 4), "\n")
## 年化风险: 0.7051
cat("\n权重分配:\n")
## 
## 权重分配:
sr_weights <- round(c(max_sr$Hualing, max_sr$Weichuang, max_sr$Chenguang, max_sr$Lechuang), 4)
names(sr_weights) <- c("华岭股份", "微创光电", "辰光医疗", "乐创技术")
print(sr_weights)
## 华岭股份 微创光电 辰光医疗 乐创技术 
##   0.0280   0.0212   0.0165   0.9343
# 最大夏普比率组合权重直方图
p3 <- data.frame(
  Asset = c("华岭股份", "微创光电", "辰光医疗", "乐创技术"),
  Weights = sr_weights
) %>%
  mutate(Asset = factor(Asset, levels = Asset[order(Weights)])) %>%
  ggplot(aes(x = Asset, y = Weights, fill = Asset)) +
  geom_bar(stat = 'identity') +
  theme_minimal() +
  labs(x = '资产', y = '权重', title = "最大夏普比率组合权重") +
  scale_y_continuous(labels = scales::percent, limits = c(0, 1)) +
  geom_text(aes(label = paste0(round(Weights * 100, 1), "%")), 
            vjust = -0.5, size = 4) +
  theme(legend.position = "bottom")

ggplotly(p3) %>% layout(title = "最大夏普比率组合权重分配")

最终我们发现最大夏普比率组合的权重分配是:华岭股份 0.0280 微创光电 0.0212 辰光医疗 0.0165 乐创技术 0.9343。

六、有效前沿分析

有效前沿是现代投资组合理论的核心概念,它表示在给定风险水平下能够获得的最大收益,或在给定收益水平下需要承担的最小风险的投资组合集合。有效前沿上的每一个点都是帕累托最优的,即无法在不增加风险的情况下提高收益,也无法在不降低收益的情况下降低风险。为了更直观地展示不同投资组合在风险与收益之间的关系,本文基于蒙特卡洛模拟结果绘制有效前沿,图中的每个点代表一个随机生成的投资组合,点的颜色表示该组合的夏普比率(蓝色较低,红色较高),同时标明了最小风险组合,最大收益组合、最大夏普比率组合各自的位置。从散点图的整体分布来看,10000个随机组合在风险-收益平面上呈现出扇形分布:左侧(风险较小区域)的收益分布较为集中,右侧(风险较大区域)的收益分布则较为分散。

# 创建标签数据框
special_points <- rbind(
  data.frame(Risk = min_var$Risk, Return = min_var$Return, Type = "最小风险组合"),
  data.frame(Risk = max_return$Risk, Return = max_return$Return, Type = "最大收益组合"),
  data.frame(Risk = max_sr$Risk, Return = max_sr$Return, Type = "最大夏普比率")
)

# 使用fill和color分开
p4 <- ggplot() +
  # 所有随机组合 - 使用color映射夏普比率
  geom_point(data = portfolio_values, 
             aes(x = Risk, y = Return, color = SharpeRatio), 
             alpha = 0.5, size = 1.5) +
  scale_color_gradient(low = "blue", high = "red", name = "夏普比率") +
  # 特殊点 - 使用fill映射
  geom_point(data = special_points, 
             aes(x = Risk, y = Return, fill = Type), 
             size = 4, shape = 21, color = "black", stroke = 1.2) +
  scale_fill_manual(values = c("最小风险组合" = "#2ca02c", 
                               "最大收益组合" = "#d62728",
                               "最大夏普比率" = "#ff7f0e"),
                    name = "特殊组合") +
  # 标签
  geom_text(data = special_points, 
            aes(x = Risk, y = Return, label = Type),
            hjust = -0.1, vjust = -0.8, size = 3.5) +
  theme_classic() +
  scale_y_continuous(labels = scales::percent, name = "年化收益率") +
  scale_x_continuous(labels = scales::percent, name = "年化风险") +
  labs(title = "投资组合优化与有效前沿",
       subtitle = paste0("基于", num_port, "个随机组合的蒙特卡洛模拟")) +
  theme(legend.position = "right",
        plot.title = element_text(hjust = 0.5, size = 14),
        plot.subtitle = element_text(hjust = 0.5, size = 10))

# 显示交互式图表
ggplotly(p4) %>% layout(title = "投资组合优化与有效前沿")

七、投资组合结果汇总

综合前文对最小风险组合、最大收益组合和最大夏普比率组合的分析,本节将三个组合的关键数据进行汇总对比,以便更清晰地呈现不同优化目标下的配置差异。

7.1 组合风险收益对比

下表汇总了三个组合的年化收益率、年化风险和夏普比率:

组合类型 年化收益率 年化风险 夏普比率
最小风险组合 -39.30% 19.96% -1.9691
最大收益组合 -29.03% 28.07% -1.0342
最大夏普比率组合 -41.56% 70.51% -0.5894

从收益角度来看,最大收益组合的年化收益率为-29.03%,在三个组合中表现最好,但其年化风险也相应较高,达到28.07%。最小风险组合虽然风险最低(19.96%),但收益也最差,为-39.30%。最大夏普比率组合的风险最高,达到70.51%,收益为-41.56%,但其夏普比率为-0.5894,在三个组合中相对最优。

7.2 组合权重分配对比

下表汇总了三个组合在各只股票上的权重分配:

股票 最小风险组合 最大收益组合 最大夏普比率组合
华岭股份 17.27% 4.63% 2.80%
微创光电 45.05% 1.08% 2.12%
辰光医疗 30.12% 89.06% 1.65%
乐创技术 7.57% 5.23% 93.43%

从权重分配可以看出,不同优化目标导出了截然不同的配置方案。最小风险组合的权重分布最为分散,四只股票的权重均未超过50%,体现出通过分散化降低风险的核心思路。最大收益组合高度集中于辰光医疗,占比接近90%,其余三只股票的权重合计仅约10%。最大夏普比率组合则几乎完全押注于乐创技术,占比超过93%,形成了极端集中的配置格局。

7.3 总结

对比发现,三个组合代表了三种不同的投资理念。最小风险组合强调风险控制,通过分散配置将年化风险控制在20%以内,适合风险厌恶型投资者。最大收益组合追求收益最大化,将资金集中于辰光医疗,在三个组合中取得了最高的年化收益,适合风险偏好型投资者。最大夏普比率组合追求风险调整后收益最优,尽管其绝对收益并非最高,风险也最大,但在夏普比率的意义上实现了相对最优,适合追求效率的理性投资者。值得注意的是,三个组合的夏普比率均为负值,这与样本期间市场整体下跌的环境一致。
  综上,我完成了作业的四个要求,生成了对应图表,通过本次作业,我学习了运用蒙特卡洛模拟方法进行投资组合优化的完整流程,加深了对现代投资组合理论中风险分散、有效前沿及夏普比率等核心概念的理解,在实际操作过程中,数据处理、可视化呈现和结果解读等环节的反复调试,也提升了我的R语言编程能力和金融数据分析思维。