本文在Creative Commons许可证下发布

试想一下,大多数基金“推荐”的配置策略都假设某种股票/债券组合。如果我们想寻求成本最小收益最高的组合(以yahoo finance上的数据来分析,因为美国股市数据更容易获得)。那么什么才是一个好的组合成为了我们的问题?指数基金包括几乎所有的股票和债券。几乎包含了美国股票及债券市场的组成的四种ETF是VTI、VXUS、BND、BNDX。让我们从这些开始数据分析。使用R语言来完成分析程序

 # Load package
library(tidyquant)
library(broom) # Load data for portfolios
symbols <- c("SPY", "SHY", "GLD")
symbols_low <- tolower(symbols) prices <- getSymbols(symbols, src = "yahoo",
from = "1990-01-01",
auto.assign = TRUE) %>%
map(~Ad(get(.))) %>%
reduce(merge) %>%
`colnames<-`(symbols_low) prices_monthly <- to.monthly(prices, indexAt = "last", OHLC = FALSE)
ret <- ROC(prices_monthly)["2005/2019"] # Load benchmark data
bench_sym <- c("VTI", "VXUS", "BND", "BNDX")
bench <- getSymbols(bench_sym, src = "yahoo",
from = "1990-01-01",
auto.assign = TRUE) %>%
map(~Ad(get(.))) %>%
reduce(merge) %>%
`colnames<-`(tolower(bench_sym))
bench <- to.monthly(bench, indexAt = "last", OHLC = FALSE)
bench_ret <- ROC(bench)["2014/2019"] # Create different weights and portflios
# Equal weigthed
wt1 <- rep(1/(ncol(ret)), ncol(ret))
port1 <- Return.portfolio(ret, wt1) %>%
`colnames<-`("ret") # Risk portfolio
wt2 <- c(0.9, 0.1, 0)
port2 <- Return.portfolio(ret, weights = wt2) %>%
`colnames<-`("ret") # Naive portfolio
wtn <- c(0.5, 0.5, 0)
portn <- Return.portfolio(ret, wtn) # Data frame of portfolios
port_comp <- data.frame(date = index(port1), equal = as.numeric(port1),
risky = as.numeric(port2),
naive = as.numeric(portn)) # Benchmark portfolio
wtb <- c(0.24, 0.21, 0.22, 0.33)
portb <- Return.portfolio(bench_ret, wtb, rebalance_on = "quarters") %>%
`colnames<-`("bench") # Graph of portfolios vs. benchmark
port_comp %>%
filter(date >= "2014-01-01") %>%
mutate(bench = portb) %>%
gather(key,value, -date) %>%
group_by(key) %>%
mutate(value = cumprod(value+1)) %>%
ggplot(aes(date, value*100, color = key)) +
geom_line() +
scale_color_manual("", labels = c("Bench", "Equal", "Naive", "Risky"),
values = c("purple", "blue", "black", "red")) +
labs(x = "",
y = "Index",
title = "The three portfolios with a benchmark",
caption = "Source: Yahoo, OSM estimates") +
theme(legend.position = "top",
plot.caption = element_text(hjust = 0)) # summary
port_comp %>%
filter(date >= "2014-01-01") %>%
mutate(bench = as.numeric(portb)) %>%
rename("Equal" = equal,
"Naive" = naive,
"Risky" = risky,
"Bench" = bench) %>%
gather(Asset, value, -date) %>%
group_by(Asset) %>%
summarise(`Mean (%)` = round(mean(value, na.rm = TRUE),3)*1200,
`Volatility (%)` = round(sd(value, na.rm = TRUE)*sqrt(12),3)*100,
`Sharpe` = round(mean(value, na.rm = TRUE)/sd(value, na.rm=TRUE)*sqrt(12),2),
`Cumulative (%)` = round(prod(1+value, na.rm = TRUE),3)*100) %>%
knitr::kable(caption = "Annualized performance metrics") # Portfolio
mean_ret <- apply(ret[,c("spy", "shy", "gld")],2,mean)
cov_port <- cov(ret[,c("spy", "shy", "gld")]) port_exam <- data.frame(ports = colnames(port_comp)[-1],
ret = as.numeric(apply(port_comp[,-1],2, mean)),
vol = as.numeric(apply(port_comp[,-1], 2, sd))) bench_exam <- data.frame(ports = "bench",
ret = mean(bench_ret),
vol = sd(bench_ret)) bench_spy <- data.frame(ports = "sp",
ret = mean(ret$spy),
vol = sd(ret$spy)) bench_spy_14 <- data.frame(ports = "sp",
ret = mean(ret$spy["2014/2019"]),
vol = sd(ret$spy["2014/2019"])) mean_ret_14 <- apply(ret[,c("spy", "shy", "gld")]["2014/2019"],2,mean) cov_port_14 <- cov(ret[,c("spy", "shy", "gld")]["2014/2019"]) port_exam_14 <- port_comp %>%
filter(date >= "2014-01-01") %>%
select(-date) %>%
gather(ports, value) %>%
group_by(ports) %>%
summarise_all(list(ret = mean, vol = sd)) %>%
data.frame() ### Random weighting
# wts for full period
wts <- matrix(nrow = 1000, ncol = 3)
set.seed(123)
for(i in 1:1000){
a <- runif(1,0,1)
b <- c()
for(j in 1:2){
b[j] <- runif(1,0,1-sum(a,b))
}
if(sum(a,b) < 1){
inc <- (1-sum(a,b))/3
vec <- c(a+inc, b+inc)
}else{
vec <- c(a,b)
}
wts[i,] <- sample(vec,replace = FALSE)
} # wts for 2014
wts1 <- matrix(nrow = 1000, ncol = 3)
set.seed(123)
for(i in 1:1000){
a <- runif(1,0,1)
b <- c()
for(j in 1:2){
if(j == 2){
b[j] <- 1 - sum(a,b)
}
else {
b[j] <- runif(1,0,1-sum(a,b))
}
vec <- c(a,b)
}
wts1[i,] <- sample(vec,replace = FALSE)
} # Calculate random portfolios
# Weighting: wts
port <- matrix(nrow = 1000, ncol = 2)
for(i in 1:1000){
port[i,1] <- as.numeric(sum(wts[i,] * mean_ret))
port[i,2] <- as.numeric(sqrt(t(wts[i,] %*% cov_port %*% wts[i,])))
} colnames(port) <- c("returns", "risk")
port <- as.data.frame(port)
port <- port %>%
mutate(sharpe = returns/risk) # Calculate random portfolios since 2014
# Weighting: wts1
port_14 <- matrix(nrow = 1000, ncol = 2)
for(i in 1:1000){
port_14[i,1] <- as.numeric(sum(wts1[i,] * mean_ret_14))
port_14[i,2] <- as.numeric(sqrt(t(wts1[i,] %*% cov_port_14 %*% wts1[i,])))
} colnames(port_14) <- c("returns", "risk")
port_14 <- as.data.frame(port_14)
port_14 <- port_14 %>%
mutate(sharpe = returns/risk) # Grraph with Sharpe ratio
port %>%
ggplot(aes(risk*sqrt(12)*100, returns*1200, color = sharpe)) +
geom_point(size = 1.2, alpha = 0.4) +
geom_point(data = port_exam, aes(port_exam[1,3]*sqrt(12)*100,
port_exam[1,2]*1200),
color = "red", size = 6) +
geom_point(data = port_exam, aes(port_exam[2,3]*sqrt(12)*100,
port_exam[2,2]*1200),
color = "purple", size = 7) +
geom_point(data = port_exam, aes(port_exam[3,3]*sqrt(12)*100,
port_exam[3,2]*1200),
color = "black", size = 5) +
scale_x_continuous(limits = c(0,14)) +
labs(x = "Risk (%)",
y = "Return (%)",
title = "Simulated portfolios",
color = "Sharpe ratio") +
scale_color_gradient(low = "red", high = "green") +
theme(legend.position = c(0.075,.8),
legend.key.size = unit(.5, "cm"),
legend.background = element_rect(fill = NA)) # Graph since 2014
port_14 %>%
ggplot(aes(risk*sqrt(12)*100, returns*1200, color = sharpe)) +
geom_point(size = 1.2, alpha = 0.4) +
geom_point(data = port_exam_14, aes(port_exam_14[1,3]*sqrt(12)*100,
port_exam_14[1,2]*1200),
color = "blue", size = 6) +
geom_point(data = port_exam_14, aes(port_exam_14[3,3]*sqrt(12)*100,
port_exam_14[3, 2]*1200),
color = "purple", size = 7) +
geom_point(data = port_exam_14, aes(port_exam_14[2,3]*sqrt(12)*100,
port_exam_14[2,2]*1200),
color = "black", size = 5) +
scale_x_continuous(limits = c(0,14)) +
labs(x = "Risk (%)",
y = "Return (%)",
title = "Simulated portfolios since 2014",
color = "Sharpe ratio") +
scale_color_gradient(low = "red", high = "green") +
theme(legend.position = c(0.075,0.8),
legend.background = element_rect(fill = NA),
legend.key.size = unit(.5, "cm")) # Portfolios benchmarked vs Vanguard
port_14 %>%
mutate(Bench = returns - bench_exam$ret) %>%
# mutate(Bench = ifelse(Bench > 0, 1, 0)) %>%
ggplot(aes(risk*sqrt(12)*100, returns*1200, color = Bench)) +
geom_point(size = 1.2, alpha = 0.4) +
scale_color_gradient(low = "red", high = "green") +
geom_point(data = port_exam_14, aes(port_exam_14[1,3]*sqrt(12)*100,
port_exam_14[1,2]*1200),
color = "blue", size = 6) +
geom_point(data = port_exam_14, aes(port_exam_14[3,3]*sqrt(12)*100,
port_exam_14[3,2]*1200),
color = "purple", size = 7) +
geom_point(data = port_exam_14, aes(port_exam_14[2,3]*sqrt(12)*100,
port_exam_14[2,2]*1200),
color = "black", size = 5) +
labs(x = "Risk (%)",
y = "Return (%)",
title = "Simulated portfolios since 2014") +
theme(legend.position = c(0.06,0.8),
legend.background = element_rect(fill = NA),
legend.key.size = unit(.5, "cm")) # Portfolios benchmarked vs Vanguard
port_14 %>%
mutate(Bench = returns - bench_exam$ret) %>%
mutate(Bench = ifelse(Bench > 0, 1, 0)) %>%
ggplot(aes(risk*sqrt(12)*100, returns*1200, color = Bench)) +
geom_point(size = 1.2, alpha = 0.4) +
scale_color_gradient(low = "red", high = "green") +
geom_point(data = port_exam_14, aes(port_exam_14[1,3]*sqrt(12)*100,
port_exam_14[1,2]*1200),
color = "blue", size = 6) +
geom_point(data = port_exam_14, aes(port_exam_14[3,3]*sqrt(12)*100,
port_exam_14[3,2]*1200),
color = "purple", size = 7) +
geom_point(data = port_exam_14, aes(port_exam_14[2,3]*sqrt(12)*100,
port_exam_14[2,2]*1200),
color = "black", size = 5) +
labs(x = "Risk (%)",
y = "Return (%)",
title = "Simulated portfolios") +
theme(legend.position = c(0.05,0.8),
legend.background = element_rect(fill = NA),
legend.key.size = unit(.5, "cm")) # Count how many portfolios are negative
pos_b <- port_14 %>%
mutate(Bench = returns - bench_exam$ret) %>%
mutate(Bench = ifelse(Bench > 0, 1, 0)) %>%
summarise(bench = round(mean(Bench),2)*100) %>%
as.numeric() port_list_14 <- list()
for(i in 1:1000){
port_list_14[[i]] <- Return.portfolio(ret["2014/2019"], wts[i,]) %>%
data.frame() %>%
summarise(returns = mean(portfolio.returns),
excess_ret = mean(portfolio.returns) - mean(portb$bench),
track_err = sd(portfolio.returns - portb$bench),
risk = sd(portfolio.returns))
} port_info <- port_list_14 %>% bind_rows
rfr <- mean(ret$shy) # Graph info
port_info %>%
mutate(info_ratio = excess_ret/track_err) %>%
ggplot(aes(risk*sqrt(12)*100, returns*1200, color = info_ratio)) +
geom_point(size = 1.2, alpha = 0.4) +
geom_point(data = port_exam_14, aes(port_exam_14[1,3]*sqrt(12)*100,
port_exam_14[1,2]*1200),
color = "blue", size = 6) +
geom_point(data = port_exam_14, aes(port_exam_14[3,3]*sqrt(12)*100,
port_exam_14[3,2]*1200),
color = "purple", size = 7) +
geom_point(data = port_exam_14, aes(port_exam_14[2,3]*sqrt(12)*100,
port_exam_14[2,2]*1200),
color = "black", size = 5) +
labs(x = "Risk (%)",
y = "Return (%)",
title = "Simulated portfolios") +
theme(legend.position = c(0.075,0.8),
legend.background = element_rect(fill = NA),
legend.key.size = unit(.5, "cm")) +
scale_color_gradient("Information ratio", low = "red", high = "green")

