1 SETUP

rm(list = ls())
library(data.table); library(dplyr); library(tidyr); library(stringr)
library(lubridate); library(purrr); library(tibble)
library(fixest); library(modelsummary)
library(knitr); library(kableExtra)
library(ggplot2); library(scales); library(patchwork)
library(readr); library(readxl)
winsorize <- function(x, probs = c(0.025, 0.975)) {
  if (all(is.na(x))) return(x)
  q <- quantile(x, probs = probs, na.rm = TRUE, names = FALSE)
  pmax(pmin(x, q[2]), q[1])
}
standardize_z <- function(x) {
  if (all(is.na(x))) return(x)
  s <- sd(x, na.rm = TRUE)
  if (is.na(s) || s == 0) return(rep(0, length(x)))
  (x - mean(x, na.rm = TRUE)) / s
}
safe_div <- function(num, denom, default = NA_real_) {
  ifelse(is.na(denom) | denom == 0, default, num / denom)
}
format_pval <- function(p) {
  case_when(is.na(p) ~ "", p < 0.01 ~ "***", p < 0.05 ~ "**", p < 0.10 ~ "*", TRUE ~ "")
}
save_figure <- function(plot_obj, filename, width = 12, height = 8) {
  ggsave(file.path(FIG_PATH, paste0(filename, ".pdf")),
    plot = plot_obj, width = width, height = height, device = "pdf")
  message("Saved: ", filename, ".pdf")
}
save_reg_latex <- function(model_list, filename, ...) {
  tex_path <- file.path(TABLE_PATH, paste0(filename, ".tex"))
  msummary(model_list, output = tex_path,
           stars = c("*" = .10, "**" = .05, "***" = .01),
           gof_omit = "AIC|BIC|Log|RMSE", ...)
  cat(sprintf("Saved: %s.tex\n", filename))
}
save_kbl_latex <- function(df, filename, col.names = NULL, caption = "", align = NULL) {
  tex <- kbl(df, format = "latex", booktabs = TRUE, escape = FALSE,
             col.names = col.names, caption = caption, align = align) %>%
    kable_styling(latex_options = c("hold_position", "scale_down"))
  writeLines(tex, file.path(TABLE_PATH, paste0(filename, ".tex")))
  cat(sprintf("Saved: %s.tex\n", filename))
}
BASE_PATH   <- "C:/Users/mferdo2/OneDrive - Louisiana State University/Finance_PhD/DW_Stigma_paper/Liquidity_project_2025"
DATA_PROC   <- file.path(BASE_PATH, "01_data/processed")
OUTPUT_PATH <- file.path(BASE_PATH, "03_documentation/new_run_Analysis_revised")
TABLE_PATH  <- file.path(OUTPUT_PATH, "tables")
FIG_PATH    <- file.path(OUTPUT_PATH, "figures")
for (path in c(TABLE_PATH, FIG_PATH)) if (!dir.exists(path)) dir.create(path, recursive = TRUE)

BASELINE_MAIN <- "2022Q4"
CRISIS_START <- as.Date("2023-03-08"); CRISIS_END <- as.Date("2023-05-04")
DW_DATA_END <- as.Date("2023-12-31")
y_10yr <- 0.0392; delta_decay <- 0.10; cap_factor <- 1 / (y_10yr + delta_decay)

2 LOAD DATA

call_q <- read_csv(file.path(DATA_PROC, "final_call_gsib.csv"), show_col_types = FALSE) %>%
  mutate(idrssd = as.character(idrssd))
btfp_loans_raw <- read_csv(file.path(DATA_PROC, "btfp_loan_bank_only.csv"), show_col_types = FALSE) %>%
  mutate(rssd_id = as.character(rssd_id), btfp_loan_date = mdy(btfp_loan_date))
dw_loans_raw <- read_csv(file.path(DATA_PROC, "dw_loan_bank_2023.csv"), show_col_types = FALSE) %>%
  mutate(rssd_id = as.character(rssd_id), dw_loan_date = ymd(dw_loan_date))
dssw_betas <- read_csv(file.path(DATA_PROC, "dssw_deposit_betas.csv"), show_col_types = FALSE) %>%
  mutate(idrssd = as.character(idrssd))
dssw_beta_2022q4 <- dssw_betas %>% filter(estimation_date == "2022Q4") %>%
  select(idrssd, beta_overall, beta_insured, beta_uninsured,
         beta_insured_w, beta_uninsured_w, gamma_hat, alpha_hat)
public_flag <- read_csv(file.path(DATA_PROC, "public_bank_flag.csv"), show_col_types = FALSE) %>%
  mutate(idrssd = as.character(idrssd)) %>% select(idrssd, period, is_public)
deposit_costs_file <- file.path(DATA_PROC, "dssw_deposit_costs.csv")
if (file.exists(deposit_costs_file)) {
  deposit_costs <- read_csv(deposit_costs_file, show_col_types = FALSE) %>%
    mutate(idrssd = as.character(idrssd))
  deposit_costs_2022q4 <- deposit_costs %>% filter(period == "2022Q4") %>%
    select(idrssd, deposit_cost_weighted, deposit_cost_insured, deposit_cost_uninsured)
  HAS_DEPOSIT_COSTS <- TRUE
} else { deposit_costs_2022q4 <- NULL; HAS_DEPOSIT_COSTS <- FALSE }

excluded_banks <- call_q %>%
  filter(period == BASELINE_MAIN, failed_bank == 1 | gsib == 1) %>% pull(idrssd)
btfp_loans <- btfp_loans_raw %>% filter(!rssd_id %in% excluded_banks)
dw_loans   <- dw_loans_raw   %>% filter(!rssd_id %in% excluded_banks)

3 CONSTRUCT VARIABLES

