Sailing the Volatility Seas – Finding Safe Harbor

The last several months have witnessed large swings in the market. The so-called VIX index captures these quite well and in an earlier post we had plotted this. Updating the data till 2018 year end we see the following – note the clear spikes in the daily change ratios plotted towards end of year:

As any goggle search will show, investing in dividend paying stocks appears to offer some kind of stability especially when the market appears to enter into so-called correction periods.  While these dividend paying companies may experience drop in their stock prices, they for the most part continue to pay out dividends.  It is suggested that this is all the more true if these comprise the so-called dividend champions or aristocrats who have very strong dividend records year after year.  This site maintains a list of such companies and the December version of this excel sheet is available from this website.  This is updated monthly and consists of the top ranked dividend paying companies split into 3 categories, i.e., Champions, Challengers and Contenders.  Champions being the list of companies which have paid out dividends for the longest time and on a consistent basis.  There are several sheets that can be downloaded.  There a couple of interest to us here, first being the complete list of them all, identified by the “All CCC” tag, and the second bearing tag “Historical” which is an almost 20-year data compilation of actual dividends paid out by company.

   Our intention here is to develop analytical tools to evaluate whether this widely touted strategy of holding dividend stocks provides adequate performance, especially in a retirement context where periodic or annual/quarterly cash flows are important as is the ability to sustain these cash flows into the future.  The idea is to first select stocks in order to build a diversified portfolio, download their adjusted price history and analyse their performance over past historical periods.  This can be extended into the future by employing simulation techniques that have been described earlier.  The detailed steps are described below followed by actual implementation in R code.  As usual, we will keep initial model simple retaining ability to add many bells and whistles later.

·       Obtain the data for say yearend from dividend champions site.  Summarize and aggregate data needed for the model.  The aggregated data will drill down to ranking companies in their individual sectors, ( sectors being e.g., Utilities, Financials, Tech etc.,).  There happen to be 11 distinct sectors in the data compilation

·       Filter the data to pick a basket of say 20 stocks according to the following criteria:  1) at least one from each sector,  some sectors will have more than one;  2) highest dividend yielding stock or highest previous 5 year dividend payout growth rate or some combination from each sector; 3) additional stocks may be picked from sector with most representation; 4) initial investment in the basket will be on an equal weight basis

·       For each of the 20 stocks, download adjusted price history for at least the past 10 or 15 years

·       Chart historic performance of this basket assuming just a Buy and Hold strategy, i.e., no rebalancing

·       Specify an initial annual requirement or withdrawal amount

·       Determine annual cash flows generated by our model portfolio taking into account dividend growth

·       Evaluate sufficiency of portfolio

    Assuming location of downloaded dividend list as inFile = “z:/Downloads/DivChamps/DivChamps181231.xls” we will first separate out data needed into object divXL as below:

require(XLConnect)  ## need the excel interface package

 

###  first get list of stocks, sector and div yield

###  this is from the All CCC sheet

###  also noyrs, CCCseq and divyield

## READ & JUST get those cols

SELWKS = “All CCC”

wb <- loadWorkbook(inFile, create = FALSE)     #  load in an Excel ss

divXL<-readWorksheet(wb, sheet = SELWKS) 

getCols<-c(“Ticker” , “Sector” , “Industry” , “NoYrs” , “CCCSeq” , “DivYield” )

colnames(divXL)<-c(“CompanyName”, “Ticker”)

colSelector<-which(gsub(\\.|\\+|\\-|\\/| |%|[:0-9]|(Symbol)|(NA)”, “”,

                        paste(divXL[4,], divXL[5,], sep=“”) ) %in% getCols)

# remove all lines upto Name;symbol

divXL<-divXL[(1:c(grep(“Name;Symbol”, paste(divXL$CompanyName,divXL$Ticker, sep=“;”) , value=FALSE)) ),]   

# remove bottom rows

