R Markdown
# 加载包
library(quantmod)
## 载入需要的程辑包:xts
## 载入需要的程辑包:zoo
##
## 载入程辑包:'zoo'
## The following objects are masked from 'package:base':
##
## as.Date, as.Date.numeric
## 载入需要的程辑包:TTR
## Registered S3 method overwritten by 'quantmod':
## method from
## as.zoo.data.frame zoo
library(PerformanceAnalytics)
##
## 载入程辑包:'PerformanceAnalytics'
## The following object is masked from 'package:graphics':
##
## legend
library(CVXR)
##
## 载入程辑包:'CVXR'
## The following object is masked from 'package:stats':
##
## power
library(ggplot2)
# 读取数据(假设数据格式为:日期 + 股票收益率列)
data <- read.csv("C:/Users/L/Desktop/new homework/data(1).csv", header = TRUE, stringsAsFactors = FALSE)
rownames(data) <- as.Date(data$close_price,format = "%Y/%m/%d") # 假设第一列是日期
returns <- data[, -1] # 去掉日期列,保留收益率数据
# 检查列名(确认股票代码列)
print(colnames(data))
## [1] "close_price" "X430047.BJ" "X430090.BJ" "X430139.BJ" "X430198.BJ"
## [6] "X430300.BJ" "X430418.BJ" "X430425.BJ" "X430476.BJ" "X430478.BJ"
## [11] "X430489.BJ" "X430510.BJ" "X430556.BJ" "X430564.BJ" "X430685.BJ"
## [16] "X430718.BJ" "X830799.BJ" "X830809.BJ" "X830832.BJ" "X830839.BJ"
## [21] "X830879.BJ"
# 根据学号后四位2275选择股票,有重复数字2,改为2375(根据实际列名调整)
selected_returns <- data[, c("X430090.BJ", "X430139.BJ", "X430425.BJ", "X430300.BJ")]
# 检查数据
head(selected_returns)
## X430090.BJ X430139.BJ X430425.BJ X430300.BJ
## 2022-01-04 10.03 20.26 24.5 8.86
## 2022-01-05 9.60 19.47 24.7 8.88
## 2022-01-06 8.50 19.49 24.7 8.91
## 2022-01-07 8.29 19.35 24.7 8.67
## 2022-01-10 8.76 19.61 24.7 8.70
## 2022-01-11 8.30 20.00 24.6 8.61
colnames(selected_returns) <- c("Stock2_1", "Stock2_2", "Stock7", "Stock5") # 重命名避免重复
#最小风险权重与直方图
# 定义优化问题(最小化方差)
min_risk_weights <- function(returns) {
n <- ncol(returns)
w <- Variable(n)
risk <- quad_form(w, cov(returns))
prob <- Problem(Minimize(risk), constraints = list(w >= 0, sum(w) == 1))
result <- solve(prob)
return(result$getValue(w))
}
weights_min_risk <- min_risk_weights(selected_returns)
rownames(weights_min_risk) <- colnames(selected_returns)
# 打印权重
print("最小风险权重:")
## [1] "最小风险权重:"
print(weights_min_risk)
## [,1]
## Stock2_1 2.015575e-23
## Stock2_2 -5.698232e-23
## Stock7 -1.632472e-24
## Stock5 1.000000e+00
# 绘制直方图
ggplot(data.frame(Stock = colnames(selected_returns), Weight = weights_min_risk[,1]),
aes(x = Stock, y = Weight)) +
geom_bar(stat = "identity", fill = "steelblue") +
labs(title = "Minimum Risk Portfolio Weights", y = "Weight") +
theme_minimal()

#最大收益权重与直方图
max_return_weights <- function(returns) {
n <- ncol(returns)
w <- Variable(n)
expected_return <- t(colMeans(returns)) %*% w
prob <- Problem(Maximize(expected_return), constraints = list(w >= 0, sum(w) == 1))
result <- solve(prob)
return(result$getValue(w))
}
weights_max_return <- max_return_weights(selected_returns)
rownames(weights_max_return) <- colnames(selected_returns)
# 打印权重
print("最大收益权重:")
## [1] "最大收益权重:"
print(weights_max_return)
## [,1]
## Stock2_1 -2.121073e-28
## Stock2_2 -2.126238e-28
## Stock7 1.000000e+00
## Stock5 -2.122475e-28
# 绘制直方图
ggplot(data.frame(Stock = colnames(selected_returns), Weight = weights_max_return[,1]),
aes(x = Stock, y = Weight)) +
geom_bar(stat = "identity", fill = "darkred") +
labs(title = "Maximum Return Portfolio Weights", y = "Weight") +
theme_minimal()

