# Connect to PostgreSQL database
library(RPostgreSQL)
drv <- dbDriver("PostgreSQL")
pg <- dbConnect(drv, dbname = "crsp")
rs <- dbGetQuery(pg, "SET work_mem='20GB'")
# Get data including a measure of shareholder support relative to "base"
# (e.g., shares outstanding) specified for each vote.
declassify <- dbGetQuery(pg, "
DROP TABLE IF EXISTS destagger.votes; --
CREATE TABLE destagger.votes AS
WITH
gvkeys AS (
SELECT DISTINCT gvkey, cusip
FROM comp.secm),
permnos AS (
SELECT DISTINCT permno, ncusip
FROM crsp.stocknames),
relevant_votes AS (
SELECT DISTINCT instid, itemonagendaid
FROM issvoting.fund_votes
WHERE mgtrec != 'For' AND (itemdesc ILIKE '%declassify %' OR
issagendaitemid IN ('M0215', 'S0201'))),
fund_num_votes AS (
SELECT instid, count(*) AS num_votes
FROM relevant_votes
GROUP BY instid),
fund_rank AS (
SELECT instid, num_votes,
rank() OVER (ORDER BY num_votes DESC) AS fund_rank
FROM fund_num_votes),
fund_rank_against AS (
SELECT itemonagendaid, min(fund_rank) AS rank_fund_against
FROM issvoting.fund_votes AS a
INNER JOIN fund_rank AS b
USING (instid)
WHERE fundvote='Against'
GROUP BY itemonagendaid),
votes AS (
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 issvoting.compvotes
LEFT JOIN fund_rank_against
USING (itemonagendaid)
WHERE mgtrec != 'For' AND (itemdesc ILIKE '%declassify %' OR
issagendaitemid IN ('M0215', 'S0201'))
ORDER BY issagendaitemid),
votes_w_gvkeys AS (
SELECT a.*, b.gvkey
FROM votes AS a
LEFT JOIN gvkeys AS b
ON a.cusip=b.cusip)
SELECT a.*, b.permno
FROM votes_w_gvkeys AS a
LEFT JOIN permnos AS b
ON b.ncusip=substr(a.cusip,1,8)")
dbDisconnect(pg)
## [1] TRUE
library(RPostgreSQL)
drv <- dbDriver("PostgreSQL")
pg <- dbConnect(drv, dbname = "crsp")
# Pull data into R
declassify <- dbGetQuery(pg, "SELECT * FROM destagger.votes")
# Get returns around meeting dates
dropbox.path <- path.expand("~/Dropbox/research/activism/")
source(paste(dropbox.path,"code/getEventReturnsDaily.R",sep=""))
ret_data <- getEventReturns(declassify$permno, declassify$meetingdate,
days.before=0, days.after=1)
# Drop duplicates (multiple votes at a single meeting)
ret_data$row.names <- NULL
ret_data <- unique(ret_data)
# Put return data back in the database
rs <- dbWriteTable(pg, c("destagger", "ret_data"), ret_data,
overwrite=TRUE, row.names=FALSE)
declassify <- dbGetQuery(pg, "
SELECT *
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
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 387 1
## None 0 0 24 0
# subset(declassify, issrec=='Against')
There are 423 votes on declassification in the sample, with 27.66% 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 17 26
## 2002 16 28
## 2003 13 33
## 2004 7 31
## 2005 6 33
## 2006 8 44
## 2007 11 22
## 2008 16 51
## 2009 23 38
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 - voterequirement,
data=subset(declassify,
percent_for <1 & percent_for > 0.01),
binwidth=.01,
main="Histogram: Shareholder support minus vote requirement",
xlab="Shareholder support minus vote requirement")
But there's virtually no response by the market to the result of the vote.
qplot(percent_for - voterequirement, ret_mkt,
data=subset(declassify,
percent_for <1 & percent_for > 0.01 & issrec!="NULL"),
main="Market-adjusted Stock Returns: Days (0,1) Around Meeting Dates",
xlab="Shareholder support minus vote requirement")
qplot(percent_for - voterequirement, ret_mkt,
data=subset(declassify,
percent_for <1 & percent_for > 0.01),
main="Market-adjusted Stock Returns: Days (0,1) Around Meeting Dates",
xlab="Shareholder support minus vote requirement",
color=mgtrec)
source("~/Dropbox/research/rdd/rd_opt_bw.R")
### source('http://iangow.me/~iangow/rd_opt_bw.R') (4) Calculate the
### treatment effect and standard errors.
table(declassify$rank_fund_against)
##
## 1 3 5 6 7 8 9 11 12 14 18 21 26 27 54 60 79 82
## 4 1 1 15 4 47 107 1 1 3 3 4 2 1 2 1 4 3
## 85 86 90 95 97 104 148 165 190
## 1 1 2 8 52 6 2 1 2
rd_data <- subset(declassify, subset = percent_for < 1 & percent_for > 0.01,
select = c(ret_mkt, percent_for, voterequirement))
rd_data$fundvote <- 1
# with(rd_data, ifelse(is.na(top_fund_against), 1,
# ifelse(top_fund_against, -1, 1)))
table(rd_data$fundvote)
##
## 1
## 423
rd_data$x <- (rd_data$percent_for - rd_data$voterequirement) * rd_data$fundvote
rd_data$y <- rd_data$ret_mkt
# First, get bandwidth
h <- with(rd_data, rd_opt_bw(y, x, c = 0))
X <- rd_data$x
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.182897 -0.002490 0.007823 -0.318217
# 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 values to the dataset
library(parallel)
rd_data$y_fitted <- with(rd_data, unlist(mclapply(X, ll, y, X, h, c, mc.cores = 8)))
# 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))
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.)
## institutionname percent_for num_votes
## 1 Fidelity Management & Research 0.98452 326
## 2 Northern Trust Global Investments 0.88660 295
## 3 Vanguard Group, Inc. 0.99303 289
## 4 TIAA-CREF Asset Management LLC 0.99262 276
## 5 T. Rowe Price Associates, Inc. (MD) 0.98540 276
## 6 Jackson National Asset Management, LLC 0.97368 270
## 7 Rodney Square Management Corporation 0.03419 265
## 8 Rydex Investments 0.42213 263
## 9 BlackRock Advisors, Inc. 0.86454 255
## 10 Barclays Global Investors NA (CA) 0.98795 249
## 11 EQ ADVISORS TRUST 0.85000 247
## 12 John Hancock Funds, LLC 0.79741 246
## 13 Charles Schwab Investment Management, Inc. 0.97021 238
## 14 Prudential Financial 0.91204 226
## 15 AST Investment Services, Inc. 0.85581 222
## 16 AIG SunAmerica Asset Management Corp. 0.94737 217
## 17 IQ Investment Advisors LLC 0.98104 217
## 18 RiverSource Investments LLC 1.00000 215
## 19 Transamerica Funds 0.84135 212
## 20 Variable Annuity Life Insurance Company 0.97525 205
## 21 State Street Global Advisors 0.71144 203
## 22 Munder Capital Management 0.97030 202
## 23 Wells Fargo Funds Management, LLC 0.93000 201
## 24 Dimensional Fund Advisors, Inc. 0.98964 199
## 25 Federated Investors, Inc. (Asset Management) 0.14136 194
## 26 Summit Investment Partners, Inc 0.35135 192
## 27 Russell Investment Group 0.98396 189
## 28 Northwestern Mutual Funds 0.96703 183
## 29 American Century Investment Management, Inc. 0.98876 179
## 30 Nationwide Fund Advisors 0.94167 124
## 31 Nationwide Fund<a0>Advisors 0.82051 78
## 32 Nationwide Fund Advisors 0.91781 74
## 33 Charles Schwab Investment Management, In 0.97727 45
## 34 American Century Investment Management, 1.00000 30
## 35 Federated Investors, Inc. (Asset Managem 0.00000 13