df_base <- call_q %>%
  filter(period == BASELINE_MAIN, !idrssd %in% excluded_banks,
         !is.na(omo_eligible) & omo_eligible > 0) %>%
  left_join(dssw_beta_2022q4, by = "idrssd") %>%
  { if (HAS_DEPOSIT_COSTS) left_join(., deposit_costs_2022q4, by = "idrssd") else . } %>%
  left_join(public_flag %>% filter(period == "2022Q4") %>% select(idrssd, is_public), by = "idrssd") %>%
  mutate(
    is_public = replace_na(is_public, 0L),
    mtm_total_raw = mtm_loss_to_total_asset,
    mtm_sec_raw   = mtm_loss_to_total_asset - mtm_loss_total_loan_to_total_asset,
    mtm_loan_raw  = mtm_loss_total_loan_to_total_asset,
    mtm_btfp_raw  = mtm_loss_omo_eligible_to_total_asset,
    uninsured_lev_raw     = uninsured_deposit_to_total_asset,
    uninsured_share_raw   = uninsured_to_deposit,
    ln_assets_raw         = log(total_asset),
    cash_ratio_raw        = cash_to_total_asset,
    book_equity_ratio_raw = book_equity_to_total_asset,
    roa_raw               = roa,
    loan_to_deposit_raw   = loan_to_deposit,
    wholesale_raw = safe_div(replace_na(fed_fund_purchase, 0) + replace_na(repo, 0) +
      replace_na(other_borrowed_less_than_1yr, 0), total_liability, 0) * 100,
    beta_u_clipped = pmin(pmax(ifelse(!is.na(beta_uninsured), beta_uninsured, NA_real_), 0), 1),
    cost_u_raw = ifelse(!is.na(deposit_cost_uninsured), deposit_cost_uninsured, 0),
    mu_decimal        = uninsured_deposit / total_asset,
    uninsured_share_d = safe_div(uninsured_deposit, insured_deposit + uninsured_deposit, NA_real_),
    net_rent  = (1 - beta_u_clipped) * y_10yr - cost_u_raw,
    f_pp      = ifelse(!is.na(beta_u_clipped), pmax(net_rent * cap_factor * mu_decimal, 0) * 100, NA_real_),
    f_u_pp    = ifelse(!is.na(f_pp) & !is.na(uninsured_share_d), uninsured_share_d * f_pp, NA_real_),
    emv_pp    = ifelse(!is.na(f_pp), book_equity_ratio_raw - mtm_total_raw + f_pp, NA_real_),
    v_pp      = ifelse(!is.na(emv_pp) & !is.na(f_u_pp), emv_pp - f_u_pp, NA_real_),
    one_minus_beta = 1 - beta_u_clipped,
    # Winsorize + z-score
    mtm_total = standardize_z(winsorize(mtm_total_raw)),
    mtm_sec = standardize_z(winsorize(mtm_sec_raw)),
    mtm_loan = standardize_z(winsorize(mtm_loan_raw)),
    uninsured_franchise = standardize_z(winsorize(f_u_pp)),
    uninsured_lev = standardize_z(winsorize(uninsured_lev_raw)),
    ln_assets = standardize_z(winsorize(ln_assets_raw)),
    cash_ratio = standardize_z(winsorize(cash_ratio_raw)),
    book_equity_ratio = standardize_z(winsorize(book_equity_ratio_raw)),
    roa = standardize_z(winsorize(roa_raw)),
    loan_to_deposit = standardize_z(winsorize(loan_to_deposit_raw)),
    wholesale = standardize_z(winsorize(wholesale_raw)),
    mtm_x_f_u = mtm_total * uninsured_franchise
  )

4 CONSTRUCT DV: ρ = Amount Borrowed / Pledged Collateral

Collateral is a pre-pledged pool at the Fed.
Banks must pre-pledge collateral at the DW before borrowing from either BTFP or DW. Both btfp_total_collateral and dw_total_collateral report this standing pool at each loan record.

  • Aggregation: max() for collateral (same pool across loans), sum() for amounts (total drawn).
  • Combined capacity: For banks using both facilities, the pools overlap. dw_total_collateral is the superset (includes non-OMO).
  • Units: Loan amounts & collateral in actual dollars. Call Report in thousands.
# ── Bank-level: MAX collateral (pool), SUM amounts (draws) ──
btfp_bank <- btfp_loans %>%
  filter(btfp_loan_date >= CRISIS_START, btfp_loan_date <= CRISIS_END) %>%
  group_by(rssd_id) %>%
  summarise(btfp_n = n(),
            btfp_amt  = sum(btfp_loan_amount, na.rm = TRUE),
            btfp_coll = max(btfp_total_collateral, na.rm = TRUE),
            .groups = "drop") %>%
  rename(idrssd = rssd_id)

dw_bank <- dw_loans %>%
  filter(dw_loan_date >= CRISIS_START, dw_loan_date <= min(CRISIS_END, DW_DATA_END)) %>%
  group_by(rssd_id) %>%
  summarise(dw_n = n(),
            dw_amt  = sum(dw_loan_amount, na.rm = TRUE),
            dw_coll = max(dw_total_collateral, na.rm = TRUE),
            dw_omo  = max(dw_omo_eligible, na.rm = TRUE),
            dw_non_omo = max(dw_non_omo_eligible, na.rm = TRUE),
            .groups = "drop") %>%
  rename(idrssd = rssd_id)

