📥 读取数据
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%"))