Search code examples
rfinancequantmod

using quantmod to download stock data in R


I am using quantmod to get stock data and the adjusted closing price is discounted with the stock dividend payout, but it may be not so accurate when it comes to actual PnL calculation as one may not have bought the stock since the IPO date so the PnL shall not include all dividend payout which reflects in the adjusted closing price. Say for example with the below df:

library(quantmod)
getSymbols("TGT",form='2018-01-01',to='2022-10-01')
TGT_dividend<-getDividends("TGT",from='2018-01-20',to='2022-10-01') *#fist dividend pays on 2018-01-20*
TGT$TGT.Close *#closing price, excluding dividend*

Here if I would like to sum up all dividend payout in the data frame (from 2018-01-20 to 2022-10-01) and then compare the closing price (instead of adjusted closing) , that way I can hypothetically calculate how much the PnL is (Traded price + all dividend payment - updated CLOSING price). May I know how should I go about it? Many thanks for reading the post.

Hi guys, thanks for the help from @phiver, I am able to come up with the following codes:

#PnL of div.paying stock
library(quantmod)
calc_pnl<-function(close,dividends,buy_price,buy_date){
  names(close) <- "close"
  names(dividends) <- "div"
  # merge close and cumsum divs from buy_date
  out <- merge(close[paste0(buy_date, "/")], cumsum(dividends[paste0(buy_date, "/")]))
  
  # roll divs forward on the empty values
  out$div <- na.locf(out$div)
  
  # calculate buy_price as close - buy_price + divs
  out$pnl <- out$close - buy_price + out$div
  
  out
}
calc_pnl_max<-function(close,dividends,buy_price,buy_date){
    names(close) <- "close"
    names(dividends) <- "div"
    # merge close and cumsum divs from buy_date
    out <- merge(close[paste0(buy_date, "/")], cumsum(dividends[paste0(buy_date, "/")]))
    
    # roll divs forward on the empty values
    out$div <- na.locf(out$div)
    
    # calculate buy_price as close - buy_price + divs
    out$pnl <- out$close - buy_price + out$div
    
    out
  }
calc_pnl_min<-function(close,dividends,buy_price,buy_date){
    names(close) <- "close"
    names(dividends) <- "div"
    # merge close and cumsum divs from buy_date
    out <- merge(close[paste0(buy_date, "/")], cumsum(dividends[paste0(buy_date, "/")]))
    
    # roll divs forward on the empty values
    out$div <- na.locf(out$div)
    
    # calculate buy_price as close - buy_price + divs
    out$pnl <- out$close - buy_price + out$div
    
    out
  }
calc_pnl_avg<-function(close,dividends,buy_price,buy_date){
    names(close) <- "close"
    names(dividends) <- "div"
    # merge close and cumsum divs from buy_date
    out <- merge(close[paste0(buy_date, "/")], cumsum(dividends[paste0(buy_date, "/")]))
    
    # roll divs forward on the empty values
    out$div <- na.locf(out$div)
    
    # calculate buy_price as close - buy_price + divs
    out$pnl <- out$close - buy_price + out$div
    
    out
  }  
  
start<-'2015-01-01'
end<- '2022-10-21'

symbols<-'0386.HK'
ticker <- na.omit(getSymbols(symbols,from = start, to = end,auto.assign=FALSE)) 
ticker_dividend<-round(getDividends(symbols,from=start,to=end),2)
buy_max<-max(ticker[,4])
buy_min<-min(ticker[,4])
buy_avg<-mean(ticker[,4])

pnl_max<-calc_pnl_max(ticker[,4],ticker_dividend,buy_price = buy_min ,buy_date = start)
pnl_min<-calc_pnl_max(ticker[,4],ticker_dividend,buy_price = buy_max ,buy_date = start) 
pnl_avg<-calc_pnl_max(ticker[,4],ticker_dividend,buy_price = buy_avg ,buy_date = start) 

df<-round(tail(cbind(pnl_max$pnl,pnl_min$pnl,pnl_avg$pnl),8),2)
colnames(df)<-c('maxPnL','minPnL','avgPnL') 

Solution

  • Not sure if I got exactly what you want, but based on the example data, I created a function where you can supply the close price, the dividends, the buy price and the buy date and it will return an xts with the PnL calculated from the buy date.

    The function merges the close price with the cumulative dividends, fills in the NA's with the previous div value and then calculates the PnL based on the close price - buy price + all collected dividends.

    library(quantmod)
    
    TGT <- getSymbols("TGT",from = '2018-01-01', to = '2022-10-01', auto.assign = FALSE)
    TGT_dividend <- getDividends("TGT", from = '2018-01-01', to = '2022-10-01')
    
    calc_pnl <- function(close, dividends, buy_price, buy_date){
      
      # rename columns
      names(close) <- "close"
      names(dividends) <- "div"
      # merge close and cumsum divs from buy_date
      out <- merge(close[paste0(buy_date, "/")], cumsum(dividends[paste0(buy_date, "/")]))
      
      # roll divs forward on the empty values
      out$div <- na.locf(out$div)
    
      # calculate buy_price as close - buy_price + divs
      out$pnl <- out$close - buy_price + out$div
      
      out
    }
    
    pnl <- calc_pnl(TGT$TGT.Close, TGT_dividend, buy_price = 127, buy_date = "2020-08-03")
    tail(pnl)
    
                close div      pnl
    2022-09-23 152.61 7.4 33.01000
    2022-09-26 148.71 7.4 29.11001
    2022-09-27 148.47 7.4 28.87000
    2022-09-28 155.87 7.4 36.26999
    2022-09-29 151.79 7.4 32.18999
    2022-09-30 148.39 7.4 28.79000