# ── Merge and build DV ──
df <- df_base %>%
  filter(!is.na(f_u_pp), total_asset > 0, is.finite(ln_assets_raw),
         !is.na(uninsured_deposit), !is.na(insured_deposit), insured_deposit > 0) %>%
  left_join(btfp_bank, by = "idrssd") %>%
  left_join(dw_bank,   by = "idrssd") %>%
  mutate(
    btfp_n = replace_na(btfp_n, 0L), btfp_amt = replace_na(btfp_amt, 0),
    btfp_coll = replace_na(btfp_coll, 0),
    dw_n = replace_na(dw_n, 0L), dw_amt = replace_na(dw_amt, 0),
    dw_coll = replace_na(dw_coll, 0), dw_omo = replace_na(dw_omo, 0),
    dw_non_omo = replace_na(dw_non_omo, 0),

    is_btfp = as.integer(btfp_amt > 0),
    is_dw   = as.integer(dw_amt > 0),
    is_fed  = as.integer(is_btfp | is_dw),

    borrower_type = case_when(
      is_btfp == 1 & is_dw == 1 ~ "Both",
      is_btfp == 1              ~ "BTFP Only",
      is_dw == 1                ~ "DW Only",
      TRUE                      ~ "Non-Borrower"),

    total_borrowed     = btfp_amt + dw_amt,
    pledged_collateral = pmax(dw_coll, btfp_coll),  # DW is superset

    # ── THE DV ──
    rho = safe_div(total_borrowed, pledged_collateral, NA_real_),

    # Facility-specific
    rho_btfp = safe_div(btfp_amt, btfp_coll, NA_real_),
    rho_dw   = safe_div(dw_amt,   dw_coll,   NA_real_),

    # Normalized
    borrowed_ta    = total_borrowed / (total_asset * 1000),
    collateral_ta  = pledged_collateral / (total_asset * 1000),

    total_n    = btfp_n + dw_n,
    multi_loan = as.integer(total_n > 1)
  )

cat(sprintf("Full sample: %d | Fed borrowers: %d (%.1f%%)\n",
    nrow(df), sum(df$is_fed), 100 * mean(df$is_fed)))
## Full sample: 4226 | Fed borrowers: 822 (19.5%)

5 SAMPLE CONSTRUCTION

df_borr <- df %>% filter(is_fed == 1, !is.na(rho), rho > 0, is.finite(rho))

asset_breaks <- quantile(df$total_asset, probs = c(0, .25, .50, .75, 1), na.rm = TRUE)
df_borr <- df_borr %>%
  mutate(size_bucket = cut(total_asset, breaks = asset_breaks,
                           labels = c("Q1 (Small)", "Q2", "Q3", "Q4 (Large)"),
                           include.lowest = TRUE))

med_rho <- median(df_borr$rho)
df_borr <- df_borr %>%
  mutate(rho_group = ifelse(rho >= med_rho, "High ρ", "Low ρ"))

cat(sprintf("=== BORROWER SAMPLE (ρ > 0) ===\n"))
## === BORROWER SAMPLE (ρ > 0) ===
cat(sprintf("  N = %d | BTFP Only: %d | DW Only: %d | Both: %d\n",
    nrow(df_borr), sum(df_borr$borrower_type == "BTFP Only"),
    sum(df_borr$borrower_type == "DW Only"), sum(df_borr$borrower_type == "Both")))
##   N = 822 | BTFP Only: 392 | DW Only: 326 | Both: 104
cat(sprintf("  Multi-loan: %d (%.1f%%)\n", sum(df_borr$multi_loan), 100*mean(df_borr$multi_loan)))
##   Multi-loan: 406 (49.4%)
cat(sprintf("  ρ: mean=%.3f, med=%.3f, sd=%.3f, min=%.4f, max=%.4f\n",
    mean(df_borr$rho), median(df_borr$rho), sd(df_borr$rho), min(df_borr$rho), max(df_borr$rho)))
##   ρ: mean=1.089, med=0.714, sd=2.245, min=0.0000, max=26.7484
cat(sprintf("  ρ > 1: %d banks\n", sum(df_borr$rho > 1)))
##   ρ > 1: 231 banks
theme_gp <- theme_minimal(base_size = 13) +
  theme(plot.title = element_text(face = "bold", size = 14),
        plot.subtitle = element_text(color = "grey40", size = 11),
        legend.position = "bottom", panel.grid.minor = element_blank())

6 DESCRIPTIVE STATISTICS

6.1 4.1 DV Distribution

rho_by_type <- df_borr %>%
  group_by(borrower_type) %>%
  summarise(N = n(), Mean = mean(rho), Median = median(rho), SD = sd(rho),
            P25 = quantile(rho, .25), P75 = quantile(rho, .75), .groups = "drop") %>%
  bind_rows(
    df_borr %>% summarise(borrower_type = "All Borrowers", N = n(),
      Mean = mean(rho), Median = median(rho), SD = sd(rho),
      P25 = quantile(rho, .25), P75 = quantile(rho, .75))
  ) %>% mutate(across(where(is.numeric) & !matches("^N$"), ~ round(., 4)))

kbl(rho_by_type, format = "html", escape = FALSE,
    col.names = c("Type", "N", "Mean", "Median", "SD", "P25", "P75"),
    caption = "ρ = Amount Borrowed / Pledged Collateral by Facility Type") %>%
  kable_styling(bootstrap_options = c("striped", "hover", "condensed"), full_width = FALSE) %>%
  footnote(general = "Collateral = pre-pledged pool (max across loans). Amount = total drawn (sum). Both in actual dollars.")
ρ = Amount Borrowed / Pledged Collateral by Facility Type
Type N Mean Median SD P25 P75
BTFP Only 392 1.0761 0.9744 0.6684 0.7132 1.3965
Both 104 1.9211 0.9973 3.0590 0.1954 1.7588
DW Only 326 0.8392 0.0065 2.9899 0.0002 0.3231
All Borrowers 822 1.0891 0.7140 2.2446 0.0114 1.1332
Note:
Collateral = pre-pledged pool (max across loans). Amount = total drawn (sum). Both in actual dollars.
save_kbl_latex(rho_by_type, "Table_Rho_ByType",
  caption = "$\\rho$ = Amount / Pledged Collateral by Facility Type")
## Saved: Table_Rho_ByType.tex

6.2 4.2 High ρ vs Low ρ (Median Split)

desc_vars <- c("rho", "borrowed_ta", "collateral_ta",
  "ln_assets_raw", "mtm_total_raw", "mtm_sec_raw", "mtm_loan_raw",
  "book_equity_ratio_raw", "cash_ratio_raw", "loan_to_deposit_raw",
  "wholesale_raw", "roa_raw",
  "uninsured_lev_raw", "uninsured_share_raw", "beta_u_clipped", "one_minus_beta",
  "f_pp", "f_u_pp", "emv_pp", "v_pp")