总结一下结论?如果您有定义良好的约束条件,那么查看不同的投资组合分配以获得所需的风险/回报参数是非常好的。如果你没有,那么合并一个足够广泛的组合来包含尽可能多的可投资风险资产是有帮助的。使用调整后的Sharpe比率来观察组合的超额回报率是很有用的,这个投资组合比率揭示了一个重要的信息:即一个包含大部分相似资产的投资组合是否因偏离基准而得到收益上补偿。在这种情况下,我们的投资组合并不是,但那可能是由于gold exposure。因此,使用不关联资产的投资组合可以降低总投资金额,比如关注某个特定指数的成分股来指定投资组合,就能够最大限度的利用资金。

指数ETF基金的组合分析方法初探的更多相关文章

  1. etf基金和lof基金区别

    ①,含义不同.etf即交易指数开放基金,是跟踪某一指数的可以在交易所上市的开放式基金.lof基金是上市向开放基金,是中国首创的一种基金类型,也是etf基金的中国化.②,申购赎回的场所不同.etf和lo ...

  2. Android 和 JS交互方法初探

    起初有个需求,就是需要监听网页的图片点击,然后图片单独跳转到另一个页面单独显示 这里就需要用JS和Android Native方法之间的通信 先说上面的解决办法之前先引出两个Android的方法 1: ...

  3. C#多线程JOIN方法初探

    [说明:刚接触多线程时,弄不明白Join()的作用,查阅了三本书,都不明不白.后来经过自己的一番试验,终于弄清了Join()的本质.大家看看我这种写法是否易懂,是否真的写出了Join()的本质,多提宝 ...

  4. solr入门之权重排序方法初探之使用edismax改变权重

    做搜索引擎避免不了排序问题,当排序没有要求时,solr有自己的排序打分机制及sorce字段 1.无特殊排序要求时,根据查询相关度来进行排序(solr自身规则) 2.当涉及到一个字段来进行相关度排序时, ...

  5. Spring5源码解析3-refresh方法初探

    接上回分析完register(annotatedClasses);后,现在来看一下refresh();方法. // new AnnotationConfigApplicationContext(App ...

  6. TinyMCE在线编辑器使用方法初探

    首先,下载TinyMCE包,地址:http://www.tinymce.com/ 然后将下载后的包解压,放置到一个文件夹下,创建一个html文件,并在其中书写如下代码: <!DOCTYPE ht ...

  7. 一个ETF基金经理的心路历程

    简介: 鹏华沪深300ETF拟任基金经理崔俊杰先生,金融工程专业管理学硕士,5年证券基金从业经验.2008年7月加盟鹏华基金管理有限公司,历任产品规划部产品设计师.量化投资部量化研究员,先后从事产品设 ...

  8. 匹夫细说C#:委托的简化语法,聊聊匿名方法和闭包

    0x00 前言 通过上一篇博客<匹夫细说C#:庖丁解牛聊委托,那些编译器藏的和U3D给的>的内容,我们实现了使用委托来构建我们自己的消息系统的过程.但是在日常的开发中,仍然有很多开发者因为 ...

  9. php获取网页header信息的4种方法

    php获取网页header信息的方法多种多样,就php语言来说,我知道的方法有4种, 下面逐一献上. 方法一:使用get_headers()函数 推荐指数: ★★★★★ get_header方法最简单 ...

随机推荐

  1. 利用geojson实现模型轨迹运动

    直接上代码 var viewer = new Cesium.Viewer('cesiumContainer'); //Set the random number seed for consistent ...

  2. Docker底层架构之简介

    简介 Docker 底层的核心技术包括 Linux 上的命名空间(Namespaces) 控制组(Control groups) Union 文件系统(Union file systems) 容器格式 ...

  3. 脚本在Shell可以执行成功,放到crontab里执行失败

    一.背景 自己写了个监控MGR状态的脚本,直接在Linux的Shell环境下可以执行成功,但是只要放到crontab里执行,就失败,脚本内容如下 #!/bin/bash MAIL_ADDR=`cat ...

  4. 前端入门nginx

    一.nginx是什么 NGINX is a free, open-source, high-performance HTTP server and reverse proxy, as well as ...

  5. 4、Oracle 数据库 startup 报错:ORA-27102: out of memory

    1.数据库启动报错: ORA-: out of memory SQL> startup pfile='/db/oracle/init.ora'; ORA-: out of memory Linu ...

  6. CCF_201612-4_交通规划

    http://115.28.138.223/view.page?gpid=T44 好像也没想象中的那么难,没办法,当初连个优先队列dij都不会写= = 在优先队列dij算法上加上相等的时候的处理就可以 ...

  7. js 浏览器兼容问题及解决办法

    JS中出现的兼容性问题的总结 1.关于获取行外样式 currentStyle 和 getComputedStyle 出现的兼容性问题  我们都知道js通过style不可以获取行外样式,当我们需要获取行 ...

  8. 转:JSON与Map互转

    JSON字符串与Map互转   //一.map转为json字符串 public static String map2jsonstr(Map<String,?> map){ return J ...

  9. 日志框架 log4j2 全解析

    概述 logging翻译为日志记录 那问题是什么是日志? 日志实际上是日记的一种,用于记录某个时间点发生了什么事情,比如大学老师的教学日志,工作日志等 为什么要记录日志? 在实际生活中记录日志主要为了 ...

  10. Spring中的可扩展接口

    1.监听器Listener(点此连接,执行流程带源码分析及demo) 2.bean定义的后置处理器(BeanDefinitionRegistryPostProcessor)和bean工厂的后置处理器( ...