#最大夏普比率权重与直方图
max_sharpe_weights <- function(returns, rf = 0) {
n <- ncol(returns)
mu <- colMeans(returns) - rf
Sigma <- cov(returns)
# 使用等效凸优化问题
y <- Variable(n)
prob <- Problem(Minimize(quad_form(y, Sigma)),
constraints = list(t(mu) %*% y == 1, y >= 0))
result <- solve(prob, solver = "ECOS")
if(result$status != "optimal") {
stop("优化失败: ", result$status)
}
# 归一化得到最终权重
w <- result$getValue(y)
return(w / sum(w))
}
# 1. 加载必要包
library(CVXR)
library(Matrix)
# 2. 准备数据
selected_returns <- as.matrix(na.omit(selected_returns))
cov_matrix <- Matrix::nearPD(cov(selected_returns))$mat
# 3. 计算最大夏普比率权重
weights_max_sharpe <- max_sharpe_weights(selected_returns)
# 4. 添加行名
rownames(weights_max_sharpe) <- colnames(selected_returns)
# 5. 输出结果
print("最大夏普比率权重:")
## [1] "最大夏普比率权重:"
print(weights_max_sharpe)
## [,1]
## Stock2_1 2.257766e-09
## Stock2_2 1.977207e-09
## Stock7 9.417137e-03
## Stock5 9.905829e-01
# 6. 可视化
barplot(weights_max_sharpe[,1],
main = "最大夏普比率组合权重",
xlab = "资产",
ylab = "权重",
col = "darkgreen")

#关于有效前沿
efficient_frontier <- function(returns, n_points = 50) {
cov_mat <- cov(returns)
mean_ret <- colMeans(returns)
n <- ncol(returns)
# 生成目标收益序列
target_returns <- seq(min(mean_ret), max(mean_ret), length.out = n_points)
target_risks <- numeric(n_points)
weights_list <- list()
for (i in 1:n_points) {
w <- Variable(n)
risk <- quad_form(w, cov_mat)
prob <- Problem(Minimize(risk),
constraints = list(t(mean_ret) %*% w == target_returns[i],
w >= 0, sum(w) == 1))
result <- solve(prob)
target_risks[i] <- sqrt(result$value)
weights_list[[i]] <- as.vector(result$getValue(w)) # 转换为向量
}
# 将权重列表转换为矩阵
weights_matrix <- do.call(rbind, weights_list)
colnames(weights_matrix) <- colnames(returns)
# 返回数据框
data.frame(
Return = target_returns,
Risk = target_risks,
Weights = weights_matrix
)
}
# 生成有效前沿数据(假设selected_returns已存在)
frontier_data <- efficient_frontier(selected_returns)
# 提取关键点
min_risk_point <- frontier_data[which.min(frontier_data$Risk), ]
max_return_point <- frontier_data[which.max(frontier_data$Return), ]
max_sharpe_point <- frontier_data[which.max((frontier_data$Return - 0) / frontier_data$Risk), ]
# 绘制有效前沿
ggplot(frontier_data, aes(x = Risk, y = Return)) +
geom_line(color = "blue") +
geom_point(data = min_risk_point, aes(x = Risk, y = Return), color = "red", size = 3) +
geom_point(data = max_return_point, aes(x = Risk, y = Return), color = "green", size = 3) +
geom_point(data = max_sharpe_point, aes(x = Risk, y = Return), color = "purple", size = 3) +
labs(title = "Efficient Frontier", x = "Risk (Standard Deviation)", y = "Expected Return") +
annotate("text", x = min_risk_point$Risk, y = min_risk_point$Return,
label = "Min Risk", vjust = -1) +
annotate("text", x = max_return_point$Risk, y = max_return_point$Return,
label = "Max Return", vjust = -1) +
annotate("text", x = max_sharpe_point$Risk, y = max_sharpe_point$Return,
label = "Max Sharpe", vjust = -1) +
theme_minimal()