desc_labels <- c("ρ (DV)", "Borrowed/TA", "Collateral/TA",
  "Log(Assets)", "Total MTM (ℓ)", "Securities MTM (ℓ_S)", "Loan MTM (ℓ_L)",
  "Book Equity (e)", "Cash/TA", "Loan/Deposit",
  "Wholesale (%)", "ROA",
  "Uninsured/TA (μ)", "D^U/D", "β^U", "1 − β^U",
  "Franchise (f)", "Unins. Franchise (f^U)", "MV Equity (E^MV)", "Run Value (v)")

split_tbl <- map_dfr(seq_along(desc_vars), function(i) {
  v <- desc_vars[i]
  h <- df_borr[[v]][df_borr$rho_group == "High ρ"]
  l <- df_borr[[v]][df_borr$rho_group == "Low ρ"]
  tt <- tryCatch(t.test(h, l), error = function(e) NULL)
  p_val <- if (!is.null(tt)) tt$p.value else NA_real_
  tibble(Variable = desc_labels[i],
         `High ρ` = sprintf("%.3f (%.3f)", mean(h, na.rm=T), sd(h, na.rm=T)),
         `Low ρ`  = sprintf("%.3f (%.3f)", mean(l, na.rm=T), sd(l, na.rm=T)),
         Diff = mean(h, na.rm=T) - mean(l, na.rm=T),
         p = p_val, Stars = format_pval(p_val))
}) %>% mutate(Difference = sprintf("%.3f%s", round(Diff, 3), Stars))

kbl(split_tbl %>% select(Variable, `High ρ`, `Low ρ`, Difference),
    format = "html", escape = FALSE,
    col.names = c("Variable",
      sprintf("High ρ ≥ %.3f (N=%d)", med_rho, sum(df_borr$rho_group == "High ρ")),
      sprintf("Low ρ < %.3f (N=%d)", med_rho, sum(df_borr$rho_group == "Low ρ")),
      "Difference"),
    caption = sprintf("Above vs Below Median ρ (median = %.4f)", med_rho)) %>%
  kable_styling(bootstrap_options = c("striped", "hover", "condensed"), full_width = FALSE) %>%
  footnote(general = "*** p<0.01, ** p<0.05, * p<0.10 (Welch t-test).")
Above vs Below Median ρ (median = 0.7140)
Variable High ρ ≥ 0.714 (N=411) Low ρ < 0.714 (N=411) Difference
ρ (DV) 2.022 (2.880) 0.156 (0.222) 1.867***
Borrowed/TA 0.155 (0.369) 0.011 (0.026) 0.144***
Collateral/TA 0.064 (0.066) 0.064 (0.077) -0.000
Log(Assets) 13.598 (1.405) 13.944 (1.620) -0.346***
Total MTM (ℓ) 6.142 (1.900) 5.729 (2.035) 0.412***
Securities MTM (ℓ_S) 2.608 (1.711) 2.185 (1.512) 0.423***
Loan MTM (ℓ_L) 3.534 (1.538) 3.545 (1.621) -0.011
Book Equity (e) 8.220 (3.040) 8.949 (3.141) -0.729***
Cash/TA 4.468 (4.640) 6.035 (6.186) -1.566***
Loan/Deposit 73.246 (20.032) 75.187 (19.564) -1.941
Wholesale (%) 1.789 (3.537) 1.269 (3.406) 0.520**
ROA 1.048 (0.569) 1.139 (0.600) -0.091**
Uninsured/TA (μ) 26.887 (12.156) 27.379 (11.976) -0.492
D^U/D 31.593 (14.171) 32.040 (14.245) -0.447
β^U 0.347 (0.118) 0.338 (0.111) 0.009
1 − β^U 0.653 (0.118) 0.662 (0.111) -0.009
Franchise (f) 2.897 (1.644) 3.008 (1.676) -0.111
Unins. Franchise (f^U) 1.086 (1.102) 1.127 (1.104) -0.041
MV Equity (E^MV) 4.976 (4.121) 6.228 (4.480) -1.252***
Run Value (v) 3.890 (3.866) 5.101 (4.164) -1.211***
Note:
*** p<0.01, ** p<0.05, * p<0.10 (Welch t-test).
save_kbl_latex(split_tbl %>% select(Variable, `High ρ`, `Low ρ`, Difference),
  "Table_Desc_RhoMedianSplit", caption = "Above vs Below Median $\\rho$")
## Saved: Table_Desc_RhoMedianSplit.tex

6.3 4.3 ρ by Size Bucket

size_tbl <- df_borr %>%
  group_by(size_bucket) %>%
  summarise(N = n(), `ρ Mean` = round(mean(rho), 4), `ρ Median` = round(median(rho), 4),
    `ρ SD` = round(sd(rho), 4),
    `ℓ` = round(mean(mtm_total_raw, na.rm=T), 3), `ℓ_S` = round(mean(mtm_sec_raw, na.rm=T), 3),
    `f^U` = round(mean(f_u_pp, na.rm=T), 3), `Cash/TA` = round(mean(cash_ratio_raw, na.rm=T), 3),
    `v` = round(mean(v_pp, na.rm=T), 3), `Multi %` = round(100*mean(multi_loan), 1),
    .groups = "drop")

kbl(size_tbl, format = "html", escape = FALSE,
    caption = "ρ by Asset Size Quartile (from full sample)") %>%
  kable_styling(bootstrap_options = c("striped", "hover", "condensed"), full_width = FALSE)
ρ by Asset Size Quartile (from full sample)
size_bucket N ρ Mean ρ Median ρ SD ℓ_S f^U Cash/TA v Multi %
Q1 (Small) 61 1.0778 0.8425 1.4845 5.808 2.809 0.615 6.842 4.377 41.0
Q2 137 0.9146 0.8009 1.4356 5.979 2.738 0.856 6.834 3.786 48.2
Q3 243 1.0885 0.7143 1.8724 6.173 2.474 0.917 5.502 3.866 46.5
Q4 (Large) 381 1.1539 0.6153 2.7480 5.789 2.158 1.396 4.268 5.172 53.0
save_kbl_latex(size_tbl, "Table_Rho_SizeBuckets", caption = "$\\rho$ by Size Quartile")
## Saved: Table_Rho_SizeBuckets.tex

