Voting on Staggered Boards

Data step

# Connect to PostgreSQL database
library(RPostgreSQL)
drv <- dbDriver("PostgreSQL")
pg <- dbConnect(drv, dbname = "crsp")

# Pull in votes from ISS Voting Analytics 
rs <- dbGetQuery(pg, "DROP TABLE IF EXISTS destagger.votes")
rs <- dbGetQuery(pg, "
    CREATE TABLE destagger.votes AS
    SELECT * FROM issvoting.compvotes 
    WHERE itemdesc ILIKE '%declassify %' OR issagendaitemid IN ('M0215', 'S0201')
    ORDER BY issagendaitemid")

# Add PERMNO and GVKEY to the table (match to CUSIP)
rs <- dbGetQuery(pg, 
                 "ALTER TABLE destagger.votes ADD COLUMN gvkey character(6)")
rs <- dbGetQuery(pg,
                 "ALTER TABLE destagger.votes ADD COLUMN permno integer")
rs <- dbGetQuery(pg,
    "UPDATE destagger.votes AS a SET gvkey = 
        (SELECT gvkey FROM destagger.gvkeys AS b 
        WHERE b.cusip=a.cusip)")
rs <- dbGetQuery(pg,
    "UPDATE destagger.votes AS a SET permno = 
        (SELECT DISTINCT permno FROM crsp.stocknames AS b 
                 WHERE b.ncusip=substr(a.cusip,1,8))")

# Pull data into R
declassify <- dbGetQuery(pg, "SELECT * FROM destagger.votes")

# Get returns around meeting dates
dropbox.path <- path.expand("~/Dropbox/research/AGL/")
source(paste(dropbox.path,"Code/R/getEventReturns.R",sep=""))
ret_data <- getEventReturns(declassify$permno, declassify$meetingdate,
                            days.before=0, days.after=1)
## Initializing database connection...                   0.01 seconds
## Preparing data for upload to database...              0.00 seconds
## Writing list of PERMNOs and event dates to database...0.10 seconds
## Identifying relevant trading dates...                 0.05 seconds
## Compounding raw returns...                            0.61 seconds
## Compounding value-weighted market returns...          0.02 seconds
## Compounding size-decile market returns...             0.02 seconds
ret_data$row.names <- NULL
ret_data <- unique(ret_data) # Drop duplicates (multiple votes at a single meeting)

# Put return data back in the database
rs <- dbWriteTable(pg, c("destagger", "ret_data"), ret_data,
                   overwrite=TRUE, row.names=FALSE)

# Get data including a measure of shareholder support relative to "base"
# (e.g., shares outstanding) specified for each vote.
declassify <- dbGetQuery(pg, "SELECT *,
  CASE WHEN base='Outstanding' AND outstandingshares>0 THEN votedfor/outstandingshares
    WHEN base='F+A' AND votedfor+votedagainst>0
      THEN votedfor/(votedfor+votedagainst)
    WHEN base='F+A+AB' AND votedfor+votedagainst+votedabstain>0 
      THEN votedfor/(votedfor+votedagainst+votedabstain)
    END AS percent_for
  FROM destagger.votes AS a
  LEFT JOIN destagger.ret_data AS b
  USING (permno)
  WHERE a.meetingdate=b.event_date AND result IN ('Fail', 'Pass')")
dbDisconnect(pg)
## [1] TRUE

Some descriptive statistics

Does ISS ever vary in its recommendation? Rarely so; it almost always recommends shareholders vote to declassify.

with(declassify, table(mgtrec, issrec))
##          issrec
## mgtrec    Against Do Not Vote For NULL
##   Abstain       0           0   1    0
##   Against       4           6 392    1
##   For           0           4 333    0
##   None          0           0  24    0
subset(declassify, issrec == "Against")
##     permno                companyname     cusip ticker meetingdate
## 141  38682 R. R. Donnelley & Sons Co. 257867101    RRD  2007-05-24
## 220  86109       R.H. Donnelley Corp. 74955W307    RHD  2008-05-15
## 244  25419      Whirlpool Corporation 963320106    WHR  2009-04-21
## 592  28804     Alaska Air Group, Inc. 011659109    ALK  2006-05-16
##         sponsor issagendaitemid itemonagendaid
## 141 Shareholder           S0201        7033966
## 220 Shareholder           S0201        7352214
## 244      Unkown           S0201        7593518
## 592 Shareholder           S0201        6779448
##                              itemdesc ballotitemnumber  mgtrec  issrec
## 141 Declassify the Board of Directors                8 Against Against
## 220 Declassify the Board of Directors                6 Against Against
## 244 Declassify the Board of Directors                7 Against Against
## 592 Declassify the Board of Directors                9 Against Against
##     voterequirements   base outstandingshares votedfor votedagainst
## 141              0.5 F+A+AB         219077233 45589073    135747179
## 220              0.5 F+A+AB          68787618 11752947     35121280
## 244              0.5 F+A+AB          73556811 32009789     26751394
## 592              0.5 F+A+AB          35965862  5135023     19681598
##     votedabstain brokernonvotes result companyid meetingid
## 141      1829322       14384596   Fail        NA        NA
## 220        30269              0   Fail        NA        NA
## 244       302268        7036597   Pass    166363    493642
## 592      1003196        3711658   Fail        NA        NA
##                     agendageneraldesc mgmtrec voterequirement
## 141                                                        NA
## 220                                                        NA
## 244 Declassify the Board of Directors Against             0.5
## 592                                                        NA
##     outstandingshare brokernonvote voteresult   usource countryofinc
## 141               NA            NA                                  
## 220               NA            NA                                  
## 244         73556811       7036597       Pass 2009-2010             
## 592               NA            NA                                  
##     votedfor1yr votedfor2yr votedfor3yr    source  gvkey event_date
## 141          NA          NA          NA      2007 004040 2007-05-24
## 220          NA          NA          NA      2008 111631 2008-05-15
## 244          NA          NA          NA 2009-2010 011465 2009-04-21
## 592          NA          NA          NA 2005_2006 001230 2006-05-16
##           ret    ret_sz    ret_mkt percent_for
## 141 -0.005612 -0.001187 -0.0005972      0.2489
## 220 -0.022556 -0.035535 -0.0361717      0.2506
## 244  0.083476  0.071009  0.0665522      0.5420
## 592 -0.061137 -0.045813 -0.0430545      0.1989

There are 765 votes on declassification in the sample, with 18.43% being rejections by shareholders. Here they are by year.

## Descriptive statistics
declassify$year <- format(declassify$meetingdate, "%Y")
with(declassify, table(year, result))
##       result
## year   Fail Pass
##   2001   19   32
##   2002   18   33
##   2003   13   58
##   2004    8   70
##   2005   11   83
##   2006   10   99
##   2007   13   65
##   2008   20  108
##   2009   29   76

The votes are fairly well dispersed around the cutoff.
Note that these are only shareholder-sponsored votes.

# Produce a histogram of (SVT - allowable cap)
library(ggplot2)
qplot(percent_for - voterequirements, 
      data=subset(declassify,
                  percent_for <1 & percent_for > 0.01 & sponsor !="Management"), 
      binwidth=.01,
      main="Histogram: Shareholder support minus vote requirement",
      xlab="Shareholder support minus vote requirement")

plot of chunk unnamed-chunk-1

But there's virtually no response by the market to the result of the vote.

qplot(percent_for - voterequirements, ret_mkt,
      data=subset(declassify, 
                  percent_for <1 & percent_for > 0.01 & sponsor !="Management"),
      main="Market-adjusted Stock Returns: Days (0,1) Around Meeting Dates",
      xlab="Shareholder support minus vote requirement",
      color=issrec)

plot of chunk unnamed-chunk-2

Estimation and inference

source("http://iangow.me/~iangow/rd_opt_bw.R")
### (4) Calculate the treatment effect and standard errors.
rd_data <- subset(declassify, subset = percent_for < 1 & percent_for > 
    0.01 & sponsor != "Management", select = c(ret_mkt, percent_for, voterequirements))
rd_data$x <- rd_data$percent_for - rd_data$voterequirements
rd_data$y <- rd_data$ret_mkt

# First, get bandwidth
h <- with(rd_data, rd_opt_bw(y, x, c = 0))
X <- rd_data$percent_for - rd_data$voterequirements
c <- 0

## Weights based on triangular kernel
wgts <- with(rd_data, (1 - abs(X - c)/h) * (abs(X - c) <= h))
local.lm <- lm(y ~ (x >= c) * x, weights = wgts, data = rd_data)

rd.est <- coef(local.lm)[[2]]
sd.est <- sqrt(vcov(local.lm)[2, 2])

## Output
out <- c(h, rd.est, sd.est, rd.est/sd.est)
names(out) <- c("Optimal Bandwidth", "RD Estimate", "Standard Error", 
    "t-statistic")
print(out)
## Optimal Bandwidth       RD Estimate    Standard Error       t-statistic 
##          0.187689          0.002056          0.007844          0.262074 

A plot of the data with fitted values

# A function to estimate local linear regression around a point (x_i)
# using bandwidth h, the triangular kernel and limiting observations to
# those on the same side of the cutoff c. In some sense, this is purely
# visual, as the IK bandwidth is optimized for x \in [c-h, c+h] and other
# data are not involved.
ll <- function(x_i, y, x, h, c) {
    wgts <- (1 - abs(x - x_i)/h) * (abs(x - x_i) <= h) * (sign(x_i - c) == sign(x - 
        c) | x_i == c)
    lm.fitted <- lm(y ~ x, weights = wgts)
    if (sum(wgts > 0) > 10) {
        # Require 10 observations around x_i
        return(predict(lm.fitted, newdata = data.frame(x = x_i)))
    } else {
        return(NA)
    }
}

# Add the fitted value to the dataset
library(parallel)
rd_data$y_fitted <- with(rd_data, unlist(mclapply(X, ll, y, X, h, 
    c, mc.cores = 12)))

# Make a plot
library(ggplot2)
ggplot(rd_data, aes(x)) + geom_point(aes(y = y, color = x > c)) + 
    geom_line(aes(y = y_fitted, color = x > c))

plot of chunk plot

Fund voting behavior

While there is essentially no variation in how ISS recommends its clients vote on shareholder proposals to declassify boards, it seems there is quite a bit of variation in how mutual funds vote. Some funds mostly side with management, others go with ISS (though it is very difficult to argue causality without additional evidence), while others mix it up. It might be interesting to see whether the ones that mix it up do so in a way consistent with shareholder-value maximization, but inconsistent with the view of ISS (and Bebchuk) of a one-size-fits-all solution here. For example, if we looked at stock returns around the time of the vote, is there a relationship (say, using RDD) between the outcome of the vote, stock returns, and how these mutual funds voted. More specifically, if the “horses for courses” shareholders voted to reject the shareholder proposal, did the market react positively (negatively) to a failed (passed) proposal? (Note that it's not clear exactly how to measure how “horses for courses” shareholders voted, as it's unlikely that all such shareholders voted in the same way on each measure.)

library(ggplot2)
m <- qplot(votes_for/(votes_for + votes_against), votes_for + votes_against, 
    data = subset(fund.data, mgtrec %in% c("For", "Against")), color = mgtrec)
m + scale_y_log10()

plot of chunk analyze_fund_data