Suppose that you consider investing in two stocks: Microsoft and General Electric. As a prudent investor, you analyze the historical performance of the stocks during the period of 1990-01-01 to 2017-12-31.
library(tidyquant)
library(tidyverse)
Hint: Add group_by(symbol) at the end of the code so that calculations below will be done per stock.
from = today() - years(20)
Stocks <- tq_get(c("^GSPC", "^IXIC"), get = "stock.prices", from = from) %>%
group_by(symbol)
Stocks
## # A tibble: 10,066 x 8
## # Groups: symbol [2]
## symbol date open high low close volume adjusted
## <chr> <date> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 ^GSPC 1999-04-12 1348. 1359. 1333. 1359. 810800000 1359.
## 2 ^GSPC 1999-04-13 1359. 1362. 1344. 1350. 810900000 1350.
## 3 ^GSPC 1999-04-14 1350. 1357. 1326. 1328. 952000000 1328.
## 4 ^GSPC 1999-04-15 1328. 1332. 1308. 1323. 1089800000 1323.
## 5 ^GSPC 1999-04-16 1323. 1325. 1311. 1319 1002300000 1319
## 6 ^GSPC 1999-04-19 1319 1340. 1284. 1289. 1214400000 1289.
## 7 ^GSPC 1999-04-20 1289. 1306. 1284. 1306. 985400000 1306.
## 8 ^GSPC 1999-04-21 1306. 1336. 1302. 1336. 920000000 1336.
## 9 ^GSPC 1999-04-22 1336. 1359. 1336. 1359. 927900000 1359.
## 10 ^GSPC 1999-04-23 1359. 1364. 1348. 1357. 744900000 1357.
## # … with 10,056 more rows
Hint: Take the adjusted variable from Stocks, and calculate monthly returns using tq_transmute(), instead of tq_mutate(), which is used when periodicity changes. Another difference between the two is that tq_transmute() returns only newly-created columns while tq_mutate() adds new columns to existing variables.
Note that there are a variety of functions available with the mutate_fun argument: See above for the result of tq_transmute_fun_options(). Note that tq_mutate allows to calculate returns using quantmod::periodReturn. Google the quantmod package manual for more information on the periodReturn function.
returns_monthly <-
Stocks %>%
tq_transmute(select = adjusted, mutate_fun = periodReturn, period = "monthly")
returns_monthly
## # A tibble: 482 x 3
## # Groups: symbol [2]
## symbol date monthly.returns
## <chr> <date> <dbl>
## 1 ^GSPC 1999-04-30 -0.0173
## 2 ^GSPC 1999-05-28 -0.0250
## 3 ^GSPC 1999-06-30 0.0544
## 4 ^GSPC 1999-07-30 -0.0320
## 5 ^GSPC 1999-08-31 -0.00625
## 6 ^GSPC 1999-09-30 -0.0286
## 7 ^GSPC 1999-10-29 0.0625
## 8 ^GSPC 1999-11-30 0.0191
## 9 ^GSPC 1999-12-31 0.0578
## 10 ^GSPC 2000-01-31 -0.0509
## # … with 472 more rows
Hint: Refer to the ggplot2 cheatsheet. Look for geom_density under One Variable. Use the fill argument to create the plot per each stock.
returns_monthly %>%
ggplot(aes(x=monthly.returns, fill= symbol)) +
geom_density(alpha = 0.3)
Hint: Take returns_monthly and pipe it to summarise. Calculate the mean monthly returns.
returns_monthly %>%
summarise(returns_avg = mean(monthly.returns))
## # A tibble: 2 x 2
## symbol returns_avg
## <chr> <dbl>
## 1 ^GSPC 0.00402
## 2 ^IXIC 0.00678
NASDAQ has the higher monthly return at 0.67% compared to S&P 500 at 0.4%.
Hint: Discuss your answer in terms of standard deviation. Take returns_monthly and pipe it to tidyquant::tq_performance. Use the performance_fun argument to compute sd (standard deviation).
returns_monthly %>%
tq_performance(Ra = monthly.returns,
Rb = NULL,
performance_fun = sd)
## # A tibble: 2 x 2
## # Groups: symbol [2]
## symbol sd.1
## <chr> <dbl>
## 1 ^GSPC 0.0418
## 2 ^IXIC 0.0648
NASDAQ has a greater standard deviation than S&P 500 so NASDAQ is the riskier of the two.
Hint: when the return distribution is not normal, the standard deviation is not an appropriate measure of risk. One can use skewness and kurtosis to detect non-normal returns. Take returns_monthly and pipe it to tidyquant::tq_performance. Use the performance_fun argument to compute skewness. Do the same for kurtosis.
For interpretation, see a hypothetical example below.
MSFT had a postiive skewness and positive kurtosis, making a large positive return more likely than a large negative return, whereas S&P 500 had a negative skewness and a positive kurtosis, which means a large negative return is more likely than a large postive return.
returns_monthly %>%
tq_performance(Ra = monthly.returns,
Rb = NULL,
performance_fun = skewness)
## # A tibble: 2 x 2
## # Groups: symbol [2]
## symbol skewness.1
## <chr> <dbl>
## 1 ^GSPC -0.568
## 2 ^IXIC -0.364
returns_monthly %>%
tq_performance(Ra = monthly.returns,
Rb = NULL,
performance_fun = kurtosis)
## # A tibble: 2 x 2
## # Groups: symbol [2]
## symbol kurtosis.1
## <chr> <dbl>
## 1 ^GSPC 1.09
## 2 ^IXIC 1.57
S&P 500 and NASDAQ both have a negative skewness and positive kurtosis which means a large negative return is more likely than a large positive return more often.
Expected Shortfall, Value at Risk, & Semi-Deviation
Hint: Take returns_monthly and pipe it to tidyquant::tq_performance. Use the performance_fun argument to compute table.DownsideRisk.
For interpretation, see a hypothetical example below.
returns_monthly %>%
tq_performance(Ra = monthly.returns,
Rb = NULL,
performance_fun = table.DownsideRisk) %>%
t()
## [,1] [,2]
## symbol "^GSPC" "^IXIC"
## DownsideDeviation(0%) "0.0297" "0.0446"
## DownsideDeviation(MAR=10%) "0.0338" "0.0487"
## DownsideDeviation(Rf=0%) "0.0297" "0.0446"
## GainDeviation "0.0237" "0.0398"
## HistoricalES(95%) "-0.0949" "-0.1456"
## HistoricalVaR(95%) "-0.0748" "-0.1047"
## LossDeviation "0.0313" "0.0481"
## MaximumDrawdown "0.5256" "0.7504"
## ModifiedES(95%) "-0.1009" "-0.1568"
## ModifiedVaR(95%) "-0.0701" "-0.1040"
## SemiDeviation "0.0316" "0.0479"
The Semi-Deviation for S&P 500 is 0.0316 and NASDAQ is 0.0479 which means the standard deviation of returns below the mean is 0.0316 and 0.0479 respectively.
Var of -0.0748 for S&P 500 means that -7.48% is the largest loss one could expect with 95% confidence. -0.1047 for NASDAQ means that -10.47% is the largest loss one could expect with 95%. It is possible to loose more than 7.48% & 10.47% but there is only a 5% chance of loosing more.
ES of -0.0949 for S&P 500 and -0.1456 for NASDAQ means that -9.49% & -14.56% is the average of the 5% most negative returns.
NASDAQ appears to present greater downside risk than S&P 500. For example, monthly returns are more volatile below the mean for NASDAQ (semideviation of 0.0479) than S&P 500 (semideviation of 0.0316); the largest loss one could expect with 95% confidence is larger for NASDAQ (VaR of -0.1047 at 5%) than S&P 500 (VaR of -0.0748 at 5%); and the average of the 5% most negative monthly returns is larger for NASDAQ (ES of -0.1456 at 5%) than S&P 500 (ES of -0.0949 at 5%).
Hint: Discuss your answer in terms of risk and reward.
Sharpe Ratio measures return per unit of risk.
returns_monthly %>%
tq_performance(Ra = monthly.returns, performance_fun = SharpeRatio)
## # A tibble: 2 x 4
## # Groups: symbol [2]
## symbol `ESSharpe(Rf=0%,p=95… `StdDevSharpe(Rf=0%,p=… `VaRSharpe(Rf=0%,p=…
## <chr> <dbl> <dbl> <dbl>
## 1 ^GSPC 0.0398 0.0962 0.0573
## 2 ^IXIC 0.0433 0.105 0.0652
In choosing between the two stocks, I would choose NASDAQ because even though it has a higher downside risk it has a higher Sharpe Ratio so the reward for NASDAQ will out weigh the risk associated with the volatility of the stock.