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)]

1 Debt-to-Income before the financial crisis of 2008

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")

2 Debt-to-Income after the financial crisis of 2008

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.

2.1 Density

## 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")

2.2 Characteristics of mortgages with DTI>43

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)]

3 Denial Rate Discontinuity at DTI 43, Conforming Loans

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.

3.1 Regression Discontinuity Figure

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")

3.2 Regression Discontinuity Table

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
## 

3.3 Regression Discontinuity Banks By Asset Size

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")

3.4 Regression Discontinuity Table by Asset Size

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
## 

3.5 Denial Rate

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

4 Securitization Discontinuity at 43%, Conforming Loans

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.

4.1 Regression Discontinuity Figure

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")

4.2 Regression Discontinuity Table

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
## 

4.3 Regression Discontinuity by Bank Asset Size Table

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
## 

4.4 Securitization Rate

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))]

5 Market Share by Types of Lenders

Big banks: 8 banks with assets over 250 billion
Shadow banks: Top 50 shadow banks from Buchak et al (2018)

countlendertype <- hmda[actiontaken==1 ,.N,by=.(asofdate,bigbank)]
countlendertype[,bigbank:=ifelse(is.na(bigbank),"22",bigbank)]
countlendertype <- data.table(countlendertype)
countlendertype <- dcast(countlendertype,asofdate~bigbank)
names(countlendertype) <- c("year","shadow","bigbank","other")
countlendertype[,'Big bank share':=bigbank/(shadow+bigbank+other)]
countlendertype[,'Shadow bank share':=shadow/(shadow+bigbank+other)]
countlendertype <- melt(countlendertype[,c("year","Big bank share","Shadow bank share")],id.vars = c("year"))

ggplot(countlendertype)+geom_line(aes(x=year,y=value*100,color=variable),size=1)+theme_minimal()+theme(legend.position = "bottom",legend.title = element_blank())+labs(x="",y="Market share (%)")

6 Mortgage denial rate

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.

6.1 Is DTI cap binding?

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.

6.1.1 Density

ggplot(bunchingfreddie)+geom_density(aes(x=dtigt43,y=..density..))+theme_minimal()

6.1.2 Corrrelation with the Houseprice

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()

6.1.3 Correlation with Income

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()

6.1.4 Correlation with Income and Houseprice

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.

6.2 Big Banks are more likely to deny mortgage applications

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.

6.2.1 Using the freddie measure

\[ 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)

6.2.2 Using the HMDA measure

\[ 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)

6.3 Lower-income applicant’s mortgages are more likely to be denied

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.

6.3.1 Using the freddie measure

\[ 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)

6.3.2 Using the HMDA measure

\[ 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)

6.4 Big banks were more likely to deny mortgages for lower-income applicants

6.4.1 Using the freddie measure

\[ 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)

6.4.2 Using the HMDA measure

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)

7 Market Share

The figure below shows that in areas where DTI caps are more likely to bind, the market share of shadow banks increased compared to the market share of big banks. This is based on a lender-zipcode-year panel.

7.0.1 Using the freddie measure

\[ noofloans = \Sigma_{t} shadow\text{ }bank \times dtigt43 \times t + Controls+ County\times Yr\text{ }FE+Lender\text{ }FE \]

noloansbylender <- hmda[ !is.na(bigbank) & asofdate>=2005 & actiontaken %in% c(1) ,.N,by=.(zip3digit,asofdate,rssd2)]

noloansbylender[,shadow:=ifelse(rssd2 %in% bigbanks,0,1)]

noloansbylender <- merge(noloansbylender,bunchingfreddie,by.x="zip3digit",by.y="zip_code")
noloansbylender[,tract_yr:=paste(zip3digit,asofdate)]
noloansbylender[,dtigt43:=dtigt43+0.0001]


r<- felm(N~shadow*dtigt43*factor(asofdate)|rssd2+tract_yr|0|zip3digit,data=noloansbylender[asofdate != 201])

.coef_plot_1reg_line(r,"shadow:dtigt43:factor(asofdate)",2005)

7.0.2 Using the freddie measure

\[ noofloans = \Sigma_{t} shadow\text{ }bank \times nodti4043 \times t + Controls+ County\times Yr\text{ }FE+Lender\text{ }FE \]

noloansbylender <- hmda[ !is.na(bigbank) & asofdate>=2005 & actiontaken %in% c(1) ,.N,by=.(countycode,asofdate,rssd2)]

dticounttemp <- dticount
dticounttemp[,countycode:=substr(censustract,1,5)]
dticounttemp <- dticounttemp[,.(nodti4043=mean(nodti4043,na.rm=T)),by=countycode]

noloansbylender[,shadow:=ifelse(rssd2 %in% bigbanks,0,1)]

noloansbylender <- merge(noloansbylender,dticounttemp,by="countycode")
noloansbylender[,county_yr:=paste(countycode,asofdate)]



r<- felm(N~shadow*nodti4043*factor(asofdate)|rssd2+county_yr|0|countycode,data=noloansbylender[asofdate != 201])

.coef_plot_1reg_line(r,"shadow:nodti4043:factor(asofdate)",2005)

8 Next Steps

  • Did DTI caps lead to lower homeownership rates in areas where DTI caps are more likely to bind? Did such measures lead to disproportionate impact on lower income and minority households
  • Did DTI caps reduce the ability to refinance after the financial crisis and lead to more bankruptcies etc?