6.4 4.4 Single vs Multi-Loan

multi_vars   <- c("rho", "borrowed_ta", "collateral_ta", "ln_assets_raw",
                   "mtm_total_raw", "mtm_sec_raw", "f_u_pp", "cash_ratio_raw", "v_pp")
multi_labels <- c("ρ (DV)", "Borrowed/TA", "Collateral/TA", "Log(Assets)",
                  "MTM (ℓ)", "Securities MTM (ℓ_S)", "f^U", "Cash/TA", "Run Value (v)")

multi_tbl <- map_dfr(seq_along(multi_vars), function(i) {
  v <- multi_vars[i]
  m <- df_borr[[v]][df_borr$multi_loan == 1]
  s <- df_borr[[v]][df_borr$multi_loan == 0]
  tt <- tryCatch(t.test(m, s), error = function(e) NULL)
  p_val <- if (!is.null(tt)) tt$p.value else NA_real_
  tibble(Variable = multi_labels[i],
         `Multi` = sprintf("%.3f (%.3f)", mean(m, na.rm=T), sd(m, na.rm=T)),
         `Single` = sprintf("%.3f (%.3f)", mean(s, na.rm=T), sd(s, na.rm=T)),
         Diff = mean(m, na.rm=T) - mean(s, na.rm=T),
         p = p_val, Stars = format_pval(p_val))
}) %>% mutate(Difference = sprintf("%.3f%s", round(Diff, 3), Stars))

kbl(multi_tbl %>% select(Variable, Multi, Single, Difference),
    format = "html", escape = FALSE,
    col.names = c("Variable", sprintf("Multi (N=%d)", sum(df_borr$multi_loan)),
      sprintf("Single (N=%d)", sum(!df_borr$multi_loan)), "Difference"),
    caption = "Multi-Loan vs Single-Loan Borrowers") %>%
  kable_styling(bootstrap_options = c("striped", "hover", "condensed"), full_width = FALSE)
Multi-Loan vs Single-Loan Borrowers
Variable Multi (N=406) Single (N=416) Difference
ρ (DV) 1.867 (2.975) 0.330 (0.402) 1.537***
Borrowed/TA 0.156 (0.372) 0.013 (0.024) 0.143***
Collateral/TA 0.080 (0.076) 0.048 (0.064) 0.031***
Log(Assets) 13.856 (1.497) 13.689 (1.549) 0.167
MTM (ℓ) 6.025 (1.991) 5.848 (1.964) 0.177
Securities MTM (ℓ_S) 2.550 (1.685) 2.246 (1.555) 0.305***
f^U 1.176 (1.229) 1.038 (0.960) 0.139*
Cash/TA 4.551 (4.772) 5.935 (6.093) -1.384***
Run Value (v) 4.300 (4.029) 4.686 (4.088) -0.386
save_kbl_latex(multi_tbl %>% select(Variable, Multi, Single, Difference),
  "Table_MultiVsSingle", caption = "Multi vs Single-Loan Borrowers")
## Saved: Table_MultiVsSingle.tex

6.5 4.5 Facility-Type Summary

fac_tbl <- df_borr %>%
  group_by(borrower_type) %>%
  summarise(N = n(), `ρ` = round(mean(rho), 3),
    `Borrowed/TA` = round(mean(borrowed_ta, na.rm=T), 4),
    `Collateral/TA` = round(mean(collateral_ta, na.rm=T), 4),
    `ℓ` = round(mean(mtm_total_raw, na.rm=T), 3),
    `f^U` = round(mean(f_u_pp, na.rm=T), 3),
    `Cash/TA` = round(mean(cash_ratio_raw, na.rm=T), 3),
    `v` = round(mean(v_pp, na.rm=T), 3),
    `μ` = round(mean(uninsured_lev_raw, na.rm=T), 3),
    `1−β^U` = round(mean(one_minus_beta, na.rm=T), 3),
    .groups = "drop")

kbl(fac_tbl, format = "html", escape = FALSE,
    caption = "Characteristics by Facility Type") %>%
  kable_styling(bootstrap_options = c("striped", "hover", "condensed"), full_width = FALSE)
Characteristics by Facility Type
borrower_type N ρ Borrowed/TA Collateral/TA f^U Cash/TA v μ 1−β^U
BTFP Only 392 1.076 0.0673 0.0590 6.165 1.054 4.677 3.904 26.173 0.663
Both 104 1.921 0.2157 0.0845 5.779 1.413 4.549 4.342 31.989 0.635
DW Only 326 0.839 0.0605 0.0626 5.710 1.071 6.166 5.256 26.737 0.659
save_kbl_latex(fac_tbl, "Table_FacilityType", caption = "Characteristics by Facility Type")
## Saved: Table_FacilityType.tex

7 REGRESSIONS

DV: \(\rho = \text{Amount Borrowed} / \text{Pledged Collateral}\)
Predictions: \(\ell \times f^U > 0\); Cash/TA \(< 0\).
All RHS standardized within borrower sample.

