1 Setup and Load Packages

library(dplyr)
library(knitr)
library(tidyverse)
library(lubridate)
library(kableExtra)
library(pander)

2 Directory Setup

# ============================================================================
# PATH SETUP
# ============================================================================
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 directories
OUTPUT_PATH <- file.path(BASE_PATH, "03_documentation/borrowing_stat_new")
TABLE_PATH <- file.path(OUTPUT_PATH, "tables")
FIG_PATH <- file.path(OUTPUT_PATH, "figures")

# Create directories if they don't exist
dir.create(TABLE_PATH, recursive = TRUE, showWarnings = FALSE)
dir.create(FIG_PATH, recursive = TRUE, showWarnings = FALSE)

cat("Output directories:\n")
## Output directories:
cat("  Tables:", TABLE_PATH, "\n")
##   Tables: C:/Users/mferdo2/OneDrive - Louisiana State University/Finance_PhD/DW_Stigma_paper/Liquidity_project_2025/03_documentation/borrowing_stat_new/tables
cat("  Figures:", FIG_PATH, "\n")
##   Figures: C:/Users/mferdo2/OneDrive - Louisiana State University/Finance_PhD/DW_Stigma_paper/Liquidity_project_2025/03_documentation/borrowing_stat_new/figures

3 Helper Functions

# ==============================================================================
# HELPER FUNCTIONS
# ==============================================================================

# Safe division to avoid Inf/NaN
safe_div <- function(num, denom) {
  result <- num / denom
  result[!is.finite(result)] <- NA_real_
  return(result)
}

# Format numbers with commas
fmt_num <- function(x, digits = 2) {
  formatC(x, format = "f", digits = digits, big.mark = ",")
}

# Calculate T-statistic with significance stars (Welch's t-test)
calc_tstat_with_stars <- function(vals1, vals2) {
  # Remove NAs
  vals1 <- vals1[!is.na(vals1)]
  vals2 <- vals2[!is.na(vals2)]
  
  n1 <- length(vals1)
  n2 <- length(vals2)
  
  # Need at least 2 observations in each group
  if (n1 < 2 | n2 < 2) return(list(tstat = NA_real_, stars = "", pval = NA_real_))
  
  # Perform Welch's t-test
  test_result <- tryCatch({
    t.test(vals1, vals2, var.equal = FALSE)
  }, error = function(e) {
    return(NULL)
  })
  
  if (is.null(test_result)) {
    return(list(tstat = NA_real_, stars = "", pval = NA_real_))
  }
  
  t_stat <- test_result$statistic
  p_val <- test_result$p.value
  
  # Assign significance stars
  stars <- case_when(
    p_val < 0.01 ~ "***",
    p_val < 0.05 ~ "**",
    p_val < 0.10 ~ "*",
    TRUE ~ ""
  )
  
  return(list(tstat = as.numeric(t_stat), stars = stars, pval = p_val))
}

# Simple T-stat calculation (for backward compatibility)
calc_tstat <- function(vals1, vals2) {
  result <- calc_tstat_with_stars(vals1, vals2)
  return(result$tstat)
}

4 Period Definitions

# ==============================================================================
# PERIOD DEFINITIONS
# ==============================================================================

periods <- tribble(
  ~period_num, ~period_name, ~start_date, ~end_date, ~description,
  0, "Pre-BTFP",   "2023-03-01", "2023-03-10", "DW only available",
  1, "Acute",      "2023-03-13", "2023-05-01", "Peak crisis phase",
  2, "Post-Acute", "2023-05-02", "2023-10-31", "Stabilization",
  3, "Arbitrage",  "2023-11-01", "2024-01-24", "BTFP rate < IORB",
  4, "Wind-down",  "2024-01-25", "2024-03-11", "BTFP closing announced"
) %>% 
  mutate(across(c(start_date, end_date), as.Date))

# Key dates
BTFP_LAUNCH <- as.Date("2023-03-12")
BTFP_CLOSE <- as.Date("2024-03-11")
DW_DATA_END <- as.Date("2023-12-31")
BASELINE_DATE <- "2022Q4"

# Display periods
periods %>%
  kable(col.names = c("Period", "Name", "Start", "End", "Description"),
        caption = "Analysis Period Definitions") %>%
  kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)
Analysis Period Definitions
Period Name Start End Description
0 Pre-BTFP 2023-03-01 2023-03-10 DW only available
1 Acute 2023-03-13 2023-05-01 Peak crisis phase
2 Post-Acute 2023-05-02 2023-10-31 Stabilization
3 Arbitrage 2023-11-01 2024-01-24 BTFP rate < IORB
4 Wind-down 2024-01-25 2024-03-11 BTFP closing announced

5 Load Data

# ==============================================================================
# LOAD DATA
# ==============================================================================

cat("=== LOADING DATA ===\n")
## === LOADING 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))

cat("Call Report:", nrow(call_q), "observations\n")
## Call Report: 75989 observations
cat("BTFP Loans:", nrow(btfp_loans_raw), "loans\n")
## BTFP Loans: 6734 loans
cat("DW Loans:", nrow(dw_loans_raw), "loans\n")
## DW Loans: 10008 loans

6 Define Exclusions

# ============================================================================
# DEFINE EXCLUDED BANKS AND GSIB IDENTIFICATION
# ============================================================================

# Identify GSIBs at baseline
gsib_banks <- call_q %>%
  filter(period == '2022Q4', gsib == 1) %>%
  pull(idrssd)

# Identify failed banks
failed_banks <- call_q %>%
  filter(period == '2022Q4', failed_bank == 1) %>%
  pull(idrssd)

# Exclude failed + GSIBs for main analysis
excluded_banks <- union(gsib_banks, failed_banks)

cat("=== EXCLUSIONS ===\n")
## === EXCLUSIONS ===
cat("G-SIBs:", length(gsib_banks), "\n")
## G-SIBs: 33
cat("Failed banks:", length(failed_banks), "\n")
## Failed banks: 8
cat("Total excluded:", length(excluded_banks), "\n")
## Total excluded: 41

7 Prepare Baseline Data (2022Q4)

cat("\n=== PREPARING BASELINE DATA (2022Q4) ===\n")
## 
## === PREPARING BASELINE DATA (2022Q4) ===
# Step 1: Filter to baseline quarter and exclude failed/GSIB banks

has_failed_bank <- "failed_bank" %in% names(call_q)
has_gsib <- "gsib" %in% names(call_q)


baseline_q <- call_q %>%
  filter(period == '2022Q4')

cat("Baseline observations (after exclusions):", nrow(baseline_q), "\n")
## Baseline observations (after exclusions): 4737
# Step 3: Calculate medians for cutoffs (BEFORE adding derived variables)
medians <- baseline_q %>%
  summarise(
    median_uninsured = median(uninsured_deposit_to_total_asset, na.rm = TRUE),
    median_mtm = median(mtm_loss_to_total_asset, na.rm = TRUE),
    q75_uninsured = quantile(uninsured_deposit_to_total_asset, 0.75, na.rm = TRUE),
    q75_mtm = quantile(mtm_loss_to_total_asset, 0.75, na.rm = TRUE),
    q90_uninsured = quantile(uninsured_deposit_to_total_asset, 0.90, na.rm = TRUE),
    q90_mtm = quantile(mtm_loss_to_total_asset, 0.90, na.rm = TRUE)
  )

cat("Median uninsured ratio:", round(medians$median_uninsured, 2), "%\n")
## Median uninsured ratio: 21.97 %
cat("Median MTM loss ratio:", round(medians$median_mtm, 2), "%\n")
## Median MTM loss ratio: 5.26 %
cat("Q75 uninsured ratio:", round(medians$q75_uninsured, 2), "%\n")
## Q75 uninsured ratio: 30.27 %
cat("Q75 MTM loss ratio:", round(medians$q75_mtm, 2), "%\n")
## Q75 MTM loss ratio: 6.95 %
# Step 4: Add ALL derived variables to baseline
baseline_q <- baseline_q %>%
  mutate(
    # ================================================================
    # EXISTING VARIABLES
    # ================================================================
    
    # Market value adjustment: (Book Asset / MV Asset) - 1
    cet1_ratio = safe_div(cet1, total_asset) * 100,
    mv_asset = mm_asset,
    mv_adjustment = if_else(mv_asset == 0 | is.na(mv_asset), NA_real_, 
                            (total_asset / mv_asset) - 1),
    
    # IDCR: (MV_Asset - s*Uninsured - Insured) / Insured
    idcr_s50 = safe_div(mv_asset - 0.5 * uninsured_deposit - insured_deposit, insured_deposit),
    idcr_s100 = safe_div(mv_asset - 1.0 * uninsured_deposit - insured_deposit, insured_deposit),
    
    # Capital Insolvency: (Equity - s*Uninsured*MVAdj) / Assets
    cap_insolvency_s50 = safe_div((total_asset - total_liability) - 0.5 * uninsured_deposit * mv_adjustment, total_asset),
    cap_insolvency_s100 = safe_div((total_asset - total_liability) - 1.0 * uninsured_deposit * mv_adjustment, total_asset),
    
    # Adjusted Equity (book equity ratio - MTM loss ratio, both in %)
    adjusted_equity = book_equity_to_total_asset - mtm_loss_to_total_asset,
    adjusted_tier1 = tier1cap_to_total_asset - mtm_loss_to_total_asset,
    adjusted_cet1 = cet1_ratio - mtm_loss_to_total_asset,
    
    # MTM Insolvent dummy (adjusted equity < 0)
    mtm_insolvent = as.integer(adjusted_equity < 0),
    mtm_insolvent_tier1 = as.integer(adjusted_tier1 < 0),
    mtm_insolvent_cet1 = as.integer(adjusted_cet1 < 0),
    
    # Uninsured leverage (uninsured deposit / book equity)
    uninsured_leverage = uninsured_deposit_to_total_asset,
    liquidity_available = safe_div(cash + rerepo + fed_fund_sold, total_asset) * 100,
    
    # Run risk dummies (median-based)
    # a. Solvent and Liquid (both uninsured and MTM below median)
    run_risk_1 = as.integer(
      uninsured_deposit_to_total_asset < medians$median_uninsured & 
        mtm_loss_to_total_asset < medians$median_mtm
    ),
    # b. Solvent and Illiquid
    run_risk_2 = as.integer(
      uninsured_deposit_to_total_asset > medians$median_uninsured & 
        mtm_loss_to_total_asset < medians$median_mtm
    ),
    # c. Insolvent and Liquid  
    run_risk_3 = as.integer(
      uninsured_deposit_to_total_asset < medians$median_uninsured & 
        mtm_loss_to_total_asset > medians$median_mtm
    ),
    # d. Insolvent and Illiquid (both uninsured and MTM above median)  
    run_risk_4 = as.integer(
      uninsured_deposit_to_total_asset > medians$median_uninsured & 
        mtm_loss_to_total_asset > medians$median_mtm
    ),
    
    # IDCR insolvency dummies
    idcr_insolvent_s50 = as.integer(idcr_s50 < 0),
    idcr_insolvent_s100 = as.integer(idcr_s100 < 0),
    
    # Capital insolvency dummies
    cap_insolvent_s50 = as.integer(cap_insolvency_s50 < 0),
    cap_insolvent_s100 = as.integer(cap_insolvency_s100 < 0),
    
    # ================================================================
    # NEW CAPACITY-BASED VARIABLES
    # ================================================================
    
    # Market value of OMO-eligible securities
    # Par value = omo_eligible (face value)
    # MV = omo_eligible * (1 - mtm_loss_omo_eligible_to_omo_eligible/100)
    mv_omo_eligible = omo_eligible * (1 - mtm_loss_omo_eligible_to_omo_eligible / 100),
    
    # Borrowing Capacity at each facility
    # BTFP: Par value (face value) - accepts at par
    btfp_capacity = omo_eligible,
    
    
    
    # DW: Market value (no haircut on OMO eligible per user clarification)
    mv_omo_eligible = (omo_eligible - mtm_loss_omo_eligible),
    
    dw_capacity = mv_omo_eligible,
    
    # THE KEY VARIABLE: Capacity Gap (BTFP - DW)
    # This equals the MTM loss on OMO-eligible securities in dollar terms
    capacity_gap = btfp_capacity - dw_capacity,
    
    # Scaled versions
    capacity_gap_to_assets = safe_div(capacity_gap, total_asset) * 100,
    capacity_gap_to_equity = safe_div(capacity_gap, total_equity) * 100,
    capacity_gap_to_uninsured = safe_div(capacity_gap, uninsured_deposit) * 100,
    
    # Par valuation benefit as % of equity (how much equity "saved" by par valuation)
    par_valuation_benefit = safe_div(capacity_gap, total_equity) * 100,
    
    # ================================================================
    # REVEALED LIQUIDITY MEASURES (using actual deposit changes)
    # ================================================================
    
    # Deposit outflow in dollars (negative change = outflow)
    deposit_outflow_uninsured = if_else(
      !is.na(change_uninsured_fwd_q) & change_uninsured_fwd_q < 0,
      -change_uninsured_fwd_q * uninsured_deposit / 100,
      0
    ),
    
    deposit_outflow_insured = if_else(
      !is.na(change_insured_deposit_fwd_q) & change_insured_deposit_fwd_q < 0,
      -change_insured_deposit_fwd_q * insured_deposit / 100,
      0
    ),
    
    total_deposit_outflow = deposit_outflow_uninsured + deposit_outflow_insured,
    
    # Liquid assets available
    liquid_assets = cash + rerepo + fed_fund_sold,
    
    # Revealed liquidity shortfall (outflow exceeding liquid assets)
    liquidity_shortfall = pmax(0, total_deposit_outflow - liquid_assets),
    liquidity_shortfall_uninsured = pmax(0, deposit_outflow_uninsured - liquid_assets),
    
    # Shortfall ratios
    shortfall_to_assets = safe_div(liquidity_shortfall, total_asset) * 100,
    shortfall_to_equity = safe_div(liquidity_shortfall, total_equity) * 100,
    
    # ================================================================
    # FACILITY SUFFICIENCY CLASSIFICATION
    # ================================================================
    
    # Could DW cover the revealed shortfall?
    dw_covers_shortfall = dw_capacity >= liquidity_shortfall,
    
    # Could BTFP cover the revealed shortfall?
    btfp_covers_shortfall = btfp_capacity >= liquidity_shortfall,
    
    # Is bank MV solvent? (Book equity > MTM losses)
    mv_solvent = mtm_insolvent,
    
    # Alternative: Adjusted equity > 0
    adj_equity_solvent = adjusted_equity > 0,
    
    # DW would have been sufficient (classic Bagehot: solvent + liquid via DW)
    dw_sufficient = dw_covers_shortfall & mv_solvent,
    
    # BTFP necessary: DW insufficient but BTFP sufficient
    btfp_necessary = !dw_sufficient & btfp_covers_shortfall,
    
    # ================================================================
    # FACILITY NEED CLASSIFICATION
    # ================================================================
    
    facility_need_category = case_when(
      # No shortfall - didn't need emergency borrowing
      liquidity_shortfall == 0 | is.na(liquidity_shortfall) ~ "No Shortfall",
      
      # Solvent and DW covers shortfall - Either facility works
      mv_solvent & dw_covers_shortfall ~ "DW Sufficient",
      
      # Solvent but DW cannot cover - BTFP capacity needed
      mv_solvent & !dw_covers_shortfall & btfp_covers_shortfall ~ "BTFP Capacity Needed",
      
      # Insolvent but BTFP covers - BTFP enables survival (solvency bridge)
      !mv_solvent & btfp_covers_shortfall ~ "BTFP Solvency Bridge",
      
      # Neither sufficient - severe distress
      !btfp_covers_shortfall ~ "Severe Distress",
      
      TRUE ~ "Unclassified"
    ),
    
    # ================================================================
    # 75TH PERCENTILE RISK CLASSIFICATION
    # ================================================================
    
    high_mtm_loss_p75 = mtm_loss_to_total_asset > medians$q75_mtm,
    high_uninsured_p75 = uninsured_deposit_to_total_asset > medians$q75_uninsured,
    
    risk_category_p75 = case_when(
      !high_mtm_loss_p75 & !high_uninsured_p75 ~ "Low Risk",
      !high_mtm_loss_p75 & high_uninsured_p75 ~ "Run Risk Only",
      high_mtm_loss_p75 & !high_uninsured_p75 ~ "MTM Risk Only",
      high_mtm_loss_p75 & high_uninsured_p75 ~ "Dual Risk"
    ),
    
    # ================================================================
    # REGULATORY CAPITAL STRESS
    # ================================================================
    
    # Would MTM recognition breach regulatory minimums?
    # CET1 ratio after MTM recognition
    cet1_post_mtm = cet1_ratio - mtm_loss_to_total_asset,
    tier1_post_mtm = tier1cap_to_total_asset - mtm_loss_to_total_asset,
    
    # Regulatory breach indicators (using standard thresholds)
    cet1_breach_4_5 = as.integer(cet1_post_mtm < 4.5),
    tier1_breach_6 = as.integer(tier1_post_mtm < 6),
    tier1_breach_4 = as.integer(tier1_post_mtm < 4),  # PCA threshold
    
    # ================================================================
    # DECOMPOSED MTM LOSS IMPACT
    # ================================================================
    
    # Ratio of eligible to non-eligible MTM losses
    mtm_eligible_share = safe_div(
      mtm_loss_omo_eligible_to_total_asset,
      mtm_loss_to_total_asset
    ) * 100,
    
    # Capacity gap as share of total MTM loss
    capacity_gap_share_of_mtm = safe_div(capacity_gap_to_assets, mtm_loss_to_total_asset) * 100
    
  ) %>%
  filter(
    gsib == 0 | is.na(gsib),
    failed_bank == 0 | is.na(failed_bank),
    !is.na(omo_eligible) & omo_eligible > 0
  )

cat("\nDerived variables added successfully.\n")
## 
## Derived variables added successfully.
cat("Final baseline observations:", nrow(baseline_q), "\n")
## Final baseline observations: 4292
# Display summary of new capacity variables
cat("\n=== CAPACITY GAP SUMMARY ===\n")
## 
## === CAPACITY GAP SUMMARY ===
baseline_q %>%
  summarise(
    mean_capacity_gap_to_assets = mean(capacity_gap_to_assets, na.rm = TRUE),
    median_capacity_gap_to_assets = median(capacity_gap_to_assets, na.rm = TRUE),
    mean_capacity_gap_to_equity = mean(capacity_gap_to_equity, na.rm = TRUE),
    median_capacity_gap_to_equity = median(capacity_gap_to_equity, na.rm = TRUE),
    mean_par_val_benefit = mean(par_valuation_benefit, na.rm = TRUE),
    median_par_val_benefit = median(par_valuation_benefit, na.rm = TRUE)
  ) %>%
  pivot_longer(everything(), names_to = "Measure", values_to = "Value") %>%
  mutate(Value = round(Value, 2)) %>%
  pander(caption = "Capacity Gap Summary Statistics")
Capacity Gap Summary Statistics
Measure Value
mean_capacity_gap_to_assets 0.68
median_capacity_gap_to_assets 0.41
mean_capacity_gap_to_equity 11.41
median_capacity_gap_to_equity 4.48
mean_par_val_benefit 11.41
median_par_val_benefit 4.48
# Display facility need classification
cat("\n=== FACILITY NEED CLASSIFICATION ===\n")
## 
## === FACILITY NEED CLASSIFICATION ===
baseline_q %>%
  count(facility_need_category) %>%
  arrange(desc(n)) %>%
  mutate(pct = round(n / sum(n) * 100, 1)) %>%
  pander(caption = "Distribution of Facility Need Categories")
Distribution of Facility Need Categories
facility_need_category n pct
No Shortfall 3707 86.4
BTFP Solvency Bridge 343 8
DW Sufficient 129 3
Severe Distress 108 2.5
BTFP Capacity Needed 5 0.1

8 Table Functions

# ==============================================================================
# TABLE FORMAT FUNCTIONS WITH T-STATISTICS AND SIGNIFICANCE STARS
# ==============================================================================

# Main function to create summary table with consistent format
# Format: Mean (Median) [T-stat***] with N below each row
# T-stat compares each group to Non-Borrower group

create_summary_table_v2 <- function(data, group_var, group_levels = NULL, reference_group = "Non-Borrower") {
  
  # Define variable specifications
  var_specs <- tribble(
    ~var_name, ~var_label, ~is_dummy,
    # Panel A: Solvency Measures
    "book_equity_to_total_asset", "Book Equity Ratio (%)", FALSE,
    "mtm_loss_to_total_asset", "MTM Loss Total (%)", FALSE,
    "mtm_loss_omo_eligible_to_total_asset", "MTM Loss BTFP-Eligible (%)", FALSE,
    "mtm_loss_non_omo_eligible_to_total_asset", "MTM Loss Non-Eligible (%)", FALSE,
    "adjusted_equity", "Adjusted Equity (%)", FALSE,
    "mtm_insolvent", "MTM Insolvent (Adj. Equity < 0)", TRUE,
    "adjusted_tier1", "Adjusted Tier1 (%)", FALSE,
    "mtm_insolvent_tier1", "Adj. Tier1 < 0", TRUE,
    "adjusted_cet1", "Adjusted CET1 (%)", FALSE,
    "mtm_insolvent_cet1", "Adj. CET1 < 0", TRUE,
    
    # Panel B: Liquidity/Run Risk Measures
    "uninsured_deposit_to_total_asset", "Uninsured Deposits/Assets (%)", FALSE,
    "uninsured_to_deposit", "Uninsured/Total Deposits (%)", FALSE,
    "liquidity_available", "Liquid Assets/Assets (%)", FALSE,
    
    # Panel C: Run Risk Classification (Median-based)
    "run_risk_1", "Low MTM & Low Uninsured", TRUE,
    "run_risk_2", "Low MTM & High Uninsured", TRUE,
    "run_risk_3", "High MTM & Low Uninsured", TRUE,
    "run_risk_4", "High MTM & High Uninsured", TRUE,
    
    # Panel D: Insolvency Measures
    "idcr_insolvent_s50", "IDCR Insolvent (s=0.5)", TRUE,
    "idcr_insolvent_s100", "IDCR Insolvent (s=1.0)", TRUE,
    "cap_insolvent_s50", "Capital Insolvent (s=0.5)", TRUE,
    "cap_insolvent_s100", "Capital Insolvent (s=1.0)", TRUE,
    
    # Panel E: Deposit Flow Outcomes
    "change_uninsured_fwd_q", "Δ Uninsured Deposits (%)", FALSE,
    "change_insured_deposit_fwd_q", "Δ Insured Deposits (%)", FALSE,
    "abnormal_uninsured_outflow_10pct", "Abnormal Uninsured Outflow (10%)", TRUE,
    "abnormal_uninsured_outflow_5pct", "Abnormal Uninsured Outflow (5%)", TRUE,
    "abnormal_insured_outflow_10pct", "Abnormal Insured Outflow (10%)", TRUE,
    "abnormal_insured_outflow_5pct", "Abnormal Insured Outflow (5%)", TRUE,
    
    # Panel F: New Capacity-Based Measures
    "capacity_gap_to_assets", "Capacity Gap/Assets (%)", FALSE,
    "capacity_gap_to_equity", "Capacity Gap/Equity (%)", FALSE,
    "par_valuation_benefit", "Par Valuation Benefit (%)", FALSE,
    "omo_eligible_to_total_asset", "BTFP-Eligible Securities/Assets (%)", FALSE,
    "mtm_loss_omo_eligible_to_omo_eligible", "MTM Loss/Eligible Securities (%)", FALSE
  )
  
  # Get unique groups
  if (is.null(group_levels)) {
    group_levels <- unique(data[[group_var]])
  }
  
  # Calculate N for each group
  n_by_group <- data %>%
    group_by(.data[[group_var]]) %>%
    summarise(N = n(), .groups = "drop")
  
  # Get reference group data for T-stat calculation
  ref_data <- data %>% filter(.data[[group_var]] == reference_group)
  
  # Initialize output list
  output_rows <- list()
  
  # Add N row first
  n_row <- c(Variable = "N", Row_Type = "count")
  for (g in group_levels) {
    n_val <- n_by_group %>% filter(.data[[group_var]] == g) %>% pull(N)
    n_row[g] <- as.character(if(length(n_val) == 0) 0 else n_val)
  }
  output_rows[[1]] <- n_row
  
  row_idx <- 2
  
  # Process each variable
  for (i in seq_len(nrow(var_specs))) {
    v <- var_specs$var_name[i]
    label <- var_specs$var_label[i]
    is_dummy <- var_specs$is_dummy[i]
    
    # Stats row: Mean (Median)
    stats_row <- c(Variable = label, Row_Type = "stats")
    # T-stat row (below stats)
    tstat_row <- c(Variable = "", Row_Type = "tstat")
    # N row (below t-stat)
    obs_row <- c(Variable = "", Row_Type = "n")
    
    # Get reference group values for T-stat
    ref_vals <- if (v %in% names(ref_data)) ref_data[[v]] else numeric(0)
    ref_vals <- ref_vals[!is.na(ref_vals)]
    
    for (g in group_levels) {
      group_data <- data %>% filter(.data[[group_var]] == g)
      
      # Check if variable exists
      if (!v %in% names(group_data)) {
        stats_row[g] <- "—"
        tstat_row[g] <- ""
        obs_row[g] <- "0"
        next
      }
      
      vals <- group_data[[v]]
      vals <- vals[!is.na(vals)]
      
      if (length(vals) == 0) {
        stats_row[g] <- "—"
        tstat_row[g] <- ""
        obs_row[g] <- "0"
      } else {
        mean_val <- mean(vals, na.rm = TRUE)
        median_val <- median(vals, na.rm = TRUE)
        n_val <- length(vals)
        
        if (is_dummy) {
          stats_row[g] <- sprintf("%.2f (%.2f)", mean_val * 100, median_val * 100)
          n_val <- sum(vals)  # Count of banks where dummy = 1
        } else {
          stats_row[g] <- sprintf("%.2f (%.2f)", mean_val, median_val)
          n_val <- length(vals)  # Total non-NA observations
        }
        
        # Calculate T-stat with stars vs reference group (skip for reference group itself)
        if (g == reference_group) {
          tstat_row[g] <- ""
        } else {
          tstat_result <- calc_tstat_with_stars(vals, ref_vals)
          if (!is.na(tstat_result$tstat) && is.finite(tstat_result$tstat)) {
            tstat_row[g] <- sprintf("[%.2f]%s", tstat_result$tstat, tstat_result$stars)
          } else {
            tstat_row[g] <- ""
          }
        }
        
        obs_row[g] <- as.character(n_val)
      }
    }
    
    output_rows[[row_idx]] <- stats_row
    output_rows[[row_idx + 1]] <- tstat_row
    output_rows[[row_idx + 2]] <- obs_row
    row_idx <- row_idx + 3
  }
  
  # Convert to data frame
  result_df <- bind_rows(lapply(output_rows, function(x) as_tibble_row(x)))
  
  return(result_df)
}

