rm(list=ls())
library(RPostgres)
library(data.table)
library(getPass)
library(lfe)
library(stargazer)
library(ggplot2)
library(fst)
library(stringr)
library(stringi)
library(lubridate)
library(FinCal)
source("C:/Users/dratnadiwakara2/Documents/OneDrive - Louisiana State University/functions.R")
freddie <- list.files(pattern="*.fst",path = "C:/Users/dratnadiwakara2/Documents/OneDrive - Louisiana State University/Raw Data/Freddie/Acq",full.names = TRUE)
freddie = lapply(freddie, read_fst,as.data.table=T, columns = c("fico","dt_first_pi","ltv","dti","orig_upb","int_rt","prop_type","zipcode","id_loan","orig_loan_term","seller_name","loan_purpose","cnt_borr","cd_msa"))
freddie <- do.call(rbind , freddie)
freddie <- freddie[orig_loan_term==360 & prop_type=="SF" & loan_purpose=="P"]
freddie[,loanyr:=year(dt_first_pi)]
# freddie[,c("orig_loan_term","dt_first_pi","prop_type","cd_msa"):=list(NULL)]
freddie[,seller_name:= ifelse(seller_name %in% c("JPMORGAN CHASE BANK, NA","JPMORGAN CHASE BANK, NATIONAL ASSOCIATION","CHASE MANHATTAN MORTGAGE CORPORATION","CHASE HOME FINANCE LLC","CHASE HOME FINANCE","CHASE HOME FINANCE, LLC","JPMORGAN CHASE BANK, NATIONAL ASSOCIATION","JPMORGAN CHASE BANK, N.A."),"JPMORGAN CHASE BANK, NA",seller_name)]
freddie[,seller_name:= ifelse(seller_name %in% c("CITIMORTGAGE, INC.","ABN AMRO, NKA CITIMORTGAGE INC.","CITIMORTGAGE, INC."),"CITIMORTGAGE, INC.",seller_name)]
freddie[,seller_name:= ifelse(seller_name %in% c("WELLS FARGO HOME MORTGAGE, INC.","WELLS FARGO BANK, N.A."),"WELLS FARGO BANK, N.A.",seller_name)]
setnames(freddie,"zipcode","zip_code")
freddie[,bank:=ifelse(seller_name %in% c("JPMORGAN CHASE BANK, NA","WELLS FARGO BANK, N.A.","BANK OF AMERICA, N.A.","WASHINGTON MUTUAL BANK","WASHINGTON MUTUAL BANK, F.A."),1,0)]
freddie[,mtgco:=ifelse(seller_name %in% c("ABN AMRO MORTGAGE GROUP, INC.","COUNTRYWIDE HOME LOANS, INC.","NATIONAL CITY MORTGAGE CO. TAYLOR","QUICKEN LOANS INC.","CALIBER HOME LOANS, INC.","AMERIHOME MORTGAGE COMPANY, LLC","LOANDEPOT.COM, LLC"),"Top 4 Shadow Banks",ifelse(bank==1,"Top 4 Banks",NA))]
freddie[,pre:=ifelse(loanyr<2008,1,ifelse(loanyr>=2012,0,NA))]
freddie[,dtigt43:=ifelse(dti>43,1,0)]
No restrictions on debt-to-income ratio. The figure blow shows that the distribution is almost normal and there is no difference between the traditional banks and shadow banks before the financial crisis.
The sample consists of single-family 30 year mortgages that funded a purchase of a new home that were sold to Freddie Mac between 2000 and 2007.
## Freddie Data
ggplot() +
geom_density(data=freddie[pre==1 & dti<80 & !is.na(mtgco) & loan_purpose=="P"], aes(x=dti, group=factor(mtgco), fill=factor(mtgco)),alpha=0.5, adjust=2)+theme_minimal()+theme(legend.title = element_blank(),legend.position = "bottom")+labs(x="Debt-to-income",y="Density")
Ability-to-Repay/Qualified Mortgage Rule (ATR/QM Rule)
The congress mandated the Ability-to-Repay/Qualified Mortgage Rule (ATR/QM Rule) in the Dodd-Frank Act of 2010 and allowed the CFPB to work out the details. ATR rule prohibits lenders from originating loans unless the lender make a reasonable and good faith determination of the borrowers’ ability to repay. Failure to make such determination makes the lender liable to borrowers.
The details fleshed out by the CFPB in 2013 defained a ‘Qualified Mortgage’. If the lenders originate a ‘qualified mortgage’, that provides the lender with a presumption of compliance of the ATR rule and will not be liable. One of the key criteria for determining a qualified mortgage is the debt-to-income ratio. According to the rule, the mortgages with debt-to-income ratio is greater than 43% deemed non-QMs and lender doesn’t have a safe harbor from litigation.
The GSE Patch
The GSE patch is an exception to the general QM definition. It exempts mortgages from the 43% dti requirement if they are eligible for GSE purchase given all the other QM criteria are met. The GSE patch expires in January 2021.
The GSEs use less restrictive underwriting standards. They purchase mortgages that have DTI above 43% (max DTI of 50% after the financial crisis; no max before the crisis).
It seems that shadow banks took advantage of the GSE patch compared to the traditional banks. It is not clear to me as to why banks traditional banks didn’t take the advantage of this exception. The rule says the mortgages eligible for GSE purchase and it doesn’t say the mortgages have to be securitized. As we can see in the next section there is clearly a discontinuity in the mortgage approval at the 43% dti threshold for traditional banks.
The sample consists of single-family 30 year mortgages that funded a purchase of a new home that were sold to Freddie Mac between 2012 and 2018.
## Freddie Data
ggplot() +
geom_density(data=freddie[pre==0 & dti<70 & !is.na(mtgco) & loan_purpose=="P"], aes(x=dti, group=factor(mtgco), fill=factor(mtgco)),alpha=0.5, adjust=2)+theme_minimal()+theme(legend.title = element_blank(),legend.position = "bottom")+labs(x="Debt-to-income",y="Density")
regsample <- freddie[pre==0 & dti>43 & !is.na(mtgco) & loan_purpose=="P"]
regsample[,mean(fico),by=mtgco]
## mtgco V1
## 1: Top 4 Banks 748.9390
## 2: Top 4 Shadow Banks 744.0851
files = paste0("C:/Users/dratnadiwakara2/Documents/OneDrive - Louisiana State University/Raw Data/HMDA/Ultimate Panel Data/",c("2018.fst","2019.fst"))
panel = lapply(files, read_fst, as.data.table = TRUE)
panel <- do.call(rbind , panel)
setorder(panel,-asofdate)
panel <- panel[!duplicated(panel[,c("respondentid")])]
panel[,totalassets:=as.numeric(totalassets)]
panel <- panel[,c("respondentid","rssd","totalassets")]
fintech <- c(3914377,3870099,3881554,4437716,3958157,3870679,5134115)
bank <- c(3284070,480228,339858,112837,476810,3378018,277053,193247,598534,3202962,255574,723112,3072606,2712969,
4114567,146672,739560,258771,413208,852218, 1583845,2489805,212465,617677,694904,817824,238791,233031,
911973,443205,817477,619877,451965)
mtg <- c(3876998,4327938,4320416,4437873,3955754,3876112,3870606,3871751,3844465,4186573,3955923,3871519,3955651,
3861163,3954355,3247123,3966116,1569885,4325019,4438209,3842407,3955491,4186591,3873456,3897500,3877575,
2888798,3332935,3875179,5023545,3875692,1072246,583295,3870651,3913099,fintech)
bigbanks <- c(497404,112837,504713,852218,817824,480228,476810,451965)
files <- NULL
files <- c(files,list.files(pattern="*.fst",path = "C:/Users/dratnadiwakara2/Documents/OneDrive - Louisiana State University/Raw Data/HMDA/OO_NP/",full.names = TRUE))
files <- c(files,list.files(pattern="*.fst",path = "C:/Users/dratnadiwakara2/Documents/OneDrive - Louisiana State University/Raw Data/HMDA/OO_RF/",full.names = TRUE))
files <- files[substr(files,100,103) %in% c("2018","2019")] #c("2014","2015","2016","2017","2018")
hmda = lapply(files, read_fst, as.data.table = TRUE,
columns=c("asofdate","respondentid","agencycode","state","actiontaken","censustract","applicantrace1","applicantincome","purposeofloan","amountofloan","interest_rate","ratespread","loan_term","property_value","debt_to_income_ratio","applicant_age","denialreason1","denialreason2","conforming_loan_limit","combined_loan_to_value_ratio","typeofloan","typeofpurchaser","co_applicant_race_1"))
hmda <- do.call(rbind , hmda)
hmda[,approved:=ifelse(actiontaken %in% c(1,2),1,0)]
hmda[,nonwhite:=ifelse(applicantrace1==5,0,1)]
hmda[,tract_yr:=paste(censustract,asofdate)]
hmda[,interest_rate:=as.numeric(interest_rate)]
hmda[,loan_term:=as.numeric(loan_term)]
hmda[,newpurchase:=ifelse(purposeofloan==1,1,0)]
hmda[,joint:=ifelse(co_applicant_race_1 %in% c(7,8),0,1)]
setkey(hmda,censustract)
hmda[,combined_loan_to_value_ratio:=as.numeric(combined_loan_to_value_ratio)]
hmda[,applicant_age:=ifelse(applicant_age %in% c("<25"),20,
ifelse(applicant_age %in% c("25-34"),30,
ifelse(applicant_age %in% c("35-44"),40,
ifelse(applicant_age %in% c("45-54"),50,
ifelse(applicant_age %in% c("55-64"),60,
ifelse(applicant_age %in% c("65-74"),70,
ifelse(applicant_age %in% c(">74"),80,NA)))))))]
hmda[,dti:=ifelse(debt_to_income_ratio %in% c("<20%"),0.15,
ifelse(debt_to_income_ratio %in% c("20%-<30%"),0.25,
ifelse(debt_to_income_ratio %in% c("30%-<36%"),0.33,
ifelse(debt_to_income_ratio %in% c("50%-60%"),0.55,
ifelse(debt_to_income_ratio %in% c(">60%"),0.65,
ifelse(debt_to_income_ratio %in% c("Exempt"),NA,debt_to_income_ratio))))))]
hmda[,dti:=as.numeric(dti)]
hmda[,dti:=ifelse(dti>1,dti/100,dti)]
hmda[,race:=ifelse(applicantrace1=="5","white",ifelse(applicantrace1=="3","black","0ther"))]
hmda[,dtigt43:=ifelse(debt_to_income_ratio %in% as.character(44:49),1,ifelse(debt_to_income_ratio %in% as.character(37:43),0,NA))]
hmda[,denied:=ifelse(actiontaken %in% c(3,7,5),1,0)]
hmda <- hmda[amountofloan>0 & applicantincome>0]
hmda[,loantoincome:=amountofloan/applicantincome]
hmda <- merge(hmda,panel,by="respondentid")
hmda[,bank:=ifelse(rssd %in% bank,1,ifelse(rssd %in% mtg,0,NA))]
hmda[,countycode:=substr(censustract,1,5)]
hmda[,county_yr:=paste(countycode,asofdate)]
hmda[,sold:=ifelse(typeofpurchaser>0,1,0)]
hmda[,soldgse:=ifelse(typeofpurchaser %in% c(1,3),1,0)]
HMDA data for years 2018 and 2019. Debt-to-income ratio is only available for this sample period. Sample consists of mortgage applications to fund the purchase of an owner-occupied new home. The sample is restricted to conventional mortgages less than conforming loan limit. (~62% of mortgages originated)
Lenders are classified into banks and shadow banks following the Appendix A1 of Buchak,Matvos,Piskorski, and Seru (2018, JFE). These lenders account for ~ 40% of mortgages originated in 2018-2019.
regsample <- hmda[!is.na(bank) & !is.na(dtigt43) & purposeofloan %in% c(1) & actiontaken!=6 & conforming_loan_limit=="C" & typeofloan==1]
rdsum <- NULL
for(lt in 0:1) {
rds <- regsample[bank==lt,.(denied=mean(denied)),by=.(dti,bank)]
rds[,bank:=ifelse(bank==1,"Banks","Shadow banks")]
rds[,dtigt43:=ifelse(dti>0.43,1,0)]
r <- lm(denied~dti+dtigt43,data=rds)
rds[,preddenied:=predict(r,newdata = rds)]
rds[,meandenied:=mean(denied)]
rds[,preddenied:= preddenied-meandenied]
rds[,denied:= denied-meandenied]
rdsum <- rbind(rdsum,rds)
}
ggplot()+geom_point(data=rdsum,aes(x=dti,y=denied))+
geom_line(data=rdsum[dtigt43==0],aes(x=dti,y=preddenied),color="royalblue")+
geom_line(data=rdsum[dtigt43==1],aes(x=dti,y=preddenied),color="darkgreen")+
geom_vline(xintercept = .43)+facet_wrap(~bank)+theme_minimal()+labs(x="Debt-to-income",y="Mean-adjusted denial rate")
Local-linear specification when dti >= 37 and dti<=49.
r <- list()
r[[1]] <- felm(denied~dti+dtigt43+log(amountofloan)+log(applicantincome)+factor(race)+applicant_age|county_yr+rssd|0|countycode+rssd,data=regsample[bank==1 & !is.na(bank) & !is.na(dtigt43) & purposeofloan %in% c(1) & actiontaken!=6 & conforming_loan_limit=="C" & typeofloan==1])
r[[2]] <- felm(denied~dti+dtigt43+log(amountofloan)+log(applicantincome)+factor(race)+applicant_age|county_yr+rssd|0|countycode+rssd,data=regsample[bank==0 & !is.na(bank) & !is.na(dtigt43) & purposeofloan %in% c(1) & actiontaken!=6 & conforming_loan_limit=="C" & typeofloan==1])
.printtable(r,column.labels = c("Banks","Shadow banks"),lines = list(c("Fixed Effects","County*Year, Lender ","County*Year, Lender "),c("SE Cluster","County, Lender","County, Lender")))
##
## ============================================================
## Dependent variable:
## ---------------------------------------
## Banks Shadow banks
## (1) (2)
## ------------------------------------------------------------
## dti 0.373** 0.035*
## (0.138) (0.018)
## dtigt43 0.015** 0.001
## (0.007) (0.001)
## log(amountofloan) -0.086*** -0.008**
## (0.016) (0.004)
## log(applicantincome) 0.034*** -0.009**
## (0.010) (0.004)
## factor(race)black 0.029*** 0.027***
## (0.006) (0.003)
## factor(race)white -0.023*** -0.010***
## (0.003) (0.003)
## applicant_age -0.0003* 0.0002*
## (0.0002) (0.0001)
## ------------------------------------------------------------
## Fixed Effects County*Year, Lender County*Year, Lender
## SE Cluster County, Lender County, Lender
## Observations 296,327 667,754
## Adjusted R2 0.048 0.055
## ============================================================
## Note: *p<0.1; **p<0.05; ***p<0.01
##
regsample <- hmda[totalassets>0 & !is.na(dtigt43) & purposeofloan %in% c(1) & actiontaken<=3 & conforming_loan_limit=="C" & typeofloan==1]
regsample[,lt10bil:=ifelse(totalassets<2e6,"0. less than 2b",ifelse(totalassets<10e6,"1. 2 to 10b",ifelse(totalassets<250e6,"2. 10 to 250b","3. greater than 250b")))]
rdsum <- NULL
for(lt in unique(regsample$lt10bil)) {
rds <- regsample[lt10bil==lt,.(denied=mean(denied)),by=.(dti,lt10bil)]
# rds[,lt10bil:=ifelse(lt10bil==1,"Less than 10 bil","More than 10 bil")]
rds[,dtigt43:=ifelse(dti>0.43,1,0)]
r <- lm(denied~dti+dtigt43,data=rds)
rds[,preddenied:=predict(r,newdata = rds)]
rds[,meandenied:=mean(denied)]
rds[,preddenied:= preddenied-meandenied]
rds[,denied:= denied-meandenied]
rdsum <- rbind(rdsum,rds)
}
ggplot()+geom_point(data=rdsum,aes(x=dti,y=denied))+
geom_line(data=rdsum[dtigt43==0],aes(x=dti,y=preddenied),color="royalblue")+
geom_line(data=rdsum[dtigt43==1],aes(x=dti,y=preddenied),color="darkgreen")+
geom_vline(xintercept = .43)+facet_wrap(~lt10bil)+theme_minimal()+labs(x="Debt-to-income",y="Mean-adjusted denial rate")
Local-linear specification when dti >= 37 and dti<=49.
r <- list()
r[[1]] <- felm(denied~dti+dtigt43+log(amountofloan)+log(applicantincome)+factor(race)+applicant_age|county_yr+rssd|0|countycode+rssd,data=regsample[bank==1 & !is.na(bank) & !is.na(dtigt43) & purposeofloan %in% c(1) & actiontaken!=6 & conforming_loan_limit=="C" & typeofloan==1 & totalassets<2e6])
r[[2]] <- felm(denied~dti+dtigt43+log(amountofloan)+log(applicantincome)+factor(race)+applicant_age|county_yr+rssd|0|countycode+rssd,data=regsample[bank==1 & !is.na(bank) & !is.na(dtigt43) & purposeofloan %in% c(1) & actiontaken!=6 & conforming_loan_limit=="C" & typeofloan==1 & totalassets>2e6 & totalassets<10e6])
r[[3]] <- felm(denied~dti+dtigt43+log(amountofloan)+log(applicantincome)+factor(race)+applicant_age|county_yr+rssd|0|countycode+rssd,data=regsample[bank==1 & !is.na(bank) & !is.na(dtigt43) & purposeofloan %in% c(1) & actiontaken!=6 & conforming_loan_limit=="C" & typeofloan==1 & totalassets>10e6 & totalassets<250e6])
r[[4]] <- felm(denied~dti+dtigt43+log(amountofloan)+log(applicantincome)+factor(race)+applicant_age|county_yr+rssd|0|countycode+rssd,data=regsample[bank==1 & !is.na(bank) & !is.na(dtigt43) & purposeofloan %in% c(1) & actiontaken!=6 & conforming_loan_limit=="C" & typeofloan==1 & totalassets>250e6])
.printtable(r,column.labels = c("Less than 2 bil", "2 to 10 bil","10 to 250 bil","greater than 250 bil"),lines = list(c("Fixed Effects",rep("County*Year, Lender ",4)),c("SE Cluster",rep("County, Lender",4))))
##
## =====================================================================================================
## Dependent variable:
## --------------------------------------------------------------------------------
## Less than 2 bil 2 to 10 bil 10 to 250 bil greater than 250 bil
## (1) (2) (3) (4)
## -----------------------------------------------------------------------------------------------------
## dti 0.049 0.090 0.148** 0.516*
## (0.009) (0.131) (0.063) (0.218)
## dtigt43 0.016 0.009 0.001 0.021*
## (0.006) (0.006) (0.003) (0.011)
## log(amountofloan) -0.022 -0.031 -0.034** -0.115***
## (0.008) (0.016) (0.013) (0.017)
## log(applicantincome) 0.020 0.008 0.005 0.051***
## (0.007) (0.006) (0.009) (0.010)
## factor(race)black 0.054 0.024* 0.030*** 0.025**
## (0.009) (0.010) (0.006) (0.010)
## factor(race)white -0.031** -0.012** -0.025*** -0.025***
## (0.001) (0.004) (0.007) (0.003)
## applicant_age -0.0002 -0.0002 -0.0001 -0.0004
## (0.0001) (0.0003) (0.0002) (0.0002)
## -----------------------------------------------------------------------------------------------------
## Fixed Effects County*Year, Lender County*Year, Lender County*Year, Lender County*Year, Lender
## SE Cluster County, Lender County, Lender County, Lender County, Lender
## Observations 1,726 15,763 81,067 193,043
## Adjusted R2 0.090 0.049 0.028 0.065
## =====================================================================================================
## Note: *p<0.1; **p<0.05; ***p<0.01
##
hmda[!is.na(bank) & !is.na(dtigt43) & purposeofloan %in% c(1) & actiontaken<=3 & conforming_loan_limit=="C" & typeofloan==1,mean(denied),by=bank]
## bank V1
## 1: 1 0.09750922
## 2: 0 0.05599640
HMDA data for years 2018 and 2019. Debt-to-income ratio is only available for this sample period. Sample consists of mortgage applications to fund the purchase of an owner-occupied new home. The sample is restricted to conventional mortgages less than conforming loan limit.
regsample <- hmda[!is.na(bank) & !is.na(dtigt43) & purposeofloan %in% c(1) & actiontaken==1 & conforming_loan_limit=="C" & typeofloan==1]
rdsum <- NULL
for(lt in 0:1) {
rds <- regsample[bank==lt,.(soldtogse=mean(soldgse)),by=.(dti,bank)]
rds[,bank:=ifelse(bank==1,"Banks","Shadow banks")]
rds[,dtigt43:=ifelse(dti>0.43,1,0)]
r <- lm(soldtogse~dti+dtigt43,data=rds)
rds[,preddenied:=predict(r,newdata = rds)]
rds[,meandenied:=mean(soldtogse)]
rds[,preddenied:= preddenied-meandenied]
rds[,soldtogse:= soldtogse-meandenied]
rdsum <- rbind(rdsum,rds)
}
ggplot()+geom_point(data=rdsum,aes(x=dti,y=soldtogse))+
geom_line(data=rdsum[dtigt43==0],aes(x=dti,y=preddenied),color="royalblue")+
geom_line(data=rdsum[dtigt43==1],aes(x=dti,y=preddenied),color="darkgreen")+
geom_vline(xintercept = .43)+facet_wrap(~bank)+theme_minimal()+labs(x="Debt-to-income",y="Mean-adjusted securitization rate")
Local-linear specification when dti >= 37 and dti<=49.
r <- list()
r[[1]] <- felm(soldgse~dti+dtigt43+log(amountofloan)+log(applicantincome)+factor(race)+applicant_age|county_yr+rssd|0|countycode+rssd,data=regsample[bank==1])
r[[2]] <- felm(soldgse~dti+dtigt43+log(amountofloan)+log(applicantincome)+factor(race)+applicant_age|county_yr+rssd|0|countycode+rssd,data=regsample[bank==0 ])
.printtable(r,column.labels = c("Banks","Shadow banks"),lines = list(c("Fixed Effects","County*Year, Lender ","County*Year, Lender "),c("SE Cluster","County, Lender","County, Lender")))
##
## ============================================================
## Dependent variable:
## ---------------------------------------
## Banks Shadow banks
## (1) (2)
## ------------------------------------------------------------
## dti 0.196 -0.052
## (0.137) (0.039)
## dtigt43 0.035*** 0.010***
## (0.010) (0.003)
## log(amountofloan) 0.114*** 0.150***
## (0.019) (0.018)
## log(applicantincome) -0.100*** -0.067***
## (0.017) (0.013)
## factor(race)black -0.018 -0.040***
## (0.015) (0.011)
## factor(race)white 0.009** -0.0001
## (0.004) (0.002)
## applicant_age -0.001* 0.001***
## (0.001) (0.0003)
## ------------------------------------------------------------
## Fixed Effects County*Year, Lender County*Year, Lender
## SE Cluster County, Lender County, Lender
## Observations 262,883 616,897
## Adjusted R2 0.337 0.385
## ============================================================
## Note: *p<0.1; **p<0.05; ***p<0.01
##
r <- list()
r[[1]] <- felm(soldgse~dti+dtigt43+log(amountofloan)+log(applicantincome)+factor(race)+applicant_age|county_yr+rssd|0|countycode+rssd,data=regsample[bank==1 & totalassets<2e6])
r[[2]] <- felm(soldgse~dti+dtigt43+log(amountofloan)+log(applicantincome)+factor(race)+applicant_age|county_yr+rssd|0|countycode+rssd,data=regsample[bank==1 & totalassets>2e6 & totalassets<10e6])
r[[3]] <- felm(soldgse~dti+dtigt43+log(amountofloan)+log(applicantincome)+factor(race)+applicant_age|county_yr+rssd|0|countycode+rssd,data=regsample[bank==1 & totalassets>10e6 & totalassets<250e6])
r[[4]] <- felm(soldgse~dti+dtigt43+log(amountofloan)+log(applicantincome)+factor(race)+applicant_age|county_yr+rssd|0|countycode+rssd,data=regsample[bank==1 & totalassets>250e6])
.printtable(r,column.labels = c("Less than 2 bil", "2 to 10 bil","10 to 250 bil","greater than 250 bil"),lines = list(c("Fixed Effects",rep("County*Year, Lender ",4)),c("SE Cluster",rep("County, Lender",4))))
##
## =====================================================================================================
## Dependent variable:
## --------------------------------------------------------------------------------
## Less than 2 bil 2 to 10 bil 10 to 250 bil greater than 250 bil
## (1) (2) (3) (4)
## -----------------------------------------------------------------------------------------------------
## dti -0.202 0.101 0.146 0.218
## (0.417) (0.250) (0.200) (0.184)
## dtigt43 0.037 0.019* 0.053* 0.029*
## (0.043) (0.008) (0.025) (0.012)
## log(amountofloan) -0.009 0.124 0.123*** 0.108**
## (0.012) (0.072) (0.029) (0.031)
## log(applicantincome) -0.027*** -0.177** -0.077** -0.104***
## (0.004) (0.047) (0.024) (0.024)
## factor(race)black -0.061 -0.031 -0.035** -0.005
## (0.029) (0.022) (0.013) (0.020)
## factor(race)white -0.013 -0.001 0.016** 0.008
## (0.017) (0.011) (0.005) (0.005)
## applicant_age -0.0004 -0.0001 0.001 -0.002*
## (0.001) (0.001) (0.001) (0.001)
## -----------------------------------------------------------------------------------------------------
## Fixed Effects County*Year, Lender County*Year, Lender County*Year, Lender County*Year, Lender
## SE Cluster County, Lender County, Lender County, Lender County, Lender
## Observations 5,984 15,011 71,437 170,451
## Adjusted R2 0.202 0.197 0.455 0.307
## =====================================================================================================
## Note: *p<0.1; **p<0.05; ***p<0.01
##
hmda[!is.na(bank) & !is.na(dtigt43) & purposeofloan %in% c(1) & actiontaken==1 & conforming_loan_limit=="C" & typeofloan==1,mean(soldgse),by=bank]
## bank V1
## 1: 1 0.6009890
## 2: 0 0.7207392
bunchingfrac <- freddie[loanyr %in% 2000:2003,.(dtigt43_mn=mean(dtigt43,na.rm=T)),by=cd_msa]
ggplot(bunchingfrac)+geom_density(aes(x=dtigt43_mn*100))
files = paste0("C:/Users/dratnadiwakara2/Documents/OneDrive - Louisiana State University/Raw Data/HMDA/Ultimate Panel Data/",as.character(2004:2019),".fst")
panel = lapply(files, read_fst, as.data.table = TRUE,columns=c("asofdate","respondentid","reportername","rssd","agencycode"))
panel <- do.call(rbind , panel)
panel[,rssd:=as.numeric(rssd)]
panel[,asofdate:=as.integer(asofdate)]
panel[,hmda_id:=ifelse(asofdate<=2017,paste(agencycode,respondentid,sep="-"),respondentid)]
panel <- panel[,c("hmda_id","asofdate","rssd","agencycode")]
names(panel) <- c("hmda_id","asofdate","rssd","agencycode2")
panel <- panel[!duplicated(panel)]
setkey(panel,hmda_id,asofdate)
bigbankhmdaid <- unique(panel[rssd %in% bank]$hmda_id)
mtghmdaid <- unique(panel[rssd %in% mtg]$hmda_id)
files <- NULL
files <- c(files,list.files(pattern="*.fst",path = "C:/Users/dratnadiwakara2/Documents/OneDrive - Louisiana State University/Raw Data/HMDA/OO_NP/",full.names = TRUE))
files <- files[substr(files,100,103) %in% as.character(2004:2019)]
hmda = lapply(files, read_fst, as.data.table = TRUE,
columns=c("asofdate","respondentid","actiontaken","censustract","typeofloan","amountofloan",
"applicantincome","typeofpurchaser","agencycode","applicantrace1"))
hmda <- do.call(rbind , hmda)
hmda <- hmda[nchar(censustract)==11]
hmda[,countycode:=substr(censustract,1,5)]
hmda[,amountofloan:=as.numeric(amountofloan)]
hmda[,applicantincome:=as.numeric(applicantincome)]
hmda[,typeofloan:=as.numeric(typeofloan)]
hmda <- hmda[amountofloan>0 & applicantincome>0] # & typeofloan==1
hmda[,typeofpurchaser:=as.numeric(typeofpurchaser)]
hmda[,actiontaken:=as.numeric(actiontaken)]
hmda[,hmda_id:=ifelse(asofdate<=2017,paste(agencycode,respondentid,sep="-"),respondentid)]
setkey(hmda,hmda_id,asofdate)
hmda <- merge(hmda,panel,by=c("hmda_id","asofdate"))
hmda[,bank:=ifelse(hmda_id %in% bigbankhmdaid,1, ifelse(hmda_id %in% mtghmdaid,0,NA))]
hmdarrssd <- hmda[,c("hmda_id","rssd")]
hmdarrssd <- hmdarrssd[rssd>0]
hmdarrssd <- hmdarrssd[!duplicated(hmdarrssd)]
names(hmdarrssd) <- c("hmda_id","rssd2")
hmdarrssd <- hmdarrssd[!duplicated(hmdarrssd[,c("hmda_id")])]
hmda <- merge(hmda,hmdarrssd,by="hmda_id",all.x=T)
# setkey(hmdar,censustract)
tractzip<-fread("C:/Users/dratnadiwakara2/Documents/OneDrive - Louisiana State University/Raw Data/Crosswalk Files/TRACT_ZIP_032016.csv")
tractzip[,TRACT:=as.character(TRACT)]
tractzip[,TRACT:=str_pad(TRACT, width=11, side="left", pad="0")]
setorder(tractzip,TRACT,-RES_RATIO)
tractzip <- tractzip[!duplicated(tractzip$TRACT),c("TRACT","ZIP")]
hmda <- merge(hmda,tractzip,by.x="censustract",by.y="TRACT",all.x=T)
hmda[,zip3digit:=floor(ZIP/100)*100]
bunchingfreddie <- fread("C:/Users/dratnadiwakara2/Documents/OneDrive - Louisiana State University/Projects/Exploring/freddie_bunchingfrac.csv")
bunchingfreddie[,V1:=NULL]
hmda <- merge(hmda,bunchingfreddie,by.x="zip3digit",by.y="zip_code")
hmda[,county_yr:=paste(countycode,asofdate)]
hmda[,denied:=ifelse(actiontaken %in% c(3,7,5),1,0)]
hmda[,dtigt43:=dtigt43+0.0001]
hmda[,race:=ifelse(applicantrace1=="5","white",ifelse(applicantrace1=="3","black","0ther"))]
hmda[,incomelt50k:=ifelse(applicantincome<50,1,0)]
hmda[,incomelt70k:=ifelse(applicantincome<70,1,0)]
hmda[,conventional:=ifelse(typeofloan==1,1,0)]
dticount<- read_fst("C:/Users/dratnadiwakara2/Documents/OneDrive - Louisiana State University/Projects/Exploring/dticount_hmda_1819.fst",as.data.table = T)
hmda <- merge(hmda,dticount,by="censustract",all.x=T)
hmda[,nodti4043:=nodti4043+0.0001]
hmda[,bigbank:=ifelse(rssd2 %in% bigbanks,1,ifelse(bank==0,0,NA))]
This section shows that banks, particularly big banks with assets over 250 billion, were more likely to deny mortgage applications in areas where the DTI ratios are likely to be higher.
Unlike for years 2018 and 2019, HMDA data does not have the debt-to-income ratio for prior years. We identify the areas where mortgage applicants are likely to have a higher debt-to-income ratio is three ways.
1. Based on Freddie Data
Freddie data gives us the 3-digit zipcode for each mortgage. We use the fraction of mortgages with debt-to-income ratios greater than 43% in years prior to DF Act (2006-2009) as a measure of likelihood that dti ratio would be binding. The figure below shows the distribution of this measure, dtigt43.
ggplot(bunchingfreddie)+geom_density(aes(x=dtigt43,y=..density..))+theme_minimal()
zhvi <- readRDS("C:/Users/dratnadiwakara2/Documents/OneDrive - Louisiana State University/Raw Data/Zillow Research Data/Zip_Zhvi_SingleFamilyResidence.rds")
zhvi <- as.data.table(zhvi)
zhvi <- zhvi[month>=as.Date("2010-01-01") & month <= as.Date("2011-01-01")]
zhvi[,zipcode:=floor(as.numeric(zipcode)/100)*100]
zhvi <- zhvi[,.(zhvi=mean(zhvi,na.rm=T)),by=zipcode]
bunchingfreddie <- merge(bunchingfreddie,zhvi,by.x="zip_code",by.y="zipcode")
ggplot(bunchingfreddie[zhvi<400000],aes(x=zhvi,y=dtigt43))+geom_point()+geom_smooth(method="lm")+theme_minimal()
irs <- read_fst("C:/Users/dratnadiwakara2/Documents/OneDrive - Louisiana State University/Raw Data/IRS SOI/zipcode2010.csv.fst",as.data.table = T)
irs[,zipcode:=floor(as.numeric(zipcode)/100)*100]
irs <- irs[,.(agi=mean(agi)),by=zipcode]
bunchingfreddie <- merge(bunchingfreddie,irs,by.x="zip_code",by.y="zipcode")
ggplot(bunchingfreddie[zhvi<400000],aes(x=zhvi,y=agi))+geom_point()+geom_smooth(method="lm")+theme_minimal()
r <- felm(dtigt43~log(zhvi)+log(agi),data=bunchingfreddie)
.printtable(r)
##
## ========================================
## Dependent variable:
## ---------------------------
## ----------------------------------------
## log(zhvi) 0.075***
## (0.004)
## log(agi) -0.108***
## (0.009)
## Constant 0.530***
## (0.063)
## ----------------------------------------
##
## Observations 846
## Adjusted R2 0.270
## ========================================
## Note: *p<0.1; **p<0.05; ***p<0.01
##
2. Based on 2018 and 2019 HMDA Data
Using 2018 and 2019 HMDA data we estimate the level of bunching at 43% DTI at census tract level. HMDA data provides exact DTI if the DTI is greater than 37 and less than 49. Other values are grouped in to categories. Therefore the usual bunching estimator as in Chetty, Friedman, Olsen, and Pistaferri (2011) cannot be calculated. Alternatively, we approximate the level of bunching by calculating the fraction of mortgages with DTI between 40 and 43 as a fraction of mortgages with DTI less than 43. The figure below shows the distribution of this measure, nodti4043.
ggplot(dticount)+geom_density(aes(x=nodti4043,y=..density..))+theme_minimal()
3. Based on 2018 and 2019 HMDA Data
Loan to income ratio of each mortgage applications as a proxy for debt-to-income ratio.
This section shows that big banks (> 250 b in assets) are more likely to deny mortgage applications in areas where DTI caps are likely to bind relative to the shadow banks. The big banks account for the vast majority of bank lending in the mortgage market when compared with smaller banks.
\[ denied = \Sigma_{t} bigbank \times dtigt43 \times t + Controls+ County\times Yr\text{ }FE+Lender\text{ }FE \] Standard errors are clustered at county level.
r <- felm(denied~bigbank*dtigt43*factor(asofdate)+log(applicantincome)+factor(race)+conventional|county_yr+rssd2|0|countycode,data=hmda[actiontaken<=3 & asofdate>=2005 & typeofloan<=2])
.coef_plot_1reg_line(r,"bigbank:dtigt43:factor(asofdate)",2005)
\[ denied = \Sigma_{t} bigbank \times nodti4043 \times t + Controls+ County\times Yr\text{ }FE+Lender\text{ }FE \] Standard errors are clustered at county level.
r <- felm(denied~bigbank*nodti4043*factor(asofdate)+log(applicantincome)+factor(race)+conventional|county_yr+rssd2|0|countycode,data=hmda[actiontaken<=3 & asofdate>=2005 & typeofloan<=2])
.coef_plot_1reg_line(r,"bigbank:nodti4043:factor(asofdate)",2005)
In general mortgage applications by lower-income applicants (income less than 50k) are more likely to be denied in areas where DTI restrictions are more likely to bind.
\[ denied = \Sigma_{t} I(income <50k) \times \times dtigt43 \times t + Controls+ County\times Yr\text{ }FE+Lender\text{ }FE \]
r <- felm(denied~incomelt50k*dtigt43*factor(asofdate)+log(applicantincome)+factor(race)+conventional|county_yr+rssd2|0|countycode,data=hmda[actiontaken<=3 & asofdate>=2005 & typeofloan<=2])
.coef_plot_1reg_line(r,"incomelt50k:dtigt43:factor(asofdate)",2005)
\[ denied = \Sigma_{t} I(income <50k) \times \times nodti4043 \times t + Controls+ County\times Yr\text{ }FE+Lender\text{ }FE \]
r <- felm(denied~incomelt50k*nodti4043*factor(asofdate)+log(applicantincome)+factor(race)+conventional|county_yr+rssd2|0|countycode,data=hmda[actiontaken<=3 & asofdate>=2005 & typeofloan<=2])
.coef_plot_1reg_line(r,"incomelt50k:nodti4043:factor(asofdate)",2005)
\[ denied = \Sigma_{t} bigbanks \times I(income <50k) \times \times dtigt43 \times t + Controls+ County\times Yr\text{ }FE+Lender\text{ }FE \]
r <- felm(denied~bigbank*incomelt50k*dtigt43*factor(asofdate)+log(applicantincome)+factor(race)|county_yr+rssd2|0|countycode,data=hmda[actiontaken<=3 & asofdate>=2005])
.coef_plot_1reg_line(r,"bigbank:incomelt50k:dtigt43:factor(asofdate)",2005)
r <- felm(denied~bigbank*incomelt50k*nodti4043*factor(asofdate)+log(amountofloan)+factor(race)|county_yr+rssd2|0|countycode,data=hmda[actiontaken<=3 & asofdate>=2005])
.coef_plot_1reg_line(r,"bigbank:incomelt50k:nodti4043:factor(asofdate)",2005)