df_reg <- df_borr %>%
  mutate(
    mtm_total_b  = standardize_z(winsorize(mtm_total_raw)),
    mtm_sec_b    = standardize_z(winsorize(mtm_sec_raw)),
    mtm_loan_b   = standardize_z(winsorize(mtm_loan_raw)),
    f_u_b        = standardize_z(winsorize(f_u_pp)),
    cash_b       = standardize_z(winsorize(cash_ratio_raw)),
    ln_assets_b  = standardize_z(winsorize(ln_assets_raw)),
    ltd_b        = standardize_z(winsorize(loan_to_deposit_raw)),
    equity_b     = standardize_z(winsorize(book_equity_ratio_raw)),
    wholesale_b  = standardize_z(winsorize(wholesale_raw)),
    roa_b        = standardize_z(winsorize(roa_raw)),
    unins_lev_b  = standardize_z(winsorize(uninsured_lev_raw)),
    one_minus_beta_b = standardize_z(winsorize(one_minus_beta)),
    mtm_x_fu_b  = mtm_total_b * f_u_b,
    sec_x_fu_b  = mtm_sec_b * f_u_b,
    loan_x_fu_b = mtm_loan_b * f_u_b,
    mtm_x_mu_b  = mtm_total_b * unins_lev_b,
    mtm_x_1mbeta_b = mtm_total_b * one_minus_beta_b,
    mtm_x_mu_x_1mbeta_b = mtm_total_b * unins_lev_b * one_minus_beta_b,
    ln_rho = log(rho)
  )

ctrl <- c("ln_assets_b", "cash_b", "ltd_b", "equity_b", "wholesale_b", "roa_b")
ctrl_str <- paste(ctrl, collapse = " + ")

coef_map <- c(
  "mtm_total_b" = "ℓ (MTM Loss)", "mtm_sec_b" = "ℓ_S (Securities)",
  "mtm_loan_b" = "ℓ_L (Loans)", "f_u_b" = "f^U (Unins. Franchise)",
  "mtm_x_fu_b" = "ℓ × f^U (expect > 0)",
  "sec_x_fu_b" = "ℓ_S × f^U", "loan_x_fu_b" = "ℓ_L × f^U",
  "unins_lev_b" = "μ", "one_minus_beta_b" = "1−β^U",
  "mtm_x_mu_b" = "ℓ × μ", "mtm_x_1mbeta_b" = "ℓ × (1−β^U)",
  "mtm_x_mu_x_1mbeta_b" = "ℓ × μ × (1−β^U)",
  "cash_b" = "Cash/TA (expect < 0)", "ln_assets_b" = "Log(Assets)",
  "ltd_b" = "Loan/Dep", "equity_b" = "Equity/TA",
  "wholesale_b" = "Wholesale", "roa_b" = "ROA")

cat(sprintf("Regression sample: %d\n", nrow(df_reg)))
## Regression sample: 822

7.1 5.1 Main

fml <- as.formula(paste0("rho ~ mtm_total_b + f_u_b + mtm_x_fu_b + ", ctrl_str))

reg_main <- list(
  "ρ: All"       = feols(fml, data = df_reg, vcov = "hetero"),
  "ρ: BTFP Only" = feols(fml, data = df_reg %>% filter(borrower_type == "BTFP Only"), vcov = "hetero"),
  "ρ: DW Only"   = feols(fml, data = df_reg %>% filter(borrower_type == "DW Only"), vcov = "hetero"),
  "ρ: Both"      = feols(fml, data = df_reg %>% filter(borrower_type == "Both"), vcov = "hetero"),
  "ln(ρ): All"   = feols(update(fml, ln_rho ~ .), data = df_reg %>% filter(is.finite(ln_rho)), vcov = "hetero")
)

msummary(reg_main, stars = c("*"=.10, "**"=.05, "***"=.01), gof_omit = "AIC|BIC|Log|RMSE",
  coef_rename = coef_map,
  title = "ρ = Amount Borrowed / Pledged Collateral",
  notes = "ℓ×f^U > 0: coordination amplifies drawdown. Cash < 0: liquid banks draw less.")
ρ = Amount Borrowed / Pledged Collateral
ρ: All ρ: BTFP Only ρ: DW Only ρ: Both ln(ρ): All
* p < 0.1, ** p < 0.05, *** p < 0.01
ℓ×f^U > 0: coordination amplifies drawdown. Cash < 0: liquid banks draw less.
(Intercept) 1.107*** 1.073*** 0.972*** 1.501*** -2.402***
(0.082) (0.037) (0.202) (0.255) (0.134)
ℓ (MTM Loss) 0.036 -0.036 0.145 -0.244 0.024
(0.110) (0.038) (0.235) (0.340) (0.150)
f^U (Unins. Franchise) 0.182 -0.035 0.245 0.514* 0.412***
(0.126) (0.044) (0.296) (0.295) (0.150)
ℓ × f^U (expect > 0) 0.181 0.018 0.198 0.794* 0.126
(0.125) (0.037) (0.236) (0.424) (0.128)
Log(Assets) 0.014 -0.025 -0.130 0.122 -1.083***
(0.076) (0.042) (0.096) (0.341) (0.189)
Cash/TA (expect < 0) -0.268*** -0.038 -0.333*** -0.549* -1.010***
(0.069) (0.054) (0.127) (0.288) (0.174)
Loan/Dep -0.102 0.020 -0.246 0.209 -0.193
(0.124) (0.046) (0.241) (0.429) (0.186)
Equity/TA -0.016 0.003 0.006 -0.320 -0.276*
(0.104) (0.036) (0.215) (0.427) (0.165)
Wholesale 0.133** 0.041 0.093 0.438 0.310**
(0.065) (0.034) (0.135) (0.321) (0.125)
ROA -0.100 -0.018 -0.062 -0.313 -0.051
(0.074) (0.041) (0.129) (0.267) (0.144)
Num.Obs. 822 392 326 104 822
R2 0.035 0.016 0.035 0.167 0.128
R2 Adj. 0.024 -0.007 0.007 0.087 0.118
Std.Errors Heteroskedasticity-robust Heteroskedasticity-robust Heteroskedasticity-robust Heteroskedasticity-robust Heteroskedasticity-robust
save_reg_latex(reg_main, "Table_Rho_Main", coef_rename = coef_map,
  title = "$\\rho$ = Amount / Pledged Collateral")
## Saved: Table_Rho_Main.tex

7.2 5.2 Single vs Multi-Loan

