# Load packages

# Core
library(tidyverse)
library(tidyquant)

Goal

Collect individual returns into a portfolio by assigning a weight to each stock

Choose your stocks.

from 2012-12-31 to 2017-12-31

1 Import stock prices

symbols <- c("JPM", "MS", "DNB.OL", "NDA-FI.HE")

prices <- tq_get(x    = symbols, 
                 get  = "stock.prices", 
                 from = "2017-01-01", 
                 to   = "2023-12-31") %>%
          filter(!is.na(close)) 

2 Convert prices to returns (quarterly)

asset_returns_tbl <-prices %>%
    
    group_by(symbol) %>%
    tq_transmute(select     = adjusted, 
                 mutate_fun = periodReturn, 
                 period     = "quarterly",
                 type = "log") %>%
    ungroup() %>%
    
    set_names(c("asset", "date", "returns"))
asset_returns_tbl
## # A tibble: 112 × 3
##    asset date       returns
##    <chr> <date>       <dbl>
##  1 JPM   2017-03-31  0.0125
##  2 JPM   2017-06-30  0.0455
##  3 JPM   2017-09-29  0.0495
##  4 JPM   2017-12-29  0.119 
##  5 JPM   2018-03-29  0.0331
##  6 JPM   2018-06-29 -0.0488
##  7 JPM   2018-09-28  0.0851
##  8 JPM   2018-12-31 -0.138 
##  9 JPM   2019-03-29  0.0444
## 10 JPM   2019-06-28  0.107 
## # ℹ 102 more rows

3 Assign a weight to each asset (change the weigting scheme)

#symbols
symbols <- asset_returns_tbl %>% distinct(asset) %>% pull()
symbols
## [1] "JPM"       "MS"        "DNB.OL"    "NDA-FI.HE"
#weights 
weights <- c(0.25, 0.25, 0.25, 0.25)
weights
## [1] 0.25 0.25 0.25 0.25
w_tbl <- tibble(symbols, weights)
w_tbl
## # A tibble: 4 × 2
##   symbols   weights
##   <chr>       <dbl>
## 1 JPM          0.25
## 2 MS           0.25
## 3 DNB.OL       0.25
## 4 NDA-FI.HE    0.25

4 Build a portfolio

# ?tq_portfolio

portfolio_returns_tbl <- asset_returns_tbl %>%
    
    tq_portfolio(assets_col   = asset, 
                 returns_col  = returns,
                 weights      = w_tbl, 
                 rebalance_on = "months")

portfolio_returns_tbl
## # A tibble: 33 × 2
##    date       portfolio.returns
##    <date>                 <dbl>
##  1 2017-03-31         0.0324   
##  2 2017-06-30         0.0531   
##  3 2017-09-29         0.0704   
##  4 2017-12-29         0.00773  
##  5 2018-03-28         0.0000821
##  6 2018-03-29        -0.00541  
##  7 2018-06-29        -0.0306   
##  8 2018-09-28         0.0706   
##  9 2018-12-28        -0.119    
## 10 2018-12-31        -0.0829   
## # ℹ 23 more rows

5 Plot: Portfolio Histogram and Density

Histogram

portfolio_returns_tbl %>%
    
    ggplot(mapping = aes(x = portfolio.returns)) +
    geom_histogram(fill = "cornflowerblue", binwidth = 0.005) +
    
    labs(x = "returns",
         title = "Portfolio Returns Distribution")

Histogram & Density Plot

portfolio_returns_tbl %>%
    
    ggplot(mapping = aes(x = portfolio.returns)) +
    geom_histogram(fill = "cornflowerblue", binwidth = 0.01) +
    geom_density() +
    
    # Formatting 
    scale_x_continuous(labels = scales::percent_format()) +
    
    labs(x = "returns",
         y = "distribution",
         title = "Portfolio Histogram & Density")

What return should you expect from the portfolio in a typical quarter?

Portfolio Histogram (Image 1):

The histogram shows a distribution of portfolio returns, and from this, you can observe that most returns are around 0% to 10%. There are some negative returns that reach around -40%, as well as some positive returns close to 20%, but these extremes occur less frequently, one quarter.

Portfolio Histogram & Density Plot (Image 2):

The density line over the histogram gives a clearer picture of where the majority of returns fall. The density peak occurs between 0% and 10% which suggests that most of the returns hover near 5%. The right tail of the density curve extends towards 20%, indicating that positive returns are also possible, though not as frequent as returns around 5%. Conclusion: In a typical quarter, you should expect returns near 0%, with some possibility of either positive or slightly negative returns. Extreme negative returns (e.g., -40%) or positive returns (e.g., 20%) are less likely based on the distribution observed.