PerformanceAnalytics

Jeb Dee

What I Did in This Project

  • Built a fictional stock portfolio using real market data
  • Used quantmod to pull adjusted stock prices
  • Bought whole shares based on a simple investment rule
  • Calculated total portfolio value over time
  • Used PerformanceAnalytics to calculate daily returns
  • Evaluated performance using return, volatility, Sharpe ratio, and drawdowns
  • Created charts and tables to visualize portfolio performance

What is PerformanceAnalytics?

PerformanceAnalytics is an R package for analyzing investment performance. It works with return data from stocks, funds, or portfolios. It measures return, risk, volatility, Sharpe ratio, and drawdowns. It creates charts and tables that make portfolio performance easier to understand. It helps answer whether a portfolio’s return was worth the risk

  • Return.calculate()
    • Calculated daily portfolio returns from total portfolio value
  • charts.PerformanceSummary()
    • Created a full performance chart showing cumulative returns, daily returns, and drawdowns
  • table.AnnualizedReturns()
    • Created a table with annualized return, annualized standard deviation, and Sharpe ratio
  • chart.CumReturns()
    • Showed cumulative portfolio growth over time
  • chart.Drawdown()
    • Showed portfolio losses from previous highs
  • VaR()
    • Calculates Value at Risk, which estimates potential loss on a bad day
  • ES()
    • Calculates Expected Shortfall, or the average loss during the worst return periods
  • CAPM.beta()
    • Measures sensitivity to a benchmark, like the S&P 500
  • CAPM.alpha()
    • Measures return above what CAPM would predict

Fictional Portfolio

  • I created a fictional portfolio using real publicly traded companies based off a personal hypothesis
  • The portfolio included stocks from several sectors, including finance, real estate, technology, healthcare, consumer staples, and energy
  • I used April 1, 2020 as the starting date for the investment (mid covid)
  • I bought whole shares instead of using perfect equal weights
  • Each stock had at least two shares purchased and about $250 invested
  • This gave me a realistic portfolio to analyze with PerformanceAnalytics

Pulling Stock Data Using quanmod

Using quantmod to pull the stock prices from yahoo finance

tickers <- c(
  "JPM",  # JPMorgan Chase
  "PLD",  # Prologis
  "BHP",  # BHP Group
  "V",    # Visa
  "TSM",  # Taiwan Semiconductor
  "NEE",  # NextEra Energy
  "UNH",  # UnitedHealth
  "COST", # Costco
  "WMT",  # Walmart
  "PG",   # Procter & Gamble
  "XOM",  # Exxon Mobil
  "CVX",  # Chevron
  "COP"   # ConocoPhillips
)

getSymbols(tickers, from = "2020-04-01")
 [1] "JPM"  "PLD"  "BHP"  "V"    "TSM"  "NEE"  "UNH"  "COST" "WMT"  "PG"  
[11] "XOM"  "CVX"  "COP" 

The total amount of stocks of each company

starting_prices <- as.numeric(prices[1, ]) # Prices on first available trading day

shares <- pmax(2, ceiling(250 / starting_prices)) # Buy at least 2 shares and at least about $250 per stock

names(shares) <- tickers # Label shares by ticker

shares # Show number of shares bought
 JPM  PLD  BHP    V  TSM  NEE  UNH COST  WMT   PG  XOM  CVX  COP 
   4    5   12    2    6    6    2    2    8    3    9    5   11 

Actual dollar amount spent on each stock

initial_investment <- shares * starting_prices # Actual dollars invested in each stock

names(initial_investment) <- tickers # Label investments by ticker
total_initial_investment <- sum(initial_investment) # Total amount invested at the start

total_initial_investment # Show total starting portfolio value
[1] 3983.983
initial_investment # Show actual investment by stock
     JPM      PLD      BHP        V      TSM      NEE      UNH     COST 
285.0641 310.3596 265.8731 293.3284 251.6251 281.7881 428.9398 524.7714 
     WMT       PG      XOM      CVX      COP 
280.3701 280.0117 257.5994 262.8045 261.4477 

Calculating Returns

portfolio_values <- sweep(prices, 2, shares, `*`) # Multiply prices by shares owned

total_portfolio_value <- xts(
  rowSums(portfolio_values),
  order.by = index(portfolio_values)
) # Convert total portfolio value back to xts format

colnames(total_portfolio_value) <- "Portfolio_Value" # Rename column

head(total_portfolio_value) # Show first few values
           Portfolio_Value
2020-04-01        3983.983
2020-04-02        4171.191
2020-04-03        4080.379
2020-04-06        4325.467
2020-04-07        4304.241
2020-04-08        4470.592
portfolio_returns <- na.omit(Return.calculate(total_portfolio_value)) # Calculate daily portfolio returns

colnames(portfolio_returns) <- "Portfolio_Returns" # Rename the returns column

head(portfolio_returns) # Show first few portfolio returns
           Portfolio_Returns
2020-04-02       0.046990055
2020-04-03      -0.021771283
2020-04-06       0.060065024
2020-04-07      -0.004907134
2020-04-08       0.038648248
2020-04-09       0.003948474

Portfolio Performance and Risk and Return Analysis

charts.PerformanceSummary(
  portfolio_returns,
  main = "Portfolio Performance Summary"
)

table.AnnualizedReturns(portfolio_returns)
                          Portfolio_Returns
Annualized Return                    0.2367
Annualized Std Dev                   0.1646
Annualized Sharpe (Rf=0%)            1.4378
chart.CumReturns(
  portfolio_returns,
  main = "Cumulative Portfolio Returns",
  wealth.index = TRUE
)

chart.Drawdown(
  portfolio_returns,
  main = "Portfolio Drawdowns"
)

annualized_return <- Return.annualized(portfolio_returns) # Annualized return

annualized_risk <- StdDev.annualized(portfolio_returns) # Annualized volatility

sharpe_ratio <- SharpeRatio.annualized(portfolio_returns, Rf = 0) # Risk-adjusted return

max_drawdown <- maxDrawdown(portfolio_returns) # Worst peak-to-trough loss

annualized_return
                  Portfolio_Returns
Annualized Return         0.2366656
annualized_risk
                              Portfolio_Returns
Annualized Standard Deviation         0.1645969
sharpe_ratio
                                        Portfolio_Returns
Annualized Sharpe Ratio (Rf=0%, p=95%):          1.373318
max_drawdown
[1] 0.1683628

Takeaways

  • PerformanceAnalytics turns return data into useful investment analysis

  • The package helps measure both performance and risk

  • The portfolio had strong annualized returns, but it also had periods of losses and volatility

  • Charts like cumulative returns and drawdowns make portfolio performance easier to understand

  • The biggest lesson is that portfolio analysis is not just about making money, but whether the return was worth the risk