reg_multi <- list(
  "All"         = feols(fml, data = df_reg, vcov = "hetero"),
  "Single-Loan" = feols(fml, data = df_reg %>% filter(multi_loan == 0), vcov = "hetero"),
  "Multi-Loan"  = feols(fml, data = df_reg %>% filter(multi_loan == 1), vcov = "hetero")
)
msummary(reg_multi, stars = c("*"=.10, "**"=.05, "***"=.01), gof_omit = "AIC|BIC|Log|RMSE",
  coef_rename = coef_map, title = "ρ: Single vs Multi-Loan")
ρ: Single vs Multi-Loan
All Single-Loan Multi-Loan
* p < 0.1, ** p < 0.05, *** p < 0.01
(Intercept) 1.107*** 0.338*** 1.810***
(0.082) (0.019) (0.140)
ℓ (MTM Loss) 0.036 -0.022 0.092
(0.110) (0.022) (0.205)
f^U (Unins. Franchise) 0.182 0.026 0.212
(0.126) (0.025) (0.183)
ℓ × f^U (expect > 0) 0.181 0.011 0.288
(0.125) (0.019) (0.220)
Log(Assets) 0.014 -0.109*** 0.101
(0.076) (0.022) (0.141)
Cash/TA (expect < 0) -0.268*** -0.071*** -0.305**
(0.069) (0.019) (0.140)
Loan/Dep -0.102 0.009 -0.133
(0.124) (0.026) (0.214)
Equity/TA -0.016 -0.069*** -0.007
(0.104) (0.022) (0.173)
Wholesale 0.133** 0.019 0.099
(0.065) (0.022) (0.104)
ROA -0.100 0.005 -0.181
(0.074) (0.021) (0.145)
Num.Obs. 822 416 406
R2 0.035 0.125 0.035
R2 Adj. 0.024 0.106 0.013
Std.Errors Heteroskedasticity-robust Heteroskedasticity-robust Heteroskedasticity-robust
save_reg_latex(reg_multi, "Table_Rho_MultiVsSingle", coef_rename = coef_map)
## Saved: Table_Rho_MultiVsSingle.tex

7.3 5.3 Signal: ℓ_S vs ℓ_L × f^U

fml_sig <- as.formula(paste0(
  "rho ~ mtm_sec_b + mtm_loan_b + f_u_b + sec_x_fu_b + loan_x_fu_b + ", ctrl_str))
reg_sig <- list(
  "ℓ × f^U"        = feols(fml, data = df_reg, vcov = "hetero"),
  "ℓ_S/ℓ_L × f^U"  = feols(fml_sig, data = df_reg, vcov = "hetero"),
  "BTFP+Both"       = feols(fml_sig, data = df_reg %>% filter(borrower_type != "DW Only"), vcov = "hetero"),
  "DW+Both"          = feols(fml_sig, data = df_reg %>% filter(borrower_type != "BTFP Only"), vcov = "hetero")
)
msummary(reg_sig, stars = c("*"=.10, "**"=.05, "***"=.01), gof_omit = "AIC|BIC|Log|RMSE",
  coef_rename = coef_map, title = "ρ: Securities vs Loan Signal")
ρ: Securities vs Loan Signal
ℓ × f^U ℓ_S/ℓ_L × f^U BTFP+Both DW+Both
* p < 0.1, ** p < 0.05, *** p < 0.01
(Intercept) 1.107*** 1.139*** 1.250*** 1.222***
(0.082) (0.092) (0.075) (0.168)
ℓ (MTM Loss) 0.036
(0.110)
f^U (Unins. Franchise) 0.182 0.187 0.142 0.305
(0.126) (0.128) (0.111) (0.220)
ℓ × f^U (expect > 0) 0.181
(0.125)
Log(Assets) 0.014 0.043 0.090 0.067
(0.076) (0.080) (0.106) (0.133)
Cash/TA (expect < 0) -0.268*** -0.243*** -0.131 -0.323**
(0.069) (0.078) (0.095) (0.143)
Loan/Dep -0.102 -0.071 0.123 -0.123
(0.124) (0.137) (0.136) (0.277)
Equity/TA -0.016 -0.004 -0.010 -0.032
(0.104) (0.108) (0.081) (0.187)
Wholesale 0.133** 0.125** 0.127* 0.191
(0.065) (0.063) (0.071) (0.129)
ROA -0.100 -0.102 -0.113 -0.125
(0.074) (0.076) (0.084) (0.129)
ℓ_S (Securities) 0.075 0.079 0.213
(0.183) (0.116) (0.381)
ℓ_L (Loans) 0.103 -0.061 0.126
(0.141) (0.088) (0.212)
ℓ_S × f^U -0.032 0.163 -0.020
(0.130) (0.161) (0.225)
ℓ_L × f^U 0.373* 0.180* 0.570*
(0.204) (0.097) (0.305)
Num.Obs. 822 822 496 430
R2 0.035 0.052 0.056 0.083
R2 Adj. 0.024 0.039 0.035 0.059
Std.Errors Heteroskedasticity-robust Heteroskedasticity-robust Heteroskedasticity-robust Heteroskedasticity-robust
save_reg_latex(reg_sig, "Table_Rho_Signal", coef_rename = coef_map)
## Saved: Table_Rho_Signal.tex

7.4 5.4 Decomposition: ℓ × μ × (1−β^U)

fml_d2 <- as.formula(paste0("rho ~ mtm_total_b + unins_lev_b + one_minus_beta_b + ",
                              "mtm_x_mu_b + mtm_x_1mbeta_b + ", ctrl_str))
fml_d3 <- as.formula(paste0("rho ~ mtm_total_b + unins_lev_b + one_minus_beta_b + ",
                              "mtm_x_mu_x_1mbeta_b + ", ctrl_str))