# ==============================================================================
# FHLB SUMMARY TABLE FUNCTION (WITH T-STATS AND STARS)
# ==============================================================================

create_fhlb_summary_table <- function(data, group_var, group_levels = NULL, reference_group = "Non-Borrower") {
  
  # Define variable specifications for FHLB table
  var_specs <- tribble(
    ~var_name, ~var_label, ~is_dummy,
    # Basic fundamentals
    "book_equity_to_total_asset", "Book Equity Ratio (%)", FALSE,
    "mtm_loss_to_total_asset", "MTM Loss Total (%)", FALSE,
    "mtm_loss_omo_eligible_to_total_asset", "MTM Loss BTFP-Eligible (%)", FALSE,
    "mtm_loss_non_omo_eligible_to_total_asset", "MTM Loss Non-Eligible (%)", FALSE,
    "adjusted_equity", "Adjusted Equity (%)", FALSE,
    "mtm_insolvent", "MTM Insolvent", TRUE,
    "adjusted_tier1", "Adjusted Tier1 (%)", FALSE,
    "mtm_insolvent_tier1", "Adj. Tier1 < 0", TRUE,
    "adjusted_cet1", "Adjusted CET1 (%)", FALSE,
    "mtm_insolvent_cet1", "Adj. CET1 < 0", TRUE,
    "uninsured_deposit_to_total_asset", "Uninsured/Assets (%)", FALSE,
    "uninsured_to_deposit", "Uninsured/Deposits (%)", FALSE,
    "run_risk_1", "Low MTM & Low Uninsured", TRUE,
    "run_risk_2", "Low MTM & High Uninsured", TRUE,
    "run_risk_3", "High MTM & Low Uninsured", TRUE,
    "run_risk_4", "High MTM & High Uninsured", TRUE,
    "idcr_insolvent_s50", "IDCR Insolvent (s=0.5)", TRUE,
    "idcr_insolvent_s100", "IDCR Insolvent (s=1.0)", TRUE,
    "cap_insolvent_s50", "Capital Insolvent (s=0.5)", TRUE,
    "cap_insolvent_s100", "Capital Insolvent (s=1.0)", TRUE,
    "liquidity_available", "Liquid Assets/Assets (%)", FALSE,
    "change_uninsured_fwd_q", "Δ Uninsured Deposits (%)", FALSE,
    "change_insured_deposit_fwd_q", "Δ Insured Deposits (%)", FALSE,
    "abnormal_insured_outflow_10pct", "Abnormal Insured Outflow (10%)", TRUE,
    "abnormal_insured_outflow_5pct", "Abnormal Insured Outflow (5%)", TRUE,
    "abnormal_uninsured_outflow_10pct", "Abnormal Uninsured Outflow (10%)", TRUE,
    "abnormal_uninsured_outflow_5pct", "Abnormal Uninsured Outflow (5%)", TRUE,
    "capacity_gap_to_assets", "Capacity Gap/Assets (%)", FALSE,
    "capacity_gap_to_equity", "Capacity Gap/Equity (%)", FALSE,
    "par_valuation_benefit", "Par Valuation Benefit (%)", FALSE
  )
  
  # Get unique groups
  if (is.null(group_levels)) {
    group_levels <- unique(data[[group_var]])
  }
  
  # Calculate N for each group
  n_by_group <- data %>%
    group_by(.data[[group_var]]) %>%
    summarise(N = n(), .groups = "drop")
  
  # Get reference group data for T-stat calculation
  ref_data <- data %>% filter(.data[[group_var]] == reference_group)
  
  # Initialize output list
  output_rows <- list()
  
  # Add N row first
  n_row <- c(Variable = "N", Row_Type = "count")
  for (g in group_levels) {
    n_val <- n_by_group %>% filter(.data[[group_var]] == g) %>% pull(N)
    n_row[g] <- as.character(if(length(n_val) == 0) 0 else n_val)
  }
  output_rows[[1]] <- n_row
  
  row_idx <- 2
  
  # Process each variable
  for (i in seq_len(nrow(var_specs))) {
    v <- var_specs$var_name[i]
    label <- var_specs$var_label[i]
    is_dummy <- var_specs$is_dummy[i]
    
    # Stats row: Mean (Median)
    stats_row <- c(Variable = label, Row_Type = "stats")
    # T-stat row (below stats)
    tstat_row <- c(Variable = "", Row_Type = "tstat")
    # N row (below t-stat)
    obs_row <- c(Variable = "", Row_Type = "n")
    
    # Get reference group values for T-stat
    ref_vals <- if (v %in% names(ref_data)) ref_data[[v]] else numeric(0)
    ref_vals <- ref_vals[!is.na(ref_vals)]
    
    for (g in group_levels) {
      group_data <- data %>% filter(.data[[group_var]] == g)
      
      # Check if variable exists
      if (!v %in% names(group_data)) {
        stats_row[g] <- "—"
        tstat_row[g] <- ""
        obs_row[g] <- "0"
        next
      }
      
      vals <- group_data[[v]]
      vals <- vals[!is.na(vals)]
      
      if (length(vals) == 0) {
        stats_row[g] <- "—"
        tstat_row[g] <- ""
        obs_row[g] <- "0"
      } else {
        mean_val <- mean(vals, na.rm = TRUE)
        median_val <- median(vals, na.rm = TRUE)
        
        if (is_dummy) {
          stats_row[g] <- sprintf("%.2f (%.2f)", mean_val * 100, median_val * 100)
          n_val <- sum(vals)
        } else if (v == "total_asset") {
          stats_row[g] <- sprintf("%.0f (%.0f)", mean_val / 1e6, median_val / 1e6)
          n_val <- length(vals)
        } else {
          stats_row[g] <- sprintf("%.2f (%.2f)", mean_val, median_val)
          n_val <- length(vals)
        }
        
        # Calculate T-stat with stars vs reference group
        if (g == reference_group) {
          tstat_row[g] <- ""
        } else {
          tstat_result <- calc_tstat_with_stars(vals, ref_vals)
          if (!is.na(tstat_result$tstat) && is.finite(tstat_result$tstat)) {
            tstat_row[g] <- sprintf("[%.2f]%s", tstat_result$tstat, tstat_result$stars)
          } else {
            tstat_row[g] <- ""
          }
        }
        
        obs_row[g] <- as.character(n_val)
      }
    }
    
    output_rows[[row_idx]] <- stats_row
    output_rows[[row_idx + 1]] <- tstat_row
    output_rows[[row_idx + 2]] <- obs_row
    row_idx <- row_idx + 3
  }
  
  # Convert to data frame
  result_df <- bind_rows(lapply(output_rows, function(x) as_tibble_row(x)))
  
  return(result_df)
}

# ==============================================================================
# CAPACITY-FOCUSED TABLE FUNCTION
# ==============================================================================

create_capacity_table <- function(data, group_var, group_levels = NULL, reference_group = "Non-Borrower") {
  
  # Define variable specifications focused on capacity measures
  var_specs <- tribble(
    ~var_name, ~var_label, ~is_dummy,
    # Core Capacity Measures
    "omo_eligible_to_total_asset", "BTFP-Eligible Securities/Assets (%)", FALSE,
    "non_omo_eligible_to_total_asset", "Non-Eligible Securities/Assets (%)", FALSE,
    "mtm_loss_omo_eligible_to_total_asset", "MTM Loss Eligible/Assets (%)", FALSE,
    "mtm_loss_non_omo_eligible_to_total_asset", "MTM Loss Non-Eligible/Assets (%)", FALSE,
    "mtm_loss_omo_eligible_to_omo_eligible", "MTM Loss/Eligible Securities (%)", FALSE,
    
    # Capacity Gap Measures
    "capacity_gap_to_assets", "Capacity Gap/Assets (%)", FALSE,
    "capacity_gap_to_equity", "Capacity Gap/Equity (%)", FALSE,
    "capacity_gap_to_uninsured", "Capacity Gap/Uninsured Deposits (%)", FALSE,
    "par_valuation_benefit", "Par Valuation Benefit (%)", FALSE,
    "mtm_eligible_share", "Eligible Share of Total MTM Loss (%)", FALSE,
    
    # Solvency Context
    "book_equity_to_total_asset", "Book Equity/Assets (%)", FALSE,
    "adjusted_equity", "Adjusted Equity (%)", FALSE,
    "mtm_insolvent", "MTM Insolvent", TRUE,
    "cet1_post_mtm", "CET1 Post-MTM (%)", FALSE,
    "cet1_breach_4_5", "CET1 < 4.5% After MTM", TRUE,
    "tier1_breach_4", "Tier1 < 4% After MTM (PCA)", TRUE,
    
    # Liquidity Context
    "uninsured_deposit_to_total_asset", "Uninsured Deposits/Assets (%)", FALSE,
    "liquidity_available", "Liquid Assets/Assets (%)", FALSE,
    "shortfall_to_assets", "Liquidity Shortfall/Assets (%)", FALSE,
    
    # Facility Sufficiency
    "dw_covers_shortfall", "DW Covers Shortfall", TRUE,
    "btfp_covers_shortfall", "BTFP Covers Shortfall", TRUE,
    "dw_sufficient", "DW Sufficient (Solvent + Covers)", TRUE,
    "btfp_necessary", "BTFP Necessary", TRUE
  )
  
  # Get unique groups
  if (is.null(group_levels)) {
    group_levels <- unique(data[[group_var]])
  }
  
  # Calculate N for each group
  n_by_group <- data %>%
    group_by(.data[[group_var]]) %>%
    summarise(N = n(), .groups = "drop")
  
  # Get reference group data for T-stat calculation
  ref_data <- data %>% filter(.data[[group_var]] == reference_group)
  
  # Initialize output list
  output_rows <- list()
  
  # Add N row first
  n_row <- c(Variable = "N", Row_Type = "count")
  for (g in group_levels) {
    n_val <- n_by_group %>% filter(.data[[group_var]] == g) %>% pull(N)
    n_row[g] <- as.character(if(length(n_val) == 0) 0 else n_val)
  }
  output_rows[[1]] <- n_row
  
  row_idx <- 2
  
  # Process each variable
  for (i in seq_len(nrow(var_specs))) {
    v <- var_specs$var_name[i]
    label <- var_specs$var_label[i]
    is_dummy <- var_specs$is_dummy[i]
    
    # Stats row: Mean (Median)
    stats_row <- c(Variable = label, Row_Type = "stats")
    # T-stat row
    tstat_row <- c(Variable = "", Row_Type = "tstat")
    # N row
    obs_row <- c(Variable = "", Row_Type = "n")
    
    # Get reference group values
    ref_vals <- if (v %in% names(ref_data)) ref_data[[v]] else numeric(0)
    ref_vals <- ref_vals[!is.na(ref_vals)]
    
    for (g in group_levels) {
      group_data <- data %>% filter(.data[[group_var]] == g)
      
      if (!v %in% names(group_data)) {
        stats_row[g] <- "—"
        tstat_row[g] <- ""
        obs_row[g] <- "0"
        next
      }
      
      vals <- group_data[[v]]
      vals <- vals[!is.na(vals)]
      
      if (length(vals) == 0) {
        stats_row[g] <- "—"
        tstat_row[g] <- ""
        obs_row[g] <- "0"
      } else {
        mean_val <- mean(vals, na.rm = TRUE)
        median_val <- median(vals, na.rm = TRUE)
        
        if (is_dummy) {
          stats_row[g] <- sprintf("%.2f (%.2f)", mean_val * 100, median_val * 100)
          n_val <- sum(vals)
        } else {
          stats_row[g] <- sprintf("%.2f (%.2f)", mean_val, median_val)
          n_val <- length(vals)
        }
        
        if (g == reference_group) {
          tstat_row[g] <- ""
        } else {
          tstat_result <- calc_tstat_with_stars(vals, ref_vals)
          if (!is.na(tstat_result$tstat) && is.finite(tstat_result$tstat)) {
            tstat_row[g] <- sprintf("[%.2f]%s", tstat_result$tstat, tstat_result$stars)
          } else {
            tstat_row[g] <- ""
          }
        }
        
        obs_row[g] <- as.character(n_val)
      }
    }
    
    output_rows[[row_idx]] <- stats_row
    output_rows[[row_idx + 1]] <- tstat_row
    output_rows[[row_idx + 2]] <- obs_row
    row_idx <- row_idx + 3
  }
  
  result_df <- bind_rows(lapply(output_rows, function(x) as_tibble_row(x)))
  return(result_df)
}

# ==============================================================================
# LATEX TABLE EXPORT FUNCTION (UPDATED FOR T-STATS WITH STARS)
# ==============================================================================

export_latex_table <- function(summary_df, filepath, caption, label, note = NULL) {
  
  # Get column names (excluding Variable and Row_Type)
  group_cols <- names(summary_df)[!names(summary_df) %in% c("Variable", "Row_Type")]
  n_groups <- length(group_cols)
  
  # Clean column names for display
  clean_cols <- gsub("_", " ", group_cols)
  clean_cols <- gsub("Non Borrower", "Non-Borrower", clean_cols)
  
  # Build LaTeX
  latex <- c(
    "\\begin{table}[htbp]",
    "\\centering",
    "\\small",
    sprintf("\\caption{%s}", caption),
    sprintf("\\label{%s}", label),
    "",
    sprintf("\\begin{tabular}{l%s}", paste(rep("c", n_groups), collapse = "")),
    "\\toprule",
    paste0(" & ", paste(clean_cols, collapse = " & "), " \\\\"),
    "\\midrule"
  )
  
  # Add rows
  for (i in seq_len(nrow(summary_df))) {
    row <- summary_df[i, ]
    var_name <- as.character(row$Variable)
    row_type <- as.character(row$Row_Type)
    vals <- as.character(row[group_cols])
    
    if (row_type == "count") {
      # N row - bold
      latex <- c(latex, 
                 sprintf("N & %s \\\\", paste(vals, collapse = " & ")),
                 "\\midrule")
    } else if (row_type == "stats" && var_name != "") {
      # Variable name row with statistics
      latex <- c(latex, sprintf("%s & %s \\\\", var_name, paste(vals, collapse = " & ")))
    } else if (row_type == "tstat") {
      # T-stat row (smaller font, with significance stars)
      tstat_vals <- paste0("\\scriptsize{", vals, "}")
      latex <- c(latex, sprintf("& %s \\\\", paste(tstat_vals, collapse = " & ")))
    } else if (row_type == "n") {
      # N below stats (italics)
      n_vals <- paste0("\\textit{", vals, "}")
      latex <- c(latex, sprintf("& %s \\\\[0.3em]", paste(n_vals, collapse = " & ")))
    }
  }
  
  latex <- c(latex,
             "\\bottomrule",
             "\\end{tabular}",
             "")
  
  # Add note if provided
  if (!is.null(note)) {
    latex <- c(latex,
               "\\vspace{0.3em}",
               "\\begin{minipage}{0.95\\textwidth}",
               "\\footnotesize",
               sprintf("\\textit{Notes:} %s T-statistics in brackets compare each borrower group to Non-Borrowers using Welch's t-test. ***, **, * denote significance at 1\\%%, 5\\%%, and 10\\%% levels, respectively.", note),
               "\\end{minipage}")
  }
  
  latex <- c(latex, "\\end{table}")
  
  # Write to file
  writeLines(latex, filepath)
  cat("LaTeX table saved:", filepath, "\n")
  
  return(invisible(latex))
}

# ==============================================================================
# HTML TABLE EXPORT FUNCTION
# ==============================================================================

export_html_table <- function(summary_df, filepath, caption) {
  
  # Get column names (excluding Row_Type)
  display_cols <- names(summary_df)[names(summary_df) != "Row_Type"]
  
  # Clean column names
  clean_names <- gsub("_", " ", display_cols)
  clean_names <- gsub("Non Borrower", "Non-Borrower", clean_names)
  
  # Create display dataframe
  display_df <- summary_df %>%
    select(all_of(display_cols))
  
  # Generate HTML table
  html_table <- display_df %>%
    kable(format = "html", 
          col.names = clean_names,
          caption = caption,
          escape = FALSE) %>%
    kable_styling(bootstrap_options = c("striped", "hover", "condensed"),
                  full_width = FALSE,
                  font_size = 12) %>%
    row_spec(1, bold = TRUE)  # Bold N row
  
  # Save to file
  save_kable(html_table, filepath)
  cat("HTML table saved:", filepath, "\n")
  
  return(invisible(html_table))
}

# ==============================================================================
# COMBINED EXPORT FUNCTION
# ==============================================================================

export_table <- function(summary_df, table_name, caption, label, note = NULL) {
  
  # LaTeX export
  latex_path <- file.path(TABLE_PATH, paste0(table_name, ".tex"))
  export_latex_table(summary_df, latex_path, caption, label, note)
  
  # HTML export
  html_path <- file.path(TABLE_PATH, paste0(table_name, ".html"))
  export_html_table(summary_df, html_path, caption)
  
  # CSV export (for reference)
  csv_path <- file.path(TABLE_PATH, paste0(table_name, ".csv"))
  write_csv(summary_df, csv_path)
  cat("CSV table saved:", csv_path, "\n")
  
  return(invisible(list(latex = latex_path, html = html_path, csv = csv_path)))
}

9 Table 1: March 10, 2023 - DW Borrowers vs Non-Borrowers

# ==============================================================================
# TABLE 1: March 10, 2023 Only - DW Borrowers vs Non-Borrowers
# ==============================================================================

cat("\n", strrep("=", 60), "\n")
## 
##  ============================================================
cat("TABLE 1: March 10, 2023 - DW Borrowers vs Non-Borrowers\n")
## TABLE 1: March 10, 2023 - DW Borrowers vs Non-Borrowers
cat(strrep("=", 60), "\n")
## ============================================================
dw_mar10 <- dw_loans_raw %>%
  filter(dw_loan_date == as.Date("2023-03-10")) %>%
  distinct(rssd_id) %>%
  pull(rssd_id)

cat("DW borrowers on March 10:", length(dw_mar10), "\n")
## DW borrowers on March 10: 52
table1_data <- baseline_q %>%
  mutate(
    borrower_type = if_else(idrssd %in% dw_mar10, "DW Borrower", "Non-Borrower")
  )

table1 <- create_summary_table_v2(table1_data, "borrower_type", 
                                   group_levels = c("DW Borrower", "Non-Borrower"))

# Display
table1 %>%
  select(-Row_Type) %>%
  kable(caption = "Table 1: Pre-Crisis Bank Characteristics - DW Borrowers vs Non-Borrowers (March 10, 2023)") %>%
  kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)
Table 1: Pre-Crisis Bank Characteristics - DW Borrowers vs Non-Borrowers (March 10, 2023)
Variable DW Borrower Non-Borrower
N 47 4245
Book Equity Ratio (%) 8.20 (8.45) 10.24 (8.85)
[-4.93]***
47 4245
MTM Loss Total (%) 5.69 (5.66) 5.46 (5.31)
[0.72]
47 4235
MTM Loss BTFP-Eligible (%) 0.89 (0.58) 0.68 (0.40)
[1.72]*
47 4235
MTM Loss Non-Eligible (%) 4.75 (4.42) 4.60 (4.39)
[0.53]
47 4235
Adjusted Equity (%) 2.51 (2.44) 4.70 (3.64)
[-3.70]***
47 4235
MTM Insolvent (Adj. Equity < 0) 23.40 (0.00) 19.22 (0.00)
[0.67]
11 814
Adjusted Tier1 (%) 3.67 (2.90) 6.33 (5.06)
[-6.67]***
47 4235
Adj. Tier1 < 0 4.26 (0.00) 3.31 (0.00)
[0.32]
2 140
Adjusted CET1 (%) 3.66 (2.90) 6.28 (5.05)
[-6.60]***
47 4179
Adj. CET1 < 0 4.26 (0.00) 3.25 (0.00)
[0.33]
2 136
Uninsured Deposits/Assets (%) 29.88 (28.54) 23.54 (22.22)
[3.44]***
47 4245
Uninsured/Total Deposits (%) 36.03 (33.84) 27.50 (25.74)
[3.62]***
47 4245
Liquid Assets/Assets (%) 3.27 (2.25) 9.36 (5.94)
[-13.94]***
47 4245
Low MTM & Low Uninsured 10.64 (0.00) 22.42 (0.00)
[-2.57]**
5 951
Low MTM & High Uninsured 29.79 (0.00) 26.56 (0.00)
[0.48]
14 1126
High MTM & Low Uninsured 19.15 (0.00) 26.55 (0.00)
[-1.27]
9 1126
High MTM & High Uninsured 40.43 (0.00) 24.30 (0.00)
[2.22]**
19 1030
IDCR Insolvent (s=0.5) 2.13 (0.00) 4.23 (0.00)
[-0.98]
1 178
IDCR Insolvent (s=1.0) 34.04 (0.00) 28.40 (0.00)
[0.80]
16 1194
Capital Insolvent (s=0.5) 4.26 (0.00) 2.17 (0.00)
[0.70]
2 92
Capital Insolvent (s=1.0) 17.02 (0.00) 7.51 (0.00)
[1.71]*
8 318
Δ Uninsured Deposits (%) -13.11 (-11.89) 0.18 (-4.54)
[-4.14]***
47 4181
Δ Insured Deposits (%) 5.35 (2.14) 3.83 (1.48)
[0.97]
47 4187
Abnormal Uninsured Outflow (10%) 42.55 (0.00) 21.25 (0.00)
[2.91]***
20 902
Abnormal Uninsured Outflow (5%) 25.53 (0.00) 9.07 (0.00)
[2.55]**
12 385
Abnormal Insured Outflow (10%) 6.38 (0.00) 7.51 (0.00)
[-0.31]
3 319
Abnormal Insured Outflow (5%) 0.00 (0.00) 2.69 (0.00)
[-10.82]***
0 114
Capacity Gap/Assets (%) 0.89 (0.58) 0.68 (0.40)
[1.72]*
47 4235
Capacity Gap/Equity (%) 16.80 (8.77) 11.35 (4.45)
[1.07]
47 4235
Par Valuation Benefit (%) 16.80 (8.77) 11.35 (4.45)
[1.07]
47 4235
BTFP-Eligible Securities/Assets (%) 10.82 (8.07) 10.77 (7.78)
[0.03]
47 4245
MTM Loss/Eligible Securities (%) 9.69 (8.16) 10.31 (6.52)
[-0.19]
47 4235
# Export
export_table(
  table1, 
  "table1_dw_mar10",
  caption = "Pre-Crisis Bank Characteristics: DW Borrowers vs Non-Borrowers (March 10, 2023)",
  label = "tab:dw_mar10",
  note = "Bank characteristics from 2022Q4 Call Reports. Values shown as Mean (Median) with N observations below. Continuous variables in percentage points. Dummy variables show proportion (\\%) with value = 1. DW borrowers identified as banks with Discount Window loans on March 10, 2023 only. Sample excludes G-SIBs and failed banks."
)
## LaTeX table saved: C:/Users/mferdo2/OneDrive - Louisiana State University/Finance_PhD/DW_Stigma_paper/Liquidity_project_2025/03_documentation/borrowing_stat_new/tables/table1_dw_mar10.tex 
## HTML table saved: C:/Users/mferdo2/OneDrive - Louisiana State University/Finance_PhD/DW_Stigma_paper/Liquidity_project_2025/03_documentation/borrowing_stat_new/tables/table1_dw_mar10.html 
## CSV table saved: C:/Users/mferdo2/OneDrive - Louisiana State University/Finance_PhD/DW_Stigma_paper/Liquidity_project_2025/03_documentation/borrowing_stat_new/tables/table1_dw_mar10.csv

10 Table 2: March 10-13, 2023 - DW Borrowers vs Non-Borrowers

# ==============================================================================
# TABLE 2: March 10-13, 2023 - DW Borrowers vs Non-Borrowers
# ==============================================================================

cat("\n", strrep("=", 60), "\n")
## 
##  ============================================================
cat("TABLE 2: March 10-13, 2023 - DW Borrowers vs Non-Borrowers\n")
## TABLE 2: March 10-13, 2023 - DW Borrowers vs Non-Borrowers
cat(strrep("=", 60), "\n")
## ============================================================
dw_mar10_13 <- dw_loans_raw %>%
  filter(dw_loan_date >= as.Date("2023-03-10") & dw_loan_date <= as.Date("2023-03-13")) %>%
  distinct(rssd_id) %>%
  pull(rssd_id)

cat("DW borrowers March 10-13:", length(dw_mar10_13), "\n")
## DW borrowers March 10-13: 98
table2_data <- baseline_q %>%
  mutate(
    borrower_type = if_else(idrssd %in% dw_mar10_13, "DW Borrower", "Non-Borrower")
  )

table2 <- create_summary_table_v2(table2_data, "borrower_type",
                                   group_levels = c("DW Borrower", "Non-Borrower"))

# Display
table2 %>%
  select(-Row_Type) %>%
  kable(caption = "Table 2: Pre-Crisis Bank Characteristics - DW Borrowers vs Non-Borrowers (March 10-13, 2023)") %>%
  kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)
