This note came from Matt Dancho’s webpage.
library(tidyquant)
library(ggplot2)
# Import stock prices
stock_prices <- c("AAPL", "GOOG", "NFLX") %>%
tq_get(get = "stock.prices",
from = "2010-01-01",
to = "2015-12-31") %>%
group_by(symbol)
stock_prices
## # A tibble: 4,527 x 8
## # Groups: symbol [3]
## symbol date open high low close volume adjusted
## <chr> <date> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 AAPL 2010-01-04 30.5 30.6 30.3 30.6 123432400 20.7
## 2 AAPL 2010-01-05 30.7 30.8 30.5 30.6 150476200 20.7
## 3 AAPL 2010-01-06 30.6 30.7 30.1 30.1 138040000 20.4
## 4 AAPL 2010-01-07 30.2 30.3 29.9 30.1 119282800 20.4
## 5 AAPL 2010-01-08 30.0 30.3 29.9 30.3 111902700 20.5
## 6 AAPL 2010-01-11 30.4 30.4 29.8 30.0 115557400 20.3
## 7 AAPL 2010-01-12 29.9 30.0 29.5 29.7 148614900 20.1
## 8 AAPL 2010-01-13 29.7 30.1 29.2 30.1 151473000 20.4
## 9 AAPL 2010-01-14 30.0 30.1 29.9 29.9 108223500 20.3
## 10 AAPL 2010-01-15 30.1 30.2 29.4 29.4 148516900 19.9
## # ... with 4,517 more rows
stock_prices %>%
ggplot(aes(x = date, y = adjusted)) +
geom_line() +
facet_wrap(~symbol)
stock_prices %>%
group_by(symbol) %>%
mutate(close = close / close[1]) %>%
ungroup() %>%
ggplot(aes(x = date, y = close, col = symbol)) +
geom_line()
# Calculate monthly returns
stock_returns_monthly <- stock_prices %>%
tq_transmute(select = adjusted,
mutate_fun = periodReturn,
period = "monthly",
col_rename = "Ra")
stock_returns_monthly
## # A tibble: 216 x 3
## # Groups: symbol [3]
## symbol date Ra
## <chr> <date> <dbl>
## 1 AAPL 2010-01-29 -0.103
## 2 AAPL 2010-02-26 0.0654
## 3 AAPL 2010-03-31 0.148
## 4 AAPL 2010-04-30 0.111
## 5 AAPL 2010-05-28 -0.0161
## 6 AAPL 2010-06-30 -0.0208
## 7 AAPL 2010-07-30 0.0227
## 8 AAPL 2010-08-31 -0.0550
## 9 AAPL 2010-09-30 0.167
## 10 AAPL 2010-10-29 0.0607
## # ... with 206 more rows
stock_returns_monthly %>%
ggplot(aes(x = date, y = Ra)) +
geom_line() +
facet_wrap(~symbol)
Step 3A can be skipped because we are only interested in the Sharpe Ratio for individual stocks (not a portfolio).
Step 3B can also be skipped because the SharpeRatio function from PerformanceAnalytics does not require a baseline
# Retrieve performance metrics
stock_returns_monthly %>%
tq_performance(Ra = Ra,
Rb = NULL, # Calculataing downside risk measures doesn't require Rb
performance_fun = table.DownsideRisk)
## # A tibble: 3 x 12
## # Groups: symbol [3]
## symbol `Downs~ `Downs~ `Downs~ GainD~ `Hist~ `Histo~ LossD~ Maxi~ `Modi~
## <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 AAPL 0.0389 0.0430 0.0389 0.0508 -0.119 -0.105 0.0407 0.329 -0.123
## 2 GOOG 0.0409 0.0455 0.0409 0.0564 -0.115 -0.0962 0.0370 0.290 -0.120
## 3 NFLX 0.101 0.104 0.101 0.163 -0.328 -0.212 0.112 0.799 -0.242
## # ... with 2 more variables: `ModifiedVaR(95%)` <dbl>, SemiDeviation <dbl>
library(tidyr)
# Select
stock_returns_monthly %>%
tq_performance(Ra = Ra,
Rb = NULL, # Calculataing downside risk measures doesn't require Rb
performance_fun = table.DownsideRisk) %>%
select(contains("histo")) %>%
gather(downside_risk, measure, 2:3) %>%
ggplot(aes(x = symbol, y = -measure, fill = downside_risk)) +
geom_col(show.legend = FALSE) +
facet_wrap(~ downside_risk) +
coord_flip() +
labs(title = "Downside Risk in abolute value",
x = NULL,
y = NULL)
Interpretation
Avaiable functions
tq_performance_fun_options()
## $table.funs
## [1] "table.AnnualizedReturns" "table.Arbitrary"
## [3] "table.Autocorrelation" "table.CAPM"
## [5] "table.CaptureRatios" "table.Correlation"
## [7] "table.Distributions" "table.DownsideRisk"
## [9] "table.DownsideRiskRatio" "table.DrawdownsRatio"
## [11] "table.HigherMoments" "table.InformationRatio"
## [13] "table.SFM" "table.SpecificRisk"
## [15] "table.Stats" "table.TrailingPeriods"
## [17] "table.UpDownRatios" "table.Variability"
##
## $CAPM.funs
## [1] "CAPM.alpha" "CAPM.beta" "CAPM.beta.bear"
## [4] "CAPM.beta.bull" "CAPM.CML" "CAPM.CML.slope"
## [7] "CAPM.dynamic" "CAPM.epsilon" "CAPM.jensenAlpha"
## [10] "CAPM.RiskPremium" "CAPM.SML.slope" "TimingRatio"
## [13] "MarketTiming"
##
## $SFM.funs
## [1] "SFM.alpha" "SFM.beta" "SFM.CML" "SFM.CML.slope"
## [5] "SFM.dynamic" "SFM.epsilon" "SFM.jensenAlpha"
##
## $descriptive.funs
## [1] "mean" "sd" "min" "max"
## [5] "cor" "mean.geometric" "mean.stderr" "mean.LCL"
## [9] "mean.UCL"
##
## $annualized.funs
## [1] "Return.annualized" "Return.annualized.excess"
## [3] "sd.annualized" "SharpeRatio.annualized"
##
## $VaR.funs
## [1] "VaR" "ES" "ETL" "CDD" "CVaR"
##
## $moment.funs
## [1] "var" "cov" "skewness"
## [4] "kurtosis" "CoVariance" "CoSkewness"
## [7] "CoSkewnessMatrix" "CoKurtosis" "CoKurtosisMatrix"
## [10] "M3.MM" "M4.MM" "BetaCoVariance"
## [13] "BetaCoSkewness" "BetaCoKurtosis"
##
## $drawdown.funs
## [1] "AverageDrawdown" "AverageLength" "AverageRecovery"
## [4] "DrawdownDeviation" "DrawdownPeak" "maxDrawdown"
##
## $Bacon.risk.funs
## [1] "MeanAbsoluteDeviation" "Frequency" "SharpeRatio"
## [4] "MSquared" "MSquaredExcess" "HurstIndex"
##
## $Bacon.regression.funs
## [1] "CAPM.alpha" "CAPM.beta" "CAPM.epsilon"
## [4] "CAPM.jensenAlpha" "SystematicRisk" "SpecificRisk"
## [7] "TotalRisk" "TreynorRatio" "AppraisalRatio"
## [10] "FamaBeta" "Selectivity" "NetSelectivity"
##
## $Bacon.relative.risk.funs
## [1] "ActivePremium" "ActiveReturn" "TrackingError"
## [4] "InformationRatio"
##
## $Bacon.drawdown.funs
## [1] "PainIndex" "PainRatio" "CalmarRatio" "SterlingRatio"
## [5] "BurkeRatio" "MartinRatio" "UlcerIndex"
##
## $Bacon.downside.risk.funs
## [1] "DownsideDeviation" "DownsidePotential"
## [3] "DownsideFrequency" "SemiDeviation"
## [5] "SemiVariance" "UpsideRisk"
## [7] "UpsidePotentialRatio" "UpsideFrequency"
## [9] "BernardoLedoitRatio" "DRatio"
## [11] "Omega" "OmegaSharpeRatio"
## [13] "OmegaExcessReturn" "SortinoRatio"
## [15] "M2Sortino" "Kappa"
## [17] "VolatilitySkewness" "AdjustedSharpeRatio"
## [19] "SkewnessKurtosisRatio" "ProspectRatio"
##
## $misc.funs
## [1] "KellyRatio" "Modigliani" "UpDownRatios"
library(tidyquant)
library(ggplot2)
# This was done previously
stock_prices
## # A tibble: 4,527 x 8
## # Groups: symbol [3]
## symbol date open high low close volume adjusted
## <chr> <date> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 AAPL 2010-01-04 30.5 30.6 30.3 30.6 123432400 20.7
## 2 AAPL 2010-01-05 30.7 30.8 30.5 30.6 150476200 20.7
## 3 AAPL 2010-01-06 30.6 30.7 30.1 30.1 138040000 20.4
## 4 AAPL 2010-01-07 30.2 30.3 29.9 30.1 119282800 20.4
## 5 AAPL 2010-01-08 30.0 30.3 29.9 30.3 111902700 20.5
## 6 AAPL 2010-01-11 30.4 30.4 29.8 30.0 115557400 20.3
## 7 AAPL 2010-01-12 29.9 30.0 29.5 29.7 148614900 20.1
## 8 AAPL 2010-01-13 29.7 30.1 29.2 30.1 151473000 20.4
## 9 AAPL 2010-01-14 30.0 30.1 29.9 29.9 108223500 20.3
## 10 AAPL 2010-01-15 30.1 30.2 29.4 29.4 148516900 19.9
## # ... with 4,517 more rows
# This was done previously
stock_returns_monthly
## # A tibble: 216 x 3
## # Groups: symbol [3]
## symbol date Ra
## <chr> <date> <dbl>
## 1 AAPL 2010-01-29 -0.103
## 2 AAPL 2010-02-26 0.0654
## 3 AAPL 2010-03-31 0.148
## 4 AAPL 2010-04-30 0.111
## 5 AAPL 2010-05-28 -0.0161
## 6 AAPL 2010-06-30 -0.0208
## 7 AAPL 2010-07-30 0.0227
## 8 AAPL 2010-08-31 -0.0550
## 9 AAPL 2010-09-30 0.167
## 10 AAPL 2010-10-29 0.0607
## # ... with 206 more rows
wts <- c(0.5, 0.0, 0.5)
portfolio_returns_monthly <- stock_returns_monthly %>%
tq_portfolio(assets_col = symbol,
returns_col = Ra,
weights = wts,
col_rename = "Ra")
portfolio_returns_monthly
## # A tibble: 72 x 2
## date Ra
## <date> <dbl>
## 1 2010-01-29 0.0307
## 2 2010-02-26 0.0629
## 3 2010-03-31 0.130
## 4 2010-04-30 0.239
## 5 2010-05-28 0.0682
## 6 2010-06-30 -0.0219
## 7 2010-07-30 -0.0272
## 8 2010-08-31 0.116
## 9 2010-09-30 0.251
## 10 2010-10-29 0.0674
## # ... with 62 more rows
Step 3B can also be skipped because the SharpeRatio function from PerformanceAnalytics does not require a baseline.
portfolio_returns_monthly %>%
tq_performance(Ra = Ra,
Rb = NULL, # Calculataing downside risk measures doesn't require Rb
performance_fun = table.DownsideRisk) %>%
select(contains("histo"))
## # A tibble: 1 x 2
## `HistoricalES(95%)` `HistoricalVaR(95%)`
## <dbl> <dbl>
## 1 -0.197 -0.124
library(tidyquant)
library(ggplot2)
# This was done previously
stock_prices
## # A tibble: 4,527 x 8
## # Groups: symbol [3]
## symbol date open high low close volume adjusted
## <chr> <date> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 AAPL 2010-01-04 30.5 30.6 30.3 30.6 123432400 20.7
## 2 AAPL 2010-01-05 30.7 30.8 30.5 30.6 150476200 20.7
## 3 AAPL 2010-01-06 30.6 30.7 30.1 30.1 138040000 20.4
## 4 AAPL 2010-01-07 30.2 30.3 29.9 30.1 119282800 20.4
## 5 AAPL 2010-01-08 30.0 30.3 29.9 30.3 111902700 20.5
## 6 AAPL 2010-01-11 30.4 30.4 29.8 30.0 115557400 20.3
## 7 AAPL 2010-01-12 29.9 30.0 29.5 29.7 148614900 20.1
## 8 AAPL 2010-01-13 29.7 30.1 29.2 30.1 151473000 20.4
## 9 AAPL 2010-01-14 30.0 30.1 29.9 29.9 108223500 20.3
## 10 AAPL 2010-01-15 30.1 30.2 29.4 29.4 148516900 19.9
## # ... with 4,517 more rows
# This was done previously
stock_returns_monthly
## # A tibble: 216 x 3
## # Groups: symbol [3]
## symbol date Ra
## <chr> <date> <dbl>
## 1 AAPL 2010-01-29 -0.103
## 2 AAPL 2010-02-26 0.0654
## 3 AAPL 2010-03-31 0.148
## 4 AAPL 2010-04-30 0.111
## 5 AAPL 2010-05-28 -0.0161
## 6 AAPL 2010-06-30 -0.0208
## 7 AAPL 2010-07-30 0.0227
## 8 AAPL 2010-08-31 -0.0550
## 9 AAPL 2010-09-30 0.167
## 10 AAPL 2010-10-29 0.0607
## # ... with 206 more rows
# Grow the portfolio for scaling to matach the number of different weighting schemes you consider
stock_returns_monthly_multi <- stock_returns_monthly %>%
tq_repeat_df(n = 3)
stock_returns_monthly_multi
## # A tibble: 648 x 4
## # Groups: portfolio [3]
## portfolio symbol date Ra
## <int> <chr> <date> <dbl>
## 1 1 AAPL 2010-01-29 -0.103
## 2 1 AAPL 2010-02-26 0.0654
## 3 1 AAPL 2010-03-31 0.148
## 4 1 AAPL 2010-04-30 0.111
## 5 1 AAPL 2010-05-28 -0.0161
## 6 1 AAPL 2010-06-30 -0.0208
## 7 1 AAPL 2010-07-30 0.0227
## 8 1 AAPL 2010-08-31 -0.0550
## 9 1 AAPL 2010-09-30 0.167
## 10 1 AAPL 2010-10-29 0.0607
## # ... with 638 more rows
# Create weights table
weights <- c(
0.50, 0.25, 0.25,
0.25, 0.50, 0.25,
0.25, 0.25, 0.50
)
stocks <- c("AAPL", "GOOG", "NFLX")
weights_table <- tibble(stocks) %>%
tq_repeat_df(n = 3) %>%
bind_cols(tibble(weights)) %>%
group_by(portfolio)
weights_table
## # A tibble: 9 x 3
## # Groups: portfolio [3]
## portfolio stocks weights
## <int> <chr> <dbl>
## 1 1 AAPL 0.500
## 2 1 GOOG 0.250
## 3 1 NFLX 0.250
## 4 2 AAPL 0.250
## 5 2 GOOG 0.500
## 6 2 NFLX 0.250
## 7 3 AAPL 0.250
## 8 3 GOOG 0.250
## 9 3 NFLX 0.500
portfolio_returns_monthly_multi <- stock_returns_monthly_multi %>%
tq_portfolio(assets_col = symbol,
returns_col = Ra,
weights = weights_table,
col_rename = "Ra")
portfolio_returns_monthly_multi
## # A tibble: 216 x 3
## # Groups: portfolio [3]
## portfolio date Ra
## <int> <date> <dbl>
## 1 1 2010-01-29 -0.0489
## 2 1 2010-02-26 0.0482
## 3 1 2010-03-31 0.123
## 4 1 2010-04-30 0.145
## 5 1 2010-05-28 0.0245
## 6 1 2010-06-30 -0.0308
## 7 1 2010-07-30 0.000600
## 8 1 2010-08-31 0.0474
## 9 1 2010-09-30 0.222
## 10 1 2010-10-29 0.0789
## # ... with 206 more rows
Step 3B can also be skipped because the SharpeRatio function from PerformanceAnalytics does not require a baseline.
portfolio_returns_monthly_multi %>%
tq_performance(Ra = Ra,
Rb = NULL, # Calculataing downside risk measures doesn't require Rb
performance_fun = table.DownsideRisk) %>%
select(contains("histo"))
## # A tibble: 3 x 3
## # Groups: portfolio [3]
## portfolio `HistoricalES(95%)` `HistoricalVaR(95%)`
## <int> <dbl> <dbl>
## 1 1 -0.138 -0.0823
## 2 2 -0.161 -0.0842
## 3 3 -0.220 -0.131
library(tidyr)
# Select
portfolio_returns_monthly_multi %>%
tq_performance(Ra = Ra,
Rb = NULL, # Calculataing downside risk measures doesn't require Rb
performance_fun = table.DownsideRisk) %>%
select(contains("histo")) %>%
gather(downside_risk, measure, 2:3) %>%
ggplot(aes(x = portfolio, y = -measure, fill = downside_risk)) +
geom_col(show.legend = FALSE) +
facet_wrap(~ downside_risk) +
coord_flip() +
labs(title = "Downside Risk in abolute value",
x = NULL,
y = NULL)