divXL<-divXL[c(grep(“(Averages for)|(Average)”, divXL$CompanyName, value=FALSE)[1]:nrow(divXL)),]  

 

divXL <- divXL[,colSelector]

colnames(divXL)<-getCols

 

> head(divXL)

   Ticker                 Sector                         Industry NoYrs CCCSeq DivYield

6    SRCE             Financials                            Banks    31     92     2.48

7     MMM            Industrials         Industrial Conglomerates    60      8     2.86

8     AOS            Industrials                Building Products    25    128     2.06

9     AAN Consumer Discretionary                 Specialty Retail    16    222     0.33

10    ABT            Health Care Health Care Equipment & Supplies     6    772     1.77

11   ABBV            Health Care                    Biotechnology     7    658     4.64

 

 

Next read in the dividend history from the “Historical” worksheet, calculate the 5-year CAGR (Compound Average Growth Rate) of the dividend increases (or decreases) per ticker/stock and just selct the most recent 5-year CAGR.  At this juncture, we don’t want all the 5-yar rolling periods but these are easily available if at some point it was necessary to look athe history of increases or decreases.  The 5-year growth rate was chosen, but one could just have just have easily chosen a different period – there must be sufficient data available though.  Data needed for selecting stocks are consolidated into the “dvGood” object.

 

SELWKS = “Historical”

CURRYR = as.numeric(format(Sys.Date(),“%Y”))

yrsCols = seq(1990, CURRYR)

histColNames<-c(“Symbol” , as.character(yrsCols) )

## inFile is location of downloaded spreadsheet

