# Load packages

# Core
library(tidyverse)
library(tidyquant)
library(readr)

# Time series
library(lubridate)
library(tibbletime)

# modeling
library(broom)

Goal

Examine how each asset contributes to portfolio standard deviation. This is to ensure that our risk is not concentrated in any one asset.

1 Import stock prices

Choose your stocks from 2012-12-31 to present.

symbols <- c("WMT", "TGT", "COST")

prices <- tq_get(x    = symbols,
                 get  = "stock.prices",    
                 from = "2012-12-31",
                 to   = "2024-06-22")

prices
## # A tibble: 8,664 × 8
##    symbol date        open  high   low close   volume adjusted
##    <chr>  <date>     <dbl> <dbl> <dbl> <dbl>    <dbl>    <dbl>
##  1 WMT    2012-12-31  22.5  22.8  22.5  22.7 21037500     17.8
##  2 WMT    2013-01-02  23.0  23.1  22.8  23.1 31172400     18.1
##  3 WMT    2013-01-03  23.1  23.1  22.8  22.9 26730300     18.0
##  4 WMT    2013-01-04  22.9  23.1  22.8  23.0 19314000     18.0
##  5 WMT    2013-01-07  22.9  23.0  22.7  22.8 18604200     17.9
##  6 WMT    2013-01-08  22.8  23.0  22.7  22.9 17600700     17.9
##  7 WMT    2013-01-09  22.9  22.9  22.7  22.9 15165600     17.9
##  8 WMT    2013-01-10  22.9  23.0  22.6  22.8 34361400     17.9
##  9 WMT    2013-01-11  22.9  22.9  22.7  22.9 18673500     17.9
## 10 WMT    2013-01-14  22.8  22.9  22.7  22.8 16471200     17.8
## # ℹ 8,654 more rows

2 Convert prices to returns (monthly)

asset_returns_tbl <- prices %>%
    
    group_by(symbol) %>%
    
    tq_transmute(select     = adjusted, 
                 mutate_fun = periodReturn, 
                 period     = "monthly",
                 type       = "log") %>%
    
    slice(-1) %>%
    
    ungroup() %>%
    
    set_names(c("asset", "date", "returns"))

3 Calculate Component Contribution to Portfolio Volatility

asset_returns_wide_tbl <- asset_returns_tbl %>%

    pivot_wider(names_from = asset, values_from = returns) %>%

    column_to_rownames(var = "date")