Table 2: Pre-Crisis Bank Characteristics - DW Borrowers vs Non-Borrowers (March 10-13, 2023)
Variable DW Borrower Non-Borrower
N 90 4202
Book Equity Ratio (%) 8.55 (8.46) 10.26 (8.85)
[-5.17]***
90 4202
MTM Loss Total (%) 5.54 (5.61) 5.47 (5.31)
[0.34]
90 4192
MTM Loss BTFP-Eligible (%) 0.84 (0.55) 0.68 (0.40)
[1.92]*
90 4192
MTM Loss Non-Eligible (%) 4.69 (4.56) 4.60 (4.39)
[0.46]
90 4192
Adjusted Equity (%) 3.01 (2.72) 4.71 (3.64)
[-3.86]***
90 4192
MTM Insolvent (Adj. Equity < 0) 20.00 (0.00) 19.25 (0.00)
[0.17]
18 807
Adjusted Tier1 (%) 4.03 (3.75) 6.35 (5.07)
[-7.80]***
90 4192
Adj. Tier1 < 0 3.33 (0.00) 3.32 (0.00)
[0.01]
3 139
Adjusted CET1 (%) 3.99 (3.82) 6.30 (5.06)
[-7.99]***
87 4139
Adj. CET1 < 0 3.45 (0.00) 3.26 (0.00)
[0.09]
3 135
Uninsured Deposits/Assets (%) 32.99 (30.99) 23.41 (22.12)
[6.81]***
90 4202
Uninsured/Total Deposits (%) 39.43 (39.63) 27.34 (25.63)
[6.97]***
90 4202
Liquid Assets/Assets (%) 4.30 (2.86) 9.40 (5.97)
[-10.23]***
90 4202
Low MTM & Low Uninsured 10.00 (0.00) 22.56 (0.00)
[-3.87]***
9 947
Low MTM & High Uninsured 33.33 (0.00) 26.45 (0.00)
[1.36]
30 1110
High MTM & Low Uninsured 12.22 (0.00) 26.77 (0.00)
[-4.11]***
11 1124
High MTM & High Uninsured 44.44 (0.00) 24.05 (0.00)
[3.84]***
40 1009
IDCR Insolvent (s=0.5) 5.56 (0.00) 4.18 (0.00)
[0.56]
5 174
IDCR Insolvent (s=1.0) 34.44 (0.00) 28.33 (0.00)
[1.20]
31 1179
Capital Insolvent (s=0.5) 5.56 (0.00) 2.12 (0.00)
[1.41]
5 89
Capital Insolvent (s=1.0) 16.67 (0.00) 7.42 (0.00)
[2.33]**
15 311
Δ Uninsured Deposits (%) -10.14 (-8.93) 0.25 (-4.45)
[-3.97]***
90 4138
Δ Insured Deposits (%) 8.03 (2.39) 3.76 (1.45)
[1.48]
90 4144
Abnormal Uninsured Outflow (10%) 41.11 (0.00) 21.06 (0.00)
[3.82]***
37 885
Abnormal Uninsured Outflow (5%) 22.22 (0.00) 8.97 (0.00)
[2.99]***
20 377
Abnormal Insured Outflow (10%) 5.56 (0.00) 7.54 (0.00)
[-0.81]
5 317
Abnormal Insured Outflow (5%) 1.11 (0.00) 2.69 (0.00)
[-1.39]
1 113
Capacity Gap/Assets (%) 0.84 (0.55) 0.68 (0.40)
[1.92]*
90 4192
Capacity Gap/Equity (%) 14.23 (6.65) 11.34 (4.44)
[0.97]
90 4192
Par Valuation Benefit (%) 14.23 (6.65) 11.34 (4.44)
[0.97]
90 4192
BTFP-Eligible Securities/Assets (%) 10.16 (6.98) 10.78 (7.78)
[-0.63]
90 4202
MTM Loss/Eligible Securities (%) 9.37 (8.29) 10.32 (6.50)
[-0.31]
90 4192
# Export
export_table(
  table2, 
  "table2_dw_mar10_13",
  caption = "Pre-Crisis Bank Characteristics: DW Borrowers vs Non-Borrowers (March 10--13, 2023)",
  label = "tab:dw_mar10_13",
  note = "Bank characteristics from 2022Q4 Call Reports. Values shown as Mean (Median) with N observations below. DW borrowers identified as banks with Discount Window loans between March 10--13, 2023. Sample excludes G-SIBs and failed banks."
)
## LaTeX table saved: C:/Users/mferdo2/OneDrive - Louisiana State University/Finance_PhD/DW_Stigma_paper/Liquidity_project_2025/03_documentation/borrowing_stat_new/tables/table2_dw_mar10_13.tex 
## HTML table saved: C:/Users/mferdo2/OneDrive - Louisiana State University/Finance_PhD/DW_Stigma_paper/Liquidity_project_2025/03_documentation/borrowing_stat_new/tables/table2_dw_mar10_13.html 
## CSV table saved: C:/Users/mferdo2/OneDrive - Louisiana State University/Finance_PhD/DW_Stigma_paper/Liquidity_project_2025/03_documentation/borrowing_stat_new/tables/table2_dw_mar10_13.csv

11 Table 3: March 9-14, 2023 - DW Borrowers vs Non-Borrowers

# ==============================================================================
# TABLE 3: March 9-14, 2023 - DW Borrowers vs Non-Borrowers
# ==============================================================================

cat("\n", strrep("=", 60), "\n")
## 
##  ============================================================
cat("TABLE 3: March 9-14, 2023 - DW Borrowers vs Non-Borrowers\n")
## TABLE 3: March 9-14, 2023 - DW Borrowers vs Non-Borrowers
cat(strrep("=", 60), "\n")
## ============================================================
dw_mar9_14 <- dw_loans_raw %>%
  filter(dw_loan_date >= as.Date("2023-03-09") & dw_loan_date <= as.Date("2023-03-14")) %>%
  distinct(rssd_id) %>%
  pull(rssd_id)

cat("DW borrowers March 9-14:", length(dw_mar9_14), "\n")
## DW borrowers March 9-14: 137
table3_data <- baseline_q %>%
  mutate(
    borrower_type = if_else(idrssd %in% dw_mar9_14, "DW Borrower", "Non-Borrower")
  )

table3 <- create_summary_table_v2(table3_data, "borrower_type",
                                   group_levels = c("DW Borrower", "Non-Borrower"))

# Display
table3 %>%
  select(-Row_Type) %>%
  kable(caption = "Table 3: Pre-Crisis Bank Characteristics - DW Borrowers vs Non-Borrowers (March 9-14, 2023)") %>%
  kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)
Table 3: Pre-Crisis Bank Characteristics - DW Borrowers vs Non-Borrowers (March 9-14, 2023)
Variable DW Borrower Non-Borrower
N 124 4168
Book Equity Ratio (%) 9.01 (8.64) 10.26 (8.85)
[-3.59]***
124 4168
MTM Loss Total (%) 5.50 (5.58) 5.47 (5.31)
[0.17]
124 4158
MTM Loss BTFP-Eligible (%) 0.77 (0.52) 0.68 (0.40)
[1.30]
124 4158
MTM Loss Non-Eligible (%) 4.67 (4.56) 4.60 (4.39)
[0.45]
124 4158
Adjusted Equity (%) 3.51 (2.91) 4.71 (3.64)
[-2.72]***
124 4158
MTM Insolvent (Adj. Equity < 0) 20.16 (0.00) 19.24 (0.00)
[0.25]
25 800
Adjusted Tier1 (%) 4.58 (3.98) 6.35 (5.07)
[-5.05]***
124 4158
Adj. Tier1 < 0 3.23 (0.00) 3.32 (0.00)
[-0.06]
4 138
Adjusted CET1 (%) 4.56 (3.98) 6.30 (5.06)
[-4.95]***
121 4105
Adj. CET1 < 0 3.31 (0.00) 3.26 (0.00)
[0.03]
4 134
Uninsured Deposits/Assets (%) 31.30 (29.52) 23.38 (22.08)
[6.50]***
124 4168
Uninsured/Total Deposits (%) 37.32 (34.86) 27.31 (25.61)
[6.77]***
124 4168
Liquid Assets/Assets (%) 5.31 (3.31) 9.42 (6.00)
[-7.31]***
124 4168
Low MTM & Low Uninsured 11.29 (0.00) 22.62 (0.00)
[-3.87]***
14 942
Low MTM & High Uninsured 33.87 (0.00) 26.38 (0.00)
[1.73]*
42 1098
High MTM & Low Uninsured 14.52 (0.00) 26.83 (0.00)
[-3.79]***
18 1117
High MTM & High Uninsured 40.32 (0.00) 24.00 (0.00)
[3.65]***
50 999
IDCR Insolvent (s=0.5) 5.65 (0.00) 4.17 (0.00)
[0.70]
7 172
IDCR Insolvent (s=1.0) 35.48 (0.00) 28.25 (0.00)
[1.65]
44 1166
Capital Insolvent (s=0.5) 4.84 (0.00) 2.12 (0.00)
[1.40]
6 88
Capital Insolvent (s=1.0) 15.32 (0.00) 7.38 (0.00)
[2.43]**
19 307
Δ Uninsured Deposits (%) -7.45 (-8.04) 0.26 (-4.46)
[-2.97]***
124 4104
Δ Insured Deposits (%) 7.31 (2.63) 3.74 (1.44)
[1.62]
124 4110
Abnormal Uninsured Outflow (10%) 37.10 (0.00) 21.02 (0.00)
[3.65]***
46 876
Abnormal Uninsured Outflow (5%) 18.55 (0.00) 8.97 (0.00)
[2.71]***
23 374
Abnormal Insured Outflow (10%) 6.45 (0.00) 7.53 (0.00)
[-0.48]
8 314
Abnormal Insured Outflow (5%) 2.42 (0.00) 2.66 (0.00)
[-0.17]
3 111
Capacity Gap/Assets (%) 0.77 (0.52) 0.68 (0.40)
[1.30]
124 4158
Capacity Gap/Equity (%) 12.32 (5.68) 11.38 (4.45)
[0.42]
124 4158
Par Valuation Benefit (%) 12.32 (5.68) 11.38 (4.45)
[0.42]
124 4158
BTFP-Eligible Securities/Assets (%) 9.57 (6.89) 10.81 (7.79)
[-1.57]
124 4168
MTM Loss/Eligible Securities (%) 8.80 (8.12) 10.35 (6.49)
[-0.51]
124 4158
# Export
export_table(
  table3, 
  "table3_dw_mar9_14",
  caption = "Pre-Crisis Bank Characteristics: DW Borrowers vs Non-Borrowers (March 9--14, 2023)",
  label = "tab:dw_mar9_14",
  note = "Bank characteristics from 2022Q4 Call Reports. Values shown as Mean (Median) with N observations below. DW borrowers identified as banks with Discount Window loans between March 9--14, 2023. Sample excludes G-SIBs and failed banks."
)
## LaTeX table saved: C:/Users/mferdo2/OneDrive - Louisiana State University/Finance_PhD/DW_Stigma_paper/Liquidity_project_2025/03_documentation/borrowing_stat_new/tables/table3_dw_mar9_14.tex 
## HTML table saved: C:/Users/mferdo2/OneDrive - Louisiana State University/Finance_PhD/DW_Stigma_paper/Liquidity_project_2025/03_documentation/borrowing_stat_new/tables/table3_dw_mar9_14.html 
## CSV table saved: C:/Users/mferdo2/OneDrive - Louisiana State University/Finance_PhD/DW_Stigma_paper/Liquidity_project_2025/03_documentation/borrowing_stat_new/tables/table3_dw_mar9_14.csv

12 Table 4: Acute Period - BTFP, DW, Both, Non-Borrowers

# ==============================================================================
# TABLE 4: Acute Period (March 13 - May 1, 2023)
# ==============================================================================

cat("\n", strrep("=", 60), "\n")
## 
##  ============================================================
cat("TABLE 4: Acute Period - BTFP, DW, Both, Non-Borrowers\n")
## TABLE 4: Acute Period - BTFP, DW, Both, Non-Borrowers
cat(strrep("=", 60), "\n")
## ============================================================
acute_start <- as.Date("2023-03-13")
acute_end <- as.Date("2023-05-01")

btfp_acute <- btfp_loans_raw %>%
  filter(btfp_loan_date >= acute_start & btfp_loan_date <= acute_end) %>%
  distinct(rssd_id) %>%
  pull(rssd_id)

dw_acute <- dw_loans_raw %>%
  filter(dw_loan_date >= acute_start & dw_loan_date <= acute_end) %>%
  distinct(rssd_id) %>%
  pull(rssd_id)

cat("BTFP borrowers (Acute):", length(btfp_acute), "\n")
## BTFP borrowers (Acute): 492
cat("DW borrowers (Acute):", length(dw_acute), "\n")
## DW borrowers (Acute): 424
cat("Both:", length(intersect(btfp_acute, dw_acute)), "\n")
## Both: 103
table4_data <- baseline_q %>%
  mutate(
    btfp_user = idrssd %in% btfp_acute,
    dw_user = idrssd %in% dw_acute,
    borrower_type = case_when(
      btfp_user & dw_user ~ "Both",
      btfp_user & !dw_user ~ "BTFP Only",
      !btfp_user & dw_user ~ "DW Only",
      TRUE ~ "Non-Borrower"
    )
  )

table4 <- create_summary_table_v2(table4_data, "borrower_type",
                                   group_levels = c("BTFP Only", "DW Only", "Both", "Non-Borrower"))

# Display
table4 %>%
  select(-Row_Type) %>%
  kable(caption = "Table 4: Pre-Crisis Bank Characteristics by Borrower Type (Acute Period: March 13 - May 1, 2023)") %>%
  kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)
Table 4: Pre-Crisis Bank Characteristics by Borrower Type (Acute Period: March 13 - May 1, 2023)
Variable BTFP Only DW Only Both Non-Borrower
N 368 299 94 3531
Book Equity Ratio (%) 8.18 (8.08) 9.05 (8.82) 8.19 (8.23) 10.59 (8.96)
[-10.58]*** [-6.25]*** [-7.48]***
368 299 94 3531
MTM Loss Total (%) 6.18 (6.13) 5.75 (5.67) 5.86 (5.75) 5.36 (5.18)
[7.42]*** [3.19]*** [2.60]**
368 299 94 3521
MTM Loss BTFP-Eligible (%) 0.88 (0.61) 0.74 (0.48) 0.92 (0.61) 0.65 (0.38)
[4.32]*** [1.85]* [2.68]***
368 299 94 3521
MTM Loss Non-Eligible (%) 5.02 (4.90) 4.95 (4.90) 4.88 (4.67) 4.52 (4.29)
[4.91]*** [3.73]*** [1.95]*
368 299 94 3521
Adjusted Equity (%) 2.00 (2.03) 3.30 (3.01) 2.33 (2.70) 5.13 (3.89)
[-11.32]*** [-6.16]*** [-6.43]***
368 299 94 3521
MTM Insolvent (Adj. Equity < 0) 30.43 (0.00) 19.06 (0.00) 21.28 (0.00) 18.06 (0.00)
[4.97]*** [0.42] [0.75]
112 57 20 636
Adjusted Tier1 (%) 4.13 (3.77) 4.71 (4.15) 3.76 (3.70) 6.73 (5.31)
[-11.55]*** [-8.16]*** [-9.80]***
368 299 94 3521
Adj. Tier1 < 0 4.62 (0.00) 3.34 (0.00) 5.32 (0.00) 3.12 (0.00)
[1.32] [0.20] [0.94]
17 10 5 110
Adjusted CET1 (%) 4.11 (3.77) 4.71 (4.19) 3.65 (3.58) 6.67 (5.29)
[-11.42]*** [-8.03]*** [-9.79]***
361 293 88 3484
Adj. CET1 < 0 4.71 (0.00) 2.73 (0.00) 5.68 (0.00) 3.10 (0.00)
[1.39] [-0.37] [1.03]
17 8 5 108
Uninsured Deposits/Assets (%) 26.21 (25.09) 26.85 (25.28) 32.63 (30.81) 22.83 (21.44)
[5.33]*** [5.78]*** [6.67]***
368 299 94 3531
Uninsured/Total Deposits (%) 30.62 (28.80) 31.58 (29.72) 38.42 (35.98) 26.65 (24.77)
[5.37]*** [6.00]*** [6.80]***
368 299 94 3531
Liquid Assets/Assets (%) 5.15 (3.63) 6.97 (4.15) 4.97 (2.85) 10.04 (6.53)
[-15.65]*** [-6.79]*** [-8.39]***
368 299 94 3531
Low MTM & Low Uninsured 11.41 (0.00) 11.37 (0.00) 7.45 (0.00) 24.75 (0.00)
[-7.36]*** [-6.77]*** [-6.14]***
42 34 7 873
Low MTM & High Uninsured 22.01 (0.00) 29.10 (0.00) 30.85 (0.00) 26.75 (0.00)
[-2.07]** [0.86] [0.85]
81 87 29 943
High MTM & Low Uninsured 26.09 (0.00) 24.75 (0.00) 12.77 (0.00) 27.02 (0.00)
[-0.39] [-0.87] [-4.03]***
96 74 12 953
High MTM & High Uninsured 40.49 (0.00) 34.78 (0.00) 48.94 (0.00) 21.28 (0.00)
[7.24]*** [4.75]*** [5.29]***
149 104 46 750
IDCR Insolvent (s=0.5) 3.53 (0.00) 7.02 (0.00) 3.19 (0.00) 4.07 (0.00)
[-0.53] [1.95]* [-0.47]
13 21 3 142
IDCR Insolvent (s=1.0) 29.08 (0.00) 33.11 (0.00) 24.47 (0.00) 28.11 (0.00)
[0.39] [1.77]* [-0.81]
107 99 23 981
Capital Insolvent (s=0.5) 1.63 (0.00) 3.68 (0.00) 7.45 (0.00) 1.99 (0.00)
[-0.51] [1.52] [2.00]**
6 11 7 70
Capital Insolvent (s=1.0) 9.78 (0.00) 11.71 (0.00) 11.70 (0.00) 6.93 (0.00)
[1.77]* [2.50]** [1.42]
36 35 11 244
Δ Uninsured Deposits (%) -6.40 (-7.40) -4.28 (-5.30) -6.38 (-6.48) 1.26 (-4.09)
[-3.01]*** [-2.15]** [-2.74]***
367 299 94 3468
Δ Insured Deposits (%) 3.58 (1.54) 4.25 (2.10) 6.92 (1.90) 3.76 (1.40)
[-0.21] [0.58] [1.12]
368 299 94 3473
Abnormal Uninsured Outflow (10%) 26.90 (0.00) 27.76 (0.00) 34.04 (0.00) 20.05 (0.00)
[2.84]*** [2.88]*** [2.82]***
99 83 32 708
Abnormal Uninsured Outflow (5%) 12.50 (0.00) 12.37 (0.00) 14.89 (0.00) 8.50 (0.00)
[2.24]** [1.97]** [1.72]*
46 37 14 300
Abnormal Insured Outflow (10%) 11.96 (0.00) 4.68 (0.00) 5.32 (0.00) 7.34 (0.00)
[2.64]*** [-2.04]** [-0.85]
44 14 5 259
Abnormal Insured Outflow (5%) 4.35 (0.00) 1.00 (0.00) 3.19 (0.00) 2.61 (0.00)
[1.59] [-2.52]** [0.32]
16 3 3 92
Capacity Gap/Assets (%) 0.88 (0.61) 0.74 (0.48) 0.92 (0.61) 0.65 (0.38)
[4.32]*** [1.85]* [2.68]***
368 299 94 3521
Capacity Gap/Equity (%) 17.38 (7.72) 12.19 (5.04) 16.14 (7.23) 10.59 (4.15)
[2.50]** [0.87] [1.97]*
368 299 94 3521
Par Valuation Benefit (%) 17.38 (7.72) 12.19 (5.04) 16.14 (7.23) 10.59 (4.15)
[2.50]** [0.87] [1.97]*
368 299 94 3521
BTFP-Eligible Securities/Assets (%) 11.61 (9.32) 9.38 (6.72) 11.15 (8.55) 10.79 (7.75)
[1.40] [-2.57]** [0.36]
368 299 94 3531
MTM Loss/Eligible Securities (%) 9.03 (7.84) 8.67 (7.86) 8.48 (8.46) 10.62 (6.12)
[-0.44] [-0.55] [-0.60]
368 299 94 3521
# Export
export_table(
  table4, 
  "table4_acute_period",
  caption = "Pre-Crisis Bank Characteristics by Borrower Type: Acute Crisis Period",
  label = "tab:acute_period",
  note = "Bank characteristics from 2022Q4 Call Reports. Acute crisis period: March 13 -- May 1, 2023. Banks classified by facility usage during this period. Sample excludes G-SIBs and failed banks."
)
## LaTeX table saved: C:/Users/mferdo2/OneDrive - Louisiana State University/Finance_PhD/DW_Stigma_paper/Liquidity_project_2025/03_documentation/borrowing_stat_new/tables/table4_acute_period.tex 
## HTML table saved: C:/Users/mferdo2/OneDrive - Louisiana State University/Finance_PhD/DW_Stigma_paper/Liquidity_project_2025/03_documentation/borrowing_stat_new/tables/table4_acute_period.html 
## CSV table saved: C:/Users/mferdo2/OneDrive - Louisiana State University/Finance_PhD/DW_Stigma_paper/Liquidity_project_2025/03_documentation/borrowing_stat_new/tables/table4_acute_period.csv

13 Table 4B: Acute Period - Capacity Measures

# ==============================================================================
# TABLE 4B: Acute Period - CAPACITY-FOCUSED ANALYSIS
# ==============================================================================

cat("\n", strrep("=", 60), "\n")
## 
##  ============================================================
cat("TABLE 4B: Acute Period - Capacity Gap Analysis\n")
## TABLE 4B: Acute Period - Capacity Gap Analysis
cat(strrep("=", 60), "\n")
## ============================================================
table4b <- create_capacity_table(table4_data, "borrower_type",
                                  group_levels = c("BTFP Only", "DW Only", "Both", "Non-Borrower"))

# Display
table4b %>%
  select(-Row_Type) %>%
  kable(caption = "Table 4B: Borrowing Capacity Analysis by Borrower Type (Acute Period)") %>%
  kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)
Table 4B: Borrowing Capacity Analysis by Borrower Type (Acute Period)
Variable BTFP Only DW Only Both Non-Borrower
N 368 299 94 3531
BTFP-Eligible Securities/Assets (%) 11.61 (9.32) 9.38 (6.72) 11.15 (8.55) 10.79 (7.75)
[1.40] [-2.57]** [0.36]
368 299 94 3531
Non-Eligible Securities/Assets (%) 78.00 (80.19) 78.41 (81.08) 78.50 (80.50) 74.18 (78.36)
[5.64]*** [5.80]*** [3.80]***
368 299 94 3531
MTM Loss Eligible/Assets (%) 0.88 (0.61) 0.74 (0.48) 0.92 (0.61) 0.65 (0.38)
[4.32]*** [1.85]* [2.68]***
368 299 94 3521
MTM Loss Non-Eligible/Assets (%) 5.02 (4.90) 4.95 (4.90) 4.88 (4.67) 4.52 (4.29)
[4.91]*** [3.73]*** [1.95]*
368 299 94 3521
MTM Loss/Eligible Securities (%) 9.03 (7.84) 8.67 (7.86) 8.48 (8.46) 10.62 (6.12)
[-0.44] [-0.55] [-0.60]
368 299 94 3521
Capacity Gap/Assets (%) 0.88 (0.61) 0.74 (0.48) 0.92 (0.61) 0.65 (0.38)
[4.32]*** [1.85]* [2.68]***
368 299 94 3521
Capacity Gap/Equity (%) 17.38 (7.72) 12.19 (5.04) 16.14 (7.23) 10.59 (4.15)
[2.50]** [0.87] [1.97]*
368 299 94 3521
Capacity Gap/Uninsured Deposits (%) 4.24 (2.57) 4.37 (1.94) 3.13 (1.93) 4.93 (1.88)
[-1.18] [-0.53] [-3.16]***
367 299 94 3486
Par Valuation Benefit (%) 17.38 (7.72) 12.19 (5.04) 16.14 (7.23) 10.59 (4.15)
[2.50]** [0.87] [1.97]*
368 299 94 3521
Eligible Share of Total MTM Loss (%) 14.34 (10.36) 13.01 (9.80) 15.54 (11.25) 15.06 (7.69)
[-0.34] [-0.98] [0.19]
368 299 94 3520
Book Equity/Assets (%) 8.18 (8.08) 9.05 (8.82) 8.19 (8.23) 10.59 (8.96)
[-10.58]*** [-6.25]*** [-7.48]***
368 299 94 3531
Adjusted Equity (%) 2.00 (2.03) 3.30 (3.01) 2.33 (2.70) 5.13 (3.89)
[-11.32]*** [-6.16]*** [-6.43]***
368 299 94 3521
MTM Insolvent 30.43 (0.00) 19.06 (0.00) 21.28 (0.00) 18.06 (0.00)
[4.97]*** [0.42] [0.75]
112 57 20 636
CET1 Post-MTM (%) 4.11 (3.77) 4.71 (4.19) 3.65 (3.58) 6.67 (5.29)
[-11.42]*** [-8.03]*** [-9.79]***
361 293 88 3484
CET1 < 4.5% After MTM 58.73 (100.00) 53.24 (100.00) 64.77 (100.00) 40.36 (0.00)
[6.74]*** [4.24]*** [4.71]***
212 156 57 1406
Tier1 < 4% After MTM (PCA) 53.26 (100.00) 47.49 (0.00) 55.32 (100.00) 33.03 (0.00)
[7.43]*** [4.82]*** [4.27]***
196 142 52 1163
Uninsured Deposits/Assets (%) 26.21 (25.09) 26.85 (25.28) 32.63 (30.81) 22.83 (21.44)
[5.33]*** [5.78]*** [6.67]***
368 299 94 3531
Liquid Assets/Assets (%) 5.15 (3.63) 6.97 (4.15) 4.97 (2.85) 10.04 (6.53)
[-15.65]*** [-6.79]*** [-8.39]***
368 299 94 3531
Liquidity Shortfall/Assets (%) 0.75 (0.00) 0.49 (0.00) 1.64 (0.00) 0.28 (0.00)
[4.35]*** [2.03]** [2.63]**
368 299 94 3531
DW Covers Shortfall 95.92 (100.00) 96.66 (100.00) 89.36 (100.00) 97.33 (100.00)
[-1.32] [-0.63] [-2.48]**
353 289 84 3427
BTFP Covers Shortfall 96.74 (100.00) 96.66 (100.00) 89.36 (100.00) 97.85 (100.00)
[-1.16] [-1.11] [-2.65]***
356 289 84 3455
DW Sufficient (Solvent + Covers) 28.53 (0.00) 18.73 (0.00) 21.28 (0.00) 17.52 (0.00)
[4.51]*** [0.51] [0.87]
105 56 20 617
BTFP Necessary 68.21 (100.00) 77.93 (100.00) 68.09 (100.00) 80.32 (100.00)
[-4.80]*** [-0.96] [-2.51]**
251 233 64 2828
# Export
export_table(
  table4b, 
  "table4b_acute_capacity",
  caption = "Borrowing Capacity Analysis by Borrower Type: Acute Crisis Period",
  label = "tab:acute_capacity",
  note = "Bank characteristics from 2022Q4 Call Reports. Capacity Gap = BTFP Borrowing Capacity (par value) - DW Borrowing Capacity (market value). Par Valuation Benefit = Capacity Gap / Book Equity. BTFP Necessary indicates banks where DW would have been insufficient. Sample excludes G-SIBs and failed banks."
)
## LaTeX table saved: C:/Users/mferdo2/OneDrive - Louisiana State University/Finance_PhD/DW_Stigma_paper/Liquidity_project_2025/03_documentation/borrowing_stat_new/tables/table4b_acute_capacity.tex 
## HTML table saved: C:/Users/mferdo2/OneDrive - Louisiana State University/Finance_PhD/DW_Stigma_paper/Liquidity_project_2025/03_documentation/borrowing_stat_new/tables/table4b_acute_capacity.html 
## CSV table saved: C:/Users/mferdo2/OneDrive - Louisiana State University/Finance_PhD/DW_Stigma_paper/Liquidity_project_2025/03_documentation/borrowing_stat_new/tables/table4b_acute_capacity.csv

