📥 读取数据

library(readxl)
library(xts)
## 载入需要的程辑包:zoo
## 
## 载入程辑包:'zoo'
## The following objects are masked from 'package:base':
## 
##     as.Date, as.Date.numeric
library(PerformanceAnalytics)
## 
## 载入程辑包:'PerformanceAnalytics'
## The following object is masked from 'package:graphics':
## 
##     legend
library(tibble)
library(tidyr)
library(ggplot2)
library(forcats)
library(timetk)
library(plotly)
## 
## 载入程辑包:'plotly'
## The following object is masked from 'package:ggplot2':
## 
##     last_plot
## The following object is masked from 'package:stats':
## 
##     filter
## The following object is masked from 'package:graphics':
## 
##     layout
raw_data <- read_excel("C:/work/data.xls")
# 处理日期列
if (is.numeric(raw_data[[1]])) {
  raw_data[[1]] <- as.Date(raw_data[[1]], origin = "1899-12-30")
} else {
  raw_data[[1]] <- as.Date(raw_data[[1]])
}
# 选取学号对应股票列 3,4,6,7
selected_data <- raw_data[, c(4, 5, 7, 8)]
colnames(selected_data) <- c("华岭股份", "微创光电", "苏轴股份", "乐创技术")
price <- xts(selected_data, order.by = raw_data[[1]])

📊 价格走势图

plot_ly(data = fortify.zoo(price), x = ~Index) %>%
  add_lines(y = ~`华岭股份`, name = '华岭股份') %>%
  add_lines(y = ~`微创光电`, name = '微创光电') %>%
  add_lines(y = ~`苏轴股份`, name = '苏轴股份') %>%
  add_lines(y = ~`乐创技术`, name = '乐创技术') %>%
  layout(title = "Stock Prices Over Time",
         xaxis = list(title = "Date"),
         yaxis = list(title = "Price"))

📈 计算收益率

pr_daily <- to.daily(price, indexAt = "lastof", OHLC = FALSE)
rt_daily <- na.omit(Return.calculate(pr_daily, method = "log"))
mean_ret <- colMeans(rt_daily)
cov_mat <- cov(rt_daily) * 252

📊 收益率走势图

plot_ly(data = fortify.zoo(rt_daily), x = ~Index) %>%
  add_lines(y = ~`华岭股份`, name = '华岭股份') %>%
  add_lines(y = ~`微创光电`, name = '微创光电') %>%
  add_lines(y = ~`苏轴股份`, name = '苏轴股份') %>%
  add_lines(y = ~`乐创技术`, name = '乐创技术') %>%
  layout(title = "Daily Log Returns",
         xaxis = list(title = "Date"),
         yaxis = list(title = "Log Return"))

🧮 模拟投资组合

num_port <- 10000  # 增加模拟次数以提高精度
all_wts <- matrix(nrow = num_port, ncol = 4)
port_returns <- numeric(num_port)
port_risk <- numeric(num_port)
sharpe_ratio <- numeric(num_port)

for (i in 1:num_port) {
  wts <- runif(4)
  wts <- wts / sum(wts)
  all_wts[i, ] <- wts
  port_ret <- sum(wts * mean_ret)
  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
  sharpe_ratio[i] <- port_ret / port_sd
}

portfolio_values <- tibble(Return = port_returns,
                           Risk = port_risk,
                           SharpeRatio = sharpe_ratio)

all_wts <- tk_tbl(all_wts)
## Warning in tk_tbl.data.frame(as.data.frame(data), preserve_index, rename_index,
## : Warning: No index to preserve. Object otherwise converted to tibble
## successfully.
colnames(all_wts) <- colnames(rt_daily)
portfolio_values <- tk_tbl(cbind(all_wts, portfolio_values))
## Warning in tk_tbl.data.frame(cbind(all_wts, portfolio_values)): Warning: No
## index to preserve. Object otherwise converted to tibble successfully.

🔍 最优组合识别

min_var <- portfolio_values[which.min(portfolio_values$Risk), ]
max_ret <- portfolio_values[which.max(portfolio_values$Return), ]
max_sr  <- portfolio_values[which.max(portfolio_values$SharpeRatio), ]

📊 可视化:最小风险组合

min_var %>%
  gather(`华岭股份`:`乐创技术`, key = Asset, value = Weights) %>%
  mutate(Asset = as.factor(Asset)) %>%
  plot_ly(x = ~Asset, y = ~Weights, type = 'bar', color = ~Asset) %>%
  layout(title = "Minimum Variance Portfolio Weights",
         xaxis = list(title = "Assets"),
         yaxis = list(title = "Weights", tickformat = ".0%"))

📊 可视化:最大收益组合

max_ret %>%
  gather(`华岭股份`:`乐创技术`, key = Asset, value = Weights) %>%
  mutate(Asset = as.factor(Asset)) %>%
  plot_ly(x = ~Asset, y = ~Weights, type = 'bar', color = ~Asset) %>%
  layout(title = "Maximum Return Portfolio Weights",
         xaxis = list(title = "Assets"),
         yaxis = list(title = "Weights", tickformat = ".0%"))

📊 可视化:最大 Sharpe 比组合

max_sr %>%
  gather(`华岭股份`:`乐创技术`, key = Asset, value = Weights) %>%
  mutate(Asset = as.factor(Asset)) %>%
  plot_ly(x = ~Asset, y = ~Weights, type = 'bar', color = ~Asset) %>%
  layout(title = "Maximum Sharpe Ratio Portfolio Weights",
         xaxis = list(title = "Assets"),
         yaxis = list(title = "Weights", tickformat = ".0%"))

📈 有效前沿图(交互式)

plot_ly(data = portfolio_values, x = ~Risk, y = ~Return,
        type = 'scatter', mode = 'markers', color = ~SharpeRatio,
        marker = list(size = 5), hoverinfo = 'text',
        text = ~paste("Sharpe:", round(SharpeRatio, 2))) %>%
  add_markers() %>%
  add_trace(data = min_var, x = ~Risk, y = ~Return,
            type = 'scatter', mode = 'markers', marker = list(color = 'blue', size = 10), name = 'Min Variance') %>%
  add_trace(data = max_ret, x = ~Risk, y = ~Return,
            type = 'scatter', mode = 'markers', marker = list(color = 'green', size = 10), name = 'Max Return') %>%
  add_trace(data = max_sr, x = ~Risk, y = ~Return,
            type = 'scatter', mode = 'markers', marker = list(color = 'red', size = 10), name = 'Max Sharpe') %>%
  layout(title = "Efficient Frontier (Interactive)",
         xaxis = list(title = "Annualized Risk", tickformat = ".0%"),
         yaxis = list(title = "Annualized Return", tickformat = ".0%"))