asset_returns_wide_tbl
##                     COST           TGT           WMT
## 2013-01-31  0.0359118563  0.0207397882  0.0248962777
## 2013-02-28 -0.0076475360  0.0470677222  0.0117953957
## 2013-03-28  0.0464884672  0.0836036093  0.0620734366
## 2013-04-30  0.0216287224  0.0303599578  0.0378939522
## 2013-05-31  0.0137933633 -0.0099612184 -0.0317802181
## 2013-06-28  0.0085374763 -0.0092511918 -0.0046875807
## 2013-07-31  0.0601083565  0.0341188690  0.0452740639
## 2013-08-30 -0.0458223790 -0.1118611724 -0.0596997724
## 2013-09-30  0.0290718441  0.0105273528  0.0133391984
## 2013-10-31  0.0242754411  0.0125805355  0.0370288807
## 2013-11-29  0.0635978788 -0.0069131646  0.0540192970
## 2013-12-31 -0.0524560565 -0.0103776577 -0.0232520007
## 2014-01-31 -0.0575835901 -0.1106955873 -0.0523041023
## 2014-02-28  0.0414544398  0.1066821378  0.0002678000
## 2014-03-31 -0.0448253631 -0.0329979090  0.0293262185
## 2014-04-30  0.0351902242  0.0202852304  0.0420196598
## 2014-05-30  0.0059920526 -0.0769022289 -0.0314088932
## 2014-06-30 -0.0074399681  0.0207485560 -0.0223931078
## 2014-07-31  0.0234830968  0.0279074480 -0.0200476361
## 2014-08-29  0.0296726310  0.0169975620  0.0323258119
## 2014-09-30  0.0344191177  0.0425319191  0.0127657392
## 2014-10-31  0.0622568237 -0.0138156491 -0.0026188998
## 2014-11-28  0.0661378445  0.1875001408  0.1378160845
## 2014-12-31 -0.0026068347  0.0254832349 -0.0135732956
## 2015-01-30  0.0087098909 -0.0307673434 -0.0105355974
## 2015-02-27  0.0623771013  0.0496017116 -0.0124326417
## 2015-03-31  0.0304253328  0.0659774514 -0.0142314497
## 2015-04-30 -0.0546596110 -0.0402788970 -0.0524135580
## 2015-05-29 -0.0032207262  0.0128401962 -0.0433514846
## 2015-06-30 -0.0542544934  0.0287064969 -0.0460133786
## 2015-07-31  0.0730815717  0.0026914443  0.0146949522
## 2015-08-31 -0.0340551354 -0.0448221582 -0.0993586562
## 2015-09-30  0.0317641347  0.0121514322  0.0016978405
## 2015-10-30  0.0895906655 -0.0189945892 -0.1246694338
## 2015-11-30  0.0232363056 -0.0547337416  0.0275686559
## 2015-12-31  0.0004952755  0.0015160492  0.0492992864
## 2016-01-29 -0.0664305203 -0.0026203738  0.0793144370
## 2016-02-29 -0.0045318319  0.0882423884 -0.0003013328
## 2016-03-31  0.0490978470  0.0476667364  0.0392707965
## 2016-04-29 -0.0588890840 -0.0343705859 -0.0239374847
## 2016-05-31  0.0043109151 -0.1372357830  0.0641211295
## 2016-06-30  0.0540990540  0.0150075140  0.0311566542
## 2016-07-29  0.0628096873  0.0759581505 -0.0006845999
## 2016-08-31 -0.0284742385 -0.0627264342 -0.0143682067
## 2016-09-30 -0.0609213806 -0.0217480981  0.0094731350
## 2016-10-31 -0.0308969373  0.0007279391 -0.0295502795
## 2016-11-30  0.0181081526  0.1251765314  0.0058382102
## 2016-12-30  0.0644926878 -0.0670619619 -0.0116433546
## 2017-01-31  0.0237000197 -0.1135005374 -0.0350394339
## 2017-02-28  0.0802950288 -0.0835533344  0.0608887230
## 2017-03-31 -0.0550492954 -0.0628498742  0.0234090972
## 2017-04-28  0.0569661568  0.0118879148  0.0421086241
## 2017-05-31  0.0587797992 -0.0018019267  0.0511562327
## 2017-06-30 -0.1206068371 -0.0532515388 -0.0378576663
## 2017-07-31 -0.0089185560  0.0804398100  0.0553878975
## 2017-08-31 -0.0080370039 -0.0272904554 -0.0180256193
## 2017-09-29  0.0470447943  0.0789557917  0.0008961231
## 2017-10-31 -0.0197321073  0.0005084595  0.1109630688
## 2017-11-30  0.1383320749  0.0247791585  0.1076142859
## 2017-12-29  0.0091214520  0.0855494777  0.0207684225
## 2018-01-31  0.0459411880  0.1421912708  0.0764919556
## 2018-02-28 -0.0179104366  0.0107465788 -0.1691627116
## 2018-03-29 -0.0130234896 -0.0826209563 -0.0056771898
## 2018-04-30  0.0452894056  0.0446462662 -0.0057487134
## 2018-05-31  0.0083743626  0.0125275346 -0.0629875063
## 2018-06-29  0.0527602865  0.0433597975  0.0369864449
## 2018-07-31  0.0455078228  0.0581794746  0.0409478591
## 2018-08-31  0.0663289443  0.0889776424  0.0774628374
## 2018-09-28  0.0074785908  0.0080818676 -0.0205518569
## 2018-10-31 -0.0269698628 -0.0533180943  0.0656295145
## 2018-11-30  0.0138982976 -0.1560250187 -0.0265767650
## 2018-12-31 -0.1269314370 -0.0710987430 -0.0417365288
## 2019-01-31  0.0522180692  0.0994421956  0.0283648380
## 2019-02-28  0.0216654347  0.0038811670  0.0324433018
## 2019-03-29  0.1016324236  0.0997557218 -0.0094927667
## 2019-04-30  0.0139030115 -0.0360263069  0.0530141786
## 2019-05-31 -0.0218347883  0.0473595390 -0.0084085450
## 2019-06-28  0.0980461487  0.0737793346  0.0854575766
## 2019-07-31  0.0421255935 -0.0024273432 -0.0009961644
## 2019-08-30  0.0693118656  0.2218670392  0.0394579920
## 2019-09-30 -0.0228189354 -0.0012152654  0.0379543711
## 2019-10-31  0.0329301277  0.0000000000 -0.0120373070
## 2019-11-29  0.0090467358  0.1623186105  0.0154858494
## 2019-12-31 -0.0198412448  0.0252759556  0.0023740623
## 2020-01-31  0.0387074313 -0.1464845700 -0.0372905292
## 2020-02-28 -0.0810563170 -0.0667810587 -0.0613235734
## 2020-03-31  0.0140923364 -0.1024521322  0.0581106668
## 2020-04-30  0.0630696791  0.1658372065  0.0674659426
## 2020-05-29  0.0178919995  0.1138938005  0.0248291095
## 2020-06-30 -0.0171991064 -0.0198141103 -0.0351086241
## 2020-07-31  0.0731777316  0.0484208443  0.0772516530
## 2020-08-31  0.0657703112  0.1882718481  0.0745884877
## 2020-09-30  0.0208926128  0.0402476399  0.0076050694
## 2020-10-30  0.0092730308 -0.0335904896 -0.0083254558
## 2020-11-30  0.0912040167  0.1691405095  0.0963904023
## 2020-12-31 -0.0131568740 -0.0168514053 -0.0545611601
## 2021-01-29 -0.0668094741  0.0259450317 -0.0257181668
## 2021-02-26 -0.0607610812  0.0160103058 -0.0782172925
## 2021-03-31  0.0628754937  0.0767328273  0.0486515442
## 2021-04-30  0.0562815715  0.0453535882  0.0295953916
## 2021-05-28  0.0164726709  0.0938665279  0.0189582671
## 2021-06-30  0.0449723170  0.0632652250 -0.0071365835
## 2021-07-30  0.0844259272  0.0768492173  0.0107912082
## 2021-08-31  0.0582399344 -0.0519786925  0.0418682054
## 2021-09-30 -0.0135716308 -0.0765902091 -0.0606839831
## 2021-10-29  0.0913578036  0.1265019698  0.0695571065
## 2021-11-30  0.0928770027 -0.0592961897 -0.0606288087
## 2021-12-31  0.0511728240 -0.0521915401  0.0324795396
## 2022-01-31 -0.1167773929 -0.0487405512 -0.0343092312
## 2022-02-28  0.0290841490 -0.0940889867 -0.0338250137
## 2022-03-31  0.1034616875  0.0604566694  0.1008101558
## 2022-04-29 -0.0781044907  0.0745690586  0.0269633655
## 2022-05-31 -0.1314594789 -0.3412236863 -0.1698041668
## 2022-06-30  0.0276274452 -0.1364655852 -0.0563675841
## 2022-07-29  0.1234132837  0.1456888697  0.0826081991
## 2022-08-31 -0.0361144843 -0.0125338930  0.0081250417
## 2022-09-30 -0.1003084089 -0.0774525323 -0.0217357908
## 2022-10-31  0.0618563544  0.1015456621  0.0929241750
## 2022-11-30  0.0725757513  0.0232761217  0.0684916163
## 2022-12-30 -0.1665906326 -0.1141983311 -0.0685300635
## 2023-01-31  0.1130549133  0.1440936163  0.0145630640
## 2023-02-28 -0.0524475710 -0.0151216610 -0.0121680534
## 2023-03-31  0.0258717045 -0.0171793421  0.0408372578
## 2023-04-28  0.0126990200 -0.0487450396  0.0235918739
## 2023-05-31  0.0185209767 -0.1795999093 -0.0237416193
## 2023-06-30  0.0510997638  0.0073812991  0.0678437301
## 2023-07-31  0.0405678126  0.0340609050  0.0169068907
## 2023-08-31 -0.0186364188 -0.0669316857  0.0206048845
## 2023-09-29  0.0281466463 -0.1349887673 -0.0166185178
## 2023-10-31 -0.0224102040  0.0019877341  0.0215263029
## 2023-11-30  0.0722446165  0.1990889251 -0.0483956693
## 2023-12-29  0.1300909610  0.0623595611  0.0162177168
## 2024-01-31  0.0513780419 -0.0237310867  0.0470820912
## 2024-02-29  0.0696229645  0.1022452202  0.0620581818
## 2024-03-28 -0.0152523574  0.1474205982  0.0296685011
## 2024-04-30 -0.0117661258 -0.0960553701 -0.0137217305
## 2024-05-31  0.1136275203 -0.0235389825  0.1060150757
## 2024-06-21  0.0463476781 -0.0663844762  0.0321715698
calculate_component_contribution <- function(.data, w) {
    
    # Covariance of asset returns
    covariance_matrix <- cov(.data)
    
    # Standard deviation of portfolio
    # Summarizes how much each asset's returns vary with those of other assets within the portfolio into a single number
    sd_portfolio <- sqrt(t(w) %*% covariance_matrix %*% w)

    # Component contribution
    # Similar to the formula for sd_portfolio
    # Mathematical trick to summarize the same, sd_portfolio, by asset instead of a single number
    component_contribution <- (t(w) %*% covariance_matrix * w) / sd_portfolio[1,1]

    # Component contribution in percentage
    component_percentages <- (component_contribution / sd_portfolio[1,1]) %>%
        round(3) %>%
        as_tibble()
    
    return(component_percentages)
}