14 Table 5A: Q1 2023 - All Facilities (10% Threshold)

# ==============================================================================
# TABLE 5A: Q1 2023 (Jan 1 - Mar 31) - BTFP, DW, FHLB (10% Threshold)
# ==============================================================================

cat("\n", strrep("=", 60), "\n")
## 
##  ============================================================
cat("TABLE 5A: Q1 2023 - BTFP, DW, FHLB (10%), Combinations, Non-Borrowers\n")
## TABLE 5A: Q1 2023 - BTFP, DW, FHLB (10%), Combinations, Non-Borrowers
cat(strrep("=", 60), "\n")
## ============================================================
q1_start <- as.Date("2023-01-01")
q1_end <- as.Date("2023-03-31")

btfp_q1 <- btfp_loans_raw %>%
  filter(btfp_loan_date >= q1_start & btfp_loan_date <= q1_end) %>%
  distinct(rssd_id) %>%
  pull(rssd_id)

dw_q1 <- dw_loans_raw %>%
  filter(dw_loan_date >= q1_start & dw_loan_date <= q1_end) %>%
  distinct(rssd_id) %>%
  pull(rssd_id)

# Define FHLB borrowers using 10% threshold (banks with abnormal FHLB advances in 2023Q1)
fhlb_borrowers_10pct <- baseline_q %>%
  filter(!is.na(abnormal_fhlb_borrowing_10pct) & abnormal_fhlb_borrowing_10pct > 0) %>%
  pull(idrssd)

cat("BTFP borrowers (Q1 2023):", length(btfp_q1), "\n")
## BTFP borrowers (Q1 2023): 302
cat("DW borrowers (Q1 2023):", length(dw_q1), "\n")
## DW borrowers (Q1 2023): 479
cat("FHLB borrowers (Q1 2023, 10%):", length(fhlb_borrowers_10pct), "\n")
## FHLB borrowers (Q1 2023, 10%): 302
table5a_data <- baseline_q %>%
  mutate(
    btfp_user = idrssd %in% btfp_q1,
    dw_user = idrssd %in% dw_q1,
    fhlb_user = idrssd %in% fhlb_borrowers_10pct,
    borrower_type = case_when(
      btfp_user & dw_user & fhlb_user ~ "All Three",
      btfp_user & dw_user & !fhlb_user ~ "BTFP+DW",
      btfp_user & !dw_user & fhlb_user ~ "BTFP+FHLB",
      !btfp_user & dw_user & fhlb_user ~ "DW+FHLB",
      btfp_user & !dw_user & !fhlb_user ~ "BTFP Only",
      !btfp_user & dw_user & !fhlb_user ~ "DW Only",
      !btfp_user & !dw_user & fhlb_user ~ "FHLB Only",
      TRUE ~ "Non-Borrower"
    )
  )

table5a <- create_summary_table_v2(table5a_data, "borrower_type",
                                   group_levels = c("BTFP Only", "DW Only", "FHLB Only", 
                                                    "BTFP+DW", "BTFP+FHLB", "DW+FHLB", 
                                                    "All Three", "Non-Borrower"))

# Display
table5a %>%
  select(-Row_Type) %>%
  kable(caption = "Table 5A: Pre-Crisis Bank Characteristics by Borrower Type (Q1 2023: Jan 1 - Mar 31) - 10% FHLB Threshold") %>%
  kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE) %>%
  scroll_box(width = "100%")
Table 5A: Pre-Crisis Bank Characteristics by Borrower Type (Q1 2023: Jan 1 - Mar 31) - 10% FHLB Threshold
Variable BTFP Only DW Only FHLB Only BTFP+DW BTFP+FHLB DW+FHLB All Three Non-Borrower
N 199 346 260 60 12 21 9 3385
Book Equity Ratio (%) 8.19 (8.06) 8.85 (8.58) 9.82 (9.28) 8.01 (8.09) 8.89 (8.36) 11.00 (10.55) 9.36 (9.47) 10.55 (8.90)
[-8.78]*** [-6.62]*** [-2.78]*** [-5.75]*** [-1.80]* [0.68] [-1.75]
199 346 260 60 12 21 9 3385
MTM Loss Total (%) 6.09 (6.03) 5.66 (5.64) 5.69 (5.26) 5.94 (5.82) 6.37 (6.54) 5.13 (5.07) 6.10 (5.66) 5.38 (5.23)
[5.05]*** [2.33]** [2.13]** [2.34]** [1.96]* [-0.65] [0.79]
199 346 260 60 12 21 9 3375
MTM Loss BTFP-Eligible (%) 0.81 (0.53) 0.85 (0.55) 0.53 (0.28) 0.98 (0.65) 0.77 (0.87) 0.46 (0.23) 0.54 (0.34) 0.66 (0.39)
[2.61]*** [3.53]*** [-3.19]*** [2.43]** [0.75] [-1.39] [-0.80]
199 346 260 60 12 21 9 3375
MTM Loss Non-Eligible (%) 5.01 (4.91) 4.76 (4.78) 4.98 (4.64) 5.15 (5.15) 5.39 (5.48) 4.80 (4.59) 5.79 (5.20) 4.51 (4.30)
[3.81]*** [2.18]** [3.55]*** [2.86]*** [1.87]* [0.83] [1.43]
199 346 260 60 12 21 9 3375
Adjusted Equity (%) 2.11 (2.08) 3.19 (2.91) 4.13 (4.12) 2.06 (2.27) 2.52 (1.53) 5.87 (6.33) 3.26 (3.04) 5.07 (3.79)
[-8.88]*** [-6.00]*** [-2.93]*** [-5.22]*** [-1.96]* [0.94] [-1.33]
199 346 260 60 12 21 9 3375
MTM Insolvent (Adj. Equity < 0) 29.65 (0.00) 19.36 (0.00) 14.23 (0.00) 28.33 (0.00) 33.33 (0.00) 4.76 (0.00) 33.33 (0.00) 18.87 (0.00)
[3.25]*** [0.22] [-2.04]** [1.60] [1.02] [-2.93]*** [0.87]
59 67 37 17 4 1 3 637
Adjusted Tier1 (%) 4.16 (3.82) 4.72 (4.21) 5.32 (5.01) 3.63 (3.28) 4.13 (3.49) 5.61 (5.57) 3.31 (4.04) 6.73 (5.24)
[-9.62]*** [-7.55]*** [-5.29]*** [-7.48]*** [-3.69]*** [-1.70] [-3.27]**
199 346 260 60 12 21 9 3375
Adj. Tier1 < 0 4.52 (0.00) 4.62 (0.00) 5.00 (0.00) 6.67 (0.00) 0.00 (0.00) 0.00 (0.00) 22.22 (0.00) 2.90 (0.00)
[1.08] [1.47] [1.51] [1.15] [-10.04]*** [-10.04]*** [1.31]
9 16 13 4 0 0 2 98
Adjusted CET1 (%) 4.13 (3.82) 4.80 (4.26) 5.31 (5.01) 3.54 (3.18) 3.83 (3.21) 5.61 (5.57) 3.31 (4.04) 6.66 (5.21)
[-9.41]*** [-6.99]*** [-5.06]*** [-7.28]*** [-4.06]*** [-1.59] [-3.20]**
193 333 258 57 11 21 9 3344
Adj. CET1 < 0 4.66 (0.00) 3.30 (0.00) 5.04 (0.00) 7.02 (0.00) 0.00 (0.00) 0.00 (0.00) 22.22 (0.00) 2.96 (0.00)
[1.10] [0.33] [1.49] [1.18] [-10.10]*** [-10.10]*** [1.31]
9 11 13 4 0 0 2 99
Uninsured Deposits/Assets (%) 26.66 (24.86) 27.17 (25.28) 23.71 (22.82) 32.21 (29.91) 31.75 (28.72) 30.18 (30.05) 28.58 (31.00) 22.82 (21.42)
[4.82]*** [6.27]*** [1.26] [5.13]*** [2.73]** [2.62]** [1.26]
199 346 260 60 12 21 9 3385
Uninsured/Total Deposits (%) 31.51 (29.43) 31.91 (29.51) 27.76 (26.73) 38.02 (34.29) 37.36 (33.86) 36.00 (34.85) 34.63 (35.45) 26.62 (24.77)
[5.16]*** [6.41]*** [1.41] [5.27]*** [2.66]** [2.68]** [1.37]
199 346 260 60 12 21 9 3385
Liquid Assets/Assets (%) 5.20 (3.79) 6.47 (3.75) 5.43 (4.31) 4.02 (2.59) 4.30 (3.76) 4.95 (3.49) 2.87 (2.22) 10.28 (6.70)
[-12.76]*** [-9.19]*** [-16.41]*** [-8.54]*** [-6.25]*** [-6.11]*** [-12.18]***
199 346 260 60 12 21 9 3385
Low MTM & Low Uninsured 10.55 (0.00) 10.98 (0.00) 19.62 (0.00) 5.00 (0.00) 0.00 (0.00) 14.29 (0.00) 0.00 (0.00) 24.84 (0.00)
[-6.20]*** [-7.53]*** [-2.03]** [-6.77]*** [-33.43]*** [-1.34] [-33.43]***
21 38 51 3 0 3 0 840
Low MTM & High Uninsured 23.12 (0.00) 30.92 (0.00) 30.38 (0.00) 30.00 (0.00) 25.00 (0.00) 42.86 (0.00) 44.44 (0.00) 25.87 (0.00)
[-0.89] [1.95]* [1.53] [0.69] [-0.07] [1.53] [1.06]
46 107 79 18 3 9 4 874
High MTM & Low Uninsured 24.12 (0.00) 26.30 (0.00) 26.92 (0.00) 11.67 (0.00) 16.67 (0.00) 14.29 (0.00) 33.33 (0.00) 26.94 (0.00)
[-0.90] [-0.26] [-0.01] [-3.60]*** [-0.91] [-1.61] [0.38]
48 91 70 7 2 3 3 911
High MTM & High Uninsured 42.21 (0.00) 31.79 (0.00) 23.08 (0.00) 53.33 (100.00) 58.33 (100.00) 28.57 (0.00) 22.22 (0.00) 22.14 (0.00)
[5.60]*** [3.70]*** [0.35] [4.77]*** [2.43]** [0.64] [0.01]
84 110 60 32 7 6 2 748
IDCR Insolvent (s=0.5) 4.02 (0.00) 5.49 (0.00) 4.62 (0.00) 3.33 (0.00) 0.00 (0.00) 4.76 (0.00) 11.11 (0.00) 4.07 (0.00)
[-0.03] [1.12] [0.41] [-0.31] [-11.90]*** [0.15] [0.63]
8 19 12 2 0 1 1 136
IDCR Insolvent (s=1.0) 28.14 (0.00) 29.77 (0.00) 27.31 (0.00) 21.67 (0.00) 8.33 (0.00) 14.29 (0.00) 33.33 (0.00) 28.71 (0.00)
[-0.17] [0.41] [-0.49] [-1.30] [-2.43]** [-1.83]* [0.28]
56 103 71 13 1 3 3 960
Capital Insolvent (s=0.5) 2.01 (0.00) 2.89 (0.00) 3.08 (0.00) 6.67 (0.00) 0.00 (0.00) 4.76 (0.00) 11.11 (0.00) 1.96 (0.00)
[0.05] [1.00] [1.02] [1.45] [-8.20]*** [0.59] [0.82]
4 10 8 4 0 1 1 66
Capital Insolvent (s=1.0) 12.06 (0.00) 11.56 (0.00) 7.31 (0.00) 8.33 (0.00) 0.00 (0.00) 4.76 (0.00) 11.11 (0.00) 6.99 (0.00)
[2.15]** [2.57]** [0.19] [0.37] [-15.93]*** [-0.47] [0.37]
24 40 19 5 0 1 1 236
Δ Uninsured Deposits (%) -6.23 (-6.25) -5.34 (-5.75) -6.08 (-7.06) -9.13 (-8.59) -10.34 (-12.20) -3.51 (-4.59) -17.22 (-12.22) 1.71 (-3.71)
[-2.96]*** [-2.67]*** [-2.85]*** [-3.76]*** [-2.43]** [-1.54] [-2.78]**
199 344 260 60 12 21 9 3323
Δ Insured Deposits (%) 3.31 (1.97) 4.62 (2.13) 1.92 (0.96) 8.70 (2.08) 6.32 (0.94) 4.53 (3.66) 9.39 (7.84) 3.84 (1.42)
[-0.56] [0.89] [-2.27]** [1.14] [0.45] [0.44] [2.14]*
199 344 260 60 12 21 9 3329
Abnormal Uninsured Outflow (10%) 25.13 (0.00) 29.19 (0.00) 29.23 (0.00) 43.33 (0.00) 41.67 (0.00) 38.10 (0.00) 55.56 (100.00) 19.23 (0.00)
[1.87]* [3.92]*** [3.44]*** [3.72]*** [1.51] [1.73]* [2.07]*
50 101 76 26 5 8 5 651
Abnormal Uninsured Outflow (5%) 8.54 (0.00) 11.85 (0.00) 12.69 (0.00) 25.00 (0.00) 33.33 (0.00) 9.52 (0.00) 22.22 (0.00) 8.36 (0.00)
[0.09] [1.93]* [2.04]** [2.94]*** [1.76] [0.18] [0.94]
17 41 33 15 4 2 2 283
Abnormal Insured Outflow (10%) 13.57 (0.00) 4.62 (0.00) 9.62 (0.00) 8.33 (0.00) 8.33 (0.00) 0.00 (0.00) 0.00 (0.00) 7.33 (0.00)
[2.52]** [-2.22]** [1.21] [0.28] [0.12] [-16.36]*** [-16.36]***
27 16 25 5 1 0 0 248
Abnormal Insured Outflow (5%) 5.03 (0.00) 1.45 (0.00) 2.69 (0.00) 1.67 (0.00) 0.00 (0.00) 0.00 (0.00) 0.00 (0.00) 2.69 (0.00)
[1.48] [-1.78]* [0.00] [-0.60] [-9.67]*** [-9.67]*** [-9.67]***
10 5 7 1 0 0 0 91
Capacity Gap/Assets (%) 0.81 (0.53) 0.85 (0.55) 0.53 (0.28) 0.98 (0.65) 0.77 (0.87) 0.46 (0.23) 0.54 (0.34) 0.66 (0.39)
[2.61]*** [3.53]*** [-3.19]*** [2.43]** [0.75] [-1.39] [-0.80]
199 346 260 60 12 21 9 3375
Capacity Gap/Equity (%) 12.96 (7.16) 15.88 (6.39) 6.74 (3.09) 29.04 (8.46) 10.27 (8.14) 4.48 (2.11) 6.03 (3.84) 10.96 (4.28)
[1.49] [2.00]** [-4.35]*** [1.58] [-0.26] [-4.02]*** [-2.45]**
199 346 260 60 12 21 9 3375
Par Valuation Benefit (%) 12.96 (7.16) 15.88 (6.39) 6.74 (3.09) 29.04 (8.46) 10.27 (8.14) 4.48 (2.11) 6.03 (3.84) 10.96 (4.28)
[1.49] [2.00]** [-4.35]*** [1.58] [-0.26] [-4.02]*** [-2.45]**
199 346 260 60 12 21 9 3375
BTFP-Eligible Securities/Assets (%) 11.16 (9.01) 10.36 (7.65) 8.24 (5.71) 11.41 (9.18) 7.87 (6.67) 7.56 (4.01) 6.38 (3.20) 11.02 (7.87)
[0.21] [-1.19] [-4.85]*** [0.34] [-1.89]* [-1.98]* [-1.97]*
199 346 260 60 12 21 9 3385
MTM Loss/Eligible Securities (%) 7.82 (7.62) 8.66 (8.24) 7.30 (7.08) 8.53 (8.62) 10.17 (9.94) 6.48 (5.46) 10.63 (10.43) 10.90 (6.06)
[-0.83] [-0.60] [-0.97] [-0.63] [-0.19] [-1.15] [-0.07]
199 346 260 60 12 21 9 3375
# Export
export_table(
  table5a, 
  "table5a_q1_2023_10pct",
  caption = "Pre-Crisis Bank Characteristics by Borrower Type: Q1 2023 (10\\% FHLB Threshold)",
  label = "tab:q1_2023_10pct",
  note = "Bank characteristics from 2022Q4 Call Reports. Q1 2023: January 1 -- March 31, 2023. FHLB borrowers identified as banks with abnormal FHLB advances at the 90th percentile. Sample excludes G-SIBs and failed banks."
)
## LaTeX table saved: C:/Users/mferdo2/OneDrive - Louisiana State University/Finance_PhD/DW_Stigma_paper/Liquidity_project_2025/03_documentation/borrowing_stat_new/tables/table5a_q1_2023_10pct.tex 
## HTML table saved: C:/Users/mferdo2/OneDrive - Louisiana State University/Finance_PhD/DW_Stigma_paper/Liquidity_project_2025/03_documentation/borrowing_stat_new/tables/table5a_q1_2023_10pct.html 
## CSV table saved: C:/Users/mferdo2/OneDrive - Louisiana State University/Finance_PhD/DW_Stigma_paper/Liquidity_project_2025/03_documentation/borrowing_stat_new/tables/table5a_q1_2023_10pct.csv

15 Table 5B: Q1 2023 - All Facilities (5% Threshold)

# ==============================================================================
# TABLE 5B: Q1 2023 (Jan 1 - Mar 31) - BTFP, DW, FHLB (5% Threshold)
# ==============================================================================

cat("\n", strrep("=", 60), "\n")
## 
##  ============================================================
cat("TABLE 5B: Q1 2023 - BTFP, DW, FHLB (5%), Combinations, Non-Borrowers\n")
## TABLE 5B: Q1 2023 - BTFP, DW, FHLB (5%), Combinations, Non-Borrowers
cat(strrep("=", 60), "\n")
## ============================================================
# Define FHLB borrowers using 5% threshold (banks with abnormal FHLB advances in 2023Q1)
fhlb_borrowers_5pct <- baseline_q %>%
  filter(!is.na(abnormal_fhlb_borrowing_5pct) & abnormal_fhlb_borrowing_5pct > 0) %>%
  pull(idrssd)

cat("BTFP borrowers (Q1 2023):", length(btfp_q1), "\n")
## BTFP borrowers (Q1 2023): 302
cat("DW borrowers (Q1 2023):", length(dw_q1), "\n")
## DW borrowers (Q1 2023): 479
cat("FHLB borrowers (Q1 2023, 5%):", length(fhlb_borrowers_5pct), "\n")
## FHLB borrowers (Q1 2023, 5%): 221
table5b_data <- baseline_q %>%
  mutate(
    btfp_user = idrssd %in% btfp_q1,
    dw_user = idrssd %in% dw_q1,
    fhlb_user = idrssd %in% fhlb_borrowers_5pct,
    borrower_type = case_when(
      btfp_user & dw_user & fhlb_user ~ "All Three",
      btfp_user & dw_user & !fhlb_user ~ "BTFP+DW",
      btfp_user & !dw_user & fhlb_user ~ "BTFP+FHLB",
      !btfp_user & dw_user & fhlb_user ~ "DW+FHLB",
      btfp_user & !dw_user & !fhlb_user ~ "BTFP Only",
      !btfp_user & dw_user & !fhlb_user ~ "DW Only",
      !btfp_user & !dw_user & fhlb_user ~ "FHLB Only",
      TRUE ~ "Non-Borrower"
    )
  )

table5b <- create_summary_table_v2(table5b_data, "borrower_type",
                                   group_levels = c("BTFP Only", "DW Only", "FHLB Only", 
                                                    "BTFP+DW", "BTFP+FHLB", "DW+FHLB", 
                                                    "All Three", "Non-Borrower"))

# Display
table5b %>%
  select(-Row_Type) %>%
  kable(caption = "Table 5B: Pre-Crisis Bank Characteristics by Borrower Type (Q1 2023: Jan 1 - Mar 31) - 5% FHLB Threshold") %>%
  kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE) %>%
  scroll_box(width = "100%")