monthEnd<-as.Date(paste(“20”, strapplyc(inFile, “.*\\/*(\\d{6})\\.xls”, simplify = TRUE), sep=“”), “%Y%m%d”) 

wb <- loadWorkbook(inFile, create = FALSE)     #  load in an Excel ss

###  get the Historical sheet – this has actual dividends

histXL<-readWorksheet(wb, sheet = SELWKS)   #  to get the “Historical”worksheet

##  need to get correct columns – eliminate not needed

##  years are repeated – discard the percentages – will calculate later

xln = paste(histXL[4,], histXL[5,], sep = “”)

xln = gsub(“vs\\.[0-9]{4}”, “DISCARD”, xln)

##  pick cols    note weird groupings!

colSelector<-which(gsub(“(Ticker)|(NA)|(Amounts.+year)”, “”,  xln)  %in% histColNames) 

colnames(histXL)<-c(“CompanyName”, “Ticker”)

# remove all lines upto Name;symbol

histXL<-histXL[(1:c(grep(“Name;Symbol”, paste(histXL$CompanyName,histXL$Ticker, sep=“;”) , value=FALSE)) ),]   

histXL<- histXL[,colSelector]

### to remove nas – “ext”  has all tickers and the previous years dividend payouts

### 

ext = cbind(histXL[,1], apply(histXL[,1], 2, function(x) round(as.numeric(x),2) ) )

###  save this in file so we can reuse later

write.table(cbind(as.character(monthEnd), ext), file=“D:/Temp/ExcelLoadCSV/tmpDivHistory.csv”, quote=FALSE,

                row.names=FALSE, col.names =FALSE, sep=“;”)

 

###  probably only want the growth CAGR for the past 5 years

###  dont need everything in  dvGrowth5Yr

dhist<-read.csv(file=“D:/Temp/ExcelLoadCSV/tmpDivHistory.csv”,head=FALSE,as.is=TRUE,sep=“;”)

dvGrLast = apply(dhist[, 3:8], 1, function (x) (diff(unlist(x), lag=5)+1)^0.2 )    ## dont need transpose /only 1 col

dvGrLast = cbind(dhist[,1:2], dvGrLast )

dvGrLast =  dvGrLast[complete.cases(dvGrLast), ]   ### throw out NAs

colnames(dvGrLast) = c(“Date”, “Ticker”, “CAGR5Yr”)

 

###   now merge up with div champs list from divXL

dvGood = cbind(divXL,0)

colnames(dvGood) = c(colnames(divXL), “CAGR5Yr”)

## check that no errors

for ( i in 1:nrow(dvGood) ) {

  ### need to test if found, else the which returns length 0

  rn = which(dvGrLast$Ticker ==  dvGood$Ticker[i], arr.ind=T) 

  if ( length(rn) != 0)   dvGood$CAGR5Yr[i] = dvGrLast$CAGR5Yr[rn]

  }

 

dvGood[101:110,]

    Ticker                 Sector                         Industry NoYrs CCCSeq DivYield  CAGR5Yr

106      B            Industrials                        Machinery     8    499     1.19 1.028347

107   BSET Consumer Discretionary               Household Durables     8    518     2.50 1.040572

108    BBT             Financials                            Banks     8    524     3.74 1.084472

109    BDX            Health Care Health Care Equipment & Supplies    47     41     1.37 1.159962

110    BMS              Materials           Containers & Packaging    35     77     2.70 1.037137

111    BBY Consumer Discretionary                 Specialty Retail    15    237     3.40 1.105342

112    BIG Consumer Discretionary                 Multiline Retail     5    801     4.15 1.148698

113    BKH              Utilities                  MultiUtilities    48     33     3.22 1.058694

114    BLK             Financials                  Capital Markets     9    393     3.19 1.379730

115     BA            Industrials              Aerospace & Defense     8    569     2.56 1.375286

 

 

   Now we want to see what the distribution of stocks is by sector on the dividend list.  From this we can estimate number of stocks to allocated per sector, remembering that a minimum of 1 per sector was a requirement. The package plyr is needed and the “grp” object below shows distribution results.  From this theoretical analysis, we see that Fractions are presented, e.g., Consumer Discretionary should have 2, Materials have 1, Industrials 3 and so on with some Comm Services as 0.  This would need to be customized.

#####   to get at sector/industry stuff

##### 

require(plyr)

crit = c(“Sector”, “Industry”)   ;  or crit = “Sector”

grp=count(divXL, crit )

grpByCount = grp[order(grp[,3], decreasing = T),]   ### [,3] because 2 columns used to group, if only one then [,2] see below

grp[order(grp[,3], decreasing = T),][1:20,]

## in 1 line –  show say the top 20

grp=count(divXL, crit ); grp[order(grp[,2], decreasing = T),][1:20,]       ###  show top 20

 

grp=cbind(grp,0)

colnames(grp) = c(“Sector”, “Freq”, “Fraction”)

grp$Fraction = (grp$Freq/sum(grp$Freq) )

grp[order(grp$Freq, decreasing = T),]

                   Sector Freq    Fraction

5              Financials  289 0.334104046

7             Industrials  124 0.143352601

2  Consumer Discretionary   83 0.095953757

10            Real Estate   75 0.086705202

11              Utilities   62 0.071676301

8  Information Technology   52 0.060115607

3        Consumer Staples   47 0.054335260

9               Materials   47 0.054335260

6             Health Care   38 0.043930636

4                  Energy   28 0.032369942

1  Communication Services   19 0.021965318

 

 

###  If theoretical number of stocks to allocate

###  assuming a basket of 20; then this would be

###  number of stocks to pick from each sector

 

grp$Fraction = round((grp$Freq/sum(grp$Freq) * 20 ), 0)

grp[order(grp$Freq, decreasing = T),]

                   Sector Freq Fraction

5              Financials  289        7

7             Industrials  124        3

2  Consumer Discretionary   83        2

10            Real Estate   75        2

11              Utilities   62        1

8  Information Technology   52        1

3        Consumer Staples   47        1

9               Materials   47        1

6             Health Care   38        1

4                  Energy   28        1

1  Communication Services   19        0

 

 

Once the first cut at number of stocks per sector derived as in the grp matrix above, this can be refined.  Remember we want only 20 stocks in our portfolio, although this can certainly be relaxed.  We now need to pick the top performing stocks per our criteria – currently can use either the dividend yield or dividend growth.  One point to note is that w are using the data as of Dec 31, 2018 and when we perform the historical backtests, the circumstances as of 2018 yearend would certainly not have been the same many years earlier.  But our goal is to construct a model which can certainly be used going forward.  If this a very controversial proposition, then we can perhaps try and get data as of a previous year end and apply that for historical performance analysis. The problem is that data from that website goes back only so far, and there have been several intermediary format changes.  The underlying model structure however, remains intact.

  First a function to sort and pick stocks based on the above is defined.  We must also specify a control array to let us know how many stocks to pick in each sector and this is where we can provide our own judgement factor.  A sample array, ‘dvsfy’ is shown which shows number for each sector, keyed off the ‘grp’ matrix. Finally we run the sort and pick function and obtain a list of candidate stocks.  This has a factor identifier as well so that we can just pick a 20 based on div yield for example.

#################################################

####  Function to Pick top div Yield & growth stocks

####  Default is top 3 & 15 years of dividends

####  Top number controlled by diversification array

#################################################

sortAndPick <- function(sector, NYRS=15, FROMTOP=3) {

  out<- c()

  FROMTOP = grp$dvsfy[(grp$Sector == sector)]

  topPick=sort(dvGood$DivYield[(dvGood$Sector==sector & dvGood$NoYrs > NYRS)] , decreasing = T) [1:FROMTOP]

  ###  Factor =0 for Div Yield; =1 for CAGR

  out <- rbind(out , cbind(dvGood[which(dvGood$Sector == sector & dvGood$NoYrs > NYRS & dvGood$DivYield %in% topPick  ,arr.ind=T), ] , Factor=0  ) )

  colnames(out)  =  c(colnames(dvGood), “Factor”)

  topPick=sort(dvGood$CAGR5Yr[(dvGood$Sector==sector & dvGood$NoYrs > NYRS)] , decreasing = T) [1:FROMTOP]

  out <- rbind(out , cbind(dvGood[which(dvGood$Sector == sector & dvGood$NoYrs > NYRS & dvGood$CAGR5Yr %in% topPick  ,arr.ind=T), ] , Factor=1 ) )

  return(out)

}

 

#####   Mow pick the 20 stocks we need

####    setup control array  number of stocks per sector in dvsfy

#### this should be in order of sectors – e.g., as.vector(grp$Sector) – should be in this order

# [1] “Communication Services” “Consumer Discretionary” “Consumer Staples”       “Energy”                 “Financials”             “Health Care”          

# [7] “Industrials”            “Information Technology” “Materials”              “Real Estate”            “Utilities”     

 

dvsfy = c(1, 2, 2, 2, 2, 2, 3, 2, 1, 2, 1  )  ## check sum to be 20 (our total in portfolio)

grp = cbind(grp, dvsfy)

## apply sort & pick function to all sectors & get list of candidate stocks

pkList = lapply(grp$Sector, sortAndPick)

candStocks = do.call(rbind, pkList)

   The ‘candstocks’ data frame has stock picks.  Because there may have been identical div yields resulting in multiple matches we may get over 20 stocks in the list.  This is in fact what has happened. If we look at this dataframe by Factor=0, i.e. dividend yield we find some similar values e.g. the highlighted Industrials category.  Similarly the Financials have multiple similar yileds also.  We therefore need to prune this, by removing a few, arriving finally at the 20 stocks that we pick for analysis:

> candStocks[(candStocks$Factor==0),]

    Ticker                 Sector                                     Industry NoYrs CCCSeq DivYield  CAGR5Yr Factor

79       T Communication Services       Diversified Telecommunication Services    35     80     7.15 1.037137      0

463    LEG Consumer Discretionary                           Household Durables    47     36     4.24 1.048964      0

749    TGT Consumer Discretionary                             Multiline Retail    51     23     3.87 1.162163      0

35      MO       Consumer Staples                                      Tobacco    49     30     6.48 1.127235      0

812    VGR       Consumer Staples                                      Tobacco    20    161    16.44 1.058694      0

255    ENB                 Energy                  Oil, Gas & Consumable Fuels    22    149     6.90 1.115859      0

260    EPD                 Energy                  Oil, Gas & Consumable Fuels    21    158     7.04 1.069610      0

514    MCY             Financials                                    Insurance    32     89     4.85 1.009806      0

610   PBCT             Financials                                        Banks    26    106     4.85 1.009806      0

850    WHG             Financials                              Capital Markets    17    196     8.47 1.148698      0

147    CAH            Health Care             Health Care Providers & Services    23    145     4.27 1.139358      0

428    JNJ            Health Care                              Pharmaceuticals    56     12     2.79 1.139358      0

15     ACU            Industrials               Commercial Services & Supplies    16    223     3.37 1.026552      0

254    EMR            Industrials                         Electrical Equipment    62      7     3.28 1.055490      0

475    LMT            Industrials                          Aerospace & Defense    16    219     3.36 1.339354      0

537    MSM            Industrials             Trading Companies & Distributors    16    218     3.28 1.122235      0

410    IBM Information Technology                                  IT Services    23    144     5.52 1.291994      0

649   QCOM Information Technology     Semiconductors & Semiconductor Equipment    16    208     4.36 1.179199      0

575    NUE              Materials                              Metals & Mining    46     48     3.09 1.009806      0

712    SON              Materials                       Containers & Packaging    36     74     3.09 1.061859      0

584    OHI            Real Estate Equity Real Estate Investment Trusts (REITs)    16    199     7.51 1.130926      0

748    SKT            Real Estate Equity Real Estate Investment Trusts (REITs)    25    118     6.92 1.087348      0

630    PPL              Utilities                           Electric Utilities    17    183     5.79 1.040572      0

 

###  by div yield – gives us 23 stocks – we will remove 3 to get final pick

###  remove EMR, MCY and NUE

> candStocks$Ticker[(candStocks$Factor==0)]

 [1] “T”    “LEG”  “TGT”  “MO”   “VGR”  “ENB”  “EPD”  “MCY”  “PBCT” “WHG”  “CAH”  “JNJ”  “ACU”  “EMR”  “LMT”  “MSM”  “IBM”  “QCOM” “NUE”  “SON”  “OHI”

[22] “SKT”  “PPL”

 

#  remove “NUE”, “EMR”, “MCY”

finalPick = finalPick[which(finalPick %in% c(“NUE”, “EMR”, “MCY”))]

finalPick

 [1] “T”    “LEG”  “TGT”  “MO”   “VGR”  “ENB”  “EPD”  “PBCT” “WHG”  “CAH”

  “JNJ”  “ACU”  “LMT”  “MSM”  “IBM”  “QCOM” “SON”  “OHI”  “SKT”  “PPL”

 

 

   Now that we have the final 20 stocks to test in our portfolio, we will download adjusted prices from tiingo ( note an api key is required, obtained after free registration with site).  Once we download, we’ll save for future analysis. Examination of data reveals some missing prices.  We can either decide to ignore the NA values or substitute another ticker symbol. For example WHG appears to have some missing values. Log returns have been calculated on a monthly basis as shown.

> head(portfolioPrices)

            T.Close LEG.Close TGT.Close MO.Close VGR.Close ENB.Close EPD.Close PBCT.Close WHG.Close CAH.Close JNJ.Close ACU.Close LMT.Close MSM.Close

2000-01-03 17.30505 10.939917  25.76829 2.010728  1.176710  2.434495  1.495531   1.975643        NA  17.89039  28.87626 0.8546563  13.74908  8.971578

2000-01-04 16.77050 10.455987  24.78749 1.984271  1.116878  2.425814  1.466019   1.934735        NA  18.25738  28.25613 0.8111604  12.49917  9.144108

2000-01-05 16.03639 10.105909  24.58777 2.032065  1.136822  2.434495  1.515471   1.934735        NA  17.98214  27.53678 0.7630860  13.28036  8.281457

2000-01-06 15.96806  9.941167  23.53920 2.005608  1.096933  2.428294  1.515471   1.941243        NA  19.15281  28.00188 0.7630860  13.12412  8.626517

2000-01-07 15.96806 10.038983  22.82589 1.984271  1.127249  2.487824  1.505900   1.941243        NA  20.36753  29.18632 0.7153931  13.59284  8.799048

2000-01-10 16.03615 10.234614  23.71753 2.026944  1.121664  2.542392  1.466019   1.908703        NA  22.01895  29.98008 0.7630860  13.36161  8.322864

           IBM.Close QCOM.Close SON.Close OHI.Close SKT.Close PPL.Close

2000-01-03  78.95010   72.77157  11.83298  3.953161  1.864770  4.829492

2000-01-04  80.04545   62.82490  11.44587  3.801117  1.864770  4.696860

2000-01-05  79.30117   58.47323  11.04830  3.877139  1.870211  4.789492

2000-01-06  82.85407   54.30441  11.54003  3.895384  1.904677  4.922124

2000-01-07  82.32745   49.00196  11.86960  4.162983  1.989934  4.882124

2000-01-10  82.32745   59.09490  11.83298  3.819362  2.075191  4.907387

> tail(portfolioPrices)

            T.Close LEG.Close TGT.Close MO.Close VGR.Close ENB.Close EPD.Close PBCT.Close WHG.Close CAH.Close JNJ.Close ACU.Close LMT.Close MSM.Close

2019-01-02 28.02516     35.37     65.06    48.91      9.60     30.74     24.53      14.31     33.68     44.12   128.130  13.89414    258.36  75.28277

2019-01-03 29.02816     35.76     66.13    48.80      9.82     31.56     25.00      14.60     35.45     44.57   128.135  14.75756    262.32  74.57854

2019-01-04 29.46083     35.88     66.24    49.49     10.04     32.18     25.87      14.76     35.74     44.62   127.120  15.08507    261.92  75.40179

2019-01-07 30.21800     36.68     66.81    49.68     10.34     33.00     26.83      14.96     36.65     44.92   127.630  15.77000    266.00  77.27000

2019-01-08 30.78834     37.60     70.18    49.26     10.60     33.85     27.49      15.20     37.33     46.04   128.180  15.75000    271.13  77.20000

2019-01-09 30.88000     37.78     69.38    49.19     10.85     34.48     27.75      15.19     37.77     46.80   129.830  15.75000    270.13  76.77000

           IBM.Close QCOM.Close SON.Close OHI.Close SKT.Close PPL.Close

2019-01-02    112.01      56.20     52.48     33.88     19.97     28.25

2019-01-03    114.53      55.95     52.18     33.82     20.46     28.11

2019-01-04    114.91      56.50     52.20     34.79     20.57     27.80

2019-01-07    117.50      56.39     51.96     35.20     21.00     28.68

2019-01-08    119.66      56.71     52.40     35.41     21.29     28.95

2019-01-09    120.91      56.26     52.32     36.30     22.03     29.21

 

returnsLog = Return.calculate(portfolioPrices[endpoints(portfolioPrices), on=”months”], method=”log”)  

 

> returnsLog = Return.calculate(portfolioPrices[endpoints(portfolioPrices), on=“months”], method=“log”)     

> tail(returnsLog)

                 T.Close   LEG.Close    TGT.Close     MO.Close   VGR.Close    ENB.Close    EPD.Close  PBCT.Close    WHG.Close   CAH.Close   JNJ.Close

2018-08-31 -0.0059291795  0.04456183  0.076621465 -0.003069579 -0.15032658 -0.008308097 -0.019782009  0.01306497 -0.001739433  0.03732725  0.02403500

2018-09-28  0.0446830755 -0.02824911  0.009859073  0.051298986 -0.06248579 -0.059973227  0.006289329 -0.08578297 -0.097448408  0.03752257  0.02567064

2018-10-31 -0.0701033020 -0.17985884 -0.013668162  0.073802675 -0.03417866 -0.054990156 -0.026870487 -0.06412885 -0.163124599 -0.03702369  0.02078183

2018-11-30  0.0006514658  0.05838750 -0.188734467 -0.158306888 -0.03304181  0.069406669 -0.033650799  0.03863409 -0.111884826  0.06604850  0.03666203

2018-12-31 -0.0722311182 -0.06682891 -0.082383100 -0.113814451 -0.23996930 -0.057801501 -0.098323365 -0.13527934 -0.087791321 -0.21035043 -0.12564030

2019-01-09  0.0945530901  0.05076405  0.060147293  0.002442501  0.11410318  0.103493222  0.141024000  0.06107732  0.072175054  0.05535010  0.01279038

              ACU.Close    LMT.Close   MSM.Close   IBM.Close   QCOM.Close    SON.Close   OHI.Close   SKT.Close    PPL.Close

2018-08-31 -0.031359079 -0.002590781  0.02313133  0.01064917  0.063137336  0.011477261  0.11363130  0.01255247  0.031391182

2018-09-28  0.004146516  0.081818359  0.02466973  0.03665191  0.059297322 -0.007191689 -0.02295434 -0.06617534 -0.017703771

2018-10-31 -0.229604777 -0.160825691 -0.06060317 -0.26053345 -0.128132166  0.000180424  0.04708529  0.03492280  0.056927307

2018-11-30 -0.117716178  0.028772002  0.06643395  0.05606947 -0.077476195  0.031097144  0.12045683  0.02367229  0.004899569

2018-12-31 -0.073260115 -0.137362496 -0.13194517 -0.07092635 -0.008276884 -0.073065170 -0.06139261 -0.12729216 -0.065150875

2019-01-09  0.110491630  0.029986466  0.01168862  0.06474255 -0.015170515 -0.008564140  0.03020364  0.06227146  0.028826445

 

 

 

 

 

 Performance of the portfolio can be plotted via the PerformanceAnalytics package

   For comparison, the performance of a SP500 portfolio for the same period shows this:

 

 

 

      We will expand on stock selection scenarios in subsequent posts.  But as mentioned above and in earlier posts, acquiring the underlying data to perform such analysis is critical and takes a majority of effort required in financial modeling.   Of course, it is always possible to subscribe to a paid service that provide all kinds of data.  Here too though, we need to process the data such that it conforms to our particular requirements. For the moment, let us assume that all data we use will be obtained without charge from web-based sources.

     For example, we used the excellent (note what I did there!)  spreadsheets from this site that conveniently focused in on just the top rated dividend stocks.  However, data from the site really does not start till about 2010 and has undergone various formatting and other changes.  These constant variations mean that it is difficult to develop a standard few lines of code to capture information. Also, dividend history in terms of actual payouts does not also appear to be sufficient.

   To get at dividend yield at some point in time, we need adjusted price at beginning of period and second we need dividend payouts during period.   So if adjusted price in say Jan 2011 was $68.00 and we received an annual dividend of $3.00 – usually companies pay out quarterly dividends so this would mean $0.75 per quarter – yield is 3.00/68.00 which works out to 4.41%.  Price data in usable downloadable form can easily be obtained from yahoo, tiingo etc., Dividend payouts however are not that easily obtained at least on a free basis.   This site which focuses on financial planning using Microsft Excel does have a spreadsheet that provides some help in this regard, although only a limited number of tickers can be downloaded at a time.  One has to examine the underlying VBA code to get the details but once done, we can implement this R and remove any scale type restriction.  So, once dividend payout has been downloaded, all this can be stored in a database for convenient access later.  The R code to get this dividend payout history is provided below and should be self-explanatory, although it covers some arcane areas of http protocols.  Data is accessed from a Yahoo site, and as long as Yahoo keeps providing it, we can use it.

 ############    getting dividend payout history from 1980 onwards#install.packages(“QuantTools”)

require(RCurl)

require(stringr)

curl = RCurl::getCurlHandle( cookiejar = )

####   To get cookies AND the crumb to use subsequently

ckie = “https://finance.yahoo.com/lookup?s=bananas”

xyzM = RCurl::getURL( ckie, curl = curl )

crumbM = gsub( ‘^.*crumb”:”\\s*|”.*’, , xyzM )

### this is absolutely necessary, since it needs to be passed in subsequent request

crumbM = gsub( ‘^.*crumb”:”\\s*|”.*’, , xyzM )

crumbM

##[1] “pXcobcKSFyi”

###  save data on output file

fileout = “z:/FinancialData/DividendHist/batch_10Jan2019.csv”

cat(NULL, file=fileout)  

options(scipen=999)

### The url template “urlSub” to use in actually getting history data 

##   period1 & period2  are unix timestamps

###   note the crumb variable

urlSub = “https://query1.finance.yahoo.com/v7/finance/download/%TICKER%?period1=%START%&period2=%LAST%&interval=1d&events=dividend&crumb=%CRUMB%”

 

### to convert date to unix timestamp

startD = as.numeric(as.POSIXct(“1980-01-12”))

lastD = as.numeric(as.POSIXct(“2018-12-31”))

########################################################

#####    Function to get dividend history

#####    Just needs ticker as input

#####    Will use crumb and cookies from above

#####    to get all dividend payouts for dates

#####    Adds downloaded data to output file

########################################################

getDividendFromYahoo <- function(ticker) {

        print (ticker)

        urlDiv =  gsub(“%TICKER%”, ticker, gsub(“%START%”, startD, gsub( “%LAST%”, lastD, gsub(“%CRUMB%”, crumbM, urlSub))) )

        dat = RCurl::getURL(urlDiv, curl = curl)

        

        if ( length(grep(“No data found”, dat) == 1) > 0  )  return()

        divd = unlist(str_split(dat,\n))

        rem = c(“Date”, “Dividends”,“”)

        

        xyz=unlist(str_split(unlist(str_split(dat,\n) ), “,”)  )   ## bring data in clean form

        divd = matrix(xyz[!(xyz %in% rem)],  ncol=2, byrow=T)   ## remove first & other place in matrix

        colnames(divd) = c(“Date”, “DivPaid”)

        storage.mode(divd[,“DivPaid”]) = “numeric”

        ##divd[,”DivPaid”] = round(divd[,”DivPaid”],4)

        divd = cbind(ticker, divd)   ## identify ticker

        

        divd=divd[order(divd[,“Date”]),]    ### sort it in Date sequence

        write.table(divd, file=fileout, sep=“,”, quote=F, row.names=FALSE, col.names=FALSE, append=TRUE)

}

#######################################################

 

###  Can repeatedly acll above with any list of required tickers say our FinalPick

###  Output file contains data

finalPick = c(“T”, “LEG”,  “TGT”,  “MO”,   “VGR”,  “ENB”,  “EPD”,  “PBCT”, “WHG”,  “CAH”,

              “JNJ”,  “ACU”,  “LMT”,  “MSM”,  “IBM”,  “QCOM”, “SON”,  “OHI”,  “SKT”,  “PPL”)

 

abc = sapply(finalPick,  function(tkr) getDividendFromYahoo(tkr)  )

 

#### And that’s all there is to it

 

####   sample contents output file

 

OHI,19930127,0.5

OHI,19930427,0.5

OHI,19930727,0.5

OHI,19931027,0.54

OHI,19940127,0.54

OHI,19940426,0.54

OHI,19940727,0.54

OHI,19941027,0.58

OHI,19950127,0.59

OHI,19950426,0.59

OHI,19950731,0.59

 

Thanx for reading