本文在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. shiro 基础使用

    引 言 相关内容 : https://blog.csdn.net/superyayaya/article/details/94408805 在web 中, 不同角色的用户, 具有不同的访问权限, 有的 ...

  2. ActiveMQ 快速入门教程系列 第一章 点对点消息实现

    ActiveMQ 开发包下载及运行环境搭建 主页:http://activemq.apache.org/目前最新版本:5.11.1开发包及源码下载地址:http://activemq.apache.o ...

  3. discuz如何修改主题列表页增加最后发表用户调用

    首页有点问题,我觉得摘要实在太长了,我调整了一下 <!--{if is_array($group['lastpost'])}--> <a href="forum.php?m ...

  4. 安卓开发实战-记账本APP(五)

    今天将昨天剩余的bug修复,并且完成图标的美化,设置长按删除,模仿支付宝实现金额的动态增加. ①将昨天的布局进行了修改:之前是fragment,改成FrameLayout布局,不再设置name,进而在 ...

  5. js代码预解析

    1.var一般用于声明变量,预解析代码的时候,等号后面的赋值过程不会执行,所以预解析时的var变量都是未定义的 2.function声明的函数,预解析的时候,值就是函数里面的内容 例:console. ...

  6. mysql笔记(暂时)

    2018-05-28 create table cms_user(id int key auto_increment,username varchar(20),password varchar(20) ...

  7. Sophus库CMakeLists.txt内容详解笔记

    CMakeLists.txt: SET(PROJECT_NAME Sophus) PROJECT(${PROJECT_NAME}) CMAKE_MINIMUM_REQUIRED(VERSION 2.6 ...

  8. Codeforces_807

    A. 严格按照题目给的两个条件来. #include<bits/stdc++.h> using namespace std; ],b[]; int main() { ios::sync_w ...

  9. postman批量接口测试/批量导入/批量参数化简要全过程及遇到问题处理方法

    简单说明下postman批量接口调用的过程及注意事项: 1.报文调试(建议先调通再批量执行,统筹安排时间) 2.参数化,例如: "address": "{{address ...

  10. vue学习(三)完善模板页(bootstrap+AdminLTE)

    1.配置index.html <!DOCTYPE html> <html> <head> <meta charset="utf-8"> ...