Table 5B: Pre-Crisis Bank Characteristics by Borrower Type (Q1 2023: Jan 1 - Mar 31) - 5% FHLB Threshold
Variable BTFP Only DW Only FHLB Only BTFP+DW BTFP+FHLB DW+FHLB All Three Non-Borrower
N 202 352 192 64 9 15 5 3453
Book Equity Ratio (%) 8.18 (8.04) 8.88 (8.61) 9.80 (9.36) 8.01 (7.93) 9.42 (8.67) 11.24 (10.89) 10.44 (9.62) 10.54 (8.90)
[-8.89]*** [-6.56]*** [-2.66]*** [-6.04]*** [-1.06] [0.82] [-0.11]
202 352 192 64 9 15 5 3453
MTM Loss Total (%) 6.08 (6.04) 5.66 (5.64) 5.60 (5.14) 5.93 (5.78) 6.59 (6.26) 5.00 (5.07) 6.35 (6.57) 5.39 (5.23)
[4.97]*** [2.23]** [1.27] [2.35]** [2.11]* [-1.14] [0.61]
202 352 192 64 9 15 5 3443
MTM Loss BTFP-Eligible (%) 0.82 (0.54) 0.84 (0.53) 0.52 (0.28) 0.96 (0.65) 0.64 (0.52) 0.57 (0.37) 0.35 (0.23) 0.66 (0.38)
[2.78]*** [3.40]*** [-2.91]*** [2.47]** [-0.12] [-0.47] [-2.27]*
202 352 192 64 9 15 5 3443
MTM Loss Non-Eligible (%) 5.00 (4.93) 4.77 (4.78) 4.89 (4.60) 5.17 (5.15) 5.58 (5.38) 4.65 (4.57) 6.07 (5.58) 4.53 (4.31)
[3.71]*** [2.13]** [2.46]** [2.98]*** [1.91]* [0.44] [1.02]
202 352 192 64 9 15 5 3443
Adjusted Equity (%) 2.10 (2.06) 3.22 (2.92) 4.20 (4.30) 2.07 (2.39) 2.82 (1.53) 6.24 (6.33) 4.09 (3.04) 5.04 (3.79)
[-8.92]*** [-5.92]*** [-2.42]** [-5.46]*** [-1.46] [1.19] [-0.40]
202 352 192 64 9 15 5 3443
MTM Insolvent (Adj. Equity < 0) 29.70 (0.00) 19.32 (0.00) 12.50 (0.00) 28.12 (0.00) 33.33 (0.00) 0.00 (0.00) 40.00 (0.00) 18.88 (0.00)
[3.29]*** [0.20] [-2.57]** [1.62] [0.87] [-28.30]*** [0.86]
60 68 24 18 3 0 2 650
Adjusted Tier1 (%) 4.16 (3.81) 4.73 (4.24) 5.25 (5.01) 3.59 (3.28) 4.12 (3.78) 5.85 (5.39) 3.59 (4.63) 6.71 (5.23)
[-9.66]*** [-7.56]*** [-5.16]*** [-7.89]*** [-3.17]** [-1.09] [-1.71]
202 352 192 64 9 15 5 3443
Adj. Tier1 < 0 4.46 (0.00) 4.55 (0.00) 4.69 (0.00) 6.25 (0.00) 0.00 (0.00) 0.00 (0.00) 40.00 (0.00) 2.96 (0.00)
[1.01] [1.38] [1.11] [1.07] [-10.25]*** [-10.25]*** [1.51]
9 16 9 4 0 0 2 102
Adjusted CET1 (%) 4.11 (3.80) 4.81 (4.29) 5.24 (5.00) 3.50 (3.18) 4.12 (3.78) 5.84 (5.39) 3.59 (4.63) 6.63 (5.21)
[-9.50]*** [-6.99]*** [-4.96]*** [-7.71]*** [-3.09]** [-1.01] [-1.67]
195 339 191 61 9 15 5 3411
Adj. CET1 < 0 4.62 (0.00) 3.24 (0.00) 4.71 (0.00) 6.56 (0.00) 0.00 (0.00) 0.00 (0.00) 40.00 (0.00) 3.02 (0.00)
[1.04] [0.22] [1.08] [1.10] [-10.30]*** [-10.30]*** [1.51]
9 11 9 4 0 0 2 103
Uninsured Deposits/Assets (%) 26.81 (25.02) 27.21 (25.31) 24.65 (23.17) 32.36 (30.12) 30.11 (26.15) 30.56 (30.05) 23.81 (22.44) 22.79 (21.40)
[5.06]*** [6.43]*** [2.33]** [5.44]*** [1.95]* [2.28]** [0.18]
202 352 192 64 9 15 5 3453
Uninsured/Total Deposits (%) 31.68 (29.43) 31.96 (29.63) 28.73 (27.48) 38.22 (34.76) 35.52 (33.46) 36.37 (36.35) 29.31 (25.17) 26.59 (24.76)
[5.38]*** [6.56]*** [2.33]** [5.56]*** [2.02]* [2.33]** [0.36]
202 352 192 64 9 15 5 3453
Liquid Assets/Assets (%) 5.20 (3.81) 6.41 (3.70) 5.35 (4.38) 3.92 (2.49) 3.95 (3.59) 5.66 (4.04) 3.24 (3.59) 10.19 (6.66)
[-12.67]*** [-9.25]*** [-15.40]*** [-9.04]*** [-6.73]*** [-3.94]*** [-9.94]***
202 352 192 64 9 15 5 3453
Low MTM & Low Uninsured 10.40 (0.00) 10.80 (0.00) 19.27 (0.00) 4.69 (0.00) 0.00 (0.00) 20.00 (0.00) 0.00 (0.00) 24.76 (0.00)
[-6.31]*** [-7.71]*** [-1.86]* [-7.27]*** [-33.69]*** [-0.44] [-33.69]***
21 38 37 3 0 3 0 854
Low MTM & High Uninsured 23.27 (0.00) 31.25 (0.00) 33.33 (0.00) 31.25 (0.00) 22.22 (0.00) 40.00 (0.00) 40.00 (0.00) 25.79 (0.00)
[-0.82] [2.11]** [2.16]** [0.93] [-0.24] [1.08] [0.58]
47 110 64 20 2 6 2 889
High MTM & Low Uninsured 23.76 (0.00) 26.42 (0.00) 23.44 (0.00) 12.50 (0.00) 22.22 (0.00) 6.67 (0.00) 40.00 (0.00) 27.14 (0.00)
[-1.09] [-0.29] [-1.17] [-3.46]*** [-0.33] [-3.05]*** [0.52]
48 93 45 8 2 1 2 936
High MTM & High Uninsured 42.57 (0.00) 31.53 (0.00) 23.96 (0.00) 51.56 (100.00) 55.56 (100.00) 33.33 (0.00) 20.00 (0.00) 22.11 (0.00)
[5.75]*** [3.66]*** [0.58] [4.65]*** [1.90]* [0.89] [-0.11]
86 111 46 33 5 5 1 762
IDCR Insolvent (s=0.5) 3.96 (0.00) 5.68 (0.00) 3.65 (0.00) 3.12 (0.00) 0.00 (0.00) 0.00 (0.00) 20.00 (0.00) 4.13 (0.00)
[-0.12] [1.21] [-0.35] [-0.45] [-12.13]*** [-12.13]*** [0.79]
8 20 7 2 0 0 1 141
IDCR Insolvent (s=1.0) 28.22 (0.00) 29.83 (0.00) 27.60 (0.00) 21.88 (0.00) 0.00 (0.00) 6.67 (0.00) 40.00 (0.00) 28.66 (0.00)
[-0.14] [0.46] [-0.32] [-1.29] [-37.02]*** [-3.28]*** [0.46]
57 105 53 14 0 1 2 978
Capital Insolvent (s=0.5) 1.98 (0.00) 3.12 (0.00) 3.12 (0.00) 6.25 (0.00) 0.00 (0.00) 0.00 (0.00) 20.00 (0.00) 1.98 (0.00)
[0.01] [1.20] [0.90] [1.40] [-8.33]*** [-8.33]*** [0.90]
4 11 6 4 0 0 1 68
Capital Insolvent (s=1.0) 11.88 (0.00) 11.65 (0.00) 7.81 (0.00) 7.81 (0.00) 0.00 (0.00) 0.00 (0.00) 20.00 (0.00) 6.97 (0.00)
[2.11]** [2.65]*** [0.42] [0.25] [-16.06]*** [-16.06]*** [0.65]
24 41 15 5 0 0 1 240
Δ Uninsured Deposits (%) -6.13 (-6.27) -5.29 (-5.75) -6.10 (-6.21) -10.11 (-8.59) -14.10 (-13.96) -3.95 (-4.59) -11.14 (-12.22) 1.56 (-3.89)
[-2.91]*** [-2.64]*** [-2.83]*** [-3.97]*** [-4.72]*** [-1.51] [-3.57]***
202 350 192 64 9 15 5 3391
Δ Insured Deposits (%) 3.59 (1.86) 4.62 (2.19) 1.49 (0.78) 8.98 (2.15) 1.07 (0.75) 4.47 (3.66) 6.42 (4.81) 3.82 (1.43)
[-0.24] [0.92] [-2.94]*** [1.29] [-1.49] [0.33] [0.80]
202 350 192 64 9 15 5 3397
Abnormal Uninsured Outflow (10%) 25.25 (0.00) 29.26 (0.00) 30.21 (0.00) 43.75 (0.00) 44.44 (0.00) 40.00 (0.00) 60.00 (100.00) 19.37 (0.00)
[1.87]* [3.92]*** [3.20]*** [3.88]*** [1.43] [1.57] [1.66]
51 103 58 28 4 6 3 669
Abnormal Uninsured Outflow (5%) 8.91 (0.00) 11.93 (0.00) 14.06 (0.00) 25.00 (0.00) 33.33 (0.00) 6.67 (0.00) 20.00 (0.00) 8.37 (0.00)
[0.26] [1.99]** [2.22]** [3.04]*** [1.50] [-0.25] [0.58]
18 42 27 16 3 1 1 289
Abnormal Insured Outflow (10%) 13.37 (0.00) 4.55 (0.00) 8.33 (0.00) 7.81 (0.00) 11.11 (0.00) 0.00 (0.00) 0.00 (0.00) 7.44 (0.00)
[2.43]** [-2.42]** [0.43] [0.11] [0.33] [-16.66]*** [-16.66]***
27 16 16 5 1 0 0 257
Abnormal Insured Outflow (5%) 4.95 (0.00) 1.42 (0.00) 2.08 (0.00) 1.56 (0.00) 0.00 (0.00) 0.00 (0.00) 0.00 (0.00) 2.72 (0.00)
[1.43] [-1.89]* [-0.60] [-0.73] [-9.83]*** [-9.83]*** [-9.83]***
10 5 4 1 0 0 0 94
Capacity Gap/Assets (%) 0.82 (0.54) 0.84 (0.53) 0.52 (0.28) 0.96 (0.65) 0.64 (0.52) 0.57 (0.37) 0.35 (0.23) 0.66 (0.38)
[2.78]*** [3.40]*** [-2.91]*** [2.47]** [-0.12] [-0.47] [-2.27]*
202 352 192 64 9 15 5 3443
Capacity Gap/Equity (%) 13.06 (7.19) 15.64 (6.31) 6.34 (3.15) 27.80 (8.46) 7.22 (6.12) 5.48 (3.64) 3.55 (1.96) 10.90 (4.28)
[1.63] [1.96]* [-4.70]*** [1.58] [-1.89]* [-2.63]** [-4.49]***
202 352 192 64 9 15 5 3443
Par Valuation Benefit (%) 13.06 (7.19) 15.64 (6.31) 6.34 (3.15) 27.80 (8.46) 7.22 (6.12) 5.48 (3.64) 3.55 (1.96) 10.90 (4.28)
[1.63] [1.96]* [-4.70]*** [1.58] [-1.89]* [-2.63]** [-4.49]***
202 352 192 64 9 15 5 3443
BTFP-Eligible Securities/Assets (%) 11.21 (9.14) 10.22 (7.33) 8.71 (6.09) 11.22 (8.99) 5.72 (3.74) 9.86 (6.43) 4.80 (2.71) 10.93 (7.81)
[0.41] [-1.32] [-3.22]*** [0.25] [-3.16]** [-0.50] [-2.64]*
202 352 192 64 9 15 5 3453
MTM Loss/Eligible Securities (%) 7.82 (7.63) 8.69 (8.25) 6.98 (6.58) 8.84 (8.67) 10.86 (12.54) 4.92 (4.30) 8.30 (6.57) 10.85 (6.12)
[-0.83] [-0.59] [-1.06] [-0.54] [0.00] [-1.56] [-0.66]
202 352 192 64 9 15 5 3443
# Export
export_table(
  table5b, 
  "table5b_q1_2023_5pct",
  caption = "Pre-Crisis Bank Characteristics by Borrower Type: Q1 2023 (5\\% FHLB Threshold)",
  label = "tab:q1_2023_5pct",
  note = "Bank characteristics from 2022Q4 Call Reports. Q1 2023: January 1 -- March 31, 2023. FHLB borrowers identified as banks with abnormal FHLB advances at the 95th percentile. Sample excludes G-SIBs and failed banks."
)
## LaTeX table saved: C:/Users/mferdo2/OneDrive - Louisiana State University/Finance_PhD/DW_Stigma_paper/Liquidity_project_2025/03_documentation/borrowing_stat_new/tables/table5b_q1_2023_5pct.tex 
## HTML table saved: C:/Users/mferdo2/OneDrive - Louisiana State University/Finance_PhD/DW_Stigma_paper/Liquidity_project_2025/03_documentation/borrowing_stat_new/tables/table5b_q1_2023_5pct.html 
## CSV table saved: C:/Users/mferdo2/OneDrive - Louisiana State University/Finance_PhD/DW_Stigma_paper/Liquidity_project_2025/03_documentation/borrowing_stat_new/tables/table5b_q1_2023_5pct.csv

16 Table 6: Arbitrage Period - BTFP, DW, Both, Non-Borrowers

# ==============================================================================
# TABLE 6: Arbitrage Period (Nov 1, 2023 - Jan 24, 2024)
# ==============================================================================

cat("\n", strrep("=", 60), "\n")
## 
##  ============================================================
cat("TABLE 6: Arbitrage Period - BTFP, DW, Both, Non-Borrowers\n")
## TABLE 6: Arbitrage Period - BTFP, DW, Both, Non-Borrowers
cat(strrep("=", 60), "\n")
## ============================================================
arb_start <- as.Date("2023-11-01")
arb_end <- as.Date("2024-01-24")

btfp_arb <- btfp_loans_raw %>%
  filter(btfp_loan_date >= arb_start & btfp_loan_date <= arb_end) %>%
  distinct(rssd_id) %>%
  pull(rssd_id)

# Note: DW data ends 2023-12-31, so only partial coverage
dw_arb <- dw_loans_raw %>%
  filter(dw_loan_date >= arb_start & dw_loan_date <= min(arb_end, DW_DATA_END)) %>%
  distinct(rssd_id) %>%
  pull(rssd_id)

cat("BTFP borrowers (Arbitrage):", length(btfp_arb), "\n")
## BTFP borrowers (Arbitrage): 801
cat("DW borrowers (Arbitrage, partial):", length(dw_arb), "\n")
## DW borrowers (Arbitrage, partial): 481
cat("Note: DW data ends", as.character(DW_DATA_END), "\n")
## Note: DW data ends 2023-12-31
table6_data <- baseline_q %>%
  mutate(
    btfp_user = idrssd %in% btfp_arb,
    dw_user = idrssd %in% dw_arb,
    borrower_type = case_when(
      btfp_user & dw_user ~ "Both",
      btfp_user & !dw_user ~ "BTFP Only",
      !btfp_user & dw_user ~ "DW Only",
      TRUE ~ "Non-Borrower"
    )
  )

table6 <- create_summary_table_v2(table6_data, "borrower_type",
                                   group_levels = c("BTFP Only", "DW Only", "Both", "Non-Borrower"))

# Display
table6 %>%
  select(-Row_Type) %>%
  kable(caption = "Table 6: Pre-Crisis Bank Characteristics by Borrower Type (Arbitrage Period: Nov 1, 2023 - Jan 24, 2024)") %>%
  kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)
Table 6: Pre-Crisis Bank Characteristics by Borrower Type (Arbitrage Period: Nov 1, 2023 - Jan 24, 2024)
Variable BTFP Only DW Only Both Non-Borrower
N 623 302 143 3224
Book Equity Ratio (%) 8.59 (8.31) 9.27 (9.17) 8.15 (8.08) 10.72 (9.01)
[-9.58]*** [-5.74]*** [-8.93]***
623 302 143 3224
MTM Loss Total (%) 6.17 (5.93) 5.36 (5.22) 6.13 (6.12) 5.31 (5.16)
[9.76]*** [0.38] [4.53]***
623 302 143 3214
MTM Loss BTFP-Eligible (%) 0.87 (0.60) 0.69 (0.51) 0.76 (0.49) 0.64 (0.36)
[6.02]*** [1.15] [1.74]*
623 302 143 3214
MTM Loss Non-Eligible (%) 5.05 (4.88) 4.58 (4.53) 5.17 (4.74) 4.49 (4.26)
[6.79]*** [0.68] [3.97]***
623 302 143 3214
Adjusted Equity (%) 2.41 (2.28) 3.91 (3.75) 2.02 (1.93) 5.30 (3.93)
[-11.47]*** [-4.44]*** [-8.39]***
623 302 143 3214
MTM Insolvent (Adj. Equity < 0) 26.97 (0.00) 15.56 (0.00) 32.17 (0.00) 17.55 (0.00)
[4.95]*** [-0.90] [3.68]***
168 47 46 564
Adjusted Tier1 (%) 4.48 (4.07) 5.23 (4.91) 3.71 (3.66) 6.87 (5.32)
[-11.09]*** [-6.18]*** [-10.92]***
623 302 143 3214
Adj. Tier1 < 0 5.62 (0.00) 3.97 (0.00) 7.69 (0.00) 2.61 (0.00)
[3.11]*** [1.17] [2.25]**
35 12 11 84
Adjusted CET1 (%) 4.46 (4.07) 5.27 (4.93) 3.66 (3.63) 6.80 (5.31)
[-10.99]*** [-5.77]*** [-10.75]***
619 290 137 3180
Adj. CET1 < 0 5.82 (0.00) 3.79 (0.00) 8.03 (0.00) 2.52 (0.00)
[3.36]*** [1.10] [2.35]**
36 11 11 80
Uninsured Deposits/Assets (%) 25.43 (23.98) 26.41 (25.24) 28.22 (26.52) 22.79 (21.42)
[5.35]*** [4.72]*** [5.19]***
623 302 143 3224
Uninsured/Total Deposits (%) 29.65 (27.49) 31.11 (29.29) 32.94 (30.23) 26.63 (24.83)
[5.21]*** [5.00]*** [5.14]***
623 302 143 3224
Liquid Assets/Assets (%) 5.33 (3.74) 7.07 (4.63) 4.96 (3.44) 10.47 (6.86)
[-18.84]*** [-7.13]*** [-13.84]***
623 302 143 3224
Low MTM & Low Uninsured 11.88 (0.00) 18.21 (0.00) 8.39 (0.00) 25.31 (0.00)
[-8.92]*** [-3.02]*** [-6.91]***
74 55 12 815
Low MTM & High Uninsured 22.47 (0.00) 32.78 (0.00) 31.47 (0.00) 26.60 (0.00)
[-2.24]** [2.20]** [1.22]
140 99 45 856
High MTM & Low Uninsured 29.70 (0.00) 22.52 (0.00) 24.48 (0.00) 26.30 (0.00)
[1.70]* [-1.50] [-0.50]
185 68 35 847
High MTM & High Uninsured 35.96 (0.00) 26.49 (0.00) 35.66 (0.00) 21.57 (0.00)
[7.00]*** [1.86]* [3.45]***
224 80 51 694
IDCR Insolvent (s=0.5) 4.82 (0.00) 3.97 (0.00) 2.80 (0.00) 4.18 (0.00)
[0.69] [-0.17] [-0.97]
30 12 4 133
IDCR Insolvent (s=1.0) 32.10 (0.00) 29.47 (0.00) 32.17 (0.00) 27.49 (0.00)
[2.27]** [0.72] [1.17]
200 89 46 875
Capital Insolvent (s=0.5) 1.77 (0.00) 4.97 (0.00) 5.59 (0.00) 1.87 (0.00)
[-0.17] [2.43]** [1.92]*
11 15 8 60
Capital Insolvent (s=1.0) 8.99 (0.00) 11.26 (0.00) 13.29 (0.00) 6.75 (0.00)
[1.82]* [2.40]** [2.27]**
56 34 19 217
Δ Uninsured Deposits (%) -1.15 (-5.82) -5.39 (-6.07) -2.18 (-3.91) 0.88 (-4.09)
[-0.48] [-2.26]** [-1.08]
623 301 143 3161
Δ Insured Deposits (%) 3.72 (1.65) 5.93 (2.87) 4.14 (1.81) 3.66 (1.31)
[0.06] [2.16]** [0.39]
623 302 143 3166
Abnormal Uninsured Outflow (10%) 26.97 (0.00) 27.48 (0.00) 23.78 (0.00) 19.76 (0.00)
[3.77]*** [2.90]*** [1.10]
168 83 34 637
Abnormal Uninsured Outflow (5%) 12.68 (0.00) 11.59 (0.00) 9.79 (0.00) 8.34 (0.00)
[3.05]*** [1.70]* [0.57]
79 35 14 269
Abnormal Insured Outflow (10%) 7.38 (0.00) 4.97 (0.00) 7.69 (0.00) 7.75 (0.00)
[-0.32] [-2.08]** [-0.03]
46 15 11 250
Abnormal Insured Outflow (5%) 2.41 (0.00) 1.99 (0.00) 2.80 (0.00) 2.76 (0.00)
[-0.52] [-0.91] [0.03]
15 6 4 89
Capacity Gap/Assets (%) 0.87 (0.60) 0.69 (0.51) 0.76 (0.49) 0.64 (0.36)
[6.02]*** [1.15] [1.74]*
623 302 143 3214
Capacity Gap/Equity (%) 15.86 (7.29) 11.07 (5.05) 12.36 (6.66) 10.53 (3.96)
[2.91]*** [0.30] [1.15]
623 302 143 3214
Par Valuation Benefit (%) 15.86 (7.29) 11.07 (5.05) 12.36 (6.66) 10.53 (3.96)
[2.91]*** [0.30] [1.15]
623 302 143 3214
BTFP-Eligible Securities/Assets (%) 11.42 (9.04) 9.51 (7.04) 9.56 (5.94) 10.82 (7.68)
[1.36] [-2.52]** [-1.62]
623 302 143 3224
MTM Loss/Eligible Securities (%) 8.42 (7.88) 7.86 (7.47) 8.92 (8.20) 10.96 (5.99)
[-0.65] [-0.79] [-0.51]
623 302 143 3214
# Export
export_table(
  table6, 
  "table6_arbitrage_period",
  caption = "Pre-Crisis Bank Characteristics by Borrower Type: Arbitrage Period",
  label = "tab:arbitrage_period",
  note = "Bank characteristics from 2022Q4 Call Reports. Arbitrage period: November 1, 2023 -- January 24, 2024 (BTFP rate below IORB). Note: DW data available only through December 31, 2023. Sample excludes G-SIBs and failed banks."
)
## LaTeX table saved: C:/Users/mferdo2/OneDrive - Louisiana State University/Finance_PhD/DW_Stigma_paper/Liquidity_project_2025/03_documentation/borrowing_stat_new/tables/table6_arbitrage_period.tex 
## HTML table saved: C:/Users/mferdo2/OneDrive - Louisiana State University/Finance_PhD/DW_Stigma_paper/Liquidity_project_2025/03_documentation/borrowing_stat_new/tables/table6_arbitrage_period.html 
## CSV table saved: C:/Users/mferdo2/OneDrive - Louisiana State University/Finance_PhD/DW_Stigma_paper/Liquidity_project_2025/03_documentation/borrowing_stat_new/tables/table6_arbitrage_period.csv
# ==============================================================================
# TABLE 6b: Arbitrage Period (Nov 1, 2023 - Jan 24, 2024)
# UPDATED: Uses 2023Q4 baseline instead of 2022Q4
# ==============================================================================

cat("\n", strrep("=", 60), "\n")
## 
##  ============================================================
cat("TABLE 6b: Arbitrage Period - BTFP, DW, Both, Non-Borrowers\n")
## TABLE 6b: Arbitrage Period - BTFP, DW, Both, Non-Borrowers
cat("Using 2023Q4 as baseline\n")
## Using 2023Q4 as baseline
cat(strrep("=", 60), "\n")
## ============================================================
# Create 2023Q4 baseline data
baseline_q4_2023 <- call_q %>%
  filter(period == '2023Q4') %>%
  filter(
    gsib == 0 | is.na(gsib),
    failed_bank == 0 | is.na(failed_bank),
    !is.na(omo_eligible) & omo_eligible > 0
  )

# Calculate medians for 2023Q4
medians_q4 <- baseline_q4_2023 %>%
  summarise(
    median_uninsured = median(uninsured_deposit_to_total_asset, na.rm = TRUE),
    median_mtm = median(mtm_loss_to_total_asset, na.rm = TRUE),
    q75_uninsured = quantile(uninsured_deposit_to_total_asset, 0.75, na.rm = TRUE),
    q75_mtm = quantile(mtm_loss_to_total_asset, 0.75, na.rm = TRUE)
  )

cat("Median uninsured ratio:", round(medians_q4$median_uninsured, 2), "%\n")
## Median uninsured ratio: 19.94 %
cat("Median MTM loss ratio:", round(medians_q4$median_mtm, 2), "%\n")
## Median MTM loss ratio: 5.13 %
# Add derived variables to 2023Q4 baseline
baseline_q4_2023 <- baseline_q4_2023 %>%
  mutate(
    # Existing variables
    cet1_ratio = safe_div(cet1, total_asset) * 100,
    mv_asset = mm_asset,
    mv_adjustment = if_else(mv_asset == 0 | is.na(mv_asset), NA_real_, 
                            (total_asset / mv_asset) - 1),
    
    idcr_s50 = safe_div(mv_asset - 0.5 * uninsured_deposit - insured_deposit, insured_deposit),
    idcr_s100 = safe_div(mv_asset - 1.0 * uninsured_deposit - insured_deposit, insured_deposit),
    
    cap_insolvency_s50 = safe_div((total_asset - total_liability) - 0.5 * uninsured_deposit * mv_adjustment, total_asset),
    cap_insolvency_s100 = safe_div((total_asset - total_liability) - 1.0 * uninsured_deposit * mv_adjustment, total_asset),
    
    adjusted_equity = book_equity_to_total_asset - mtm_loss_to_total_asset,
    adjusted_tier1 = tier1cap_to_total_asset - mtm_loss_to_total_asset,
    adjusted_cet1 = cet1_ratio - mtm_loss_to_total_asset,
    
    mtm_insolvent = as.integer(adjusted_equity < 0),
    mtm_insolvent_tier1 = as.integer(adjusted_tier1 < 0),
    mtm_insolvent_cet1 = as.integer(adjusted_cet1 < 0),
    
    uninsured_leverage = uninsured_deposit_to_total_asset,
    liquidity_available = safe_div(cash + rerepo + fed_fund_sold, total_asset) * 100,
    
    run_risk_1 = as.integer(
      uninsured_deposit_to_total_asset < medians_q4$median_uninsured & 
        mtm_loss_to_total_asset < medians_q4$median_mtm
    ),
    run_risk_2 = as.integer(
      uninsured_deposit_to_total_asset > medians_q4$median_uninsured & 
        mtm_loss_to_total_asset < medians_q4$median_mtm
    ),
    run_risk_3 = as.integer(
      uninsured_deposit_to_total_asset < medians_q4$median_uninsured & 
        mtm_loss_to_total_asset > medians_q4$median_mtm
    ),
    run_risk_4 = as.integer(
      uninsured_deposit_to_total_asset > medians_q4$median_uninsured & 
        mtm_loss_to_total_asset > medians_q4$median_mtm
    ),
    
    idcr_insolvent_s50 = as.integer(idcr_s50 < 0),
    idcr_insolvent_s100 = as.integer(idcr_s100 < 0),
    cap_insolvent_s50 = as.integer(cap_insolvency_s50 < 0),
    cap_insolvent_s100 = as.integer(cap_insolvency_s100 < 0),
    
    # New capacity variables
    mv_omo_eligible = omo_eligible * (1 - mtm_loss_omo_eligible_to_omo_eligible / 100),
    btfp_capacity = omo_eligible,
    dw_capacity = mv_omo_eligible,
    capacity_gap = btfp_capacity - dw_capacity,
    capacity_gap_to_assets = safe_div(capacity_gap, total_asset) * 100,
    capacity_gap_to_equity = safe_div(capacity_gap, total_equity) * 100,
    capacity_gap_to_uninsured = safe_div(capacity_gap, uninsured_deposit) * 100,
    par_valuation_benefit = safe_div(capacity_gap, total_equity) * 100
  )

cat("2023Q4 baseline observations:", nrow(baseline_q4_2023), "\n")
## 2023Q4 baseline observations: 4197
table6b_data <- baseline_q4_2023 %>%
  mutate(
    btfp_user = idrssd %in% btfp_arb,
    dw_user = idrssd %in% dw_arb,
    borrower_type = case_when(
      btfp_user & dw_user ~ "Both",
      btfp_user & !dw_user ~ "BTFP Only",
      !btfp_user & dw_user ~ "DW Only",
      TRUE ~ "Non-Borrower"
    )
  )

table6b <- create_summary_table_v2(table6b_data, "borrower_type",
                                   group_levels = c("BTFP Only", "DW Only", "Both", "Non-Borrower"))

# Display
table6b %>%
  select(-Row_Type) %>%
  kable(caption = "Table 6b: Bank Characteristics by Borrower Type (Arbitrage Period: Nov 1, 2023 - Jan 24, 2024) - 2023Q4 Baseline") %>%
  kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)
