# Load packages
# Core
library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr 1.1.4 ✔ readr 2.1.5
## ✔ forcats 1.0.0 ✔ stringr 1.5.2
## ✔ ggplot2 3.5.2 ✔ tibble 3.3.0
## ✔ lubridate 1.9.4 ✔ tidyr 1.3.1
## ✔ purrr 1.1.0
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag() masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(tidyquant)
## Registered S3 method overwritten by 'quantmod':
## method from
## as.zoo.data.frame zoo
## ── Attaching core tidyquant packages ─────────────────────── tidyquant 1.0.11 ──
## ✔ PerformanceAnalytics 2.0.8 ✔ TTR 0.24.4
## ✔ quantmod 0.4.28 ✔ xts 0.14.1── Conflicts ────────────────────────────────────────── tidyquant_conflicts() ──
## ✖ zoo::as.Date() masks base::as.Date()
## ✖ zoo::as.Date.numeric() masks base::as.Date.numeric()
## ✖ dplyr::filter() masks stats::filter()
## ✖ xts::first() masks dplyr::first()
## ✖ dplyr::lag() masks stats::lag()
## ✖ xts::last() masks dplyr::last()
## ✖ PerformanceAnalytics::legend() masks graphics::legend()
## ✖ quantmod::summary() masks base::summary()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(ggrepel)
Examine how each asset contributes to portfolio standard deviation. This is to ensure that our risk is not concentrated in any one asset.
I chose the stocks NVDA, AMD, INTC, QCOM, AVGO
symbols <- c("NVDA", "AMD", "INTC", "QCOM", "AVGO")
prices <- tq_get(x = symbols,
get = "stock.prices",
from = "2012-12-31",
to = "2025-11-23")
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"))
asset_returns_wide_tbl <- asset_returns_tbl %>%
pivot_wider(names_from = asset, values_from = returns) %>%
column_to_rownames(var = "date")
asset_returns_wide_tbl
## AMD AVGO INTC NVDA QCOM
## 2013-01-31 0.080042631 0.1223715009 0.020164044 0.000000000 0.0650839358
## 2013-02-28 -0.043228694 -0.0442993202 0.003056545 0.038221563 -0.0057722553
## 2013-03-28 0.023810626 0.0537860816 0.044951225 0.013338741 0.0232962903
## 2013-04-30 0.100643521 -0.1168089872 0.092225413 0.070706445 -0.0831348211
## 2013-05-31 0.349557500 0.1659702776 0.023060206 0.054651980 0.0300627242
## 2013-06-28 0.019802609 -0.0034658619 -0.002061275 -0.030167210 -0.0328476078
## 2013-07-31 -0.079021973 -0.0189043749 -0.037422708 0.028091529 0.0552469583
## 2013-08-30 -0.142285017 0.0486862799 -0.050298554 0.026270515 0.0315531082
## 2013-09-30 0.152839195 0.1180137070 0.041877208 0.053460262 0.0155694397
## 2013-10-31 -0.131658393 0.0531135335 0.065437486 -0.024066063 0.0317253729
## 2013-11-29 0.086012929 -0.0155281658 -0.016764777 0.032034585 0.0619539969
## 2013-12-31 0.061270767 0.1720590567 0.085191680 0.026567294 0.0090645214
## 2014-01-31 -0.120694197 0.0327415478 -0.056252361 -0.020177178 -0.0004038518
## 2014-02-28 0.078471606 0.1215174448 0.018415691 0.162107317 0.0143131483
## 2014-03-31 0.077759411 0.0472522625 0.041532646 -0.025903988 0.0509868943
## 2014-04-30 0.019753709 -0.0142289505 0.033526739 0.030788748 -0.0019042970
## 2014-05-30 -0.022250646 0.1069811385 0.031886464 0.032886222 0.0218655352
## 2014-06-30 0.046406386 0.0237166879 0.123136860 -0.024508306 -0.0104252407
## 2014-07-31 -0.069163352 -0.0380393494 0.092363787 -0.057729706 -0.0717021467
## 2014-08-29 0.064378658 0.1682173165 0.036569636 0.110060003 0.0372909934
## 2014-09-30 -0.201203738 0.0617383865 -0.002867734 -0.052782399 -0.0176313647
## 2014-10-31 -0.197092916 -0.0086579016 -0.023537313 0.057398853 0.0488093396
## 2014-11-28 -0.003577818 0.0796412483 0.097532549 0.074852327 -0.0683086431
## 2014-12-31 -0.043963081 0.0777639278 -0.026109310 -0.044863611 0.0194256384
## 2015-01-30 -0.038172628 0.0225105184 -0.093823440 -0.043318837 -0.1739881884
## 2015-02-27 0.190716820 0.2154937075 0.013482797 0.142698634 0.1491981489
## 2015-03-31 -0.148805873 -0.0020798842 -0.061395451 -0.052582437 -0.0388932997
## 2015-04-30 -0.170452010 -0.0828815813 0.040118355 0.058909294 -0.0195144526
## 2015-05-29 0.008810621 0.2365372043 0.064226833 0.001459480 0.0244057966
## 2015-06-30 0.051293347 -0.1050411858 -0.124698690 -0.095717045 -0.0997563934
## 2015-07-31 -0.217948801 -0.0603895495 -0.049530329 -0.007987836 0.0277138483
## 2015-08-31 -0.064193162 0.0066105042 -0.005990421 0.123595325 -0.1209126873
## 2015-09-30 -0.051002506 -0.0045194981 0.054546321 0.092151038 -0.0516838826
## 2015-10-30 0.209091727 -0.0151530047 0.116381107 0.140555322 0.1006589794
## 2015-11-30 0.107245540 0.0577493271 0.033540493 0.115405179 -0.1872810023
## 2015-12-31 0.195650415 0.1098535687 -0.009245897 0.038347304 0.0242975922
## 2016-01-29 -0.265854608 -0.0820948337 -0.104876885 -0.118048695 -0.0976335940
## 2016-02-29 -0.027651504 0.0019429754 -0.038432670 0.071923794 0.1228523304
## 2016-03-31 0.286513083 0.1458838206 0.089177565 0.127654968 0.0068673104
## 2016-04-29 0.219628629 -0.0583010614 -0.066126403 -0.002810703 -0.0121980073
## 2016-05-31 0.252565652 0.0573944161 0.050953761 0.276388593 0.0930625899
## 2016-06-30 0.117539811 0.0098647258 0.037587907 0.006187842 -0.0248885116
## 2016-07-29 0.288654408 0.0414703870 0.060911437 0.194443549 0.1554566217
## 2016-08-31 0.075772552 0.0853948901 0.036670380 0.073469226 0.0162518241
## 2016-09-30 -0.068510397 -0.0193431425 0.050526479 0.110693595 0.0825885830
## 2016-10-31 0.045269423 -0.0130690704 -0.079358468 0.037805333 0.0032065304
## 2016-11-30 0.208935186 0.0012327939 0.002655559 0.260525108 -0.0008315142
## 2016-12-30 0.241162087 0.0418729700 0.044251168 0.146435648 -0.0439580218
## 2017-01-31 -0.089419301 0.1209648631 0.015050662 0.022602381 -0.1990870571
## 2017-02-28 0.332469208 0.0557121175 -0.009868855 -0.071874969 0.0648199657
## 2017-03-31 0.006204787 0.0418879117 -0.003597297 0.070843454 0.0151116803
## 2017-04-28 -0.089826957 0.0084134055 0.002215375 -0.043433834 -0.0648405204
## 2017-05-31 -0.172743565 0.0811673820 0.006304483 0.326022248 0.0734189150
## 2017-06-30 0.109106841 -0.0229673720 -0.067885801 0.001453548 -0.0364517674
## 2017-07-31 0.086677465 0.0567574351 0.050003371 0.117044836 -0.0374550381
## 2017-08-31 -0.045855434 0.0216964976 -0.003862534 0.042639695 -0.0064316618
## 2017-09-29 -0.019418086 -0.0344611333 0.082343361 0.053601031 -0.0082609306
## 2017-10-31 -0.148545524 0.0844416098 0.177803081 0.145700288 -0.0161402804
## 2017-11-30 -0.009140779 0.0517972893 -0.008483167 -0.029245013 0.2711718434
## 2017-12-29 -0.057644734 -0.0721110396 0.029012645 -0.036583721 -0.0355976888
## 2018-01-31 0.290111036 -0.0351372161 0.042000556 0.239241270 0.0639819607
## 2018-02-28 -0.126279741 -0.0063499517 0.030369007 -0.014959636 -0.0402439264
## 2018-03-29 -0.186458876 -0.0303056003 0.055059722 -0.043969141 -0.1596270468
## 2018-04-30 0.079353598 -0.0267929331 -0.008872201 -0.029312612 -0.0827386519
## 2018-05-31 0.232656934 0.0941522165 0.072809007 0.115145044 0.1408822241
## 2018-06-29 0.087800110 -0.0248072857 -0.104757115 -0.062544835 -0.0350174797
## 2018-07-31 0.201155761 -0.0899382481 -0.032923919 0.033048806 0.1327960799
## 2018-08-31 0.317113754 -0.0124317410 0.012900459 0.137075382 0.0696065516
## 2018-09-28 0.204779675 0.1265657460 -0.023820489 0.001210692 0.0562519228
## 2018-10-31 -0.528461644 -0.0989278250 -0.008707685 -0.287373596 -0.1356952099
## 2018-11-30 0.156736193 0.0604220707 0.056809261 -0.253667834 -0.0764713586
## 2018-12-31 -0.143100857 0.0791298119 -0.049470056 -0.202282829 -0.0126469057
## 2019-01-31 0.279386699 0.0534835446 0.004040761 0.073974188 -0.1390944994
## 2019-02-28 -0.036716646 0.0261598639 0.123157658 0.071593884 0.0752467458
## 2019-03-29 0.081186244 0.0969600981 0.013876406 0.151869729 0.0775147762
## 2019-04-30 0.079439632 0.0571619355 -0.050803381 0.007987991 0.4122805193
## 2019-05-31 -0.007994204 -0.2353085969 -0.141405977 -0.288680055 -0.2538552678
## 2019-06-28 0.102547402 0.1440163226 0.083390516 0.192591354 0.1387503540
## 2019-07-31 0.002630713 0.0073721516 0.054474322 0.026972988 -0.0390052067
## 2019-08-30 0.032312988 -0.0256724777 -0.057400737 -0.006208336 0.0611071129
## 2019-09-30 -0.081448072 -0.0143600786 0.083330803 0.038414579 -0.0114368412
## 2019-10-31 0.157348653 0.0590064133 0.092607302 0.143946827 0.0531007618
## 2019-11-29 0.143100874 0.0767457965 0.032021744 0.076031415 0.0379336150
## 2019-12-31 0.158192829 0.0094774769 0.030536787 0.082163062 0.0622258062
## 2020-01-31 0.024554311 -0.0349691926 0.065947292 0.004790717 -0.0336554731
## 2020-02-28 -0.032874943 -0.1127574417 -0.136132889 0.133627179 -0.0857438151
## 2020-03-31 0.000000000 -0.1227418744 -0.025539484 -0.024248320 -0.1382769360
## 2020-04-30 0.141443063 0.1359220127 0.102807393 0.103279264 0.1509146007
## 2020-05-29 0.026557731 0.0698468383 0.053644740 0.194461799 0.0277045711
## 2020-06-30 -0.022367226 0.0905060949 -0.050515713 0.068216642 0.1279080762
## 2020-07-31 0.386468079 0.0036056387 -0.225947203 0.111189735 0.1465885782
## 2020-08-31 0.159505216 0.0916441182 0.072053235 0.231105164 0.1202102197
## 2020-09-30 -0.102282260 0.0573513188 0.016158964 0.011895803 -0.0066525938
## 2020-10-30 -0.085249927 -0.0411569324 -0.156470648 -0.076501434 0.0471379477
## 2020-11-30 0.207589583 0.1385310409 0.095180299 0.066921690 0.1764813813
## 2020-12-31 -0.010305505 0.0949545015 0.029950145 -0.025900267 0.0388329822
## 2021-01-29 -0.068478958 0.0284815375 0.108146794 -0.005010491 0.0255342441
## 2021-02-26 -0.013282561 0.0420977710 0.096749057 0.054293128 -0.1375984143
## 2021-03-31 -0.073771271 -0.0055179939 0.051622367 -0.026723313 -0.0220346286
## 2021-04-30 0.038975739 -0.0162202942 -0.106576559 0.117297943 0.0457724370
## 2021-05-28 -0.019048206 0.0347466409 -0.001012068 0.079070969 -0.0311726328
## 2021-06-30 0.159523669 0.0173004343 -0.017305829 0.208332464 0.0655832256
## 2021-07-30 0.122680138 0.0177921640 -0.044063048 -0.025494376 0.0469462705
## 2021-08-31 0.041774537 0.0240391965 0.012786545 0.138204178 -0.0209796714
## 2021-09-30 -0.073246845 -0.0177059044 -0.014533630 -0.077484748 -0.1240176874
## 2021-10-29 0.155648945 0.0920186447 -0.083740751 0.210396107 0.0309923584
## 2021-11-30 0.275527434 0.0405635592 0.011003486 0.245338475 0.3054134615
## 2021-12-31 -0.095815465 0.1901931856 0.045688233 -0.105149837 0.0164854526
## 2022-01-31 -0.230729542 -0.1272884175 -0.053441766 -0.183267084 -0.0396562652
## 2022-02-28 0.076555710 0.0026592014 -0.015619780 -0.004133359 -0.0216830148
## 2022-03-31 -0.120482480 0.0761769891 0.038252640 0.112576096 -0.1140126152
## 2022-04-29 -0.245712033 -0.1273432870 -0.128356236 -0.386065860 -0.0898349567
## 2022-05-31 0.174849100 0.0453838963 0.026735525 0.006717184 0.0249560698
## 2022-06-30 -0.286700804 -0.1691784100 -0.171751720 -0.208219456 -0.1091346281
## 2022-07-29 0.211383814 0.0973458850 -0.029844955 0.180792162 0.1271506888
## 2022-08-31 -0.107161630 -0.0703370571 -0.118815610 -0.185089223 -0.0867066714
## 2022-09-30 -0.292287949 -0.1086290426 -0.214021590 -0.217576889 -0.1576344623
## 2022-10-31 -0.053488672 0.0571406683 0.098233757 0.106044087 0.0405882821
## 2022-11-30 0.256609830 0.1588013386 0.069498834 0.226461963 0.0787199409
## 2022-12-30 -0.181111434 0.0229019120 -0.129028356 -0.146693509 -0.1402284624
## 2023-01-31 0.148643655 0.0452469137 0.066947689 0.290330053 0.1919921120
## 2023-02-28 0.044631101 0.0157385952 -0.113264151 0.172531463 -0.0754429421
## 2023-03-31 0.220952299 0.0836757225 0.270385215 0.179536623 0.0383496984
## 2023-04-28 -0.092284450 -0.0237227003 -0.050536327 -0.001008545 -0.0882806164
## 2023-05-31 0.279677610 0.2543637437 0.016246810 0.310008421 -0.0225331147
## 2023-06-30 -0.037054001 0.0763356640 0.061671765 0.111729633 0.0484499546
## 2023-07-31 0.004292397 0.0353588044 0.067356828 0.099530604 0.1046294120
## 2023-08-31 -0.078906991 0.0266165270 -0.014178264 0.054674143 -0.1361961617
## 2023-09-29 -0.027814218 -0.0999543969 0.011599853 -0.126218959 -0.0307663011
## 2023-10-31 -0.042923335 0.0129073788 0.026372304 -0.064546004 -0.0188144018
## 2023-11-30 0.207055468 0.0955511258 0.205943948 0.137050180 0.1752834663
## 2023-12-29 0.196105829 0.1917352680 0.117037092 0.057262971 0.1139789213
## 2024-01-31 0.128899206 0.0555394007 -0.153951666 0.217059119 0.0264733762
## 2024-02-29 0.138134928 0.0972266814 0.002230210 0.251388578 0.0656793327
## 2024-03-28 -0.064576574 0.0232305869 0.025683568 0.132939640 0.0704072904
## 2024-04-30 -0.130678165 -0.0191500659 -0.371303188 -0.044746473 -0.0205884618
## 2024-05-31 0.052397554 0.0215163024 0.016447718 0.238127430 0.2113710734
## 2024-06-28 -0.028502961 0.1925359758 0.003882183 0.119508692 -0.0241562563
## 2024-07-31 -0.115750773 0.0007906828 -0.007454249 -0.054220207 -0.0959882314
## 2024-08-30 0.027847841 0.0132306216 -0.326382133 0.019883219 -0.0317218484
## 2024-09-30 0.099365224 0.0610354808 0.062437778 0.017277876 -0.0252518272
## 2024-10-31 -0.130054782 -0.0159525136 -0.086314048 0.089122780 -0.0437542883
## 2024-11-29 -0.049005465 -0.0463546288 0.111152208 0.040520596 -0.0263942762
## 2024-12-31 -0.127240370 0.3606331958 -0.181905849 -0.028993152 -0.0262445749
## 2025-01-31 -0.040894471 -0.0466637674 -0.031410837 -0.111926722 0.1184048458
## 2025-02-28 -0.149389826 -0.1039204207 0.199921772 0.039598542 -0.0955587357
## 2025-03-31 0.028432293 -0.1718766200 -0.043934735 -0.141937940 -0.0175335609
## 2025-04-30 -0.053888788 0.1393750503 -0.122085482 0.004970095 -0.0341013903
## 2025-05-30 0.128782120 0.2292866468 -0.027744587 0.215623691 -0.0222033127
## 2025-06-30 0.248027705 0.1322559258 0.136085694 0.156363898 0.0984148325
## 2025-07-31 0.217121254 0.0634269180 -0.123379043 0.118521141 -0.0817394491
## 2025-08-29 -0.080766083 0.0124855590 0.206849966 -0.020963722 0.0909274171
## 2025-09-30 -0.005178555 0.1054873450 0.320504975 0.068827263 0.0401029048
## 2025-10-31 0.459346909 0.1136826174 0.175592624 0.081830424 0.0837902561
## 2025-11-21 -0.228605091 -0.0829688027 -0.147670141 -0.123975327 -0.1023554008
covariance_matrix <- cov(asset_returns_wide_tbl)
covariance_matrix
## AMD AVGO INTC NVDA QCOM
## AMD 0.024257654 0.005227882 0.003571723 0.010406738 0.006640727
## AVGO 0.005227882 0.007718952 0.002395779 0.004908708 0.002931620
## INTC 0.003571723 0.002395779 0.009137455 0.003786169 0.002205370
## NVDA 0.010406738 0.004908708 0.003786169 0.014694213 0.005222502
## QCOM 0.006640727 0.002931620 0.002205370 0.005222502 0.009235837
w <- c(0.25, 0.25, 0.2, 0.2, 0.1)
sd_portfolio <- sqrt(t(w) %*% covariance_matrix %*% w)
sd_portfolio
## [,1]
## [1,] 0.08309374
component_contribution <- (t(w) %*% covariance_matrix * w) / sd_portfolio[1,1]
component_contribution
## AMD AVGO INTC NVDA QCOM
## [1,] 0.03258714 0.01501548 0.01034287 0.01936894 0.00577931
rowSums(component_contribution)
## [1] 0.08309374
component_percentages <- (component_contribution / sd_portfolio[1,1]) %>%
round(3) %>%
as_tibble()
component_percentages
## # A tibble: 1 × 5
## AMD AVGO INTC NVDA QCOM
## <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 0.392 0.181 0.124 0.233 0.07
component_percentages %>%
as_tibble() %>%
gather(key = "asset", value = "contribution")
## # A tibble: 5 × 2
## asset contribution
## <chr> <dbl>
## 1 AMD 0.392
## 2 AVGO 0.181
## 3 INTC 0.124
## 4 NVDA 0.233
## 5 QCOM 0.07
# Transform data into wide form
asset_returns_wide_tbl <- asset_returns_tbl %>%
pivot_wider(names_from = asset, values_from = returns) %>%
column_to_rownames(var = "date")
# Custom function
calculate_component_contribution <- function(asset_returns_wide_tbl, w) {
# Covariance of asset returns
covariance_matrix <- cov(asset_returns_wide_tbl)
# Standard deviation of portfolio
sd_portfolio <- sqrt(t(w) %*% covariance_matrix %*% w)
# Component contribution
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(0.25,0.25,0.2,0.2,0.1))
## # A tibble: 1 × 5
## AMD AVGO INTC NVDA QCOM
## <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 0.392 0.181 0.124 0.233 0.07
asset_returns_wide_tbl %>%
calculate_component_contribution(w = c(0.25,0.25,0.2,0.2,0.1)) %>%
gather(key = "asset", value = "contribution") %>%
ggplot(aes(asset, contribution)) +
geom_col(fill = "cornflowerblue") +
theme(plot.title = element_text(hjust = 0.5)) +
scale_y_continuous(labels = scales::percent_format(accuracy = 1)) +
labs(title = "Percent Contribution to Portfolio Standard Deviation",
y = "Percent Contribution to Risk",
x = NULL)
asset_returns_wide_tbl %>%
calculate_component_contribution(w = c(0.25,0.25,0.2,0.2,0.1)) %>%
gather(key = "asset", value = "contribution") %>%
add_column(weights = c(0.25,0.25,0.2,0.2,0.1)) %>%
pivot_longer(cols = c(contribution, weights), names_to = "type", values_to = "value") %>%
ggplot(aes(asset, value, fill = type)) +
geom_col(position = "dodge") +
theme(plot.title = element_text(hjust = 0.5)) +
scale_y_continuous(labels = scales::percent_format(accuracy = 1)) +
theme_tq() +
scale_fill_tq() +
labs(title = "Percent Contribution to Volatility",
y = "percent",
x = "asset")
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?
Based on the bar chart, AMD is the largest contributor to the portfolio’s volatility, accounting for roughly 39–40% of the total risk. In terms of concentration, the portfolio is somewhat concentrated in AMD since its contribution is noticeably higher than any other holding. However, AMD isn’t the only meaningful source of risk, NVDA also represents a significant portion (around 23%), and AVGO contributes a moderate amount (around 18%). INTC and QCOM, by comparison, have much smaller impacts on overall volatility.