Exchange Traded Funds
A collection of securities for example stocks which usually tracks an underlying index is known as an Exchange - Traded Fund(ETF). ETF’s share some similarity with mutual funds although they are listed on exchanges and their share is traded like stocks throughout the day. ETF’s can be made up of various strategies and invest in diverse number of industry sectors.
The most popular index tracked by most ETF’s is the S&P 500. For example the SPDR S&P 500 ETF (SPY) tracks the S&P 500. ETFs can include different types of investments, including stocks, commodities, bonds, or a mixture of investment types. ETF’s is traded on financial markets as a security with a price at which it can be bought and sold. Most ETF’s are set up as Open-end funds meaning there is no cap on the number of investors allowed in on the product.
Types of ETFs
There are various types of ETFs available to investors that can be used for income generation, speculation, price increases, and to hedge or partly offset risk in an investor’s portfolio. Below are several examples of the types of ETFs.
- Bond ETFs may include government bonds, corporate bonds, and state and local government bonds called municipal bonds.
- Industry ETFs track a particular industry such as technology, banking, or the oil and gas sector.
- Commodity ETFs invest in commodities including crude oil or gold.
- Currency ETFs invest in foreign currencies such as the Euro or the British pound.
- Inverse ETFs attempt to earn gains from stock declines by shorting stocks. Shorting is selling a stock, expecting a decline in value, and repurchasing it at a lower price. Many inverse ETFs are Exchange Traded Notes (ETNs) and not true ETFs. An ETN is a bond but trades like a stock and is backed by an issuer like a bank.
How to Buy and Sell ETFs
ETF’s are traded through licensed online and traditional broker dealers. Most of the poular ETF brokers like Vanguard also have robo-advisors which is a computer algorithm that attempts to mimic a human trader. Some ETF’s go a step further by offering commision free products. Examples of such brokers can easily be found online.
The following libraries required is loaded loaded here.
library(ggplot2)
library(plotly)
library(rvest)
library(pbapply)
library(TTR)
library(dygraphs)
library(lubridate)
library(tidyquant)
library(timetk)
library(htmlwidgets)
library(kableExtra)
pacman::p_load(kable,dygraphs,DT,tidyverse,janitor,ggthemes,scales,ggpubr,viridis)
theme_set(theme_pubclean())
The table below shows some popular U.S. ETF brands and issuers.
library(rvest)
library(XML)
library(gt)
library(tidyverse)
library(glue)
webpage <- read_html("https://www.etf.com/sections/etf-league-tables/etf-league-table-2020-02-10")
tbls <- html_nodes(webpage, "table")
print(head(tbls))
## {xml_nodeset (2)}
## [1] <table border="0" cellpadding="2" cellspacing="0" class="IUtable" style=" ...
## [2] <table border="0" cellpadding="2" cellspacing="0" class="IUtable" style=" ...
tbls_ls <- webpage %>%
html_nodes("table") %>%
.[[1]] %>%
html_table(fill = TRUE)
colnames(tbls_ls) <- c("Brand","AUM ($, mm)","Net Flows ($, mm)","% of AUM")
tbls_ls <- tbls_ls %>% janitor::clean_names()
#DT::datatable(tbls_ls, class = 'cell-border stripe')
tbls_ls %>%head()%>%
kable(escape = F, align = "c") %>%
kable_styling(c("striped", "condensed"), full_width = F)
brand | aum_mm | net_flows_mm | percent_of_aum |
---|---|---|---|
Brand | AUM ($, mm) | Net Flows ($, mm) | % of AUM |
iShares | 1,761,739.92 | 1,120.23 | 0.06% |
Vanguard | 1,195,773.48 | 1,154.64 | 0.10% |
SPDR | 737,904.99 | -710.71 | -0.10% |
Invesco | 232,732.50 | 250.17 | 0.11% |
Schwab | 168,568.37 | 165.32 | 0.10% |
We can download the following ETF’s some of which are actively managed and others which are passively managed from the yahoo API using the quantmod API.
#library("RSelenium")
tickers= c("QQQ","IVV","SPY","VOO","VTI","IWB","GLD","EEM","XLF",
"GDX","ARKW")
actively_managed =c("ARKW")
passively_managed <- c("AGZ","IHI","IEUS","FCOM","VGT.IV","
VUG.IV")
vanguard <- c("MGK.IV","MGC.IV","VGT.IV","
VUG.IV","VONG.IV")
# The symbols vector holds our tickers.
symbols <- c("SPY","EFA", "IJS", "EEM","AGG")
# The prices object will hold our raw price data
prices <-
quantmod::getSymbols(tickers, src = 'yahoo', from = "2010-01-01",
auto.assign = TRUE, warnings = FALSE) %>%
furrr::future_map(~Ad(get(.))) %>%
reduce(merge) %>% #reduce() combines from the left, reduce_right() combines from the right
`colnames<-`(tickers)
#DT::datatable(data.frame(head(prices)))
data.frame(head(prices)) %>%head()%>%
kable(escape = F, align = "c") %>%
kable_styling(c("striped", "condensed"), full_width = F)
QQQ | IVV | SPY | VOO | VTI | IWB | GLD | EEM | XLF | GDX | ARKW | |
---|---|---|---|---|---|---|---|---|---|---|---|
2010-01-04 | 41.71869 | 92.10523 | 92.24605 | NA | 46.96941 | 51.31325 | 109.80 | 34.66187 | 7.660890 | 44.59262 | NA |
2010-01-05 | 41.71869 | 92.37265 | 92.49020 | NA | 47.14971 | 51.47793 | 109.70 | 34.91345 | 7.801696 | 45.02256 | NA |
2010-01-06 | 41.46705 | 92.44558 | 92.55533 | NA | 47.21528 | 51.54378 | 111.51 | 34.98648 | 7.817341 | 46.11611 | NA |
2010-01-07 | 41.49401 | 92.85078 | 92.94606 | NA | 47.41198 | 51.74965 | 110.82 | 34.78360 | 7.984223 | 45.89180 | NA |
2010-01-08 | 41.83553 | 93.16687 | 93.25535 | NA | 47.56769 | 51.92256 | 111.37 | 35.05952 | 7.937286 | 46.58344 | NA |
2010-01-11 | 41.66477 | 93.29655 | 93.38558 | NA | 47.63326 | 51.99666 | 112.85 | 34.98648 | 7.942502 | 46.89188 | NA |
The prices of these ETF’s can be visualized with dygraph package, it allows a user to set a date window which lets you expand and narrow the windows to focus on detail visualization within the range of interest.
dateWindow <- c("2015-01-01", "2020-02-20")
p1= dygraph(prices, main = "Value", group = "stock",
xlab = "Time",ylab = "Adjusted Prices") %>%
dyRebase(value = 100) %>%
dyRangeSelector(dateWindow = dateWindow)
htmlwidgets::saveWidget(as_widget(p1), "p1.html")
p1
Convert daily prices to monthly prices using a call to to.monthly(prices, indexAt = “last”, OHLC = FALSE) from quantmod. The argument index = “last” tells the function whether we want to index to the first day of the month or the last day.
prices_monthly <- to.monthly(prices, indexAt = "last", OHLC = FALSE)%>%tk_tbl()%>% rename(date=index)
start_date <-first(index(prices_monthly))
end_date <- last(index(prices_monthly))
#prices_monthly %>% head() %>% gt() %>%
# tab_header(
# title = " Monthly Prices for ETF's",
# subtitle = glue::glue("{start_date} to {end_date}")
# )
prices_monthly %>% head()%>%
kable(escape = F, align = "c") %>%
kable_styling(c("striped", "condensed"), full_width = F)
date | QQQ | IVV | SPY | VOO | VTI | IWB | GLD | EEM | XLF | GDX | ARKW |
---|---|---|---|---|---|---|---|---|---|---|---|
2014-09-30 | 93.71915 | 176.6444 | 176.5203 | 161.6403 | 91.02445 | 98.94495 | 116.21 | 36.63364 | 12.99660 | 20.55621 | 16.92123 |
2014-10-31 | 96.19518 | 180.8587 | 180.6775 | 165.5249 | 93.52393 | 101.31341 | 112.66 | 37.15370 | 13.37242 | 16.56238 | 17.20904 |
2014-11-28 | 100.56856 | 185.8393 | 185.6411 | 170.0898 | 95.84360 | 104.06014 | 112.11 | 36.58075 | 13.68653 | 17.66910 | 17.52985 |
2014-12-31 | 98.31519 | 185.2874 | 185.1702 | 169.5703 | 95.80689 | 103.75922 | 113.58 | 35.13086 | 13.94251 | 17.80461 | 17.37833 |
2015-01-30 | 96.26794 | 179.9134 | 179.6837 | 164.7011 | 93.18576 | 100.97132 | 123.45 | 34.88944 | 12.97279 | 21.59221 | 17.32754 |
2015-02-27 | 103.21903 | 190.0703 | 189.7828 | 173.8906 | 98.53648 | 106.68292 | 116.16 | 36.42736 | 13.72827 | 20.61383 | 18.75810 |
We now have an xts object, and we have moved from daily prices to monthly prices.
Return.calculate(prices_monthly, method = “log”) to convert to returns and save as an object called assed_returns_xts. Note this will give us log returns by the method = “log” argument. We could have used method = “discrete” to get simple returns. The daily percentage return on a stock is the difference between the previous day’s price and the current day’s price relative to the previous day’s price. The monthly perentage return follows as the difference between the previous month and the current month’s price divided by the previous months price.
#asset_returns_xts <- na.omit(Return.calculate(prices_monthly, method = "discreet"))
prices_monthly <- to.monthly(prices, indexAt = "last", OHLC = FALSE)
asset_returns_quantmod <- na.omit(CalculateReturns(prices_monthly, method = "log"))
head(asset_returns_quantmod)%>%tk_tbl()%>%
kable(escape = F, align = "c") %>%
kable_styling(c("striped", "condensed"), full_width = F)
index | QQQ | IVV | SPY | VOO | VTI | IWB | GLD | EEM | XLF | GDX | ARKW |
---|---|---|---|---|---|---|---|---|---|---|---|
2014-10-31 | 0.0260767 | 0.0235776 | 0.0232774 | 0.0237483 | 0.0270893 | 0.0236552 | -0.0310244 | 0.0140965 | 0.0285065 | -0.2160296 | 0.0168654 |
2014-11-28 | 0.0444605 | 0.0271660 | 0.0271016 | 0.0272043 | 0.0245003 | 0.0267502 | -0.0048939 | -0.0155414 | 0.0232182 | 0.0646838 | 0.0184708 |
2014-12-31 | -0.0226612 | -0.0029742 | -0.0025398 | -0.0030584 | -0.0003830 | -0.0028959 | 0.0130269 | -0.0404422 | 0.0185299 | 0.0076400 | -0.0086811 |
2015-01-30 | -0.0210432 | -0.0294324 | -0.0300770 | -0.0291356 | -0.0277397 | -0.0272365 | 0.0833287 | -0.0068957 | -0.0720882 | 0.1928753 | -0.0029269 |
2015-02-27 | 0.0697179 | 0.0549183 | 0.0546819 | 0.0542943 | 0.0558319 | 0.0550246 | -0.0608676 | 0.0431361 | 0.0566029 | -0.0463706 | 0.0793286 |
2015-03-31 | -0.0238725 | -0.0160997 | -0.0158302 | -0.0158327 | -0.0116970 | -0.0131021 | -0.0217570 | -0.0150863 | -0.0061797 | -0.1541505 | -0.0067920 |
pacman::p_load(kable,kableExtra)
ETF_returns <- prices %>%
tk_tbl(preserve_index = TRUE, rename_index = "date") %>%
pivot_longer(-date , names_to = "symbol",values_to = "Adjusted_Prices")%>%
group_by(symbol) %>%
tq_transmute(mutate_fun = periodReturn, period = "monthly", type = "log") %>%
arrange(desc(monthly.returns))
ETF_returns%>%head()%>%
kable(escape = F, align = "c") %>%
kable_styling(c("striped", "condensed"), full_width = F)
symbol | date | monthly.returns |
---|---|---|
GDX | 2020-04-30 | 0.3365961 |
GDX | 2016-02-29 | 0.3102956 |
GDX | 2016-04-29 | 0.2573056 |
XLF | 2016-09-30 | 0.2350068 |
ARKW | 2020-04-30 | 0.2197622 |
GDX | 2016-06-30 | 0.2047288 |
An interactive visualiation for the monthly returns for the ETF’s selected is displayed below.
library(crosstalk)
ETF_returns <- ETF_returns %>% ungroup(symbol)
d <-
SharedData$new(ETF_returns, ~symbol)
p2 <- ggplot(d, aes(date,monthly.returns,color=symbol)) +
geom_line(aes(group = symbol))+
#scale_y_continuous(trans = log10_trans(), labels = scales::comma)+
#scale_fill_viridis_d()+
scale_color_viridis_d(option="D") +
# scale_shape_manual(values = 1:6 ) +
# theme_economist() +
scale_x_date(labels = date_format("%d-%m-%Y"),date_breaks = "1 year") +
theme(axis.text.x=element_text(angle=45, hjust=1)) +
labs(title = "Monthly Returns Performance of Exhcange Traded Funds",
subtitle = " 2010 - 2020",
caption = "www.restsanalytics.com",
x = "Time", y = "Returns")
(gg <- ggplotly(p2, tooltip = "symbol"))
gg=highlight(gg, "plotly_hover")
ggsave("p2.png")
#htmlwidgets::saveWidget(as_widget(gg), "p2.html")
htmlwidgets::saveWidget(gg, "p2.html", selfcontained = F, libdir = "lib")
#saveWidget(gg, file="p2.html")
gg
ETF_returns %>% mutate(Year= format(date,"%Y")) %>% group_by(symbol,Year) %>%
summarize(meanreturn =mean(monthly.returns,na.rm = TRUE))%>%
ggplot(aes(x=Year,y=meanreturn,fill=symbol))+
geom_col()+
#scale_color_viridis(discrete=TRUE,option = "A")
scale_fill_viridis(discrete=TRUE,option = "D")+
theme(
legend.position="top",
legend.direction="horizontal",
legend.title = element_blank(),
text=element_text(size=8, family="Comic Sans MS"),
axis.text.x=element_text(angle=45,hjust=1,size = 9),
axis.text.y=element_text(size = 8),
legend.text = element_text(size=8)
)+
labs(y="Mean Yearly Return",x="Year",title="")
# scale_x_date(breaks = date_breaks("1 year"),labels=date_format("%b %Y") )
The analysis above in which the data was downloaded with the quantmod package, can be replicated with the tidyquant package. The tidyquant package builds a wrapper around the quantmod and converts the data from xts format to tibble dataframes.
end<-Sys.Date()
start<-as.Date("2010-01-10")
Prices <- tq_get(tickers , get = "stock.prices", from = start,to=end)
#Prices%>%head() %>% DT::datatable()
Prices%>%head() %>%tk_tbl()%>%
kable(escape = F, align = "c") %>%
kable_styling(c("striped", "condensed"), full_width = F)
symbol | date | open | high | low | close | volume | adjusted |
---|---|---|---|---|---|---|---|
QQQ | 2010-01-11 | 46.61 | 46.64 | 46.12 | 46.36 | 104673400 | 41.66477 |
QQQ | 2010-01-12 | 46.08 | 46.14 | 45.53 | 45.78 | 90673900 | 41.14353 |
QQQ | 2010-01-13 | 45.92 | 46.49 | 45.61 | 46.35 | 100661000 | 41.65579 |
QQQ | 2010-01-14 | 46.26 | 46.52 | 46.22 | 46.39 | 75209000 | 41.69173 |
QQQ | 2010-01-15 | 46.47 | 46.55 | 45.65 | 45.85 | 126849300 | 41.20641 |
QQQ | 2010-01-19 | 45.96 | 46.64 | 45.95 | 46.59 | 84388200 | 41.87149 |
library(crosstalk)
d <- SharedData$new(Prices, ~symbol)
p3 <- ggplot(d, aes(date, adjusted,color=symbol)) +
geom_line(aes(group = symbol))+
#scale_y_continuous(trans = log10_trans(), labels = scales::comma)+
#scale_fill_viridis_d()+
scale_color_viridis_d(option="D") +
# scale_shape_manual(values = 1:6 ) +
# theme_economist() +
scale_x_date(labels = date_format("%d-%m-%Y"),date_breaks = "1 year") +
theme(axis.text.x=element_text(angle=45, hjust=1)) +
labs(title = "Performance of Exhcange Traded Funds",
subtitle = " 2010 - 2020",
caption = "www.restsanalytics.com",
x = "Time", y = "Adjusted Prices")
(gg <- ggplotly(p3, tooltip = "symbol"))
gg=highlight(gg, "plotly_hover")
ggsave("p3.png")
htmlwidgets::saveWidget(as_widget(gg), "p3.html")
#htmlwidgets::saveWidget(gg, "p3.html", selfcontained = F, libdir = "lib")
gg
Returns
monthlyreturns <-Prices%>% select(symbol,date,adjusted)%>%
group_by(symbol)%>%
tq_transmute(
mutate_fun = periodReturn,
period = "monthly",
type = "arithmetic")%>%head()
#monthlyreturns%>%head() %>% gt()
monthlyreturns%>%head() %>%tk_tbl()%>%
kable(escape = F, align = "c") %>%
kable_styling(c("striped", "condensed"), full_width = F)
symbol | date | monthly.returns |
---|---|---|
QQQ | 2010-01-29 | -0.0770059 |
QQQ | 2010-02-26 | 0.0460387 |
QQQ | 2010-03-31 | 0.0771089 |
QQQ | 2010-04-30 | 0.0224255 |
QQQ | 2010-05-28 | -0.0739236 |
QQQ | 2010-06-30 | -0.0597572 |
ETF_returns %>%
ggplot(aes(x = date, y = monthly.returns, group = symbol)) +
geom_area(aes(fill = symbol), position = "stack") +
labs(title = "Quantity Sold: Month Plot", x = "", y = "Sales",
subtitle = "March through July tend to be most active") +
theme(
legend.position="top",
legend.direction="horizontal",
legend.title = element_blank(),
text=element_text(size=8, family="Comic Sans MS"),
axis.text.x=element_text(angle=45,hjust=1,size = 9),
axis.text.y=element_text(size = 8),
legend.text = element_text(size=8)
)+
scale_x_date(breaks = date_breaks("12 month"),labels=date_format("%b %Y") ) +
# theme_tq()+
#scale_color_viridis()
#scale_color_continuous_tableau()
scale_fill_viridis(discrete = T,option="B")
#scale_color_viridis_d()