Table 6b: Bank Characteristics by Borrower Type (Arbitrage Period: Nov 1, 2023 - Jan 24, 2024) - 2023Q4 Baseline
Variable BTFP Only DW Only Both Non-Borrower
N 632 302 141 3122
Book Equity Ratio (%) 9.06 (8.74) 9.84 (9.75) 8.75 (8.65) 11.46 (9.56)
[-11.05]*** [-6.57]*** [-9.96]***
632 302 141 3122
MTM Loss Total (%) 5.92 (5.69) 5.17 (5.06) 5.86 (5.76) 5.16 (4.99)
[8.61]*** [0.13] [3.93]***
632 302 141 3104
MTM Loss BTFP-Eligible (%) 0.84 (0.56) 0.66 (0.49) 0.75 (0.48) 0.63 (0.35)
[5.61]*** [0.86] [1.79]*
632 302 141 3104
MTM Loss Non-Eligible (%) 4.82 (4.63) 4.41 (4.28) 4.90 (4.51) 4.34 (4.09)
[5.86]*** [0.52] [3.32]***
632 302 141 3104
Adjusted Equity (%) 3.14 (3.12) 4.66 (4.57) 2.89 (2.94) 6.11 (4.69)
[-12.19]*** [-4.75]*** [-8.64]***
632 302 141 3104
MTM Insolvent (Adj. Equity < 0) 20.41 (0.00) 11.26 (0.00) 22.70 (0.00) 12.21 (0.00)
[4.80]*** [-0.50] [2.92]***
129 34 32 379
Adjusted Tier1 (%) 4.71 (4.40) 5.61 (5.24) 4.12 (3.97) 7.26 (5.71)
[-12.25]*** [-6.36]*** [-10.83]***
632 302 141 3104
Adj. Tier1 < 0 3.32 (0.00) 3.64 (0.00) 7.09 (0.00) 2.16 (0.00)
[1.53] [1.34] [2.26]**
21 11 10 67
Adjusted CET1 (%) 4.68 (4.38) 5.59 (5.25) 4.06 (3.87) 7.19 (5.69)
[-12.15]*** [-6.17]*** [-10.63]***
627 288 135 3072
Adj. CET1 < 0 3.51 (0.00) 3.47 (0.00) 7.41 (0.00) 2.15 (0.00)
[1.74]* [1.19] [2.31]**
22 10 10 66
Uninsured Deposits/Assets (%) 22.06 (20.68) 22.63 (21.30) 24.60 (23.23) 20.84 (19.45)
[2.71]*** [2.71]*** [3.84]***
632 302 141 3122
Uninsured/Total Deposits (%) 26.76 (25.10) 27.17 (25.30) 29.75 (28.51) 24.80 (23.05)
[3.67]*** [3.00]*** [4.17]***
632 302 141 3122
Liquid Assets/Assets (%) 5.77 (4.25) 6.75 (4.95) 5.18 (4.11) 10.12 (7.25)
[-16.63]*** [-7.98]*** [-13.57]***
632 302 141 3122
Low MTM & Low Uninsured 15.82 (0.00) 21.85 (0.00) 14.18 (0.00) 25.50 (0.00)
[-5.87]*** [-1.45] [-3.71]***
100 66 20 794
Low MTM & High Uninsured 22.94 (0.00) 29.80 (0.00) 26.95 (0.00) 26.86 (0.00)
[-2.12]** [1.07] [0.02]
145 90 38 836
High MTM & Low Uninsured 31.01 (0.00) 21.85 (0.00) 26.24 (0.00) 26.04 (0.00)
[2.48]** [-1.67]* [0.05]
196 66 37 811
High MTM & High Uninsured 30.06 (0.00) 26.49 (0.00) 32.62 (0.00) 21.27 (0.00)
[4.47]*** [1.97]** [2.82]***
190 80 46 662
IDCR Insolvent (s=0.5) 10.92 (0.00) 15.56 (0.00) 10.64 (0.00) 11.64 (0.00)
[-0.53] [1.81]* [-0.38]
69 47 15 358
IDCR Insolvent (s=1.0) 34.81 (0.00) 37.75 (0.00) 41.13 (0.00) 36.36 (0.00)
[-0.74] [0.48] [1.12]
220 114 58 1118
Capital Insolvent (s=0.5) 3.80 (0.00) 5.63 (0.00) 5.67 (0.00) 3.41 (0.00)
[0.46] [1.62] [1.14]
24 17 8 106
Capital Insolvent (s=1.0) 12.03 (0.00) 12.91 (0.00) 17.73 (0.00) 10.76 (0.00)
[0.90] [1.07] [2.13]**
76 39 25 334
Δ Uninsured Deposits (%) 0.81 (0.31) 0.62 (0.71) 2.17 (1.39) 20.41 (-0.31)
[-1.27] [-1.29] [-1.19]
629 301 141 3073
Δ Insured Deposits (%) 1.99 (1.09) 2.30 (1.74) 2.02 (1.00) 1.83 (1.23)
[0.57] [1.26] [0.37]
629 301 141 3076
Abnormal Uninsured Outflow (10%) 11.23 (0.00) 9.93 (0.00) 4.96 (0.00) 10.95 (0.00)
[0.20] [-0.56] [-3.12]***
71 30 7 342
Abnormal Uninsured Outflow (5%) 6.49 (0.00) 5.63 (0.00) 3.55 (0.00) 6.21 (0.00)
[0.26] [-0.42] [-1.65]
41 17 5 194
Abnormal Insured Outflow (10%) 8.86 (0.00) 7.28 (0.00) 10.64 (0.00) 7.85 (0.00)
[0.82] [-0.36] [1.05]
56 22 15 245
Abnormal Insured Outflow (5%) 5.06 (0.00) 3.97 (0.00) 5.67 (0.00) 4.93 (0.00)
[0.14] [-0.81] [0.37]
32 12 8 154
Capacity Gap/Assets (%) 0.84 (0.56) 0.66 (0.49) 0.75 (0.48) 0.63 (0.35)
[5.61]*** [0.86] [1.79]*
632 302 141 3104
Capacity Gap/Equity (%) 12.38 (6.33) 8.49 (4.75) 9.60 (5.74) 17.50 (3.58)
[-0.54] [-0.95] [-0.83]
632 302 141 3104
Par Valuation Benefit (%) 12.38 (6.33) 8.49 (4.75) 9.60 (5.74) 17.50 (3.58)
[-0.54] [-0.95] [-0.83]
632 302 141 3104
BTFP-Eligible Securities/Assets (%) 10.15 (7.70) 8.58 (6.48) 8.62 (6.21) 9.77 (6.64)
[0.92] [-2.52]** [-1.67]*
632 302 141 3122
MTM Loss/Eligible Securities (%) 8.97 (8.17) 8.47 (7.91) 9.62 (8.77) 8.22 (6.38)
[1.07] [0.37] [1.18]
632 302 141 3104
# Export
export_table(
  table6b, 
  "table6b_arbitrage_period_2023q4",
  caption = "Bank Characteristics by Borrower Type: Arbitrage Period (2023Q4 Baseline)",
  label = "tab:arbitrage_period_2023q4",
  note = "Bank characteristics from 2023Q4 Call Reports. Arbitrage period: November 1, 2023 -- January 24, 2024 (BTFP rate below IORB). Note: DW data available only through December 31, 2023. Sample excludes G-SIBs and failed banks."
)
## LaTeX table saved: C:/Users/mferdo2/OneDrive - Louisiana State University/Finance_PhD/DW_Stigma_paper/Liquidity_project_2025/03_documentation/borrowing_stat_new/tables/table6b_arbitrage_period_2023q4.tex 
## HTML table saved: C:/Users/mferdo2/OneDrive - Louisiana State University/Finance_PhD/DW_Stigma_paper/Liquidity_project_2025/03_documentation/borrowing_stat_new/tables/table6b_arbitrage_period_2023q4.html 
## CSV table saved: C:/Users/mferdo2/OneDrive - Louisiana State University/Finance_PhD/DW_Stigma_paper/Liquidity_project_2025/03_documentation/borrowing_stat_new/tables/table6b_arbitrage_period_2023q4.csv

17 Table 7: FHLB Borrower Characteristics (5% Threshold)

# ==============================================================================
# TABLE 7: FHLB Borrower Characteristics - 5% Threshold (Q1 2023)
# ==============================================================================

# First, identify banks with abnormal FHLB borrowing at 5% threshold
fhlb_borrower_5pct <- baseline_q %>%
  filter(!is.na(abnormal_fhlb_borrowing_5pct) & abnormal_fhlb_borrowing_5pct > 0) %>%
  pull(idrssd)

# Prepare data with FHLB variables (5% threshold)
table7_data <- baseline_q %>%
  mutate(
    # Categorize by FHLB usage (5% threshold)
    fhlb_user = idrssd %in% fhlb_borrower_5pct,
    btfp_user = idrssd %in% btfp_q1,
    dw_user = idrssd %in% dw_q1,
    borrower_type = case_when(
      fhlb_user & btfp_user & dw_user ~ "FHLB+BTFP+DW",
      fhlb_user & btfp_user & !dw_user ~ "FHLB+BTFP",
      fhlb_user & !btfp_user & dw_user ~ "FHLB+DW",
      fhlb_user & !btfp_user & !dw_user ~ "FHLB Only",
      !fhlb_user & (btfp_user | dw_user) ~ "Fed Only",
      TRUE ~ "Non-Borrower"
    )
  )

# Count by category
table7_data %>%
  count(borrower_type) %>%
  arrange(desc(n)) %>%
  pander(caption = "FHLB Borrower Breakdown (5% Threshold)")
FHLB Borrower Breakdown (5% Threshold)
borrower_type n
Non-Borrower 3453
Fed Only 618
FHLB Only 192
FHLB+DW 15
FHLB+BTFP 9
FHLB+BTFP+DW 5
table7 <- create_fhlb_summary_table(table7_data, "borrower_type",
                                     group_levels = c("FHLB Only", "FHLB+BTFP", "FHLB+DW", 
                                                      "FHLB+BTFP+DW", "Fed Only", "Non-Borrower"))

# Display
table7 %>%
  select(-Row_Type) %>%
  kable(caption = "Table 7: Bank Characteristics by FHLB Borrower Type - 5% Threshold (Q1 2023)") %>%
  kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE) %>%
  scroll_box(width = "100%")
Table 7: Bank Characteristics by FHLB Borrower Type - 5% Threshold (Q1 2023)
Variable FHLB Only FHLB+BTFP FHLB+DW FHLB+BTFP+DW Fed Only Non-Borrower
N 192 9 15 5 618 3453
Book Equity Ratio (%) 9.80 (9.36) 9.42 (8.67) 11.24 (10.89) 10.44 (9.62) 8.56 (8.36) 10.54 (8.90)
[-2.66]*** [-1.06] [0.82] [-0.11] [-9.28]***
192 9 15 5 618 3453
MTM Loss Total (%) 5.60 (5.14) 6.59 (6.26) 5.00 (5.07) 6.35 (6.57) 5.83 (5.83) 5.39 (5.23)
[1.27] [2.11]* [-1.14] [0.61] [4.81]***
192 9 15 5 618 3443
MTM Loss BTFP-Eligible (%) 0.52 (0.28) 0.64 (0.52) 0.57 (0.37) 0.35 (0.23) 0.84 (0.56) 0.66 (0.38)
[-2.91]*** [-0.12] [-0.47] [-2.27]* [4.74]***
192 9 15 5 618 3443
MTM Loss Non-Eligible (%) 4.89 (4.60) 5.58 (5.38) 4.65 (4.57) 6.07 (5.58) 4.89 (4.86) 4.53 (4.31)
[2.46]** [1.91]* [0.44] [1.02] [4.24]***
192 9 15 5 618 3443
Adjusted Equity (%) 4.20 (4.30) 2.82 (1.53) 6.24 (6.33) 4.09 (3.04) 2.73 (2.47) 5.04 (3.79)
[-2.42]** [-1.46] [1.19] [-0.40] [-9.20]***
192 9 15 5 618 3443
MTM Insolvent 12.50 (0.00) 33.33 (0.00) 0.00 (0.00) 40.00 (0.00) 23.62 (0.00) 18.88 (0.00)
[-2.57]** [0.87] [-28.30]*** [0.86] [2.59]***
24 3 0 2 146 650
Adjusted Tier1 (%) 5.25 (5.01) 4.12 (3.78) 5.85 (5.39) 3.59 (4.63) 4.42 (3.99) 6.71 (5.23)
[-5.16]*** [-3.17]** [-1.09] [-1.71] [-10.67]***
192 9 15 5 618 3443
Adj. Tier1 < 0 4.69 (0.00) 0.00 (0.00) 0.00 (0.00) 40.00 (0.00) 4.69 (0.00) 2.96 (0.00)
[1.11] [-10.25]*** [-10.25]*** [1.51] [1.92]*
9 0 0 2 29 102
Adjusted CET1 (%) 5.24 (5.00) 4.12 (3.78) 5.84 (5.39) 3.59 (4.63) 4.45 (4.00) 6.63 (5.21)
[-4.96]*** [-3.09]** [-1.01] [-1.67] [-10.26]***
191 9 15 5 595 3411
Adj. CET1 < 0 4.71 (0.00) 0.00 (0.00) 0.00 (0.00) 40.00 (0.00) 4.03 (0.00) 3.02 (0.00)
[1.08] [-10.30]*** [-10.30]*** [1.51] [1.18]
9 0 0 2 24 103
Uninsured/Assets (%) 24.65 (23.17) 30.11 (26.15) 30.56 (30.05) 23.81 (22.44) 27.61 (25.53) 22.79 (21.40)
[2.33]** [1.95]* [2.28]** [0.18] [9.10]***
192 9 15 5 618 3453
Uninsured/Deposits (%) 28.73 (27.48) 35.52 (33.46) 36.37 (36.35) 29.31 (25.17) 32.52 (30.10) 26.59 (24.76)
[2.33]** [2.02]* [2.33]** [0.36] [9.40]***
192 9 15 5 618 3453
Low MTM & Low Uninsured 19.27 (0.00) 0.00 (0.00) 20.00 (0.00) 0.00 (0.00) 10.03 (0.00) 24.76 (0.00)
[-1.86]* [-33.69]*** [-0.44] [-33.69]*** [-10.41]***
37 0 3 0 62 854
Low MTM & High Uninsured 33.33 (0.00) 22.22 (0.00) 40.00 (0.00) 40.00 (0.00) 28.64 (0.00) 25.79 (0.00)
[2.16]** [-0.24] [1.08] [0.58] [1.45]
64 2 6 2 177 889
High MTM & Low Uninsured 23.44 (0.00) 22.22 (0.00) 6.67 (0.00) 40.00 (0.00) 24.11 (0.00) 27.14 (0.00)
[-1.17] [-0.33] [-3.05]*** [0.52] [-1.61]
45 2 1 2 149 936
High MTM & High Uninsured 23.96 (0.00) 55.56 (100.00) 33.33 (0.00) 20.00 (0.00) 37.22 (0.00) 22.11 (0.00)
[0.58] [1.90]* [0.89] [-0.11] [7.30]***
46 5 5 1 230 762
IDCR Insolvent (s=0.5) 3.65 (0.00) 0.00 (0.00) 0.00 (0.00) 20.00 (0.00) 4.85 (0.00) 4.13 (0.00)
[-0.35] [-12.13]*** [-12.13]*** [0.79] [0.78]
7 0 0 1 30 141
IDCR Insolvent (s=1.0) 27.60 (0.00) 0.00 (0.00) 6.67 (0.00) 40.00 (0.00) 28.48 (0.00) 28.66 (0.00)
[-0.32] [-37.02]*** [-3.28]*** [0.46] [-0.09]
53 0 1 2 176 978
Capital Insolvent (s=0.5) 3.12 (0.00) 0.00 (0.00) 0.00 (0.00) 20.00 (0.00) 3.07 (0.00) 1.98 (0.00)
[0.90] [-8.33]*** [-8.33]*** [0.90] [1.50]
6 0 0 1 19 68
Capital Insolvent (s=1.0) 7.81 (0.00) 0.00 (0.00) 0.00 (0.00) 20.00 (0.00) 11.33 (0.00) 6.97 (0.00)
[0.42] [-16.06]*** [-16.06]*** [0.65] [3.23]***
15 0 0 1 70 240
Liquid Assets/Assets (%) 5.35 (4.38) 3.95 (3.59) 5.66 (4.04) 3.24 (3.59) 5.76 (3.57) 10.19 (6.66)
[-15.40]*** [-6.73]*** [-3.94]*** [-9.94]*** [-14.39]***
192 9 15 5 618 3453
Δ Uninsured Deposits (%) -6.10 (-6.21) -14.10 (-13.96) -3.95 (-4.59) -11.14 (-12.22) -6.06 (-6.30) 1.56 (-3.89)
[-2.83]*** [-4.72]*** [-1.51] [-3.57]*** [-3.01]***
192 9 15 5 616 3391
Δ Insured Deposits (%) 1.49 (0.78) 1.07 (0.75) 4.47 (3.66) 6.42 (4.81) 4.73 (2.05) 3.82 (1.43)
[-2.94]*** [-1.49] [0.33] [0.80] [1.03]
192 9 15 5 616 3397
Abnormal Insured Outflow (10%) 8.33 (0.00) 11.11 (0.00) 0.00 (0.00) 0.00 (0.00) 7.77 (0.00) 7.44 (0.00)
[0.43] [0.33] [-16.66]*** [-16.66]*** [0.28]
16 1 0 0 48 257
Abnormal Insured Outflow (5%) 2.08 (0.00) 0.00 (0.00) 0.00 (0.00) 0.00 (0.00) 2.59 (0.00) 2.72 (0.00)
[-0.60] [-9.83]*** [-9.83]*** [-9.83]*** [-0.19]
4 0 0 0 16 94
Abnormal Uninsured Outflow (10%) 30.21 (0.00) 44.44 (0.00) 40.00 (0.00) 60.00 (100.00) 29.45 (0.00) 19.37 (0.00)
[3.20]*** [1.43] [1.57] [1.66] [5.16]***
58 4 6 3 182 669
Abnormal Uninsured Outflow (5%) 14.06 (0.00) 33.33 (0.00) 6.67 (0.00) 20.00 (0.00) 12.30 (0.00) 8.37 (0.00)
[2.22]** [1.50] [-0.25] [0.58] [2.80]***
27 3 1 1 76 289
Capacity Gap/Assets (%) 0.52 (0.28) 0.64 (0.52) 0.57 (0.37) 0.35 (0.23) 0.84 (0.56) 0.66 (0.38)
[-2.91]*** [-0.12] [-0.47] [-2.27]* [4.74]***
192 9 15 5 618 3443
Capacity Gap/Equity (%) 6.34 (3.15) 7.22 (6.12) 5.48 (3.64) 3.55 (1.96) 16.06 (7.08) 10.90 (4.28)
[-4.70]*** [-1.89]* [-2.63]** [-4.49]*** [2.71]***
192 9 15 5 618 3443
Par Valuation Benefit (%) 6.34 (3.15) 7.22 (6.12) 5.48 (3.64) 3.55 (1.96) 16.06 (7.08) 10.90 (4.28)
[-4.70]*** [-1.89]* [-2.63]** [-4.49]*** [2.71]***
192 9 15 5 618 3443
# Export (silently)
invisible(export_table(
  table7, 
  "table7_fhlb_borrowers_5pct",
  caption = "Bank Characteristics by FHLB Borrower Type: Q1 2023 (5\\% Threshold)",
  label = "tab:fhlb_borrowers_5pct",
  note = "Bank characteristics from 2022Q4 Call Reports. FHLB borrowers identified as banks with abnormal FHLB advances at the 95th percentile in 2023Q1. Abnormal FHLB borrowing is measured using Z-scores calculated as (current quarter change $-$ mean) / std, where mean and standard deviation are computed from the prior 8 quarters (2021Q1--2022Q4). Abnormal FHLB (5\\%) indicates Z $>$ 1.65 (top 5 percentile). Fed Only = BTFP and/or DW but no abnormal FHLB increase. Sample excludes G-SIBs and failed banks."
))

LaTeX table saved: C:/Users/mferdo2/OneDrive - Louisiana State University/Finance_PhD/DW_Stigma_paper/Liquidity_project_2025/03_documentation/borrowing_stat_new/tables/table7_fhlb_borrowers_5pct.tex HTML table saved: C:/Users/mferdo2/OneDrive - Louisiana State University/Finance_PhD/DW_Stigma_paper/Liquidity_project_2025/03_documentation/borrowing_stat_new/tables/table7_fhlb_borrowers_5pct.html CSV table saved: C:/Users/mferdo2/OneDrive - Louisiana State University/Finance_PhD/DW_Stigma_paper/Liquidity_project_2025/03_documentation/borrowing_stat_new/tables/table7_fhlb_borrowers_5pct.csv

18 Table 8: FHLB Borrower Characteristics (10% Threshold)

# ==============================================================================
# TABLE 8: FHLB Borrower Characteristics - 10% Threshold (Q1 2023)
# ==============================================================================

# Identify banks with abnormal FHLB borrowing at 10% threshold
fhlb_borrower_10pct <- baseline_q %>%
  filter(!is.na(abnormal_fhlb_borrowing_10pct) & abnormal_fhlb_borrowing_10pct > 0) %>%
  pull(idrssd)

# Prepare data with FHLB variables (10% threshold)
table8_data <- baseline_q %>%
  mutate(
    # Categorize by FHLB usage (10% threshold)
    fhlb_user = idrssd %in% fhlb_borrower_10pct,
    btfp_user = idrssd %in% btfp_q1,
    dw_user = idrssd %in% dw_q1,
    borrower_type = case_when(
      fhlb_user & btfp_user & dw_user ~ "FHLB+BTFP+DW",
      fhlb_user & btfp_user & !dw_user ~ "FHLB+BTFP",
      fhlb_user & !btfp_user & dw_user ~ "FHLB+DW",
      fhlb_user & !btfp_user & !dw_user ~ "FHLB Only",
      !fhlb_user & (btfp_user | dw_user) ~ "Fed Only",
      TRUE ~ "Non-Borrower"
    )
  )

# Count by category
table8_data %>%
  count(borrower_type) %>%
  arrange(desc(n)) %>%
  pander(caption = "FHLB Borrower Breakdown (10% Threshold)")
FHLB Borrower Breakdown (10% Threshold)
borrower_type n
Non-Borrower 3385
Fed Only 605
FHLB Only 260
FHLB+DW 21
FHLB+BTFP 12
FHLB+BTFP+DW 9
table8 <- create_fhlb_summary_table(table8_data, "borrower_type",
                                     group_levels = c("FHLB Only", "FHLB+BTFP", "FHLB+DW", 
                                                      "FHLB+BTFP+DW", "Fed Only", "Non-Borrower"))

# Display
table8 %>%
  select(-Row_Type) %>%
  kable(caption = "Table 8: Bank Characteristics by FHLB Borrower Type - 10% Threshold (Q1 2023)") %>%
  kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE) %>%
  scroll_box(width = "100%")
Table 8: Bank Characteristics by FHLB Borrower Type - 10% Threshold (Q1 2023)
Variable FHLB Only FHLB+BTFP FHLB+DW FHLB+BTFP+DW Fed Only Non-Borrower
N 260 12 21 9 605 3385
Book Equity Ratio (%) 9.82 (9.28) 8.89 (8.36) 11.00 (10.55) 9.36 (9.47) 8.55 (8.35) 10.55 (8.90)
[-2.78]*** [-1.80]* [0.68] [-1.75] [-9.22]***
260 12 21 9 605 3385
MTM Loss Total (%) 5.69 (5.26) 6.37 (6.54) 5.13 (5.07) 6.10 (5.66) 5.83 (5.83) 5.38 (5.23)
[2.13]** [1.96]* [-0.65] [0.79] [4.92]***
260 12 21 9 605 3375
MTM Loss BTFP-Eligible (%) 0.53 (0.28) 0.77 (0.87) 0.46 (0.23) 0.54 (0.34) 0.85 (0.56) 0.66 (0.39)
[-3.19]*** [0.75] [-1.39] [-0.80] [4.74]***
260 12 21 9 605 3375
MTM Loss Non-Eligible (%) 4.98 (4.64) 5.39 (5.48) 4.80 (4.59) 5.79 (5.20) 4.88 (4.86) 4.51 (4.30)
[3.55]*** [1.87]* [0.83] [1.43] [4.30]***
260 12 21 9 605 3375
Adjusted Equity (%) 4.13 (4.12) 2.52 (1.53) 5.87 (6.33) 3.26 (3.04) 2.72 (2.44) 5.07 (3.79)
[-2.93]*** [-1.96]* [0.94] [-1.33] [-9.19]***
260 12 21 9 605 3375
MTM Insolvent 14.23 (0.00) 33.33 (0.00) 4.76 (0.00) 33.33 (0.00) 23.64 (0.00) 18.87 (0.00)
[-2.04]** [1.02] [-2.93]*** [0.87] [2.57]**
37 4 1 3 143 637
Adjusted Tier1 (%) 5.32 (5.01) 4.13 (3.49) 5.61 (5.57) 3.31 (4.04) 4.43 (3.99) 6.73 (5.24)
[-5.29]*** [-3.69]*** [-1.70] [-3.27]** [-10.58]***
260 12 21 9 605 3375
Adj. Tier1 < 0 5.00 (0.00) 0.00 (0.00) 0.00 (0.00) 22.22 (0.00) 4.79 (0.00) 2.90 (0.00)
[1.51] [-10.04]*** [-10.04]*** [1.31] [2.06]**
13 0 0 2 29 98
Adjusted CET1 (%) 5.31 (5.01) 3.83 (3.21) 5.61 (5.57) 3.31 (4.04) 4.46 (4.00) 6.66 (5.21)
[-5.06]*** [-4.06]*** [-1.59] [-3.20]** [-10.15]***
258 11 21 9 583 3344
Adj. CET1 < 0 5.04 (0.00) 0.00 (0.00) 0.00 (0.00) 22.22 (0.00) 4.12 (0.00) 2.96 (0.00)
[1.49] [-10.10]*** [-10.10]*** [1.31] [1.32]
13 0 0 2 24 99
Uninsured/Assets (%) 23.71 (22.82) 31.75 (28.72) 30.18 (30.05) 28.58 (31.00) 27.51 (25.38) 22.82 (21.42)
[1.26] [2.73]** [2.62]** [1.26] [8.75]***
260 12 21 9 605 3385
Uninsured/Deposits (%) 27.76 (26.73) 37.36 (33.86) 36.00 (34.85) 34.63 (35.45) 32.38 (29.83) 26.62 (24.77)
[1.41] [2.66]** [2.68]** [1.37] [9.07]***
260 12 21 9 605 3385
Low MTM & Low Uninsured 19.62 (0.00) 0.00 (0.00) 14.29 (0.00) 0.00 (0.00) 10.25 (0.00) 24.84 (0.00)
[-2.03]** [-33.43]*** [-1.34] [-33.43]*** [-10.13]***
51 0 3 0 62 840
Low MTM & High Uninsured 30.38 (0.00) 25.00 (0.00) 42.86 (0.00) 44.44 (0.00) 28.26 (0.00) 25.87 (0.00)
[1.53] [-0.07] [1.53] [1.06] [1.21]
79 3 9 4 171 874
High MTM & Low Uninsured 26.92 (0.00) 16.67 (0.00) 14.29 (0.00) 33.33 (0.00) 24.13 (0.00) 26.94 (0.00)
[-0.01] [-0.91] [-1.61] [0.38] [-1.48]
70 2 3 3 146 911
High MTM & High Uninsured 23.08 (0.00) 58.33 (100.00) 28.57 (0.00) 22.22 (0.00) 37.36 (0.00) 22.14 (0.00)
[0.35] [2.43]** [0.64] [0.01] [7.27]***
60 7 6 2 226 748
IDCR Insolvent (s=0.5) 4.62 (0.00) 0.00 (0.00) 4.76 (0.00) 11.11 (0.00) 4.79 (0.00) 4.07 (0.00)
[0.41] [-11.90]*** [0.15] [0.63] [0.78]
12 0 1 1 29 136
IDCR Insolvent (s=1.0) 27.31 (0.00) 8.33 (0.00) 14.29 (0.00) 33.33 (0.00) 28.43 (0.00) 28.71 (0.00)
[-0.49] [-2.43]** [-1.83]* [0.28] [-0.14]
71 1 3 3 172 960
Capital Insolvent (s=0.5) 3.08 (0.00) 0.00 (0.00) 4.76 (0.00) 11.11 (0.00) 2.98 (0.00) 1.96 (0.00)
[1.02] [-8.20]*** [0.59] [0.82] [1.39]
8 0 1 1 18 66
Capital Insolvent (s=1.0) 7.31 (0.00) 0.00 (0.00) 4.76 (0.00) 11.11 (0.00) 11.40 (0.00) 6.99 (0.00)
[0.19] [-15.93]*** [-0.47] [0.37] [3.23]***
19 0 1 1 69 236
Liquid Assets/Assets (%) 5.43 (4.31) 4.30 (3.76) 4.95 (3.49) 2.87 (2.22) 5.81 (3.57) 10.28 (6.70)
[-16.41]*** [-6.25]*** [-6.11]*** [-12.18]*** [-14.28]***
260 12 21 9 605 3385
Δ Uninsured Deposits (%) -6.08 (-7.06) -10.34 (-12.20) -3.51 (-4.59) -17.22 (-12.22) -6.01 (-6.29) 1.71 (-3.71)
[-2.85]*** [-2.43]** [-1.54] [-2.78]** [-3.00]***
260 12 21 9 603 3323
Δ Insured Deposits (%) 1.92 (0.96) 6.32 (0.94) 4.53 (3.66) 9.39 (7.84) 4.59 (2.02) 3.84 (1.42)
[-2.27]** [0.45] [0.44] [2.14]* [0.84]
260 12 21 9 603 3329
Abnormal Insured Outflow (10%) 9.62 (0.00) 8.33 (0.00) 0.00 (0.00) 0.00 (0.00) 7.93 (0.00) 7.33 (0.00)
[1.21] [0.12] [-16.36]*** [-16.36]*** [0.51]
25 1 0 0 48 248
Abnormal Insured Outflow (5%) 2.69 (0.00) 0.00 (0.00) 0.00 (0.00) 0.00 (0.00) 2.64 (0.00) 2.69 (0.00)
[0.00] [-9.67]*** [-9.67]*** [-9.67]*** [-0.06]
7 0 0 0 16 91
Abnormal Uninsured Outflow (10%) 29.23 (0.00) 41.67 (0.00) 38.10 (0.00) 55.56 (100.00) 29.26 (0.00) 19.23 (0.00)
[3.44]*** [1.51] [1.73]* [2.07]* [5.09]***
76 5 8 5 177 651
Abnormal Uninsured Outflow (5%) 12.69 (0.00) 33.33 (0.00) 9.52 (0.00) 22.22 (0.00) 12.07 (0.00) 8.36 (0.00)
[2.04]** [1.76] [0.18] [0.94] [2.63]***
33 4 2 2 73 283
Capacity Gap/Assets (%) 0.53 (0.28) 0.77 (0.87) 0.46 (0.23) 0.54 (0.34) 0.85 (0.56) 0.66 (0.39)
[-3.19]*** [0.75] [-1.39] [-0.80] [4.74]***
260 12 21 9 605 3375
Capacity Gap/Equity (%) 6.74 (3.09) 10.27 (8.14) 4.48 (2.11) 6.03 (3.84) 16.22 (7.08) 10.96 (4.28)
[-4.35]*** [-0.26] [-4.02]*** [-2.45]** [2.71]***
260 12 21 9 605 3375
Par Valuation Benefit (%) 6.74 (3.09) 10.27 (8.14) 4.48 (2.11) 6.03 (3.84) 16.22 (7.08) 10.96 (4.28)
[-4.35]*** [-0.26] [-4.02]*** [-2.45]** [2.71]***
260 12 21 9 605 3375
# Export (silently)
invisible(export_table(
  table8, 
  "table8_fhlb_borrowers_10pct",
  caption = "Bank Characteristics by FHLB Borrower Type: Q1 2023 (10\\% Threshold)",
  label = "tab:fhlb_borrowers_10pct",
  note = "Bank characteristics from 2022Q4 Call Reports. FHLB borrowers identified as banks with abnormal FHLB advances at the 90th percentile in 2023Q1. Abnormal FHLB borrowing is measured using Z-scores calculated as (current quarter change $-$ mean) / std, where mean and standard deviation are computed from the prior 8 quarters (2021Q1--2022Q4). Abnormal FHLB (10\\%) indicates Z $>$ 1.28 (top 10 percentile). Fed Only = BTFP and/or DW but no abnormal FHLB increase. Sample excludes G-SIBs and failed banks."
))