asset_returns_wide_tbl %>% calculate_component_contribution(w = c(.45, .35, .2))
## # A tibble: 1 × 3
##    COST   TGT   WMT
##   <dbl> <dbl> <dbl>
## 1  0.39 0.478 0.133

6 Plot: Colum Chart of Component Contribution and Weight

plot_data <-asset_returns_wide_tbl %>% 
    
    calculate_component_contribution(w = c(0.4, 0.35, 0.25)) %>%
    
    #Transform to long form
    pivot_longer(cols = everything(), names_to = "Asset", values_to = "Contribution") %>%
    
    # Add weights
    add_column(weight = c(0.4, 0.35, 0.25)) %>%
    
    # Transform to long
    pivot_longer(cols = c(Contribution, weight), names_to = "type", values_to = "value")

plot_data %>%
    
    ggplot(aes(x = Asset, y = value, fill = type)) +
    geom_col(position = "dodge") +
    
    scale_y_continuous(labels = scales::percent_format(accuracy = 1)) +
    scale_fill_tq() +
    theme(plot.title = element_text(hjust = 0.5)) +
    theme_tq() + 
    labs(title = "Percent Contribution to Porfolio Volatility and Weight", 
         y = "Percent",
         x = NULL)

Which of the assets in your portfolio the largest contributor to the portfolio volatility? Do you think your portfolio risk is concentrated in any one asset?

    The largest contributor in this profloio is Target, but not by as much as I would have thought. Target is sitting below 50% around 48% followed by Costco at around 34% and Walmart at around 17%. I don't think this portfolio is concentrated in anyone asset, I do feel that Target has the most concentration data wise, but having Costco so close behind I don't see how the majoirity would be within Target. Therefore, I feel this portfolio is not concentrated in any one asset instead divded amoung all 3.