reg_decomp <- list(
  "ℓ × f^U (baseline)" = feols(fml, data = df_reg, vcov = "hetero"),
  "ℓ×μ + ℓ×(1−β^U)"    = feols(fml_d2, data = df_reg, vcov = "hetero"),
  "ℓ × μ × (1−β^U)"    = feols(fml_d3, data = df_reg, vcov = "hetero")
)
msummary(reg_decomp, stars = c("*"=.10, "**"=.05, "***"=.01), gof_omit = "AIC|BIC|Log|RMSE",
  coef_rename = coef_map,
  title = "Decomposition: ℓ × f^U → ℓ × μ × (1−β^U)",
  notes = "Col 1: baseline. Col 2: separate interactions. Col 3: triple.")
Decomposition: ℓ × f^U → ℓ × μ × (1−β^U)
ℓ × f^U (baseline) ℓ×μ + ℓ×(1−β^U) ℓ × μ × (1−β^U)
* p < 0.1, ** p < 0.05, *** p < 0.01
Col 1: baseline. Col 2: separate interactions. Col 3: triple.
(Intercept) 1.107*** 1.102*** 1.091***
(0.082) (0.082) (0.078)
ℓ (MTM Loss) 0.036 0.049 0.031
(0.110) (0.108) (0.108)
f^U (Unins. Franchise) 0.182
(0.126)
ℓ × f^U (expect > 0) 0.181
(0.125)
Log(Assets) 0.014 0.004 0.007
(0.076) (0.068) (0.069)
Cash/TA (expect < 0) -0.268*** -0.267*** -0.291***
(0.069) (0.071) (0.064)
Loan/Dep -0.102 -0.107 -0.132
(0.124) (0.123) (0.116)
Equity/TA -0.016 -0.009 -0.021
(0.104) (0.099) (0.109)
Wholesale 0.133** 0.137** 0.144**
(0.065) (0.062) (0.063)
ROA -0.100 -0.106 -0.092
(0.074) (0.076) (0.071)
μ 0.169 0.162*
(0.106) (0.092)
1−β^U -0.006 -0.033
(0.100) (0.084)
ℓ × μ 0.139
(0.102)
ℓ × (1−β^U) 0.066
(0.087)
ℓ × μ × (1−β^U) -0.031
(0.032)
Num.Obs. 822 822 822
R2 0.035 0.034 0.029
R2 Adj. 0.024 0.020 0.017
Std.Errors Heteroskedasticity-robust Heteroskedasticity-robust Heteroskedasticity-robust
save_reg_latex(reg_decomp, "Table_Rho_Decomposition", coef_rename = coef_map)
## Saved: Table_Rho_Decomposition.tex

8 PLOTS

8.1 6.1 ρ Distribution

p1 <- ggplot(df_borr, aes(x = rho)) +
  geom_histogram(aes(y = after_stat(density)), bins = 40, fill = "#1565C0", alpha = 0.6) +
  geom_density(linewidth = 0.8, color = "#C62828") +
  geom_vline(xintercept = med_rho, linetype = "dashed") +
  annotate("text", x = med_rho + 0.03, y = Inf, vjust = 2,
           label = sprintf("Median = %.3f", med_rho), size = 3.5) +
  labs(title = "Distribution of ρ = Borrowed / Pledged Collateral",
       x = "ρ", y = "Density") + theme_gp
p2 <- ggplot(df_borr, aes(x = rho, fill = borrower_type, color = borrower_type)) +
  geom_density(alpha = 0.3, linewidth = 0.7) +
  scale_fill_manual(values = c("BTFP Only"="#1565C0","DW Only"="#E53935","Both"="#6A1B9A")) +
  scale_color_manual(values = c("BTFP Only"="#1565C0","DW Only"="#E53935","Both"="#6A1B9A")) +
  labs(title = "ρ by Facility Type", x = "ρ", y = "Density") + theme_gp
print(p1 + p2)

save_figure(p1 + p2, "Fig_Rho_Distribution", width = 14, height = 6)

8.2 6.2 ρ by Size

ggplot(df_borr, aes(x = size_bucket, y = rho, fill = size_bucket)) +
  geom_boxplot(alpha = 0.7, outlier.alpha = 0.3) +
  labs(title = "ρ by Size Quartile", x = NULL, y = "ρ") +
  theme_gp + theme(legend.position = "none")

8.3 6.3 ρ vs ℓ × f^U and Cash

p4 <- ggplot(df_reg, aes(x = mtm_x_fu_b, y = rho)) +
  geom_point(aes(color = borrower_type), alpha = 0.5, size = 2) +
  geom_smooth(method = "lm", color = "black", se = TRUE, linewidth = 0.8) +
  scale_color_manual(values = c("BTFP Only"="#1565C0","DW Only"="#E53935","Both"="#6A1B9A"), name = NULL) +
  labs(title = "ρ vs ℓ × f^U", x = "ℓ × f^U (z-score)", y = "ρ") + theme_gp
p5 <- ggplot(df_reg, aes(x = cash_b, y = rho)) +
  geom_point(aes(color = borrower_type), alpha = 0.5, size = 2) +
  geom_smooth(method = "lm", color = "black", se = TRUE, linewidth = 0.8) +
  scale_color_manual(values = c("BTFP Only"="#1565C0","DW Only"="#E53935","Both"="#6A1B9A"), name = NULL) +
  labs(title = "ρ vs Cash/TA", x = "Cash/TA (z-score)", y = "ρ") + theme_gp
print(p4 + p5)

save_figure(p4 + p5, "Fig_Rho_Scatter", width = 14, height = 6)

8.4 6.4 ρ vs Run Value

ggplot(df_reg, aes(x = v_pp, y = rho)) +
  geom_point(aes(color = borrower_type), alpha = 0.4, size = 2) +
  geom_smooth(method = "lm", color = "black", se = TRUE, linewidth = 0.8) +
  geom_vline(xintercept = 0, linetype = "dashed") +
  scale_color_manual(values = c("BTFP Only"="#1565C0","DW Only"="#E53935","Both"="#6A1B9A"), name = NULL) +
  labs(title = "ρ vs Run Value (v = E^MV − F^U)",
       subtitle = "v < 0: run equilibrium possible → expect higher ρ.",
       x = "v (pp of TA)", y = "ρ") + theme_gp