LaTeX table saved: C:/Users/mferdo2/OneDrive - Louisiana State University/Finance_PhD/DW_Stigma_paper/Liquidity_project_2025/03_documentation/borrowing_stat_new/tables/table8_fhlb_borrowers_10pct.tex HTML table saved: C:/Users/mferdo2/OneDrive - Louisiana State University/Finance_PhD/DW_Stigma_paper/Liquidity_project_2025/03_documentation/borrowing_stat_new/tables/table8_fhlb_borrowers_10pct.html CSV table saved: C:/Users/mferdo2/OneDrive - Louisiana State University/Finance_PhD/DW_Stigma_paper/Liquidity_project_2025/03_documentation/borrowing_stat_new/tables/table8_fhlb_borrowers_10pct.csv

19 Table 9: Facility Necessity Analysis (Acute Period)

# ==============================================================================
# TABLE 9: FACILITY NECESSITY ANALYSIS
# Who Actually NEEDED BTFP vs DW Would Have Sufficed?
# ==============================================================================

cat("\n", strrep("=", 60), "\n")

============================================================

cat("TABLE 9: Facility Necessity Analysis - Acute Period\n")

TABLE 9: Facility Necessity Analysis - Acute Period

cat(strrep("=", 60), "\n")

============================================================

# Create facility necessity classification for borrowers during acute period
table9_data <- baseline_q %>%
  mutate(
    btfp_user = idrssd %in% btfp_acute,
    dw_user = idrssd %in% dw_acute,
    any_borrower = btfp_user | dw_user,
    
    # Facility classification among borrowers
    facility_choice = case_when(
      btfp_user & dw_user ~ "Both",
      btfp_user & !dw_user ~ "BTFP Only",
      !btfp_user & dw_user ~ "DW Only",
      TRUE ~ "Non-Borrower"
    )
  )

# Summary of facility necessity by borrower type
cat("\n=== Facility Necessity by Borrower Type ===\n")

=== Facility Necessity by Borrower Type ===

table9_data %>%
  filter(any_borrower) %>%
  group_by(facility_choice) %>%
  summarise(
    N = n(),
    Mean_Capacity_Gap_Assets = mean(capacity_gap_to_assets, na.rm = TRUE),
    Mean_Capacity_Gap_Equity = mean(capacity_gap_to_equity, na.rm = TRUE),
    Pct_DW_Sufficient = mean(dw_sufficient, na.rm = TRUE) * 100,
    Pct_BTFP_Necessary = mean(btfp_necessary, na.rm = TRUE) * 100,
    Mean_MTM_Eligible = mean(mtm_loss_omo_eligible_to_total_asset, na.rm = TRUE),
    Mean_MTM_NonEligible = mean(mtm_loss_non_omo_eligible_to_total_asset, na.rm = TRUE),
    .groups = "drop"
  ) %>%
  pander(caption = "Facility Necessity Summary: Acute Period Borrowers")
Facility Necessity Summary: Acute Period Borrowers (continued below)
facility_choice N Mean_Capacity_Gap_Assets Mean_Capacity_Gap_Equity
BTFP Only 368 0.8845 17.38
Both 94 0.916 16.14
DW Only 299 0.7414 12.19
Table continues below
Pct_DW_Sufficient Pct_BTFP_Necessary Mean_MTM_Eligible
28.53 68.21 0.8845
21.28 68.09 0.916
18.73 77.93 0.7414
Mean_MTM_NonEligible
5.022
4.879
4.949
# Create table comparing by facility need
table9_borrowers <- table9_data %>%
  filter(any_borrower) %>%
  mutate(
    necessity_category = case_when(
      dw_sufficient ~ "DW Would Have Sufficed",
      btfp_necessary ~ "BTFP Was Necessary",
      TRUE ~ "Neither Sufficient"
    )
  )

table9 <- create_capacity_table(table9_borrowers, "necessity_category",
                                 group_levels = c("DW Would Have Sufficed", "BTFP Was Necessary", "Neither Sufficient"),
                                 reference_group = "DW Would Have Sufficed")

# Display
table9 %>%
  select(-Row_Type) %>%
  kable(caption = "Table 9: Facility Necessity Analysis - Acute Period Borrowers") %>%
  kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)
Table 9: Facility Necessity Analysis - Acute Period Borrowers
Variable DW Would Have Sufficed BTFP Was Necessary Neither Sufficient
N 181 548 32
BTFP-Eligible Securities/Assets (%) 13.31 (11.47) 10.26 (7.64) 2.99 (2.06)
[-3.20]*** [-9.71]***
181 548 32
Non-Eligible Securities/Assets (%) 77.24 (78.77) 77.96 (80.50) 88.32 (89.08)
[0.69] [8.49]***
181 548 32
MTM Loss Eligible/Assets (%) 1.29 (0.93) 0.71 (0.49) 0.39 (0.17)
[-5.50]*** [-6.23]***
181 548 32
MTM Loss Non-Eligible/Assets (%) 6.11 (6.35) 4.56 (4.45) 5.64 (5.52)
[-9.92]*** [-1.27]
181 548 32
MTM Loss/Eligible Securities (%) 9.80 (9.28) 8.33 (7.27) 11.60 (9.47)
[-2.25]** [1.05]
181 548 32
Capacity Gap/Assets (%) 1.29 (0.93) 0.71 (0.49) 0.39 (0.17)
[-5.50]*** [-6.23]***
181 548 32
Capacity Gap/Equity (%) 38.26 (19.51) 8.18 (5.26) 4.82 (1.98)
[-5.19]*** [-5.64]***
181 548 32
Capacity Gap/Uninsured Deposits (%) 6.22 (3.76) 3.65 (1.93) 1.04 (0.50)
[-2.70]*** [-6.15]***
181 547 32
Par Valuation Benefit (%) 38.26 (19.51) 8.18 (5.26) 4.82 (1.98)
[-5.19]*** [-5.64]***
181 548 32
Eligible Share of Total MTM Loss (%) 16.60 (11.82) 13.49 (10.06) 7.37 (3.04)
[-2.36]** [-3.90]***
181 548 32
Book Equity/Assets (%) 5.21 (5.33) 9.62 (9.15) 8.39 (8.35)
[24.37]*** [6.78]***
181 548 32
Adjusted Equity (%) -2.67 (-2.28) 4.28 (3.51) 2.35 (2.61)
[34.65]*** [7.19]***
181 548 32
MTM Insolvent 100.00 (100.00) 0.18 (0.00) 21.88 (0.00)
[-547.00]*** [-10.52]***
181 1 7
CET1 Post-MTM (%) 1.35 (1.16) 5.32 (4.78) 3.50 (3.84)
[23.39]*** [4.89]***
178 533 31
CET1 < 4.5% After MTM 98.88 (100.00) 42.78 (0.00) 67.74 (100.00)
[-24.53]*** [-3.63]***
176 228 21
Tier1 < 4% After MTM (PCA) 95.58 (100.00) 35.95 (0.00) 62.50 (100.00)
[-23.29]*** [-3.75]***
173 197 20
Uninsured Deposits/Assets (%) 26.23 (25.98) 27.11 (25.31) 35.44 (31.80)
[0.92] [3.50]***
181 548 32
Liquid Assets/Assets (%) 4.46 (3.40) 6.47 (3.88) 2.98 (2.46)
[5.01]*** [-3.14]***
181 548 32
Liquidity Shortfall/Assets (%) 0.74 (0.00) 0.35 (0.00) 7.77 (4.14)
[-2.79]*** [5.07]***
181 548 32
DW Covers Shortfall 100.00 (100.00) 99.45 (100.00) 0.00 (0.00)
[-1.74]*
181 545 0
BTFP Covers Shortfall 100.00 (100.00) 100.00 (100.00) 0.00 (0.00)
181 548 0
DW Sufficient (Solvent + Covers) 100.00 (100.00) 0.00 (0.00) 0.00 (0.00)
181 0 0
BTFP Necessary 0.00 (0.00) 100.00 (100.00) 0.00 (0.00)
0 548 0
# Export
export_table(
  table9, 
  "table9_facility_necessity",
  caption = "Facility Necessity Analysis: Acute Period Borrowers",
  label = "tab:facility_necessity",
  note = "Analysis limited to banks that borrowed from BTFP or DW during the acute crisis period (March 13 -- May 1, 2023). DW Would Have Sufficed = Bank was MV-solvent and DW capacity covered revealed liquidity shortfall. BTFP Was Necessary = DW would have been insufficient but BTFP capacity was sufficient. Capacity Gap = Par Value - Market Value of BTFP-eligible securities."
)

LaTeX table saved: C:/Users/mferdo2/OneDrive - Louisiana State University/Finance_PhD/DW_Stigma_paper/Liquidity_project_2025/03_documentation/borrowing_stat_new/tables/table9_facility_necessity.tex HTML table saved: C:/Users/mferdo2/OneDrive - Louisiana State University/Finance_PhD/DW_Stigma_paper/Liquidity_project_2025/03_documentation/borrowing_stat_new/tables/table9_facility_necessity.html CSV table saved: C:/Users/mferdo2/OneDrive - Louisiana State University/Finance_PhD/DW_Stigma_paper/Liquidity_project_2025/03_documentation/borrowing_stat_new/tables/table9_facility_necessity.csv

20 Table 10: Capacity Gap by Facility Choice

# ==============================================================================
# TABLE 10: CAPACITY GAP ANALYSIS BY FACILITY CHOICE
# Key Test: Do BTFP borrowers have systematically higher capacity gaps?
# ==============================================================================

cat("\n", strrep("=", 60), "\n")

============================================================

cat("TABLE 10: Capacity Gap Analysis by Facility Choice\n")

TABLE 10: Capacity Gap Analysis by Facility Choice

cat(strrep("=", 60), "\n")

============================================================

# Focus on acute period facility choice
table10_data <- table4_data  # Reuse acute period data

# Detailed capacity analysis
table10 <- create_capacity_table(table10_data, "borrower_type",
                                  group_levels = c("BTFP Only", "DW Only", "Both", "Non-Borrower"))

# Display
table10 %>%
  select(-Row_Type) %>%
  kable(caption = "Table 10: Borrowing Capacity Analysis - Acute Period") %>%
  kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)
Table 10: Borrowing Capacity Analysis - Acute Period
Variable BTFP Only DW Only Both Non-Borrower
N 368 299 94 3531
BTFP-Eligible Securities/Assets (%) 11.61 (9.32) 9.38 (6.72) 11.15 (8.55) 10.79 (7.75)
[1.40] [-2.57]** [0.36]
368 299 94 3531
Non-Eligible Securities/Assets (%) 78.00 (80.19) 78.41 (81.08) 78.50 (80.50) 74.18 (78.36)
[5.64]*** [5.80]*** [3.80]***
368 299 94 3531
MTM Loss Eligible/Assets (%) 0.88 (0.61) 0.74 (0.48) 0.92 (0.61) 0.65 (0.38)
[4.32]*** [1.85]* [2.68]***
368 299 94 3521
MTM Loss Non-Eligible/Assets (%) 5.02 (4.90) 4.95 (4.90) 4.88 (4.67) 4.52 (4.29)
[4.91]*** [3.73]*** [1.95]*
368 299 94 3521
MTM Loss/Eligible Securities (%) 9.03 (7.84) 8.67 (7.86) 8.48 (8.46) 10.62 (6.12)
[-0.44] [-0.55] [-0.60]
368 299 94 3521
Capacity Gap/Assets (%) 0.88 (0.61) 0.74 (0.48) 0.92 (0.61) 0.65 (0.38)
[4.32]*** [1.85]* [2.68]***
368 299 94 3521
Capacity Gap/Equity (%) 17.38 (7.72) 12.19 (5.04) 16.14 (7.23) 10.59 (4.15)
[2.50]** [0.87] [1.97]*
368 299 94 3521
Capacity Gap/Uninsured Deposits (%) 4.24 (2.57) 4.37 (1.94) 3.13 (1.93) 4.93 (1.88)
[-1.18] [-0.53] [-3.16]***
367 299 94 3486
Par Valuation Benefit (%) 17.38 (7.72) 12.19 (5.04) 16.14 (7.23) 10.59 (4.15)
[2.50]** [0.87] [1.97]*
368 299 94 3521
Eligible Share of Total MTM Loss (%) 14.34 (10.36) 13.01 (9.80) 15.54 (11.25) 15.06 (7.69)
[-0.34] [-0.98] [0.19]
368 299 94 3520
Book Equity/Assets (%) 8.18 (8.08) 9.05 (8.82) 8.19 (8.23) 10.59 (8.96)
[-10.58]*** [-6.25]*** [-7.48]***
368 299 94 3531
Adjusted Equity (%) 2.00 (2.03) 3.30 (3.01) 2.33 (2.70) 5.13 (3.89)
[-11.32]*** [-6.16]*** [-6.43]***
368 299 94 3521
MTM Insolvent 30.43 (0.00) 19.06 (0.00) 21.28 (0.00) 18.06 (0.00)
[4.97]*** [0.42] [0.75]
112 57 20 636
CET1 Post-MTM (%) 4.11 (3.77) 4.71 (4.19) 3.65 (3.58) 6.67 (5.29)
[-11.42]*** [-8.03]*** [-9.79]***
361 293 88 3484
CET1 < 4.5% After MTM 58.73 (100.00) 53.24 (100.00) 64.77 (100.00) 40.36 (0.00)
[6.74]*** [4.24]*** [4.71]***
212 156 57 1406
Tier1 < 4% After MTM (PCA) 53.26 (100.00) 47.49 (0.00) 55.32 (100.00) 33.03 (0.00)
[7.43]*** [4.82]*** [4.27]***
196 142 52 1163
Uninsured Deposits/Assets (%) 26.21 (25.09) 26.85 (25.28) 32.63 (30.81) 22.83 (21.44)
[5.33]*** [5.78]*** [6.67]***
368 299 94 3531
Liquid Assets/Assets (%) 5.15 (3.63) 6.97 (4.15) 4.97 (2.85) 10.04 (6.53)
[-15.65]*** [-6.79]*** [-8.39]***
368 299 94 3531
Liquidity Shortfall/Assets (%) 0.75 (0.00) 0.49 (0.00) 1.64 (0.00) 0.28 (0.00)
[4.35]*** [2.03]** [2.63]**
368 299 94 3531
DW Covers Shortfall 95.92 (100.00) 96.66 (100.00) 89.36 (100.00) 97.33 (100.00)
[-1.32] [-0.63] [-2.48]**
353 289 84 3427
BTFP Covers Shortfall 96.74 (100.00) 96.66 (100.00) 89.36 (100.00) 97.85 (100.00)
[-1.16] [-1.11] [-2.65]***
356 289 84 3455
DW Sufficient (Solvent + Covers) 28.53 (0.00) 18.73 (0.00) 21.28 (0.00) 17.52 (0.00)
[4.51]*** [0.51] [0.87]
105 56 20 617
BTFP Necessary 68.21 (100.00) 77.93 (100.00) 68.09 (100.00) 80.32 (100.00)
[-4.80]*** [-0.96] [-2.51]**
251 233 64 2828
# Export
export_table(
  table10, 
  "table10_capacity_gap_analysis",
  caption = "Borrowing Capacity Analysis by Facility Choice: Acute Crisis Period",
  label = "tab:capacity_gap_analysis",
  note = "Bank characteristics from 2022Q4 Call Reports. Acute crisis period: March 13 -- May 1, 2023. Capacity Gap measures the additional borrowing capacity available at BTFP (par valuation) versus DW (market valuation). Par Valuation Benefit = Capacity Gap / Book Equity, representing the equity 'saved' by borrowing at par. BTFP Necessary indicates banks where DW collateral capacity would not have covered the revealed liquidity shortfall."
)

LaTeX table saved: C:/Users/mferdo2/OneDrive - Louisiana State University/Finance_PhD/DW_Stigma_paper/Liquidity_project_2025/03_documentation/borrowing_stat_new/tables/table10_capacity_gap_analysis.tex HTML table saved: C:/Users/mferdo2/OneDrive - Louisiana State University/Finance_PhD/DW_Stigma_paper/Liquidity_project_2025/03_documentation/borrowing_stat_new/tables/table10_capacity_gap_analysis.html CSV table saved: C:/Users/mferdo2/OneDrive - Louisiana State University/Finance_PhD/DW_Stigma_paper/Liquidity_project_2025/03_documentation/borrowing_stat_new/tables/table10_capacity_gap_analysis.csv

# Additional diagnostic: T-tests for key capacity variables
cat("\n=== T-Tests: BTFP Only vs DW Only ===\n")

=== T-Tests: BTFP Only vs DW Only ===

btfp_only_data <- table10_data %>% filter(borrower_type == "BTFP Only")
dw_only_data <- table10_data %>% filter(borrower_type == "DW Only")

test_vars <- c("capacity_gap_to_assets", "capacity_gap_to_equity", "par_valuation_benefit",
               "mtm_loss_omo_eligible_to_total_asset", "mtm_loss_non_omo_eligible_to_total_asset")

for (v in test_vars) {
  if (v %in% names(btfp_only_data) & v %in% names(dw_only_data)) {
    result <- calc_tstat_with_stars(btfp_only_data[[v]], dw_only_data[[v]])
    cat(sprintf("%s: t = %.3f%s (p = %.4f)\n", v, result$tstat, result$stars, result$pval))
  }
}

capacity_gap_to_assets: t = 2.007** (p = 0.0452) capacity_gap_to_equity: t = 1.657* (p = 0.0980) par_valuation_benefit: t = 1.657* (p = 0.0980) mtm_loss_omo_eligible_to_total_asset: t = 2.007** (p = 0.0452) mtm_loss_non_omo_eligible_to_total_asset: t = 0.500 (p = 0.6170)

21 Table 11: Risk Category Analysis (75th Percentile)

# ==============================================================================
# TABLE 11: RISK CATEGORY ANALYSIS (75th PERCENTILE CLASSIFICATION)
# ==============================================================================

cat("\n", strrep("=", 60), "\n")

============================================================

cat("TABLE 11: Risk Category Analysis - 75th Percentile Classification\n")

TABLE 11: Risk Category Analysis - 75th Percentile Classification

cat(strrep("=", 60), "\n")

============================================================

# Add risk category to acute period data
table11_data <- table4_data %>%
  mutate(
    risk_category = risk_category_p75
  )

# Summary by risk category and facility choice
cat("\n=== Facility Choice by Risk Category ===\n")

=== Facility Choice by Risk Category ===

table11_data %>%
  group_by(risk_category, borrower_type) %>%
  summarise(N = n(), .groups = "drop") %>%
  pivot_wider(names_from = borrower_type, values_from = N, values_fill = 0) %>%
  pander(caption = "Facility Choice by Risk Category")
Facility Choice by Risk Category
risk_category BTFP Only Both DW Only Non-Borrower
Dual Risk 29 12 19 131
Low Risk 160 35 134 1980
MTM Risk Only 96 11 66 724
Run Risk Only 83 36 80 686
NA 0 0 0 10
# Create summary table by risk category
table11 <- create_capacity_table(table11_data, "risk_category",
                                  group_levels = c("Low Risk", "Run Risk Only", "MTM Risk Only", "Dual Risk"),
                                  reference_group = "Low Risk")

# Display
table11 %>%
  select(-Row_Type) %>%
  kable(caption = "Table 11: Bank Characteristics by Risk Category (75th Percentile Classification)") %>%
  kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)
Table 11: Bank Characteristics by Risk Category (75th Percentile Classification)
Variable Low Risk Run Risk Only MTM Risk Only Dual Risk
N 2309 885 897 191
BTFP-Eligible Securities/Assets (%) 11.35 (8.18) 10.11 (7.58) 9.77 (6.68) 10.83 (8.00)
[-3.01]*** [-3.97]*** [-0.72]
2309 885 897 191
Non-Eligible Securities/Assets (%) 73.31 (77.43) 73.92 (78.43) 79.62 (82.05) 78.52 (79.15)
[1.00] [12.69]*** [6.45]***
2309 885 897 191
MTM Loss Eligible/Assets (%) 0.59 (0.37) 0.60 (0.35) 0.91 (0.52) 1.06 (0.70)
[0.46] [7.69]*** [5.92]***
2309 885 897 191
MTM Loss Non-Eligible/Assets (%) 3.79 (3.81) 3.71 (3.69) 7.11 (7.06) 6.67 (6.86)
[-1.34] [53.72]*** [25.69]***
2309 885 897 191
MTM Loss/Eligible Securities (%) 11.79 (5.35) 6.93 (6.14) 9.69 (8.96) 10.71 (9.63)
[-0.90] [-0.39] [-0.20]
2309 885 897 191
Capacity Gap/Assets (%) 0.59 (0.37) 0.60 (0.35) 0.91 (0.52) 1.06 (0.70)
[0.46] [7.69]*** [5.92]***
2309 885 897 191
Capacity Gap/Equity (%) 7.63 (3.89) 10.03 (3.85) 18.84 (6.47) 28.51 (11.79)
[2.21]** [4.66]*** [3.23]***
2309 885 897 191
Capacity Gap/Uninsured Deposits (%) 5.24 (2.04) 1.57 (0.90) 7.24 (3.33) 2.80 (1.97)
[-5.45]*** [2.37]** [-3.49]***
2276 885 894 191
Par Valuation Benefit (%) 7.63 (3.89) 10.03 (3.85) 18.84 (6.47) 28.51 (11.79)
[2.21]** [4.66]*** [3.23]***
2309 885 897 191
Eligible Share of Total MTM Loss (%) 16.87 (8.55) 14.05 (8.84) 10.88 (6.45) 13.08 (8.31)
[-0.92] [-2.00]** [-1.21]
2308 885 897 191
Book Equity/Assets (%) 11.09 (9.17) 9.42 (9.01) 9.15 (8.04) 6.57 (6.33)
[-6.65]*** [-6.32]*** [-14.78]***
2309 885 897 191
Adjusted Equity (%) 6.56 (4.62) 5.06 (4.76) 0.75 (-0.08) -1.52 (-1.95)
[-5.45]*** [-18.45]*** [-24.30]***
2309 885 897 191
MTM Insolvent 6.50 (0.00) 8.93 (0.00) 51.73 (100.00) 69.11 (100.00)
[2.23]** [25.90]*** [18.46]***
150 79 464 132
CET1 Post-MTM (%) 7.70 (5.70) 6.09 (5.50) 3.59 (2.48) 1.91 (1.55)
[-6.58]*** [-14.06]*** [-21.66]***
2290 857 892 187
CET1 < 4.5% After MTM 31.88 (0.00) 32.67 (0.00) 72.76 (100.00) 91.98 (100.00)
[0.42] [22.95]*** [27.11]***
730 280 649 172
Tier1 < 4% After MTM (PCA) 23.39 (0.00) 25.76 (0.00) 68.56 (100.00) 89.01 (100.00)
[1.39] [25.33]*** [26.95]***
540 228 615 170
Uninsured Deposits/Assets (%) 18.45 (19.11) 40.27 (37.52) 17.45 (17.68) 37.46 (35.61)
[62.32]*** [-3.55]*** [32.62]***
2309 885 897 191
Liquid Assets/Assets (%) 10.26 (6.62) 11.18 (7.41) 5.47 (4.11) 5.60 (4.52)
[2.12]** [-17.56]*** [-12.57]***
2309 885 897 191
Liquidity Shortfall/Assets (%) 0.21 (0.00) 0.77 (0.00) 0.27 (0.00) 0.87 (0.00)
[6.02]*** [1.74]* [4.27]***
2309 885 897 191
DW Covers Shortfall 98.22 (100.00) 93.79 (100.00) 97.32 (100.00) 95.29 (100.00)
[-5.18]*** [-1.49] [-1.88]*
2268 830 873 182
BTFP Covers Shortfall 98.57 (100.00) 94.58 (100.00) 97.77 (100.00) 96.34 (100.00)
[-4.99]*** [-1.45] [-1.61]
2276 837 877 184
DW Sufficient (Solvent + Covers) 6.32 (0.00) 8.59 (0.00) 49.94 (0.00) 67.02 (100.00)
[2.12]** [24.99]*** [17.60]***
146 76 448 128
BTFP Necessary 92.25 (100.00) 85.99 (100.00) 47.83 (0.00) 29.32 (0.00)
[-4.84]*** [-25.25]*** [-18.79]***
2130 761 429 56
# Export
export_table(
  table11, 
  "table11_risk_category_p75",
  caption = "Bank Characteristics by Risk Category (75th Percentile Classification)",
  label = "tab:risk_category_p75",
  note = "Banks classified based on 75th percentile cutoffs for MTM losses and uninsured deposits. Low Risk = both below 75th percentile. Run Risk Only = high uninsured deposits, low MTM losses. MTM Risk Only = high MTM losses, low uninsured deposits. Dual Risk = both above 75th percentile (SVB-type profile). T-statistics compare to Low Risk category."
)

LaTeX table saved: C:/Users/mferdo2/OneDrive - Louisiana State University/Finance_PhD/DW_Stigma_paper/Liquidity_project_2025/03_documentation/borrowing_stat_new/tables/table11_risk_category_p75.tex HTML table saved: C:/Users/mferdo2/OneDrive - Louisiana State University/Finance_PhD/DW_Stigma_paper/Liquidity_project_2025/03_documentation/borrowing_stat_new/tables/table11_risk_category_p75.html CSV table saved: C:/Users/mferdo2/OneDrive - Louisiana State University/Finance_PhD/DW_Stigma_paper/Liquidity_project_2025/03_documentation/borrowing_stat_new/tables/table11_risk_category_p75.csv

# Facility choice rates by risk category
cat("\n=== BTFP Selection Rate by Risk Category ===\n")

=== BTFP Selection Rate by Risk Category ===

table11_data %>%
  filter(borrower_type != "Non-Borrower") %>%
  group_by(risk_category) %>%
  summarise(
    N_Borrowers = n(),
    N_BTFP = sum(borrower_type %in% c("BTFP Only", "Both")),
    BTFP_Rate = mean(borrower_type %in% c("BTFP Only", "Both")) * 100,
    .groups = "drop"
  ) %>%
  pander(caption = "BTFP Selection Rate Among Borrowers by Risk Category")
BTFP Selection Rate Among Borrowers by Risk Category
risk_category N_Borrowers N_BTFP BTFP_Rate
Dual Risk 60 41 68.33
Low Risk 329 195 59.27
MTM Risk Only 173 107 61.85
Run Risk Only 199 119 59.8

22 Summary Statistics

# ==============================================================================
# SUMMARY OF BORROWER COUNTS
# ==============================================================================

cat("\n", strrep("=", 60), "\n")
## 
##  ============================================================
cat("SUMMARY OF BORROWER COUNTS\n")
## SUMMARY OF BORROWER COUNTS
cat(strrep("=", 60), "\n")
## ============================================================
summary_counts <- tribble(
  ~Table, ~Period, ~Baseline, ~Description, ~N_Borrowers, ~N_Total,
  "Table 1", "March 10, 2023", "2022Q4", "DW only", 
    sum(baseline_q$idrssd %in% dw_mar10), nrow(baseline_q),
  "Table 2", "March 10-13, 2023", "2022Q4", "DW only", 
    sum(baseline_q$idrssd %in% dw_mar10_13), nrow(baseline_q),
  "Table 3", "March 9-14, 2023", "2022Q4", "DW only", 
    sum(baseline_q$idrssd %in% dw_mar9_14), nrow(baseline_q),
  "Table 4", "Acute (Mar 13 - May 1)", "2022Q4", "BTFP + DW", 
    sum(baseline_q$idrssd %in% union(btfp_acute, dw_acute)), nrow(baseline_q),
  "Table 4B", "Acute (Mar 13 - May 1)", "2022Q4", "Capacity Analysis", 
    sum(baseline_q$idrssd %in% union(btfp_acute, dw_acute)), nrow(baseline_q),
  "Table 5A", "Q1 2023 (Jan-Mar)", "2022Q4", "BTFP + DW + FHLB (10%)", 
    sum(baseline_q$idrssd %in% union(union(btfp_q1, dw_q1), fhlb_borrowers_10pct)), nrow(baseline_q),
  "Table 5B", "Q1 2023 (Jan-Mar)", "2022Q4", "BTFP + DW + FHLB (5%)", 
    sum(baseline_q$idrssd %in% union(union(btfp_q1, dw_q1), fhlb_borrowers_5pct)), nrow(baseline_q),
  "Table 6", "Arbitrage (Nov 1 - Jan 24)", "2022Q4", "BTFP + DW", 
    sum(baseline_q$idrssd %in% union(btfp_arb, dw_arb)), nrow(baseline_q),
  "Table 6b", "Arbitrage (Nov 1 - Jan 24)", "2023Q4", "BTFP + DW", 
    sum(baseline_q4_2023$idrssd %in% union(btfp_arb, dw_arb)), nrow(baseline_q4_2023),
  "Table 7", "Q1 2023", "2022Q4", "FHLB focus (5%)", 
    sum(baseline_q$idrssd %in% fhlb_borrower_5pct), nrow(baseline_q),
  "Table 8", "Q1 2023", "2022Q4", "FHLB focus (10%)", 
    sum(baseline_q$idrssd %in% fhlb_borrower_10pct), nrow(baseline_q),
  "Table 9", "Acute (Mar 13 - May 1)", "2022Q4", "Facility Necessity", 
    sum(baseline_q$idrssd %in% union(btfp_acute, dw_acute)), nrow(baseline_q),
  "Table 10", "Acute (Mar 13 - May 1)", "2022Q4", "Capacity Gap Analysis", 
    sum(baseline_q$idrssd %in% union(btfp_acute, dw_acute)), nrow(baseline_q),
  "Table 11", "Acute (Mar 13 - May 1)", "2022Q4", "Risk Category (P75)", 
    nrow(baseline_q), nrow(baseline_q)
)

summary_counts %>%
  kable(caption = "Summary of Borrower Counts Across Tables") %>%
  kable_styling(bootstrap_options = c("striped", "hover"), full_width = FALSE)
Summary of Borrower Counts Across Tables
Table Period Baseline Description N_Borrowers N_Total
Table 1 March 10, 2023 2022Q4 DW only 47 4292
Table 2 March 10-13, 2023 2022Q4 DW only 90 4292
Table 3 March 9-14, 2023 2022Q4 DW only 124 4292
Table 4 Acute (Mar 13 - May 1) 2022Q4 BTFP + DW 761 4292
Table 4B Acute (Mar 13 - May 1) 2022Q4 Capacity Analysis 761 4292
Table 5A Q1 2023 (Jan-Mar) 2022Q4 BTFP + DW + FHLB (10%) 907 4292
Table 5B Q1 2023 (Jan-Mar) 2022Q4 BTFP + DW + FHLB (5%) 839 4292
Table 6 Arbitrage (Nov 1 - Jan 24) 2022Q4 BTFP + DW 1068 4292
Table 6b Arbitrage (Nov 1 - Jan 24) 2023Q4 BTFP + DW 1075 4197
Table 7 Q1 2023 2022Q4 FHLB focus (5%) 221 4292
Table 8 Q1 2023 2022Q4 FHLB focus (10%) 302 4292
Table 9 Acute (Mar 13 - May 1) 2022Q4 Facility Necessity 761 4292
Table 10 Acute (Mar 13 - May 1) 2022Q4 Capacity Gap Analysis 761 4292
Table 11 Acute (Mar 13 - May 1) 2022Q4 Risk Category (P75) 4292 4292
# Save summary
write_csv(summary_counts, file.path(TABLE_PATH, "summary_borrower_counts.csv"))

cat("\n=== ALL TABLES EXPORTED ===\n")
## 
## === ALL TABLES EXPORTED ===
cat("Output directory:", TABLE_PATH, "\n")
## Output directory: C:/Users/mferdo2/OneDrive - Louisiana State University/Finance_PhD/DW_Stigma_paper/Liquidity_project_2025/03_documentation/borrowing_stat_new/tables
cat("Files created:\n")
## Files created:
list.files(TABLE_PATH, pattern = "\\.(tex|html|csv)$") %>%
  paste("  -", .) %>%
  cat(sep = "\n")
##   - summary_borrower_counts.csv
##   - table_beta1_dw_mar10.csv
##   - table_beta1_dw_mar10.html
##   - table_beta1_dw_mar10.tex
##   - table_beta2_dw_mar10_13.csv
##   - table_beta2_dw_mar10_13.html
##   - table_beta2_dw_mar10_13.tex
##   - table_beta3_acute.csv
##   - table_beta3_acute.html
##   - table_beta3_acute.tex
##   - table_beta4_q1_2023.csv
##   - table_beta4_q1_2023.html
##   - table_beta4_q1_2023.tex
##   - table_beta5_arbitrage.csv
##   - table_beta5_arbitrage.html
##   - table_beta5_arbitrage.tex
##   - table1_dw_mar10.csv
##   - table1_dw_mar10.html
##   - table1_dw_mar10.tex
##   - table10_capacity_gap_analysis.csv
##   - table10_capacity_gap_analysis.html
##   - table10_capacity_gap_analysis.tex
##   - table11_risk_category_p75.csv
##   - table11_risk_category_p75.html
##   - table11_risk_category_p75.tex
##   - table2_dw_mar10_13.csv
##   - table2_dw_mar10_13.html
##   - table2_dw_mar10_13.tex
##   - table3_dw_mar9_14.csv
##   - table3_dw_mar9_14.html
##   - table3_dw_mar9_14.tex
##   - table4_acute_period.csv
##   - table4_acute_period.html
##   - table4_acute_period.tex
##   - table4b_acute_capacity.csv
##   - table4b_acute_capacity.html
##   - table4b_acute_capacity.tex
##   - table5a_q1_2023_10pct.csv
##   - table5a_q1_2023_10pct.html
##   - table5a_q1_2023_10pct.tex
##   - table5b_q1_2023_5pct.csv
##   - table5b_q1_2023_5pct.html
##   - table5b_q1_2023_5pct.tex
##   - table6_arbitrage_period.csv
##   - table6_arbitrage_period.html
##   - table6_arbitrage_period.tex
##   - table6b_arbitrage_period_2023q4.csv
##   - table6b_arbitrage_period_2023q4.html
##   - table6b_arbitrage_period_2023q4.tex
##   - table7_fhlb_borrowers_5pct.csv
##   - table7_fhlb_borrowers_5pct.html
##   - table7_fhlb_borrowers_5pct.tex
##   - table8_fhlb_borrowers_10pct.csv
##   - table8_fhlb_borrowers_10pct.html
##   - table8_fhlb_borrowers_10pct.tex
##   - table9_facility_necessity.csv
##   - table9_facility_necessity.html
##   - table9_facility_necessity.tex

23 Key Findings Summary

# ==============================================================================
# KEY FINDINGS SUMMARY
# ==============================================================================

cat("\n", strrep("=", 60), "\n")
## 
##  ============================================================
cat("KEY FINDINGS SUMMARY\n")
## KEY FINDINGS SUMMARY
cat(strrep("=", 60), "\n")
## ============================================================
# 1. Capacity Gap Analysis
cat("\n--- CAPACITY GAP ANALYSIS ---\n")
## 
## --- CAPACITY GAP ANALYSIS ---
table4_data %>%
  filter(borrower_type != "Non-Borrower") %>%
  group_by(borrower_type) %>%
  summarise(
    N = n(),
    Mean_CapGap_Assets = round(mean(capacity_gap_to_assets, na.rm = TRUE), 2),
    Mean_CapGap_Equity = round(mean(capacity_gap_to_equity, na.rm = TRUE), 2),
    Mean_ParValBenefit = round(mean(par_valuation_benefit, na.rm = TRUE), 2),
    .groups = "drop"
  ) %>%
  pander(caption = "Capacity Gap by Facility Choice (Acute Period)")
Capacity Gap by Facility Choice (Acute Period) (continued below)
borrower_type N Mean_CapGap_Assets Mean_CapGap_Equity
BTFP Only 368 0.88 17.38
Both 94 0.92 16.14
DW Only 299 0.74 12.19
Mean_ParValBenefit
17.38
16.14
12.19
# 2. MTM Loss Decomposition
cat("\n--- MTM LOSS DECOMPOSITION ---\n")
## 
## --- MTM LOSS DECOMPOSITION ---
table4_data %>%
  filter(borrower_type != "Non-Borrower") %>%
  group_by(borrower_type) %>%
  summarise(
    N = n(),
    MTM_Total = round(mean(mtm_loss_to_total_asset, na.rm = TRUE), 2),
    MTM_Eligible = round(mean(mtm_loss_omo_eligible_to_total_asset, na.rm = TRUE), 2),
    MTM_NonEligible = round(mean(mtm_loss_non_omo_eligible_to_total_asset, na.rm = TRUE), 2),
    Eligible_Share = round(mean(mtm_eligible_share, na.rm = TRUE), 1),
    .groups = "drop"
  ) %>%
  pander(caption = "MTM Loss Decomposition by Facility Choice")
MTM Loss Decomposition by Facility Choice
borrower_type N MTM_Total MTM_Eligible MTM_NonEligible Eligible_Share
BTFP Only 368 6.18 0.88 5.02 14.3
Both 94 5.86 0.92 4.88 15.5
DW Only 299 5.75 0.74 4.95 13
# 3. Facility Necessity
cat("\n--- FACILITY NECESSITY ---\n")
## 
## --- FACILITY NECESSITY ---
table4_data %>%
  filter(borrower_type != "Non-Borrower") %>%
  group_by(borrower_type) %>%
  summarise(
    N = n(),
    Pct_DW_Sufficient = round(mean(dw_sufficient, na.rm = TRUE) * 100, 1),
    Pct_BTFP_Necessary = round(mean(btfp_necessary, na.rm = TRUE) * 100, 1),
    .groups = "drop"
  ) %>%
  pander(caption = "Facility Necessity by Borrower Type")
Facility Necessity by Borrower Type
borrower_type N Pct_DW_Sufficient Pct_BTFP_Necessary
BTFP Only 368 28.5 68.2
Both 94 21.3 68.1
DW Only 299 18.7 77.9
# 4. Key T-test: BTFP Only vs DW Only for capacity gap
cat("\n--- KEY STATISTICAL TESTS ---\n")
## 
## --- KEY STATISTICAL TESTS ---
btfp_vals <- table4_data %>% filter(borrower_type == "BTFP Only") %>% pull(capacity_gap_to_equity)
dw_vals <- table4_data %>% filter(borrower_type == "DW Only") %>% pull(capacity_gap_to_equity)
test_result <- calc_tstat_with_stars(btfp_vals, dw_vals)
cat(sprintf("Capacity Gap/Equity: BTFP Only vs DW Only\n"))
## Capacity Gap/Equity: BTFP Only vs DW Only
cat(sprintf("  BTFP Only mean: %.2f%%\n", mean(btfp_vals, na.rm = TRUE)))
##   BTFP Only mean: 17.38%
cat(sprintf("  DW Only mean: %.2f%%\n", mean(dw_vals, na.rm = TRUE)))
##   DW Only mean: 12.19%
cat(sprintf("  Difference: %.2f pp\n", mean(btfp_vals, na.rm = TRUE) - mean(dw_vals, na.rm = TRUE)))
##   Difference: 5.19 pp
cat(sprintf("  T-statistic: %.3f%s (p = %.4f)\n", test_result$tstat, test_result$stars, test_result$pval))
##   T-statistic: 1.657* (p = 0.0980)
# ==============================================================================
# VARIABLE DEFINITIONS TABLE
# ==============================================================================

cat("\n", strrep("=", 60), "\n")
## 
##  ============================================================
cat("VARIABLE DEFINITIONS\n")
## VARIABLE DEFINITIONS
cat(strrep("=", 60), "\n")
## ============================================================
variable_definitions <- tribble(
  ~Category, ~Variable, ~Definition, ~Source,
  
  # Core Capacity Measures
  "Core Capacity", "BTFP-Eligible Securities/Assets (%)", "BTFP-eligible securities (Treasury, Agency debt, Agency MBS) / Total assets (×100)", "Call Report",
  "Core Capacity", "Non-Eligible Securities/Assets (%)", "Non-BTFP-eligible securities / Total assets (×100)", "Call Report",
  "Core Capacity", "MTM Loss Eligible/Assets (%)", "Mark-to-market losses on BTFP-eligible securities / Total assets (×100)", "Derived",
  "Core Capacity", "MTM Loss Non-Eligible/Assets (%)", "Mark-to-market losses on non-eligible securities / Total assets (×100)", "Derived",
  "Core Capacity", "MTM Loss/Eligible Securities (%)", "Mark-to-market losses / BTFP-eligible securities (×100)", "Derived",
  
  # Capacity Gap Measures
  "Capacity Gap", "Capacity Gap/Assets (%)", "Additional borrowing capacity at BTFP vs DW / Total assets (×100)", "Derived",
  "Capacity Gap", "Capacity Gap/Equity (%)", "Additional borrowing capacity at BTFP vs DW / Book equity (×100)", "Derived",
  "Capacity Gap", "Capacity Gap/Uninsured Deposits (%)", "Additional borrowing capacity at BTFP vs DW / Uninsured deposits (×100)", "Derived",
  "Capacity Gap", "Par Valuation Benefit (%)", "Equity 'saved' by BTFP's par valuation feature (Capacity Gap / Book equity × 100)", "Derived",
  "Capacity Gap", "Eligible Share of Total MTM Loss (%)", "MTM losses on eligible securities as % of total MTM losses", "Derived",
  
  # Solvency Context
  "Solvency", "Book Equity/Assets (%)", "Total equity / Total assets (×100)", "Call Report",
  "Solvency", "Adjusted Equity (%)", "Book equity ratio − MTM loss ratio (percentage points)", "Derived",
  "Solvency", "MTM Insolvent", "Indicator = 1 if adjusted equity < 0 (mark-to-market insolvent)", "Derived",
  "Solvency", "CET1 Post-MTM (%)", "Common Equity Tier 1 ratio after MTM recognition (CET1 − MTM loss ratio)", "Derived",
  "Solvency", "CET1 < 4.5% After MTM", "Indicator = 1 if CET1 post-MTM < 4.5% (regulatory minimum)", "Derived",
  "Solvency", "Tier1 < 4% After MTM (PCA)", "Indicator = 1 if Tier1 post-MTM < 4% (Prompt Corrective Action threshold)", "Derived",
  
  # Liquidity Context
  "Liquidity", "Uninsured Deposits/Assets (%)", "Estimated uninsured deposits / Total assets (×100)", "Call Report",
  "Liquidity", "Liquid Assets/Assets (%)", "(Cash + Reserve balances + Reverse repo + Fed funds sold) / Total assets (×100)", "Call Report",
  "Liquidity", "Liquidity Shortfall/Assets (%)", "Deposit outflow exceeding liquid assets / Total assets (×100)", "Derived",
  
  # Facility Sufficiency
  "Sufficiency", "DW Covers Shortfall", "Indicator = 1 if Discount Window capacity ≥ liquidity shortfall", "Derived",
  "Sufficiency", "BTFP Covers Shortfall", "Indicator = 1 if BTFP capacity ≥ liquidity shortfall", "Derived",
  "Sufficiency", "DW Sufficient (Solvent + Covers)", "Indicator = 1 if bank is MV solvent AND DW capacity covers shortfall", "Derived",
  "Sufficiency", "BTFP Necessary", "Indicator = 1 if DW insufficient but BTFP capacity covers shortfall", "Derived"
)

# Display variable definitions
variable_definitions %>%
  kable(caption = "Table: Variable Definitions",
        col.names = c("Category", "Variable", "Definition", "Source")) %>%
  kable_styling(bootstrap_options = c("striped", "hover"), full_width = TRUE) %>%
  collapse_rows(columns = 1, valign = "top")
Table: Variable Definitions
Category Variable Definition Source
Core Capacity BTFP-Eligible Securities/Assets (%) BTFP-eligible securities (Treasury, Agency debt, Agency MBS) / Total assets (×100) Call Report
Non-Eligible Securities/Assets (%) Non-BTFP-eligible securities / Total assets (×100) Call Report
MTM Loss Eligible/Assets (%) Mark-to-market losses on BTFP-eligible securities / Total assets (×100) Derived
MTM Loss Non-Eligible/Assets (%) Mark-to-market losses on non-eligible securities / Total assets (×100) Derived
MTM Loss/Eligible Securities (%) Mark-to-market losses / BTFP-eligible securities (×100) Derived
Capacity Gap Capacity Gap/Assets (%) Additional borrowing capacity at BTFP vs DW / Total assets (×100) Derived
Capacity Gap/Equity (%) Additional borrowing capacity at BTFP vs DW / Book equity (×100) Derived
Capacity Gap/Uninsured Deposits (%) Additional borrowing capacity at BTFP vs DW / Uninsured deposits (×100) Derived
Par Valuation Benefit (%) Equity ‘saved’ by BTFP’s par valuation feature (Capacity Gap / Book equity × 100) Derived
Eligible Share of Total MTM Loss (%) MTM losses on eligible securities as % of total MTM losses Derived
Solvency Book Equity/Assets (%) Total equity / Total assets (×100) Call Report
Adjusted Equity (%) Book equity ratio − MTM loss ratio (percentage points) Derived
MTM Insolvent Indicator = 1 if adjusted equity < 0 (mark-to-market insolvent) Derived
CET1 Post-MTM (%) Common Equity Tier 1 ratio after MTM recognition (CET1 − MTM loss ratio) Derived
CET1 < 4.5% After MTM Indicator = 1 if CET1 post-MTM < 4.5% (regulatory minimum) Derived
Tier1 < 4% After MTM (PCA) Indicator = 1 if Tier1 post-MTM < 4% (Prompt Corrective Action threshold) Derived
Liquidity Uninsured Deposits/Assets (%) Estimated uninsured deposits / Total assets (×100) Call Report
Liquid Assets/Assets (%) (Cash + Reserve balances + Reverse repo + Fed funds sold) / Total assets (×100) Call Report
Liquidity Shortfall/Assets (%) Deposit outflow exceeding liquid assets / Total assets (×100) Derived
Sufficiency DW Covers Shortfall Indicator = 1 if Discount Window capacity ≥ liquidity shortfall Derived
BTFP Covers Shortfall Indicator = 1 if BTFP capacity ≥ liquidity shortfall Derived
DW Sufficient (Solvent + Covers) Indicator = 1 if bank is MV solvent AND DW capacity covers shortfall Derived
BTFP Necessary Indicator = 1 if DW insufficient but BTFP capacity covers shortfall Derived
# Export to LaTeX
var_def_latex <- c(
  "\\begin{table}[htbp]",
  "\\centering",
  "\\caption{Variable Definitions}",
  "\\label{tab:variable_definitions}",
  "\\small",
  "\\begin{tabular}{p{2.5cm}p{5cm}p{7cm}p{1.5cm}}",
  "\\toprule",
  "Category & Variable & Definition & Source \\\\",
  "\\midrule"
)

current_category <- ""
for (i in seq_len(nrow(variable_definitions))) {
  row <- variable_definitions[i, ]
  cat_display <- if (row$Category != current_category) row$Category else ""
  current_category <- row$Category
  
  # Escape special LaTeX characters
  def_escaped <- gsub("%", "\\\\%", row$Definition)
  def_escaped <- gsub("×", "$\\\\times$", def_escaped)
  def_escaped <- gsub("−", "$-$", def_escaped)
  def_escaped <- gsub("'", "'", def_escaped)
  def_escaped <- gsub("≥", "$\\\\geq$", def_escaped)
  
  var_def_latex <- c(var_def_latex,
                     sprintf("%s & %s & %s & %s \\\\",
                             cat_display, row$Variable, def_escaped, row$Source))
  
  # Add midrule between categories
  if (i < nrow(variable_definitions) && variable_definitions$Category[i+1] != current_category) {
    var_def_latex <- c(var_def_latex, "\\midrule")
  }
}

var_def_latex <- c(var_def_latex,
                   "\\bottomrule",
                   "\\end{tabular}",
                   "\\vspace{0.3em}",
                   "\\begin{minipage}{0.95\\textwidth}",
                   "\\footnotesize",
                   "\\textit{Notes:} All variables measured at baseline (2022Q4) unless otherwise specified. MTM = Mark-to-market. BTFP = Bank Term Funding Program. DW = Discount Window. BTFP-eligible securities include U.S. Treasuries, agency debt, and agency MBS eligible as collateral for Federal Reserve open market operations. \\textbf{Capacity Gap} = BTFP capacity $-$ DW capacity = MTM losses on BTFP-eligible securities (dollars); represents the additional borrowing capacity available at BTFP (par valuation) versus DW (market valuation). \\textbf{Par Valuation Benefit} = (Capacity Gap / Book Equity) $\\times$ 100; measures equity ``saved'' by BTFP's par valuation feature. \\textbf{Liquidity Shortfall} = Total deposit outflow $-$ liquid assets, where deposit outflow is calculated from realized changes in deposits from 2022Q4 to 2023Q1. \\textbf{MV Solvent} = Adjusted equity $>$ 0 (book equity exceeds MTM losses). Uninsured deposits estimated following Jiang et al. (2023). Sample excludes failed banks (SVB, Signature, First Republic) and G-SIBs.",
                   "\\end{minipage}",
                   "\\end{table}")

writeLines(var_def_latex, file.path(TABLE_PATH, "variable_definitions.tex"))
cat("\nVariable definitions table saved to:", file.path(TABLE_PATH, "variable_definitions.tex"), "\n")
## 
## Variable definitions table saved to: C:/Users/mferdo2/OneDrive - Louisiana State University/Finance_PhD/DW_Stigma_paper/Liquidity_project_2025/03_documentation/borrowing_stat_new/tables/variable_definitions.tex
# Also save as CSV
write_csv(variable_definitions, file.path(TABLE_PATH, "variable_definitions.csv"))
cat("Variable definitions CSV saved to:", file.path(TABLE_PATH, "variable_definitions.csv"), "\n")
## Variable definitions CSV saved to: C:/Users/mferdo2/OneDrive - Louisiana State University/Finance_PhD/DW_Stigma_paper/Liquidity_project_2025/03_documentation/borrowing_stat_new/tables/variable_definitions.csv