1 Summary

This analysis examines bank borrowing choices during the 2023 banking crisis using three complementary approaches:

Model Framework:

  1. Linear Probability Model (LPM): BTFP vs DW among borrowers
  2. Logit Model: BTFP vs DW among borrowers
  3. Multinomial Logit: Choice among {No participation, BTFP only, DW only, Both BTFP+DW}
  4. Trivariate Probit: Joint modeling of BTFP, DW, and FHLB decisions with error correlations

Key Variables:

  • MTM Losses: Separated into BTFP-eligible (omo_eligible) vs. other assets
  • Uninsured Deposits: Run risk exposure
  • FHLB Borrowing: Crisis-period increases (2+ std above historical mean)
  • Run Risk Measures: Continuous and binary indicators
  • Insolvency Measures: Three alternative specifications

Sample:

  • Excludes: G-SIB banks, failed banks
  • Period: March 13 - April 30, 2023 (acute crisis phase)
  • Baseline: 2022Q4 characteristics

2 Setup and Configuration

################################################################################
# SECTION 0: SETUP AND PACKAGES
################################################################################

# Update rlang first if needed
if (packageVersion("rlang") < "1.1.4") {
  cat("Updating rlang to resolve dependencies...\n")
  install.packages("rlang", repos = "https://cloud.r-project.org")
}
#> Updating rlang to resolve dependencies...
#> 
#>   There is a binary version available but the source version is later:
#>       binary source needs_compilation
#> rlang  1.1.5  1.1.6              TRUE
# Required packages
required_packages <- c(
  # Data manipulation
  "data.table", "dplyr", "tidyr", "tibble", "lubridate", "stringr", "readr",
  
  # Modeling
  "fixest",           # Fast fixed effects
  "nnet",             # Multinomial logit
  "mlogit",           # Advanced multinomial models
  "mvtnorm",          # Multivariate normal
  "sandwich",         # Robust standard errors
  "lmtest",           # Model testing
  "broom",            # Tidy model output
  "margins",          # Marginal effects
  
  # Visualization
  "ggplot2", "ggthemes", "scales", "patchwork", "gridExtra",
  
  # Tables
  "knitr", "kableExtra", "stargazer", "modelsummary",
  
  # Statistics
  "DescTools", "moments", "psych"
)

# Install missing packages
missing_packages <- required_packages[!required_packages %in% installed.packages()[,"Package"]]
if (length(missing_packages) > 0) {
  cat("Installing:", paste(missing_packages, collapse = ", "), "\n")
  install.packages(missing_packages, repos = "https://cloud.r-project.org", 
                   dependencies = TRUE)
}

# Load packages
suppressPackageStartupMessages({
  library(data.table)
  library(dplyr)
  library(tidyr)
  library(tibble)
  library(lubridate)
  library(stringr)
  library(readr)
  library(fixest)
  library(nnet)
  library(mlogit)
  library(mvtnorm)
  library(sandwich)
  library(lmtest)
  library(broom)
  library(ggplot2)
  library(ggthemes)
  library(scales)
  library(patchwork)
  library(gridExtra)
  library(knitr)
  library(kableExtra)
  library(stargazer)
  library(modelsummary)
  library(DescTools)
  library(moments)
  library(psych)
})

options(scipen = 999)
set.seed(20230313)  # SVB failure date

cat("✓ All packages loaded successfully\n")
#> ✓ All packages loaded successfully
################################################################################
# CONFIGURE PATHS
################################################################################

BASE_PATH <- "C:/Users/mferdo2/OneDrive - Louisiana State University/Finance_PhD/DW_Stigma_paper/Liquidity_project_2025"

# Only set working directory if path exists (for portability)
if (dir.exists(BASE_PATH)) {
  setwd(BASE_PATH)
}

DATA_RAW    <- file.path(BASE_PATH, "01_data/raw")
DATA_PROC   <- file.path(BASE_PATH, "01_data/processed")
DOC_PATH    <- file.path(BASE_PATH, "03_documentation")
TABLE_PATH  <- file.path(DOC_PATH, "regression_tables/multinomial_analysis")
FIG_PATH    <- file.path(DOC_PATH, "figures/multinomial_analysis")

# Create output directories
dir.create(TABLE_PATH, recursive = TRUE, showWarnings = FALSE)
dir.create(FIG_PATH, recursive = TRUE, showWarnings = FALSE)

cat("Working directory:", getwd(), "\n")
#> Working directory: C:/Users/mferdo2/OneDrive - Louisiana State University/Finance_PhD/DW_Stigma_paper/Liquidity_project_2025
cat("Data paths configured successfully\n")
#> Data paths configured successfully
################################################################################
# CRISIS PARAMETERS
################################################################################

CRISIS_START      <- as.Date("2023-03-13")  # Monday after SVB weekend
CRISIS_END_ACUTE  <- as.Date("2023-04-30")  # End of acute phase
CRISIS_END_BTFP   <- as.Date("2024-03-11")  # BTFP program closure
MTM_START         <- as.Date("2022-03-16")  # First FFR hike
MTM_END           <- as.Date("2023-03-10")  # SVB failure
BASELINE_DATE     <- "2022Q4"               # 2022Q4

cat("\n")
cat("================================================================\n")
#> ================================================================
cat("MULTINOMIAL CHOICE ANALYSIS - 2023 BANKING CRISIS\n")
#> MULTINOMIAL CHOICE ANALYSIS - 2023 BANKING CRISIS
cat("================================================================\n")
#> ================================================================
cat("Crisis Window:     ", as.character(CRISIS_START), " to ", as.character(CRISIS_END_ACUTE), "\n")
#> Crisis Window:      2023-03-13  to  2023-04-30
cat("Baseline Date:     ", BASELINE_DATE, "\n")
#> Baseline Date:      2022Q4
cat("================================================================\n\n")
#> ================================================================
################################################################################
# HELPER FUNCTIONS
################################################################################

#' Winsorize at specified quantiles
winsorize <- function(x, probs = c(0.01, 0.99)) {
  if (all(is.na(x))) return(x)
  q <- quantile(x, probs = probs, na.rm = TRUE, names = FALSE)
  pmax(pmin(x, q[2]), q[1])
}

#' Winsorize at 95th percentile
winsorize_95 <- function(x) {
  winsorize(x, probs = c(0.025, 0.975))
}

#' Standardize (z-score transformation)
standardize <- function(x) {
  (x - mean(x, na.rm = TRUE)) / sd(x, na.rm = TRUE)
}

#' Safe division
safe_div <- function(num, denom) {
  ifelse(is.na(denom) | denom == 0, NA_real_, num / denom)
}

#' Parse dates flexibly
parse_date_safe <- function(x) {
  if (inherits(x, "Date")) return(x)
  x_char <- as.character(x)
  result <- suppressWarnings(mdy(x_char))
  if (all(is.na(result))) result <- suppressWarnings(ymd(x_char))
  if (all(is.na(result))) result <- suppressWarnings(dmy(x_char))
  return(result)
}

#' Create summary statistics table
create_summary_table <- function(df, vars, digits = 3) {
  df %>%
    select(all_of(vars)) %>%
    pivot_longer(everything(), names_to = "Variable", values_to = "Value") %>%
    group_by(Variable) %>%
    summarise(
      N = sum(!is.na(Value)),
      Mean = round(mean(Value, na.rm = TRUE), digits),
      SD = round(sd(Value, na.rm = TRUE), digits),
      Min = round(min(Value, na.rm = TRUE), digits),
      P25 = round(quantile(Value, 0.25, na.rm = TRUE), digits),
      Median = round(quantile(Value, 0.50, na.rm = TRUE), digits),
      P75 = round(quantile(Value, 0.75, na.rm = TRUE), digits),
      Max = round(max(Value, na.rm = TRUE), digits),
      .groups = "drop"
    )
}

cat("✓ Helper functions loaded\n")
#> ✓ Helper functions loaded

3 Data Loading

################################################################################
# SECTION 1: LOAD DATA
################################################################################

cat("\n")
cat(strrep("=", 80), "\n", sep = "")
#> ================================================================================
cat("LOADING DATA\n")
#> LOADING DATA
cat(strrep("=", 80), "\n", sep = "")
#> ================================================================================
# 1.1 Load Call Report Data
call_q <- read_csv(
  file.path(DATA_PROC, "final_call_gsib.csv"), 
  show_col_types = FALSE
) %>%
  mutate(idrssd = as.character(idrssd))

cat("✓ Call reports loaded:", nrow(call_q), "obs,", n_distinct(call_q$idrssd), "banks\n")
#> ✓ Call reports loaded: 61002 obs, 4926 banks
# 1.2 Load BTFP Loan Data
btfp_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 = parse_date_safe(btfp_loan_date)
  )

cat("✓ BTFP loans loaded:", nrow(btfp_raw), "obs\n")
#> ✓ BTFP loans loaded: 6734 obs
cat("  Date range:", as.character(min(btfp_raw$btfp_loan_date, na.rm = TRUE)), 
    "to", as.character(max(btfp_raw$btfp_loan_date, na.rm = TRUE)), "\n")
#>   Date range: 2023-03-13 to 2024-03-11
# 1.3 Load DW Loan Data
dw_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 = parse_date_safe(dw_loan_date)
  )

cat("✓ DW loans loaded:", nrow(dw_raw), "obs\n")
#> ✓ DW loans loaded: 7724 obs
cat("  Date range:", as.character(min(dw_raw$dw_loan_date, na.rm = TRUE)), 
    "to", as.character(max(dw_raw$dw_loan_date, na.rm = TRUE)), "\n")
#>   Date range: 2023-01-03 to 2023-09-29
# 1.4 Load Public Bank Data (CRSP)
file_public_bank <- file.path(DATA_PROC, "df_public_bank.csv")
if (file.exists(file_public_bank)) {
  df_public <- read_csv(file_public_bank, show_col_types = FALSE) %>%
    mutate(
      rssd_bank = as.character(rssd_bank),
      DlyCalDt = as.Date(DlyCalDt)
    )
  cat("✓ Public bank data loaded:", nrow(df_public), "observations\n")
} else {
  cat("  WARNING: Public bank file not found\n")
  df_public <- NULL
}
#> ✓ Public bank data loaded: 135943 observations
cat("\n✓ All data loaded successfully\n")
#> 
#> ✓ All data loaded successfully

4 Baseline Sample Creation

################################################################################
# SECTION 2: AGGREGATE FACILITY USAGE
################################################################################

cat("\n")
cat(strrep("=", 80), "\n", sep = "")
#> ================================================================================
cat("AGGREGATING FACILITY USAGE\n")
#> AGGREGATING FACILITY USAGE
cat(strrep("=", 80), "\n", sep = "")
#> ================================================================================
# 2.1 BTFP usage during acute crisis
btfp_crisis <- btfp_raw %>%
  filter(btfp_loan_date >= CRISIS_START, btfp_loan_date <= CRISIS_END_ACUTE) %>%
  group_by(rssd_id) %>%
  summarise(
    btfp_user = 1L,
    btfp_total_amt = sum(btfp_loan_amount, na.rm = TRUE),
    btfp_n_loans = n(),
    btfp_first_date = min(btfp_loan_date),
    .groups = "drop"
  ) %>%
  rename(idrssd = rssd_id)

cat("✓ BTFP users (acute crisis):", nrow(btfp_crisis), "\n")
#> ✓ BTFP users (acute crisis): 481
# 2.2 DW usage during acute crisis
dw_crisis <- dw_raw %>%
  filter(dw_loan_date >= CRISIS_START, dw_loan_date <= CRISIS_END_ACUTE) %>%
  group_by(rssd_id) %>%
  summarise(
    dw_user = 1L,
    dw_total_amt = sum(dw_loan_amount, na.rm = TRUE),
    dw_n_loans = n(),
    dw_first_date = min(dw_loan_date),
    .groups = "drop"
  ) %>%
  rename(idrssd = rssd_id)

cat("✓ DW users (acute crisis):", nrow(dw_crisis), "\n")
#> ✓ DW users (acute crisis): 415
# 2.3 Extended BTFP usage (full program)
btfp_full <- btfp_raw %>%
  filter(btfp_loan_date >= CRISIS_START, btfp_loan_date <= CRISIS_END_BTFP) %>%
  group_by(rssd_id) %>%
  summarise(
    btfp_user_full = 1L,
    btfp_total_amt_full = sum(btfp_loan_amount, na.rm = TRUE),
    .groups = "drop"
  ) %>%
  rename(idrssd = rssd_id)

cat("✓ BTFP users (full program):", nrow(btfp_full), "\n")
#> ✓ BTFP users (full program): 1327
cat("\n✓ Facility usage aggregated\n")
#> 
#> ✓ Facility usage aggregated
################################################################################
# SECTION 3: CREATE 2022Q4 BASELINE WITH KEY VARIABLES
################################################################################

cat("\n")
cat(strrep("=", 80), "\n", sep = "")
#> ================================================================================
cat("CREATING 2022Q4 BASELINE\n")
#> CREATING 2022Q4 BASELINE
cat(strrep("=", 80), "\n", sep = "")
#> ================================================================================
# Check available columns
has_failed_bank <- "failed_bank" %in% names(call_q)
has_gsib <- "gsib" %in% names(call_q)
has_size_bin <- "size_bin" %in% names(call_q)
has_mv_asset <- "mm_asset" %in% names(call_q)

cat("Data availability checks:\n")
#> Data availability checks:
cat("  - failed_bank column:", ifelse(has_failed_bank, "YES", "NO"), "\n")
#>   - failed_bank column: YES
cat("  - gsib column:", ifelse(has_gsib, "YES", "NO"), "\n")
#>   - gsib column: YES
cat("  - size_bin column:", ifelse(has_size_bin, "YES", "NO"), "\n")
#>   - size_bin column: YES
cat("  - mv_asset column:", ifelse(has_mv_asset, "YES", "NO"), "\n\n")
#>   - mv_asset column: YES
# Create baseline dataset from 2022Q4 (preserving all Python-created variables)
baseline <- call_q %>%
  filter(quarter == BASELINE_DATE) %>%
  transmute(
    idrssd = as.character(idrssd),
    
    # Bank identifiers and flags
    failed_bank = if (has_failed_bank) failed_bank else 0L,
    gsib = if (has_gsib) gsib else 0L,
    
    # Balance sheet fundamentals
    size_bin = if (has_size_bin) size_bin else NA_character_,
    total_asset,
    total_liability,
    total_equity,
    total_deposit,
    insured_deposit = pmax(insured_deposit, 1),
    uninsured_deposit = pmax(uninsured_deposit, 0),
    security_to_total_asset,
    loan_to_deposit,
    roa,
    
    # Cash and liquid assets
    cash,
    fed_fund_sold,
    rerepo,
    
    # Securities (from Python cleaning)
    security,           # total_sec in some versions
    omo_eligible,       # Treasury + Agency debt + Agency MBS (BTFP-eligible)
    non_omo_securities, # Other securities
    
    # Loans
    total_loan,
    
    # Size measures
    log_assets = log(pmax(total_asset, 1)),
    
    # MTM variables (from Python MTM calculation)
    mm_asset = if (has_mv_asset) mm_asset else total_asset,
    mtm_total_loss,
    mtm_loss_to_total_asset,
    equity_after_mtm,
    
    # MTM losses: OMO-eligible vs Other
    mtm_loss_omo_eligible,
    mtm_loss_omo_eligible_to_omo_eligible = safe_div(mtm_loss_omo_eligible, omo_eligible),
    mtm_loss_omo_eligible_to_total_asset,
    omo_eligible_to_total_asset,
    
    # Calculate MTM loss on OTHER assets (non-OMO-eligible)
    
    mtm_loss_other = mtm_loss_non_omo_eligible,
    mtm_loss_other_to_total_asset = mtm_loss_non_omo_eligible_to_total_asset,
    
    # Wholesale funding & FHLB
    repo,
    fed_fund_purchase,
    other_borr,
    other_borrowed_less_than_1yr,
    fhlb_adv,
    fhlb_less_than_1yr,
    fhlb_to_total_asset,
    
    # Control variables
    cash_to_total_asset,
    book_equity_to_total_asset,
    
    # Additional controls
    net_income_q,
    avg_assets
  )

cat("✓ Initial baseline:", nrow(baseline), "banks\n")
#> ✓ Initial baseline: 4737 banks
# Apply sample filters
baseline <- baseline %>%
  filter(
    # Exclude G-SIBs
    gsib == 0 | is.na(gsib),
    # Exclude failed banks
    failed_bank == 0 | is.na(failed_bank),
    # Keep only banks with OMO-eligible assets (BTFP collateral)
    !is.na(omo_eligible) & omo_eligible > 0
  )

cat("✓ After filters:", nrow(baseline), "banks\n")
#> ✓ After filters: 4292 banks
cat("  - Excluded G-SIBs\n")
#>   - Excluded G-SIBs
cat("  - Excluded failed banks\n")
#>   - Excluded failed banks
cat("  - Kept only banks with BTFP-eligible assets (omo_eligible > 0)\n")
#>   - Kept only banks with BTFP-eligible assets (omo_eligible > 0)
cat("\n✓ Baseline sample created\n")
#> 
#> ✓ Baseline sample created
################################################################################
# SECTION 4: CONSTRUCT KEY RISK VARIABLES
################################################################################

cat("\n")
cat(strrep("=", 80), "\n", sep = "")
#> ================================================================================
cat("CONSTRUCTING KEY RISK VARIABLES\n")
#> CONSTRUCTING KEY RISK VARIABLES
cat(strrep("=", 80), "\n", sep = "")
#> ================================================================================
baseline <- baseline %>%
  mutate(
    # =========================================================================
    # VARIABLE CREATION AS SPECIFIED
    # =========================================================================
   
    # Borrowing subsidy (%) - valuation benefit from par pricing
    borrowing_subsidy = mtm_loss_omo_eligible_to_omo_eligible,
    
    # % MTM Loss on BTFP-eligible securities (omo_eligible)
    mtm_btfp_pct = mtm_loss_omo_eligible_to_total_asset,
    
    # % MTM Loss on Other (non-eligible) securities
    mtm_other_pct = mtm_loss_other_to_total_asset,
    
    # % Uninsured deposits
    pct_uninsured = safe_div(uninsured_deposit, total_deposit) * 100,
    
    # Uninsured deposit leverage (% of assets)
    uninsured_lev = safe_div(uninsured_deposit, total_asset) * 100,
    
    # % Wholesale Liability
    pct_wholesale_liability = safe_div(fed_fund_purchase + repo + other_borrowed_less_than_1yr, total_liability) * 100,
    
    # % Run-able Liability
    pct_runable_liability = safe_div(uninsured_deposit + fed_fund_purchase + repo + other_borrowed_less_than_1yr, total_liability) * 100,
    
    # % Liquidity Available
    pct_liquidity_available = safe_div(cash + rerepo + fed_fund_sold, total_asset) * 100,
    
    # % MTM Loss (total)
    pct_mtm_loss = mtm_loss_to_total_asset,
    
    # Cash to asset ratio (%)
    cash_to_asset = cash_to_total_asset,
    
    # FHLB to asset ratio (%)
    fhlb_to_asset = fhlb_to_total_asset,
    
    # Book equity to asset ratio (%)
    book_equity_to_asset = book_equity_to_total_asset,
    
    # Securities ratio
    securities_ratio = security_to_total_asset,
    
    # Loan to deposit
    loan_to_deposit = loan_to_deposit,
    
    # ROA (annualized)
    roa = roa,
    
    # =========================================================================
    # RUN RISK MEASURES
    # =========================================================================
    # Run-risk 1: % Uninsured × % MTM loss
    run_risk_1 = pct_uninsured * pct_mtm_loss,
    
    # Run-risk 2: % Run-able Liability × % MTM loss
    run_risk_2 = pct_runable_liability * pct_mtm_loss,
    
    # Calculate medians for run risk dummies
    median_pct_uninsured = median(pct_uninsured, na.rm = TRUE),
    median_pct_mtm_loss = median(pct_mtm_loss, na.rm = TRUE),
    median_pct_runable = median(pct_runable_liability, na.rm = TRUE),
    
    # Run Risk 1 DUMMY: = 1 if BOTH %Uninsured > median AND %MTM loss > median
    run_risk_1_dummy = as.integer(
      pct_uninsured > median_pct_uninsured & pct_mtm_loss > median_pct_mtm_loss
    ),
    
    # Run Risk 2 DUMMY: = 1 if BOTH %Runable > median AND %MTM loss > median
    run_risk_2_dummy = as.integer(
      pct_runable_liability > median_pct_runable & 
      pct_mtm_loss > median_pct_mtm_loss
    ),

    # =========================================================================
    # INSOLVENCY MEASURES
    # =========================================================================
    
    # Market value of assets
    mv_asset = mm_asset,
    mv_adjustment = if_else(mv_asset == 0, NA_real_, (total_asset / mv_asset) - 1), # Formula: (total_asset / mv_asset - 1)
    
    # Insolvency: Insolvent Banks under Different Uninsured Deposits Runs Cases (Insured Deposit Coverage Ratio)
    
    # Insured Deposit Coverage Ratio (s = 0.5)
    idcr_1 = safe_div(
      mv_asset - 0.5 * uninsured_deposit - insured_deposit,
      insured_deposit
    ),
    
    # Insured Deposit Coverage Ratio (s = 1.0)
    idcr_2 = safe_div(
      mv_asset - 1.0 * uninsured_deposit - insured_deposit,
      insured_deposit
    ),
    
    # Insolvency: Insolvent Banks under Different Uninsured Deposits Runs Cases (Capital Ratio Metric)
    
    
    insolvency_1 = safe_div(
      total_asset-total_liability - 0.5 *uninsured_deposit * mv_adjustment,
      total_asset
    ),
    
    insolvency_2 = safe_div(
      total_asset-total_liability - 1.0 *uninsured_deposit * mv_adjustment,
      total_asset
    )
  )

cat("✓ Risk variables constructed:\n")
#> ✓ Risk variables constructed:
cat("  - Borrowing subsidy\n")
#>   - Borrowing subsidy
cat("  - MTM losses (BTFP-eligible vs Other)\n")
#>   - MTM losses (BTFP-eligible vs Other)
cat("  - Uninsured deposit measures\n")
#>   - Uninsured deposit measures
cat("  - Run risk measures (continuous + dummies)\n")
#>   - Run risk measures (continuous + dummies)
cat("  - Insolvency measures (3 specifications)\n")
#>   - Insolvency measures (3 specifications)
cat("\nKey statistics:\n")
#> 
#> Key statistics:
cat("  Mean MTM BTFP-eligible (%):", sprintf("%.2f", mean(baseline$mtm_btfp_pct, na.rm = TRUE)), "\n")
#>   Mean MTM BTFP-eligible (%): 0.68
cat("  Mean MTM other (%):", sprintf("%.2f", mean(baseline$mtm_other_pct, na.rm = TRUE)), "\n")
#>   Mean MTM other (%): 4.60
cat("  Mean uninsured leverage (%):", sprintf("%.2f", mean(baseline$uninsured_lev, na.rm = TRUE)), "\n")
#>   Mean uninsured leverage (%): 23.61
cat("  % with high run risk 1:", sprintf("%.1f%%", 100 * mean(baseline$run_risk_1_dummy, na.rm = TRUE)), "\n")
#>   % with high run risk 1: 23.0%
cat("\n✓ Risk variables created\n")
#> 
#> ✓ Risk variables created
################################################################################
# SECTION 5: CREATE FHLB CRISIS BORROWING INDICATOR
################################################################################

cat("\n")
cat(strrep("=", 80), "\n", sep = "")
#> ================================================================================
cat("CREATING FHLB CRISIS BORROWING INDICATOR\n")
#> CREATING FHLB CRISIS BORROWING INDICATOR
cat(strrep("=", 80), "\n", sep = "")
#> ================================================================================
# Need historical FHLB borrowing (past 4 quarters before 2022Q4)
historical_quarters <- c("2021Q4", "2022Q1", "2022Q2", "2022Q3")

# Calculate FHLB statistics for each bank
df_fhlb_history <- call_q %>%
  filter(quarter %in% historical_quarters) %>%
  group_by(idrssd) %>%
  summarise(
    fhlb_mean_hist = mean(fhlb_to_total_asset, na.rm = TRUE),
    fhlb_sd_hist = sd(fhlb_to_total_asset, na.rm = TRUE),
    .groups = "drop"
  )

# Get crisis period FHLB borrowing (2023Q1)
df_fhlb_crisis <- call_q %>%
  filter(quarter == "2023Q1") %>%
  select(idrssd, fhlb_to_asset_crisis = fhlb_to_total_asset)

# Merge and create indicator
baseline <- baseline %>%
  left_join(df_fhlb_history, by = "idrssd") %>%
  left_join(df_fhlb_crisis, by = "idrssd") %>%
  mutate(
    # FHLB crisis indicator: 2+ std above historical mean
    fhlb_crisis = ifelse(
      !is.na(fhlb_to_asset_crisis) & !is.na(fhlb_mean_hist) & !is.na(fhlb_sd_hist),
      as.numeric(fhlb_to_asset_crisis > (fhlb_mean_hist + 2 * fhlb_sd_hist)),
      0
    ),
    
    # Alternative: change in FHLB (for continuous measure)
    delta_fhlb = ifelse(
      !is.na(fhlb_to_asset_crisis) & !is.na(fhlb_mean_hist),
      pmax(0, fhlb_to_asset_crisis - fhlb_mean_hist),
      0
    )
  )

cat("FHLB crisis borrowing:\n")
#> FHLB crisis borrowing:
cat("  Banks with crisis FHLB increase:", 
    sum(baseline$fhlb_crisis == 1, na.rm = TRUE),
    sprintf("(%.1f%%)", 100 * mean(baseline$fhlb_crisis == 1, na.rm = TRUE)), "\n")
#>   Banks with crisis FHLB increase: 1125 (26.2%)
cat("  Mean FHLB ratio (2022Q4 baseline):", 
    sprintf("%.2f%%", mean(baseline$fhlb_to_asset, na.rm = TRUE)), "\n")
#>   Mean FHLB ratio (2022Q4 baseline): 2.65%
cat("  Mean FHLB ratio (2023Q1 crisis):", 
    sprintf("%.2f%%", mean(baseline$fhlb_to_asset_crisis, na.rm = TRUE)), "\n")
#>   Mean FHLB ratio (2023Q1 crisis): 2.79%
cat("\n✓ FHLB crisis indicator created\n")
#> 
#> ✓ FHLB crisis indicator created
################################################################################
# SECTION 6: MERGE BORROWING DATA AND CREATE OUTCOMES
################################################################################

cat("\n")
cat(strrep("=", 80), "\n", sep = "")
#> ================================================================================
cat("MERGING BORROWING DATA\n")
#> MERGING BORROWING DATA
cat(strrep("=", 80), "\n", sep = "")
#> ================================================================================
# Merge BTFP and DW usage
baseline <- baseline %>%
  left_join(btfp_crisis, by = "idrssd") %>%
  left_join(dw_crisis, by = "idrssd") %>%
  left_join(btfp_full, by = "idrssd") %>%
  mutate(
    # Fill missing with 0
    btfp_user = replace_na(btfp_user, 0),
    dw_user = replace_na(dw_user, 0),
    btfp_total_amt = replace_na(btfp_total_amt, 0),
    dw_total_amt = replace_na(dw_total_amt, 0),
    
    # Create multinomial outcome
    # Y = 0: No participation
    # Y = 1: BTFP only
    # Y = 2: DW only  
    # Y = 3: Both BTFP and DW
    Y = case_when(
      btfp_user == 0 & dw_user == 0 ~ 0,
      btfp_user == 1 & dw_user == 0 ~ 1,
      btfp_user == 0 & dw_user == 1 ~ 2,
      btfp_user == 1 & dw_user == 1 ~ 3,
      TRUE ~ 0
    ),
    
    # Factor version for modeling
    Y_factor = factor(Y, 
                      levels = 0:3,
                      labels = c("No_Participation", "BTFP_Only", "DW_Only", "Both")),
    
    # Borrower indicator (used any Fed facility)
    any_borrower = as.integer(btfp_user == 1 | dw_user == 1),
    
    # BTFP vs DW choice (among borrowers only)
    # 1 = BTFP (includes "Both"), 0 = DW only
    btfp_vs_dw = ifelse(any_borrower == 1, 
                        as.integer(btfp_user == 1),
                        NA_integer_),
    
    # Borrowing amounts as % of assets
    btfp_amt_pct = safe_div(btfp_total_amt, total_asset) * 100,
    dw_amt_pct = safe_div(dw_total_amt, total_asset) * 100
  )

# Summary of outcomes
cat("\nBorrowing patterns (acute crisis):\n")
#> 
#> Borrowing patterns (acute crisis):
cat("  No participation:     ", sum(baseline$Y == 0), 
    sprintf("(%.1f%%)", 100 * mean(baseline$Y == 0)), "\n")
#>   No participation:      3544 (82.6%)
cat("  BTFP only:           ", sum(baseline$Y == 1), 
    sprintf("(%.1f%%)", 100 * mean(baseline$Y == 1)), "\n")
#>   BTFP only:            363 (8.5%)
cat("  DW only:             ", sum(baseline$Y == 2), 
    sprintf("(%.1f%%)", 100 * mean(baseline$Y == 2)), "\n")
#>   DW only:              295 (6.9%)
cat("  Both BTFP and DW:    ", sum(baseline$Y == 3), 
    sprintf("(%.1f%%)", 100 * mean(baseline$Y == 3)), "\n")
#>   Both BTFP and DW:     90 (2.1%)
cat("\nBorrower subsample:\n")
#> 
#> Borrower subsample:
cat("  Total borrowers:", sum(baseline$any_borrower == 1), "\n")
#>   Total borrowers: 748
cat("  Chose BTFP:", sum(baseline$btfp_vs_dw == 1, na.rm = TRUE), 
    sprintf("(%.1f%%)", 100 * mean(baseline$btfp_vs_dw == 1, na.rm = TRUE)), "\n")
#>   Chose BTFP: 453 (60.6%)
cat("  Chose DW only:", sum(baseline$btfp_vs_dw == 0, na.rm = TRUE), 
    sprintf("(%.1f%%)", 100 * mean(baseline$btfp_vs_dw == 0, na.rm = TRUE)), "\n")
#>   Chose DW only: 295 (39.4%)
cat("\n✓ Borrowing outcomes created\n")
#> 
#> ✓ Borrowing outcomes created
################################################################################
# SECTION 7: MERGE PUBLIC BANK DATA
################################################################################

cat("\n")
cat(strrep("=", 80), "\n", sep = "")
#> ================================================================================
cat("MERGING PUBLIC BANK DATA\n")
#> MERGING PUBLIC BANK DATA
cat(strrep("=", 80), "\n", sep = "")
#> ================================================================================
if (!is.null(df_public)) {
  # Aggregate public bank returns during crisis
  df_public_crisis <- df_public %>%
    filter(DlyCalDt >= CRISIS_START & DlyCalDt <= CRISIS_END_ACUTE) %>%
    group_by(rssd_bank) %>%
    summarise(
      n_days = n(),
      mean_ret = mean(ret, na.rm = TRUE),
      cum_ret = sum(ret, na.rm = TRUE),
      sd_ret = sd(ret, na.rm = TRUE),
      min_ret = min(ret, na.rm = TRUE),
      max_ret = max(ret, na.rm = TRUE),
      is_public = 1,
      .groups = "drop"
    ) %>%
    rename(idrssd = rssd_bank)
  
  # Merge with baseline
  baseline <- baseline %>%
    left_join(df_public_crisis, by = "idrssd") %>%
    mutate(
      is_public = replace_na(is_public, 0)
    )
  
  cat("Public bank data merged:\n")
  cat("  Public banks:", sum(baseline$is_public == 1, na.rm = TRUE), 
      sprintf("(%.1f%%)", 100 * mean(baseline$is_public == 1, na.rm = TRUE)), "\n")
  cat("  Mean cumulative return:", 
      sprintf("%.2f%%", 100 * mean(baseline$cum_ret, na.rm = TRUE)), "\n")
} else {
  baseline$is_public <- 0
  cat("  No public bank data available\n")
}
#> Public bank data merged:
#>   Public banks: 270 (6.3%) 
#>   Mean cumulative return: -13.77%
cat("\n✓ Public bank data merged\n")
#> 
#> ✓ Public bank data merged
################################################################################
# SECTION 8: WINSORIZE AND STANDARDIZE
################################################################################

cat("\n")
cat(strrep("=", 80), "\n", sep = "")
#> ================================================================================
cat("WINSORIZING AND STANDARDIZING VARIABLES\n")
#> WINSORIZING AND STANDARDIZING VARIABLES
cat(strrep("=", 80), "\n", sep = "")
#> ================================================================================
# Variables to winsorize and standardize
vars_to_process <- c(
  # MTM variables
  "mtm_btfp_pct", "mtm_other_pct", "borrowing_subsidy",
  
  # Risk variables
  "pct_uninsured", "uninsured_lev", "pct_wholesale_liability",
  "pct_runable_liability", "pct_liquidity_available", "pct_mtm_loss",
  "run_risk_1", "run_risk_2", "run_risk_1_dummy", "run_risk_2_dummy",
  
  # Insolvency
  "idcr_1", "idcr_2", "insolvency_1", "insolvency_2",
  
  # Controls
  "log_assets", "cash_to_asset", "fhlb_to_asset", "book_equity_to_asset",
  "securities_ratio", "loan_to_deposit", "roa", "delta_fhlb",
  
  # Borrowing amounts
  "btfp_amt_pct", "dw_amt_pct"
)

# Winsorize at 1st and 99th percentiles
baseline <- baseline %>%
  mutate(across(
    all_of(vars_to_process),
    ~winsorize(., probs = c(0.01, 0.99)),
    .names = "{.col}_w"
  ))

# Standardize (z-scores)
baseline <- baseline %>%
  mutate(across(
    ends_with("_w"),
    ~standardize(.),
    .names = "{.col}_z"
  ))

# Create interaction terms
baseline <- baseline %>%
  mutate(
    # MTM BTFP × Uninsured
    mtm_btfp_x_unins_w = mtm_btfp_pct_w * uninsured_lev_w,
    mtm_btfp_x_unins_w_z = standardize(mtm_btfp_x_unins_w)
  )

cat("Winsorization and standardization complete:\n")
#> Winsorization and standardization complete:
cat("  Variables processed:", length(vars_to_process), "\n")
#>   Variables processed: 27
cat("  Final sample size:", nrow(baseline), "\n")
#>   Final sample size: 4292
cat("\n✓ Variables processed\n")
#> 
#> ✓ Variables processed

5 Descriptive Statistics

################################################################################
# SECTION 9: SUMMARY STATISTICS - OVERALL
################################################################################

cat("\n")
cat(strrep("=", 80), "\n", sep = "")
#> ================================================================================
cat("SUMMARY STATISTICS\n")
#> SUMMARY STATISTICS
cat(strrep("=", 80), "\n", sep = "")
#> ================================================================================
# Variables for summary table
summ_vars <- c(
  "mtm_btfp_pct", "mtm_other_pct", "borrowing_subsidy",
  "pct_uninsured", "uninsured_lev", "pct_wholesale_liability",
  "pct_liquidity_available", "pct_mtm_loss",
  "run_risk_1", "run_risk_2",
  "idcr_1", "idcr_2", "insolvency_1", "insolvency_2",
  "log_assets", "cash_to_asset", "fhlb_to_asset", 
  "book_equity_to_asset", "securities_ratio", "loan_to_deposit", "roa"
)

# Overall summary
summ_overall <- create_summary_table(baseline, summ_vars, digits = 3)

# Print table
summ_overall %>%
  kbl(caption = "Table 1: Summary Statistics - Full Sample",
      booktabs = TRUE,
      align = c("l", rep("r", 8))) %>%
  kable_styling(bootstrap_options = c("striped", "hover", "condensed"),
                full_width = FALSE,
                font_size = 11) %>%
  row_spec(0, bold = TRUE, background = "#F0F0F0") %>%
  pack_rows("MTM Losses", 1, 3) %>%
  pack_rows("Risk Measures", 4, 10) %>%
  pack_rows("Insolvency Measures", 11, 12) %>%
  pack_rows("Control Variables", 13, 19)
Table 1: Summary Statistics - Full Sample
Variable N Mean SD Min P25 Median P75 Max
MTM Losses
book_equity_to_asset 4292 10.220 8.817 0.110 7.143 8.842 10.888 99.966
borrowing_subsidy 4282 0.103 1.909 -0.034 0.032 0.065 0.098 124.830
cash_to_asset 4292 8.148 9.191 0.000 2.667 5.030 10.051 96.724
Risk Measures
fhlb_to_asset 4292 2.647 4.215 0.000 0.000 0.346 4.073 48.713
idcr_1 4282 1291.921 69365.863 -1.018 0.149 0.248 0.392 4531503.818
idcr_2 4282 1291.537 69365.870 -1.825 -0.012 0.069 0.162 4531503.818
insolvency_1 4282 0.087 0.095 -1.583 0.055 0.076 0.099 1.000
insolvency_2 4282 0.072 0.116 -3.296 0.039 0.065 0.094 1.000
loan_to_deposit 4292 70.866 27.432 0.000 56.561 71.818 86.500 890.476
log_assets 4292 12.882 1.483 8.222 11.903 12.721 13.650 20.187
Insolvency Measures
mtm_btfp_pct 4282 0.681 0.848 -0.141 0.136 0.405 0.932 16.393
mtm_other_pct 4282 4.599 2.062 -0.097 3.110 4.395 5.972 13.350
Control Variables
pct_liquidity_available 4292 9.297 9.941 0.000 3.045 5.870 11.555 98.879
pct_mtm_loss 4282 5.467 2.223 -0.141 3.863 5.320 6.975 27.631
pct_uninsured 4261 27.796 14.113 0.000 18.109 25.957 35.165 99.876
pct_wholesale_liability 4292 1.000 3.166 0.000 0.000 0.000 0.533 85.016
roa 4290 1.187 2.592 -62.459 0.702 1.101 1.498 53.461
run_risk_1 4251 147.195 89.294 -2.932 83.550 133.157 194.236 1295.061
run_risk_2 4282 143.513 86.366 -2.490 81.210 130.370 190.665 1189.577
securities_ratio 4292 25.681 15.784 0.004 13.704 23.323 35.090 97.611
uninsured_lev 4292 23.611 12.158 0.000 15.285 22.247 30.353 94.597
cat("\n✓ Overall summary statistics created\n")
#> 
#> ✓ Overall summary statistics created
################################################################################
# SUMMARY STATISTICS BY OUTCOME
################################################################################

cat("\n")
cat(strrep("=", 80), "\n", sep = "")
#> ================================================================================
cat("SUMMARY STATISTICS BY BORROWING CHOICE\n")
#> SUMMARY STATISTICS BY BORROWING CHOICE
cat(strrep("=", 80), "\n", sep = "")
#> ================================================================================
# By borrowing status
summ_by_outcome <- baseline %>%
  select(Y_factor, all_of(summ_vars)) %>%
  pivot_longer(-Y_factor, names_to = "Variable", values_to = "Value") %>%
  group_by(Y_factor, Variable) %>%
  summarise(
    N = sum(!is.na(Value)),
    Mean = mean(Value, na.rm = TRUE),
    SD = sd(Value, na.rm = TRUE),
    .groups = "drop"
  ) %>%
  pivot_wider(
    names_from = Y_factor,
    values_from = c(N, Mean, SD),
    names_glue = "{Y_factor}_{.value}"
  ) %>%
  select(Variable, ends_with("_N"), ends_with("_Mean"), ends_with("_SD")) %>%
  mutate(across(where(is.numeric), ~round(., 3)))

# Print table (showing means only for readability)
summ_by_outcome %>%
  select(Variable, ends_with("_Mean")) %>%
  rename_with(~gsub("_Mean", "", .), ends_with("_Mean")) %>%
  kbl(caption = "Table 2: Summary Statistics by Borrowing Choice (Means)",
      booktabs = TRUE) %>%
  kable_styling(bootstrap_options = c("striped", "hover"),
                full_width = FALSE,
                font_size = 10) %>%
  row_spec(0, bold = TRUE, background = "#F0F0F0")
Table 2: Summary Statistics by Borrowing Choice (Means)
Variable No_Participation BTFP_Only DW_Only Both
book_equity_to_asset 10.582 8.166 9.017 8.227
borrowing_subsidy 0.106 0.091 0.087 0.084
cash_to_asset 8.755 4.666 6.173 4.736
fhlb_to_asset 2.420 3.959 3.270 4.255
idcr_1 1565.290 0.327 0.334 0.604
idcr_2 1564.883 0.073 0.066 0.183
insolvency_1 0.091 0.065 0.069 0.063
insolvency_2 0.077 0.049 0.048 0.044
loan_to_deposit 70.193 72.613 75.846 73.977
log_assets 12.690 13.545 13.850 14.591
mtm_btfp_pct 0.650 0.883 0.747 0.865
mtm_other_pct 4.517 5.033 4.951 4.922
pct_liquidity_available 10.030 5.118 6.953 4.987
pct_mtm_loss 5.361 6.179 5.754 5.839
pct_uninsured 26.888 30.623 31.903 38.361
pct_wholesale_liability 0.883 1.517 1.593 1.600
roa 1.196 1.083 1.212 1.182
run_risk_1 139.061 183.144 177.376 219.887
run_risk_2 135.371 179.826 175.030 213.425
securities_ratio 25.515 28.165 23.999 27.706
uninsured_lev 22.825 26.202 27.126 32.597
cat("\n✓ Summary by outcome created\n")
#> 
#> ✓ Summary by outcome created
################################################################################
# CORRELATION MATRIX
################################################################################

cat("\n")
cat(strrep("=", 80), "\n", sep = "")
#> ================================================================================
cat("CORRELATION MATRIX\n")
#> CORRELATION MATRIX
cat(strrep("=", 80), "\n", sep = "")
#> ================================================================================
# Calculate correlations for key standardized variables
cor_vars <- c(
  "mtm_btfp_pct_w_z", "mtm_other_pct_w_z", "uninsured_lev_w_z",
  "pct_wholesale_liability_w_z", "pct_liquidity_available_w_z",
  "run_risk_1_w_z", "idcr_2_w_z", "insolvency_2_w_z",
  "log_assets_w_z", "book_equity_to_asset_w_z", "fhlb_to_asset_w_z"
)

cor_matrix <- baseline %>%
  select(all_of(cor_vars)) %>%
  cor(use = "pairwise.complete.obs")

# Clean names for display
rownames(cor_matrix) <- colnames(cor_matrix) <- c(
  "MTM BTFP", "MTM Other", "Unins Lev", "Wholesale", "Liquidity",
  "Run Risk","IDCR", "Insolvency", "Log Assets", "Equity", "FHLB"
)

# Print correlation table
cor_matrix %>%
  round(3) %>%
  kbl(caption = "Table 3: Correlation Matrix (Standardized Variables)",
      booktabs = TRUE) %>%
  kable_styling(bootstrap_options = c("striped", "hover"),
                full_width = FALSE,
                font_size = 10) %>%
  row_spec(0, bold = TRUE, background = "#F0F0F0")
Table 3: Correlation Matrix (Standardized Variables)
MTM BTFP MTM Other Unins Lev Wholesale Liquidity Run Risk IDCR Insolvency Log Assets Equity FHLB
MTM BTFP 1.000 -0.031 0.013 0.084 -0.117 0.176 -0.037 -0.062 0.070 -0.157 -0.077
MTM Other -0.031 1.000 -0.107 0.002 -0.407 0.460 -0.147 -0.122 0.113 -0.201 0.197
Unins Lev 0.013 -0.107 1.000 -0.027 0.022 0.684 -0.171 -0.413 0.441 -0.241 -0.076
Wholesale 0.084 0.002 -0.027 1.000 -0.101 0.044 -0.016 -0.029 0.085 -0.063 -0.021
Liquidity -0.117 -0.407 0.022 -0.101 1.000 -0.266 0.167 0.213 -0.333 0.253 -0.299
Run Risk 0.176 0.460 0.684 0.044 -0.266 1.000 0.058 -0.288 0.393 -0.208 0.078
IDCR -0.037 -0.147 -0.171 -0.016 0.167 0.058 1.000 0.645 -0.142 0.742 -0.061
Insolvency -0.062 -0.122 -0.413 -0.029 0.213 -0.288 0.645 1.000 -0.255 0.832 -0.129
Log Assets 0.070 0.113 0.441 0.085 -0.333 0.393 -0.142 -0.255 1.000 -0.164 0.194
Equity -0.157 -0.201 -0.241 -0.063 0.253 -0.208 0.742 0.832 -0.164 1.000 -0.061
FHLB -0.077 0.197 -0.076 -0.021 -0.299 0.078 -0.061 -0.129 0.194 -0.061 1.000
cat("\n✓ Correlation matrix created\n")
#> 
#> ✓ Correlation matrix created

6 Model 1: Linear Probability Model (BTFP vs DW)

################################################################################
# SECTION 10: LINEAR PROBABILITY MODEL - BTFP VS DW (BORROWERS ONLY)
################################################################################

cat("\n")
cat(strrep("=", 80), "\n", sep = "")
#> ================================================================================
cat("MODEL 1: LINEAR PROBABILITY MODEL (BTFP VS DW)\n")
#> MODEL 1: LINEAR PROBABILITY MODEL (BTFP VS DW)
cat(strrep("=", 80), "\n", sep = "")
#> ================================================================================
# Create borrower subsample
df_borrowers <- baseline %>%
  filter(any_borrower == 1) %>%
  filter(complete.cases(
    btfp_vs_dw,
    mtm_btfp_pct_w_z, mtm_other_pct_w_z, uninsured_lev_w_z,
    log_assets_w_z, pct_wholesale_liability_w_z, pct_liquidity_available_w_z,
    securities_ratio_w_z, loan_to_deposit_w_z, book_equity_to_asset_w_z,
    roa_w_z, fhlb_to_asset_w_z, delta_fhlb_w_z
  ))

cat("Borrower subsample:\n")
#> Borrower subsample:
cat("  Total borrowers:", nrow(df_borrowers), "\n")
#>   Total borrowers: 748
cat("  BTFP users:", sum(df_borrowers$btfp_vs_dw == 1), "\n")
#>   BTFP users: 453
cat("  DW only:", sum(df_borrowers$btfp_vs_dw == 0), "\n\n")
#>   DW only: 295
# Specification 1: Main effects only
lpm_1 <- feols(
  btfp_vs_dw ~ 
    mtm_btfp_pct_w_z + mtm_other_pct_w_z + uninsured_lev_w_z +
    log_assets_w_z + pct_wholesale_liability_w_z + pct_liquidity_available_w_z +
    securities_ratio_w_z + loan_to_deposit_w_z + book_equity_to_asset_w_z +
    roa_w_z + fhlb_to_asset_w_z + delta_fhlb_w_z,
  data = df_borrowers,
  vcov = "hetero"
)

# Specification 2: With interaction
lpm_2 <- feols(
  btfp_vs_dw ~ 
    mtm_btfp_pct_w_z + mtm_other_pct_w_z + uninsured_lev_w_z +
    mtm_btfp_x_unins_w_z +
    log_assets_w_z + pct_wholesale_liability_w_z + pct_liquidity_available_w_z +
    securities_ratio_w_z + loan_to_deposit_w_z + book_equity_to_asset_w_z +
    roa_w_z + fhlb_to_asset_w_z + delta_fhlb_w_z,
  data = df_borrowers,
  vcov = "hetero"
)

# Specification 3: With run risk dummy
lpm_3 <- feols(
  btfp_vs_dw ~ 
    mtm_btfp_pct_w_z + mtm_other_pct_w_z + uninsured_lev_w_z +
    run_risk_1_dummy_w_z +
    log_assets_w_z + pct_wholesale_liability_w_z + pct_liquidity_available_w_z +
    securities_ratio_w_z + loan_to_deposit_w_z + book_equity_to_asset_w_z +
    roa_w_z + fhlb_to_asset_w_z + delta_fhlb_w_z,
  data = df_borrowers,
  vcov = "hetero"
)

# Display results using etable (native to fixest)
etable(
  lpm_1, lpm_2, lpm_3,
  headers = c("LPM (1)", "LPM (2)", "LPM (3)"),
  title = "Table 4: Linear Probability Model - BTFP vs DW (Borrowers Only)",
  fitstat = c("n", "r2", "ar2"),
  signif.code = c("***"=0.01, "**"=0.05, "*"=0.10),
  digits = 3
)
#>                                         lpm_1             lpm_2
#>                                       LPM (1)           LPM (2)
#> Dependent Var.:                    btfp_vs_dw        btfp_vs_dw
#>                                                                
#> Constant                     0.563*** (0.025)  0.564*** (0.025)
#> mtm_btfp_pct_w_z               -0.002 (0.019)    -0.006 (0.042)
#> mtm_other_pct_w_z              -0.034 (0.022)    -0.034 (0.022)
#> uninsured_lev_w_z               0.035 (0.021)     0.033 (0.027)
#> log_assets_w_z               -0.048** (0.023)  -0.048** (0.023)
#> pct_wholesale_liability_w_z     0.018 (0.018)     0.018 (0.018)
#> pct_liquidity_available_w_z -0.167*** (0.059) -0.167*** (0.059)
#> securities_ratio_w_z           -0.051 (0.099)    -0.051 (0.099)
#> loan_to_deposit_w_z            -0.139 (0.122)    -0.139 (0.123)
#> book_equity_to_asset_w_z       -0.034 (0.053)    -0.034 (0.053)
#> roa_w_z                        -0.013 (0.025)    -0.013 (0.025)
#> fhlb_to_asset_w_z             0.057** (0.029)   0.057** (0.029)
#> delta_fhlb_w_z                  0.025 (0.017)     0.025 (0.017)
#> mtm_btfp_x_unins_w_z                              0.004 (0.038)
#> run_risk_1_dummy_w_z                                           
#> ___________________________ _________________ _________________
#> S.E. type                   Heteroskeda.-rob. Heteroskeda.-rob.
#> Observations                              748               748
#> R2                                    0.06211           0.06212
#> Adj. R2                               0.04680           0.04551
#> 
#>                                         lpm_3
#>                                       LPM (3)
#> Dependent Var.:                    btfp_vs_dw
#>                                              
#> Constant                     0.563*** (0.025)
#> mtm_btfp_pct_w_z               -0.001 (0.019)
#> mtm_other_pct_w_z              -0.031 (0.023)
#> uninsured_lev_w_z               0.038 (0.024)
#> log_assets_w_z               -0.048** (0.023)
#> pct_wholesale_liability_w_z     0.018 (0.019)
#> pct_liquidity_available_w_z -0.169*** (0.060)
#> securities_ratio_w_z           -0.051 (0.099)
#> loan_to_deposit_w_z            -0.139 (0.123)
#> book_equity_to_asset_w_z       -0.034 (0.053)
#> roa_w_z                        -0.013 (0.025)
#> fhlb_to_asset_w_z              0.057* (0.029)
#> delta_fhlb_w_z                  0.025 (0.017)
#> mtm_btfp_x_unins_w_z                         
#> run_risk_1_dummy_w_z           -0.007 (0.019)
#> ___________________________ _________________
#> S.E. type                   Heteroskeda.-rob.
#> Observations                              748
#> R2                                    0.06230
#> Adj. R2                               0.04570
#> ---
#> Signif. codes: 0 '***' 0.01 '**' 0.05 '*' 0.1 ' ' 1
cat("\n✓ LPM models estimated\n")
#> 
#> ✓ LPM models estimated

7 Model 2: Logit (BTFP vs DW)

################################################################################
# SECTION 11: LOGIT MODEL - BTFP VS DW (BORROWERS ONLY)
################################################################################

# ==============================================================================
# MODEL 2: LOGIT (BTFP VS DW) - Re-estimated with feglm for etable compatibility
# ==============================================================================

# Specification 1: Main effects only
logit_1 <- feglm(
  btfp_vs_dw ~ 
    mtm_btfp_pct_w_z + mtm_other_pct_w_z + uninsured_lev_w_z +
    log_assets_w_z + pct_wholesale_liability_w_z + pct_liquidity_available_w_z +
    securities_ratio_w_z + loan_to_deposit_w_z + book_equity_to_asset_w_z +
    roa_w_z + fhlb_to_asset_w_z + delta_fhlb_w_z,
  data = df_borrowers,
  family = "logit", # feglm uses this syntax for logistic regression
  vcov = "hetero"   # robust standard errors
)

# Specification 2: With interaction
logit_2 <- feglm(
  btfp_vs_dw ~ 
    mtm_btfp_pct_w_z + mtm_other_pct_w_z + uninsured_lev_w_z +
    mtm_btfp_x_unins_w_z +
    log_assets_w_z + pct_wholesale_liability_w_z + pct_liquidity_available_w_z +
    securities_ratio_w_z + loan_to_deposit_w_z + book_equity_to_asset_w_z +
    roa_w_z + fhlb_to_asset_w_z + delta_fhlb_w_z,
  data = df_borrowers,
  family = "logit",
  vcov = "hetero"
)

# Specification 3: With run risk dummy
logit_3 <- feglm(
  btfp_vs_dw ~ 
    mtm_btfp_pct_w_z + mtm_other_pct_w_z + uninsured_lev_w_z +
    run_risk_1_dummy_w_z +
    log_assets_w_z + pct_wholesale_liability_w_z + pct_liquidity_available_w_z +
    securities_ratio_w_z + loan_to_deposit_w_z + book_equity_to_asset_w_z +
    roa_w_z + fhlb_to_asset_w_z + delta_fhlb_w_z,
  data = df_borrowers,
  family = "logit",
  vcov = "hetero"
)

# Display results using etable
etable(
  logit_1, logit_2, logit_3,
  headers = c("Logit (1)", "Logit (2)", "Logit (3)"),
  title = "Table 5: Logit Model - BTFP vs DW (Borrowers Only)",
  fitstat = c("n", "ll", "aic", "bic"),
  signif.code = c("***"=0.01, "**"=0.05, "*"=0.10),
  digits = 3
)
#>                                      logit_1          logit_2          logit_3
#>                                    Logit (1)        Logit (2)        Logit (3)
#> Dependent Var.:                   btfp_vs_dw       btfp_vs_dw       btfp_vs_dw
#>                                                                               
#> Constant                     0.272** (0.109)  0.273** (0.109)  0.272** (0.109)
#> mtm_btfp_pct_w_z              -0.006 (0.089)   -0.030 (0.202) -6.22e-5 (0.091)
#> mtm_other_pct_w_z             -0.153 (0.097)   -0.155 (0.098)   -0.135 (0.106)
#> uninsured_lev_w_z              0.158 (0.097)    0.148 (0.121)    0.177 (0.109)
#> log_assets_w_z              -0.218** (0.104) -0.220** (0.104) -0.221** (0.105)
#> pct_wholesale_liability_w_z    0.078 (0.086)    0.078 (0.086)    0.082 (0.087)
#> pct_liquidity_available_w_z -0.737** (0.288) -0.737** (0.288) -0.750** (0.292)
#> securities_ratio_w_z          -0.239 (0.474)   -0.238 (0.474)   -0.239 (0.477)
#> loan_to_deposit_w_z           -0.635 (0.586)   -0.634 (0.586)   -0.645 (0.591)
#> book_equity_to_asset_w_z      -0.143 (0.241)   -0.144 (0.241)   -0.144 (0.242)
#> roa_w_z                       -0.058 (0.110)   -0.058 (0.110)   -0.058 (0.111)
#> fhlb_to_asset_w_z             0.265* (0.140)   0.264* (0.140)   0.267* (0.141)
#> delta_fhlb_w_z                 0.115 (0.080)    0.114 (0.080)    0.116 (0.080)
#> mtm_btfp_x_unins_w_z                            0.025 (0.184)                 
#> run_risk_1_dummy_w_z                                            -0.038 (0.087)
#> ___________________________ ________________ ________________ ________________
#> S.E. type                   Heterosked.-rob. Heterosked.-rob. Heterosked.-rob.
#> Observations                             748              748              748
#> Log-Likelihood                       -477.77          -477.76          -477.67
#> AIC                                   981.53           983.51           983.33
#> BIC                                  1,041.6          1,048.2          1,048.0
#> ---
#> Signif. codes: 0 '***' 0.01 '**' 0.05 '*' 0.1 ' ' 1
cat("\n✓ Logit models estimated\n")
#> 
#> ✓ Logit models estimated
################################################################################
# LOGIT MARGINAL EFFECTS
################################################################################

cat("\n")
cat(strrep("=", 80), "\n", sep = "")
#> ================================================================================
cat("LOGIT MARGINAL EFFECTS\n")
#> LOGIT MARGINAL EFFECTS
cat(strrep("=", 80), "\n", sep = "")
#> ================================================================================
# Calculate average marginal effects for Logit 2
# Simple approach: numerical derivatives at mean
calc_ame_logit <- function(model, data, var_name, delta = 0.01) {
  # Baseline predictions
  pred_base <- predict(model, newdata = data, type = "response")
  
  # Create counterfactual data
  data_cf <- data
  data_cf[[var_name]] <- data_cf[[var_name]] + delta
  
  # Counterfactual predictions
  pred_cf <- predict(model, newdata = data_cf, type = "response")
  
  # Marginal effect = change in probability / delta
  me <- (pred_cf - pred_base) / delta
  
  # Average marginal effect
  ame <- mean(me, na.rm = TRUE)
  
  return(ame)
}

# Calculate AMEs for key variables
key_vars_logit <- c(
  "mtm_btfp_pct_w_z", "mtm_other_pct_w_z", "uninsured_lev_w_z",
  "mtm_btfp_x_unins_w_z", "log_assets_w_z", "book_equity_to_asset_w_z"
)

ame_logit <- data.frame(
  Variable = key_vars_logit,
  AME = sapply(key_vars_logit, function(v) calc_ame_logit(logit_2, df_borrowers, v))
) %>%
  mutate(
    Variable = gsub("_w_z", "", Variable),
    AME_pct = round(AME * 100, 2)
  )

# Display AME table
ame_logit %>%
  kbl(caption = "Table 6: Average Marginal Effects - Logit Model (Percentage Points)",
      booktabs = TRUE,
      col.names = c("Variable", "AME", "AME (%)")) %>%
  kable_styling(bootstrap_options = c("striped", "hover"),
                full_width = FALSE) %>%
  footnote(general = "AME represents change in probability of choosing BTFP for one SD increase in variable.")
Table 6: Average Marginal Effects - Logit Model (Percentage Points)
Variable AME AME (%)
mtm_btfp_pct_w_z mtm_btfp_pct -0.0068279 -0.68
mtm_other_pct_w_z mtm_other_pct -0.0346313 -3.46
uninsured_lev_w_z uninsured_lev 0.0332398 3.32
mtm_btfp_x_unins_w_z mtm_btfp_x_unins 0.0056708 0.57
log_assets_w_z log_assets -0.0492872 -4.93
book_equity_to_asset_w_z book_equity_to_asset -0.0321643 -3.22
Note:
AME represents change in probability of choosing BTFP for one SD increase in variable.
cat("\n✓ Marginal effects calculated\n")
#> 
#> ✓ Marginal effects calculated

8 Model 3: Multinomial Logit

################################################################################
# SECTION 12: MULTINOMIAL LOGIT - FULL CHOICE SET
################################################################################

cat("\n")
cat(strrep("=", 80), "\n", sep = "")
#> ================================================================================
cat("MODEL 3: MULTINOMIAL LOGIT\n")
#> MODEL 3: MULTINOMIAL LOGIT
cat(strrep("=", 80), "\n", sep = "")
#> ================================================================================
# Create analysis dataset with complete cases
df_mlogit <- baseline %>%
  filter(complete.cases(
    Y_factor,
    mtm_btfp_pct_w_z, mtm_other_pct_w_z, uninsured_lev_w_z,
    log_assets_w_z, pct_wholesale_liability_w_z, pct_liquidity_available_w_z,
    securities_ratio_w_z, loan_to_deposit_w_z, book_equity_to_asset_w_z,
    roa_w_z, fhlb_to_asset_w_z, delta_fhlb_w_z
  ))

cat("Multinomial logit sample:\n")
#> Multinomial logit sample:
cat("  Total observations:", nrow(df_mlogit), "\n")
#>   Total observations: 4282
cat("  Outcome distribution:\n")
#>   Outcome distribution:
table(df_mlogit$Y_factor) %>% print()
#> 
#> No_Participation        BTFP_Only          DW_Only             Both 
#>             3534              363              295               90
cat("\n")
################################################################################
# ESTIMATE MULTINOMIAL LOGIT
################################################################################

# Specification 1: Main effects only
mlogit_1 <- multinom(
  Y_factor ~ 
    mtm_btfp_pct_w_z + mtm_other_pct_w_z + uninsured_lev_w_z +
    log_assets_w_z + pct_wholesale_liability_w_z + pct_liquidity_available_w_z +
    securities_ratio_w_z + loan_to_deposit_w_z + book_equity_to_asset_w_z +
    roa_w_z + fhlb_to_asset_w_z + delta_fhlb_w_z,
  data = df_mlogit,
  trace = FALSE
)

# Specification 2: With interaction
mlogit_2 <- multinom(
  Y_factor ~ 
    mtm_btfp_pct_w_z + mtm_other_pct_w_z + uninsured_lev_w_z +
    mtm_btfp_x_unins_w_z +
    log_assets_w_z + pct_wholesale_liability_w_z + pct_liquidity_available_w_z +
    securities_ratio_w_z + loan_to_deposit_w_z + book_equity_to_asset_w_z +
    roa_w_z + fhlb_to_asset_w_z + delta_fhlb_w_z,
  data = df_mlogit,
  trace = FALSE
)

# Specification 3: With run risk dummy
mlogit_3 <- multinom(
  Y_factor ~ 
    mtm_btfp_pct_w_z + mtm_other_pct_w_z + uninsured_lev_w_z +
    run_risk_1_dummy_w_z +
    log_assets_w_z + pct_wholesale_liability_w_z + pct_liquidity_available_w_z +
    securities_ratio_w_z + loan_to_deposit_w_z + book_equity_to_asset_w_z +
    roa_w_z + fhlb_to_asset_w_z + delta_fhlb_w_z,
  data = df_mlogit,
  trace = FALSE
)

cat("✓ Multinomial logit models estimated\n")
#> ✓ Multinomial logit models estimated
cat("  Model 1 AIC:", round(AIC(mlogit_1), 2), "\n")
#>   Model 1 AIC: 4926.15
cat("  Model 2 AIC:", round(AIC(mlogit_2), 2), "\n")
#>   Model 2 AIC: 4931.06
cat("  Model 3 AIC:", round(AIC(mlogit_3), 2), "\n\n")
#>   Model 3 AIC: 4924.71
################################################################################
# DISPLAY MULTINOMIAL LOGIT RESULTS
################################################################################

cat("Multinomial Logit Results:\n")
#> Multinomial Logit Results:
cat(strrep("-", 80), "\n", sep = "")
#> --------------------------------------------------------------------------------
# Get tidy output for each outcome
tidy_mlogit_2 <- broom::tidy(mlogit_2, conf.int = TRUE) %>%
  mutate(
    sig = case_when(
      p.value < 0.01 ~ "***",
      p.value < 0.05 ~ "**",
      p.value < 0.10 ~ "*",
      TRUE ~ ""
    ),
    estimate_sig = paste0(sprintf("%.3f", estimate), sig)
  )

# Print results for each outcome
for (outcome in c("BTFP_Only", "DW_Only", "Both")) {
  cat("\n", strrep("-", 80), "\n", sep = "")
  cat("Outcome:", outcome, "vs. No Participation\n")
  cat(strrep("-", 80), "\n", sep = "")
  
  tidy_mlogit_2 %>%
    filter(y.level == outcome) %>%
    select(term, estimate, std.error, statistic, p.value, sig) %>%
    mutate(across(where(is.numeric), ~round(., 4))) %>%
    kbl(booktabs = TRUE) %>%
    kable_styling(bootstrap_options = c("striped", "hover"),
                  full_width = FALSE,
                  font_size = 10) %>%
    print()
}
#> 
#> --------------------------------------------------------------------------------
#> Outcome: BTFP_Only vs. No Participation
#> --------------------------------------------------------------------------------
#> <table class="table table-striped table-hover" style="font-size: 10px; width: auto !important; margin-left: auto; margin-right: auto;">
#>  <thead>
#>   <tr>
#>    <th style="text-align:left;"> term </th>
#>    <th style="text-align:right;"> estimate </th>
#>    <th style="text-align:right;"> std.error </th>
#>    <th style="text-align:right;"> statistic </th>
#>    <th style="text-align:right;"> p.value </th>
#>    <th style="text-align:left;"> sig </th>
#>   </tr>
#>  </thead>
#> <tbody>
#>   <tr>
#>    <td style="text-align:left;"> (Intercept) </td>
#>    <td style="text-align:right;"> -2.6681 </td>
#>    <td style="text-align:right;"> 0.0817 </td>
#>    <td style="text-align:right;"> -32.6474 </td>
#>    <td style="text-align:right;"> 0.0000 </td>
#>    <td style="text-align:left;"> *** </td>
#>   </tr>
#>   <tr>
#>    <td style="text-align:left;"> mtm_btfp_pct_w_z </td>
#>    <td style="text-align:right;"> 0.1730 </td>
#>    <td style="text-align:right;"> 0.1235 </td>
#>    <td style="text-align:right;"> 1.4004 </td>
#>    <td style="text-align:right;"> 0.1614 </td>
#>    <td style="text-align:left;">  </td>
#>   </tr>
#>   <tr>
#>    <td style="text-align:left;"> mtm_other_pct_w_z </td>
#>    <td style="text-align:right;"> 0.0311 </td>
#>    <td style="text-align:right;"> 0.0669 </td>
#>    <td style="text-align:right;"> 0.4644 </td>
#>    <td style="text-align:right;"> 0.6424 </td>
#>    <td style="text-align:left;">  </td>
#>   </tr>
#>   <tr>
#>    <td style="text-align:left;"> uninsured_lev_w_z </td>
#>    <td style="text-align:right;"> 0.2226 </td>
#>    <td style="text-align:right;"> 0.0888 </td>
#>    <td style="text-align:right;"> 2.5055 </td>
#>    <td style="text-align:right;"> 0.0122 </td>
#>    <td style="text-align:left;"> ** </td>
#>   </tr>
#>   <tr>
#>    <td style="text-align:left;"> mtm_btfp_x_unins_w_z </td>
#>    <td style="text-align:right;"> -0.0948 </td>
#>    <td style="text-align:right;"> 0.1216 </td>
#>    <td style="text-align:right;"> -0.7801 </td>
#>    <td style="text-align:right;"> 0.4353 </td>
#>    <td style="text-align:left;">  </td>
#>   </tr>
#>   <tr>
#>    <td style="text-align:left;"> log_assets_w_z </td>
#>    <td style="text-align:right;"> 0.3862 </td>
#>    <td style="text-align:right;"> 0.0728 </td>
#>    <td style="text-align:right;"> 5.3066 </td>
#>    <td style="text-align:right;"> 0.0000 </td>
#>    <td style="text-align:left;"> *** </td>
#>   </tr>
#>   <tr>
#>    <td style="text-align:left;"> pct_wholesale_liability_w_z </td>
#>    <td style="text-align:right;"> 0.1665 </td>
#>    <td style="text-align:right;"> 0.0590 </td>
#>    <td style="text-align:right;"> 2.8231 </td>
#>    <td style="text-align:right;"> 0.0048 </td>
#>    <td style="text-align:left;"> *** </td>
#>   </tr>
#>   <tr>
#>    <td style="text-align:left;"> pct_liquidity_available_w_z </td>
#>    <td style="text-align:right;"> -0.6295 </td>
#>    <td style="text-align:right;"> 0.2058 </td>
#>    <td style="text-align:right;"> -3.0587 </td>
#>    <td style="text-align:right;"> 0.0022 </td>
#>    <td style="text-align:left;"> *** </td>
#>   </tr>
#>   <tr>
#>    <td style="text-align:left;"> securities_ratio_w_z </td>
#>    <td style="text-align:right;"> 0.1212 </td>
#>    <td style="text-align:right;"> 0.3195 </td>
#>    <td style="text-align:right;"> 0.3793 </td>
#>    <td style="text-align:right;"> 0.7045 </td>
#>    <td style="text-align:left;">  </td>
#>   </tr>
#>   <tr>
#>    <td style="text-align:left;"> loan_to_deposit_w_z </td>
#>    <td style="text-align:right;"> -0.0203 </td>
#>    <td style="text-align:right;"> 0.3875 </td>
#>    <td style="text-align:right;"> -0.0525 </td>
#>    <td style="text-align:right;"> 0.9582 </td>
#>    <td style="text-align:left;">  </td>
#>   </tr>
#>   <tr>
#>    <td style="text-align:left;"> book_equity_to_asset_w_z </td>
#>    <td style="text-align:right;"> -0.5408 </td>
#>    <td style="text-align:right;"> 0.1565 </td>
#>    <td style="text-align:right;"> -3.4552 </td>
#>    <td style="text-align:right;"> 0.0005 </td>
#>    <td style="text-align:left;"> *** </td>
#>   </tr>
#>   <tr>
#>    <td style="text-align:left;"> roa_w_z </td>
#>    <td style="text-align:right;"> 0.0340 </td>
#>    <td style="text-align:right;"> 0.0785 </td>
#>    <td style="text-align:right;"> 0.4335 </td>
#>    <td style="text-align:right;"> 0.6646 </td>
#>    <td style="text-align:left;">  </td>
#>   </tr>
#>   <tr>
#>    <td style="text-align:left;"> fhlb_to_asset_w_z </td>
#>    <td style="text-align:right;"> 0.2615 </td>
#>    <td style="text-align:right;"> 0.0921 </td>
#>    <td style="text-align:right;"> 2.8395 </td>
#>    <td style="text-align:right;"> 0.0045 </td>
#>    <td style="text-align:left;"> *** </td>
#>   </tr>
#>   <tr>
#>    <td style="text-align:left;"> delta_fhlb_w_z </td>
#>    <td style="text-align:right;"> -0.0415 </td>
#>    <td style="text-align:right;"> 0.0601 </td>
#>    <td style="text-align:right;"> -0.6899 </td>
#>    <td style="text-align:right;"> 0.4902 </td>
#>    <td style="text-align:left;">  </td>
#>   </tr>
#> </tbody>
#> </table>
#> --------------------------------------------------------------------------------
#> Outcome: DW_Only vs. No Participation
#> --------------------------------------------------------------------------------
#> <table class="table table-striped table-hover" style="font-size: 10px; width: auto !important; margin-left: auto; margin-right: auto;">
#>  <thead>
#>   <tr>
#>    <th style="text-align:left;"> term </th>
#>    <th style="text-align:right;"> estimate </th>
#>    <th style="text-align:right;"> std.error </th>
#>    <th style="text-align:right;"> statistic </th>
#>    <th style="text-align:right;"> p.value </th>
#>    <th style="text-align:left;"> sig </th>
#>   </tr>
#>  </thead>
#> <tbody>
#>   <tr>
#>    <td style="text-align:left;"> (Intercept) </td>
#>    <td style="text-align:right;"> -2.7535 </td>
#>    <td style="text-align:right;"> 0.0776 </td>
#>    <td style="text-align:right;"> -35.4660 </td>
#>    <td style="text-align:right;"> 0.0000 </td>
#>    <td style="text-align:left;"> *** </td>
#>   </tr>
#>   <tr>
#>    <td style="text-align:left;"> mtm_btfp_pct_w_z </td>
#>    <td style="text-align:right;"> 0.1213 </td>
#>    <td style="text-align:right;"> 0.1483 </td>
#>    <td style="text-align:right;"> 0.8180 </td>
#>    <td style="text-align:right;"> 0.4133 </td>
#>    <td style="text-align:left;">  </td>
#>   </tr>
#>   <tr>
#>    <td style="text-align:left;"> mtm_other_pct_w_z </td>
#>    <td style="text-align:right;"> 0.2020 </td>
#>    <td style="text-align:right;"> 0.0718 </td>
#>    <td style="text-align:right;"> 2.8126 </td>
#>    <td style="text-align:right;"> 0.0049 </td>
#>    <td style="text-align:left;"> *** </td>
#>   </tr>
#>   <tr>
#>    <td style="text-align:left;"> uninsured_lev_w_z </td>
#>    <td style="text-align:right;"> 0.1523 </td>
#>    <td style="text-align:right;"> 0.0882 </td>
#>    <td style="text-align:right;"> 1.7271 </td>
#>    <td style="text-align:right;"> 0.0841 </td>
#>    <td style="text-align:left;"> * </td>
#>   </tr>
#>   <tr>
#>    <td style="text-align:left;"> mtm_btfp_x_unins_w_z </td>
#>    <td style="text-align:right;"> -0.0641 </td>
#>    <td style="text-align:right;"> 0.1393 </td>
#>    <td style="text-align:right;"> -0.4599 </td>
#>    <td style="text-align:right;"> 0.6456 </td>
#>    <td style="text-align:left;">  </td>
#>   </tr>
#>   <tr>
#>    <td style="text-align:left;"> log_assets_w_z </td>
#>    <td style="text-align:right;"> 0.6817 </td>
#>    <td style="text-align:right;"> 0.0733 </td>
#>    <td style="text-align:right;"> 9.3039 </td>
#>    <td style="text-align:right;"> 0.0000 </td>
#>    <td style="text-align:left;"> *** </td>
#>   </tr>
#>   <tr>
#>    <td style="text-align:left;"> pct_wholesale_liability_w_z </td>
#>    <td style="text-align:right;"> 0.1230 </td>
#>    <td style="text-align:right;"> 0.0657 </td>
#>    <td style="text-align:right;"> 1.8731 </td>
#>    <td style="text-align:right;"> 0.0611 </td>
#>    <td style="text-align:left;"> * </td>
#>   </tr>
#>   <tr>
#>    <td style="text-align:left;"> pct_liquidity_available_w_z </td>
#>    <td style="text-align:right;"> 0.1785 </td>
#>    <td style="text-align:right;"> 0.1812 </td>
#>    <td style="text-align:right;"> 0.9850 </td>
#>    <td style="text-align:right;"> 0.3246 </td>
#>    <td style="text-align:left;">  </td>
#>   </tr>
#>   <tr>
#>    <td style="text-align:left;"> securities_ratio_w_z </td>
#>    <td style="text-align:right;"> 0.4072 </td>
#>    <td style="text-align:right;"> 0.3094 </td>
#>    <td style="text-align:right;"> 1.3164 </td>
#>    <td style="text-align:right;"> 0.1880 </td>
#>    <td style="text-align:left;">  </td>
#>   </tr>
#>   <tr>
#>    <td style="text-align:left;"> loan_to_deposit_w_z </td>
#>    <td style="text-align:right;"> 0.5799 </td>
#>    <td style="text-align:right;"> 0.3698 </td>
#>    <td style="text-align:right;"> 1.5682 </td>
#>    <td style="text-align:right;"> 0.1168 </td>
#>    <td style="text-align:left;">  </td>
#>   </tr>
#>   <tr>
#>    <td style="text-align:left;"> book_equity_to_asset_w_z </td>
#>    <td style="text-align:right;"> -0.3343 </td>
#>    <td style="text-align:right;"> 0.1542 </td>
#>    <td style="text-align:right;"> -2.1681 </td>
#>    <td style="text-align:right;"> 0.0302 </td>
#>    <td style="text-align:left;"> ** </td>
#>   </tr>
#>   <tr>
#>    <td style="text-align:left;"> roa_w_z </td>
#>    <td style="text-align:right;"> 0.0936 </td>
#>    <td style="text-align:right;"> 0.0785 </td>
#>    <td style="text-align:right;"> 1.1923 </td>
#>    <td style="text-align:right;"> 0.2332 </td>
#>    <td style="text-align:left;">  </td>
#>   </tr>
#>   <tr>
#>    <td style="text-align:left;"> fhlb_to_asset_w_z </td>
#>    <td style="text-align:right;"> 0.0452 </td>
#>    <td style="text-align:right;"> 0.0981 </td>
#>    <td style="text-align:right;"> 0.4603 </td>
#>    <td style="text-align:right;"> 0.6453 </td>
#>    <td style="text-align:left;">  </td>
#>   </tr>
#>   <tr>
#>    <td style="text-align:left;"> delta_fhlb_w_z </td>
#>    <td style="text-align:right;"> -0.1602 </td>
#>    <td style="text-align:right;"> 0.0724 </td>
#>    <td style="text-align:right;"> -2.2121 </td>
#>    <td style="text-align:right;"> 0.0270 </td>
#>    <td style="text-align:left;"> ** </td>
#>   </tr>
#> </tbody>
#> </table>
#> --------------------------------------------------------------------------------
#> Outcome: Both vs. No Participation
#> --------------------------------------------------------------------------------
#> <table class="table table-striped table-hover" style="font-size: 10px; width: auto !important; margin-left: auto; margin-right: auto;">
#>  <thead>
#>   <tr>
#>    <th style="text-align:left;"> term </th>
#>    <th style="text-align:right;"> estimate </th>
#>    <th style="text-align:right;"> std.error </th>
#>    <th style="text-align:right;"> statistic </th>
#>    <th style="text-align:right;"> p.value </th>
#>    <th style="text-align:left;"> sig </th>
#>   </tr>
#>  </thead>
#> <tbody>
#>   <tr>
#>    <td style="text-align:left;"> (Intercept) </td>
#>    <td style="text-align:right;"> -4.6738 </td>
#>    <td style="text-align:right;"> 0.2074 </td>
#>    <td style="text-align:right;"> -22.5350 </td>
#>    <td style="text-align:right;"> 0.0000 </td>
#>    <td style="text-align:left;"> *** </td>
#>   </tr>
#>   <tr>
#>    <td style="text-align:left;"> mtm_btfp_pct_w_z </td>
#>    <td style="text-align:right;"> -0.2007 </td>
#>    <td style="text-align:right;"> 0.2743 </td>
#>    <td style="text-align:right;"> -0.7318 </td>
#>    <td style="text-align:right;"> 0.4643 </td>
#>    <td style="text-align:left;">  </td>
#>   </tr>
#>   <tr>
#>    <td style="text-align:left;"> mtm_other_pct_w_z </td>
#>    <td style="text-align:right;"> 0.0577 </td>
#>    <td style="text-align:right;"> 0.1315 </td>
#>    <td style="text-align:right;"> 0.4387 </td>
#>    <td style="text-align:right;"> 0.6609 </td>
#>    <td style="text-align:left;">  </td>
#>   </tr>
#>   <tr>
#>    <td style="text-align:left;"> uninsured_lev_w_z </td>
#>    <td style="text-align:right;"> 0.3851 </td>
#>    <td style="text-align:right;"> 0.1514 </td>
#>    <td style="text-align:right;"> 2.5443 </td>
#>    <td style="text-align:right;"> 0.0109 </td>
#>    <td style="text-align:left;"> ** </td>
#>   </tr>
#>   <tr>
#>    <td style="text-align:left;"> mtm_btfp_x_unins_w_z </td>
#>    <td style="text-align:right;"> 0.0918 </td>
#>    <td style="text-align:right;"> 0.2126 </td>
#>    <td style="text-align:right;"> 0.4319 </td>
#>    <td style="text-align:right;"> 0.6658 </td>
#>    <td style="text-align:left;">  </td>
#>   </tr>
#>   <tr>
#>    <td style="text-align:left;"> log_assets_w_z </td>
#>    <td style="text-align:right;"> 0.9876 </td>
#>    <td style="text-align:right;"> 0.1216 </td>
#>    <td style="text-align:right;"> 8.1216 </td>
#>    <td style="text-align:right;"> 0.0000 </td>
#>    <td style="text-align:left;"> *** </td>
#>   </tr>
#>   <tr>
#>    <td style="text-align:left;"> pct_wholesale_liability_w_z </td>
#>    <td style="text-align:right;"> 0.0853 </td>
#>    <td style="text-align:right;"> 0.1067 </td>
#>    <td style="text-align:right;"> 0.8000 </td>
#>    <td style="text-align:right;"> 0.4237 </td>
#>    <td style="text-align:left;">  </td>
#>   </tr>
#>   <tr>
#>    <td style="text-align:left;"> pct_liquidity_available_w_z </td>
#>    <td style="text-align:right;"> 0.0764 </td>
#>    <td style="text-align:right;"> 0.3405 </td>
#>    <td style="text-align:right;"> 0.2245 </td>
#>    <td style="text-align:right;"> 0.8224 </td>
#>    <td style="text-align:left;">  </td>
#>   </tr>
#>   <tr>
#>    <td style="text-align:left;"> securities_ratio_w_z </td>
#>    <td style="text-align:right;"> 1.4846 </td>
#>    <td style="text-align:right;"> 0.5285 </td>
#>    <td style="text-align:right;"> 2.8093 </td>
#>    <td style="text-align:right;"> 0.0050 </td>
#>    <td style="text-align:left;"> *** </td>
#>   </tr>
#>   <tr>
#>    <td style="text-align:left;"> loan_to_deposit_w_z </td>
#>    <td style="text-align:right;"> 1.4533 </td>
#>    <td style="text-align:right;"> 0.6321 </td>
#>    <td style="text-align:right;"> 2.2992 </td>
#>    <td style="text-align:right;"> 0.0215 </td>
#>    <td style="text-align:left;"> ** </td>
#>   </tr>
#>   <tr>
#>    <td style="text-align:left;"> book_equity_to_asset_w_z </td>
#>    <td style="text-align:right;"> -0.9232 </td>
#>    <td style="text-align:right;"> 0.3227 </td>
#>    <td style="text-align:right;"> -2.8610 </td>
#>    <td style="text-align:right;"> 0.0042 </td>
#>    <td style="text-align:left;"> *** </td>
#>   </tr>
#>   <tr>
#>    <td style="text-align:left;"> roa_w_z </td>
#>    <td style="text-align:right;"> 0.0403 </td>
#>    <td style="text-align:right;"> 0.1457 </td>
#>    <td style="text-align:right;"> 0.2766 </td>
#>    <td style="text-align:right;"> 0.7821 </td>
#>    <td style="text-align:left;">  </td>
#>   </tr>
#>   <tr>
#>    <td style="text-align:left;"> fhlb_to_asset_w_z </td>
#>    <td style="text-align:right;"> -0.0351 </td>
#>    <td style="text-align:right;"> 0.1670 </td>
#>    <td style="text-align:right;"> -0.2102 </td>
#>    <td style="text-align:right;"> 0.8335 </td>
#>    <td style="text-align:left;">  </td>
#>   </tr>
#>   <tr>
#>    <td style="text-align:left;"> delta_fhlb_w_z </td>
#>    <td style="text-align:right;"> -0.0262 </td>
#>    <td style="text-align:right;"> 0.1060 </td>
#>    <td style="text-align:right;"> -0.2476 </td>
#>    <td style="text-align:right;"> 0.8044 </td>
#>    <td style="text-align:left;">  </td>
#>   </tr>
#> </tbody>
#> </table>
cat("\n✓ Multinomial logit results displayed\n")
#> 
#> ✓ Multinomial logit results displayed
# Display Multinomial Logit results in an 'etable-like' format


modelsummary(
  mlogit_2,
  shape = term ~ response,  # <--- This puts outcomes as columns (like etable)
  stars = c('*' = 0.10, '**' = 0.05, '***' = 0.01),
  estimate = "{estimate}{stars}",
  statistic = "std.error",  # Standard errors in parentheses
  gof_map = c("nobs", "AIC", "BIC", "logLik"),
  title = "Table 6: Multinomial Logit Results (Reference: No Participation)",
  output = "markdown"       # Use "markdown" for console text, or "kableExtra" for PDF/HTML
)
Table 6: Multinomial Logit Results (Reference: No Participation)
BTFP_Only DW_Only Both
(Intercept) -2.668*** -2.754*** -4.674***
(0.082) (0.078) (0.207)
mtm_btfp_pct_w_z 0.173 0.121 -0.201
(0.124) (0.148) (0.274)
mtm_other_pct_w_z 0.031 0.202*** 0.058
(0.067) (0.072) (0.131)
uninsured_lev_w_z 0.223** 0.152* 0.385**
(0.089) (0.088) (0.151)
mtm_btfp_x_unins_w_z -0.095 -0.064 0.092
(0.122) (0.139) (0.213)
log_assets_w_z 0.386*** 0.682*** 0.988***
(0.073) (0.073) (0.122)
pct_wholesale_liability_w_z 0.167*** 0.123* 0.085
(0.059) (0.066) (0.107)
pct_liquidity_available_w_z -0.629*** 0.178 0.076
(0.206) (0.181) (0.340)
securities_ratio_w_z 0.121 0.407 1.485***
(0.320) (0.309) (0.528)
loan_to_deposit_w_z -0.020 0.580 1.453**
(0.388) (0.370) (0.632)
book_equity_to_asset_w_z -0.541*** -0.334** -0.923***
(0.157) (0.154) (0.323)
roa_w_z 0.034 0.094 0.040
(0.078) (0.079) (0.146)
fhlb_to_asset_w_z 0.261*** 0.045 -0.035
(0.092) (0.098) (0.167)
delta_fhlb_w_z -0.041 -0.160** -0.026
(0.060) (0.072) (0.106)
Num.Obs. 4282
cat("\n✓ Multinomial logit results displayed\n")
#> 
#> ✓ Multinomial logit results displayed
################################################################################
# MULTINOMIAL LOGIT MARGINAL EFFECTS
################################################################################

cat("\n")
cat(strrep("=", 80), "\n", sep = "")
#> ================================================================================
cat("MULTINOMIAL LOGIT MARGINAL EFFECTS\n")
#> MULTINOMIAL LOGIT MARGINAL EFFECTS
cat(strrep("=", 80), "\n", sep = "")
#> ================================================================================
# Calculate marginal effects at means
calc_mlogit_ame <- function(model, data, var_name, delta = 0.01) {
  # Baseline predictions
  pred_base <- predict(model, newdata = data, type = "probs")
  
  # Create counterfactual data
  data_cf <- data
  data_cf[[var_name]] <- data_cf[[var_name]] + delta
  
  # Counterfactual predictions
  pred_cf <- predict(model, newdata = data_cf, type = "probs")
  
  # Marginal effect = change in probability / delta
  me <- (pred_cf - pred_base) / delta
  
  # Average marginal effect for each outcome
  ame <- colMeans(me, na.rm = TRUE)
  
  return(ame)
}

# Calculate AMEs for key variables
key_vars_mlogit <- c(
  "mtm_btfp_pct_w_z", "mtm_other_pct_w_z", "uninsured_lev_w_z",
  "mtm_btfp_x_unins_w_z", "log_assets_w_z", "book_equity_to_asset_w_z",
  "fhlb_to_asset_w_z"
)

ame_list_mlogit <- lapply(key_vars_mlogit, function(v) {
  me <- calc_mlogit_ame(mlogit_2, df_mlogit, v)
  data.frame(
    Variable = v,
    No_Participation = me[1],
    BTFP_Only = me[2],
    DW_Only = me[3],
    Both = me[4]
  )
})

ame_mlogit <- do.call(rbind, ame_list_mlogit) %>%
  mutate(
    Variable = gsub("_w_z", "", Variable),
    across(where(is.numeric), ~round(. * 100, 2))  # Convert to percentage points
  )

# Display AME table
ame_mlogit %>%
  kbl(caption = "Table 7: Multinomial Logit Average Marginal Effects (Percentage Points)",
      booktabs = TRUE) %>%
  kable_styling(bootstrap_options = c("striped", "hover"),
                full_width = FALSE) %>%
  row_spec(0, bold = TRUE, background = "#F0F0F0") %>%
  footnote(general = "AME represents change in probability (in pp) for one SD increase in each variable. Row sums to zero.")
Table 7: Multinomial Logit Average Marginal Effects (Percentage Points)
Variable No_Participation BTFP_Only DW_Only Both
No_Participation mtm_btfp_pct -1.43 1.24 0.67 -0.48
No_Participation1 mtm_other_pct -1.30 0.05 1.20 0.05
No_Participation2 uninsured_lev -2.69 1.40 0.65 0.63
No_Participation3 mtm_btfp_x_unins 0.80 -0.68 -0.34 0.23
No_Participation4 log_assets -7.22 1.99 3.62 1.60
No_Participation5 book_equity_to_asset 6.31 -3.42 -1.37 -1.52
No_Participation6 fhlb_to_asset -1.82 1.90 0.08 -0.16
Note:
AME represents change in probability (in pp) for one SD increase in each variable. Row sums to zero.
cat("\n✓ Marginal effects calculated\n")
#> 
#> ✓ Marginal effects calculated

9 Model 4: Trivariate Probit

# ==============================================================================
# MODEL 4: TRIVARIATE PROBIT (APPROXIMATION VIA SEPARATE PROBITS)
# ==============================================================================

cat("\n")
cat(strrep("=", 80), "\n", sep = "")
#> ================================================================================
cat("MODEL 4: SEPARATE PROBITS (PROXY FOR TRIVARIATE)\n")
#> MODEL 4: SEPARATE PROBITS (PROXY FOR TRIVARIATE)
cat(strrep("=", 80), "\n", sep = "")
#> ================================================================================
# 1. Define Formulas
formula_btfp <- btfp_user ~ 
  mtm_btfp_pct_w_z + mtm_other_pct_w_z + uninsured_lev_w_z +
  mtm_btfp_x_unins_w_z +
  log_assets_w_z + pct_wholesale_liability_w_z + pct_liquidity_available_w_z +
  securities_ratio_w_z + loan_to_deposit_w_z + book_equity_to_asset_w_z +
  roa_w_z + fhlb_to_asset_w_z + delta_fhlb_w_z

formula_dw <- dw_user ~ 
  mtm_btfp_pct_w_z + mtm_other_pct_w_z + uninsured_lev_w_z +
  mtm_btfp_x_unins_w_z +
  log_assets_w_z + pct_wholesale_liability_w_z + pct_liquidity_available_w_z +
  securities_ratio_w_z + loan_to_deposit_w_z + book_equity_to_asset_w_z +
  roa_w_z + fhlb_to_asset_w_z + delta_fhlb_w_z

formula_fhlb <- fhlb_crisis ~ 
  mtm_btfp_pct_w_z + mtm_other_pct_w_z + uninsured_lev_w_z +
  mtm_btfp_x_unins_w_z +
  log_assets_w_z + pct_wholesale_liability_w_z + pct_liquidity_available_w_z +
  securities_ratio_w_z + loan_to_deposit_w_z + book_equity_to_asset_w_z +
  roa_w_z + fhlb_to_asset_w_z + delta_fhlb_w_z

# 2. Estimate using feglm (fixest) for etable compatibility
# Note: family = binomial(link = "probit") sets this to Probit
probit_btfp <- feglm(formula_btfp, data = df_mlogit, family = binomial(link = "probit"))
probit_dw   <- feglm(formula_dw,   data = df_mlogit, family = binomial(link = "probit"))
probit_fhlb <- feglm(formula_fhlb, data = df_mlogit, family = binomial(link = "probit"))

cat("✓ Separate probit models estimated with feglm\n\n")
#> ✓ Separate probit models estimated with feglm
# 3. Display results using etable
etable(
  probit_btfp, probit_dw, probit_fhlb,
  headers = c("BTFP", "DW", "FHLB Crisis"),
  title = "Table 8: Separate Probit Models (BTFP, DW, FHLB)",
  fitstat = c("n", "ll", "aic", "bic"),
  signif.code = c("***"=0.01, "**"=0.05, "*"=0.10),
  digits = 3
)
#>                                   probit_btfp         probit_dw
#>                                          BTFP                DW
#> Dependent Var.:                     btfp_user           dw_user
#>                                                                
#> Constant                     -1.46*** (0.036)  -1.51*** (0.034)
#> mtm_btfp_pct_w_z                0.056 (0.062)     0.022 (0.068)
#> mtm_other_pct_w_z               0.008 (0.032)   0.079** (0.033)
#> uninsured_lev_w_z            0.130*** (0.042)   0.082** (0.041)
#> mtm_btfp_x_unins_w_z           -0.029 (0.060)    -0.009 (0.064)
#> log_assets_w_z               0.227*** (0.034)  0.380*** (0.035)
#> pct_wholesale_liability_w_z  0.080*** (0.029)     0.042 (0.031)
#> pct_liquidity_available_w_z -0.250*** (0.095)    0.159* (0.087)
#> securities_ratio_w_z            0.144 (0.153)   0.363** (0.147)
#> loan_to_deposit_w_z             0.059 (0.187)   0.444** (0.179)
#> book_equity_to_asset_w_z    -0.272*** (0.074) -0.205*** (0.073)
#> roa_w_z                         0.011 (0.037)     0.031 (0.037)
#> fhlb_to_asset_w_z            0.122*** (0.045)    -0.010 (0.046)
#> delta_fhlb_w_z                 -0.007 (0.030)   -0.061* (0.033)
#> ___________________________ _________________ _________________
#> S.E. type                                 IID               IID
#> Observations                            4,282             4,282
#> Log-Likelihood                       -1,278.9          -1,153.4
#> AIC                                   2,585.9           2,334.9
#> BIC                                   2,675.0           2,423.9
#> 
#>                                   probit_fhlb
#>                                   FHLB Crisis
#> Dependent Var.:                   fhlb_crisis
#>                                              
#> Constant                    -0.841*** (0.032)
#> mtm_btfp_pct_w_z               0.109* (0.063)
#> mtm_other_pct_w_z            0.119*** (0.032)
#> uninsured_lev_w_z              -0.040 (0.043)
#> mtm_btfp_x_unins_w_z           -0.097 (0.070)
#> log_assets_w_z               0.114*** (0.037)
#> pct_wholesale_liability_w_z     0.021 (0.031)
#> pct_liquidity_available_w_z -0.335*** (0.080)
#> securities_ratio_w_z           -0.147 (0.124)
#> loan_to_deposit_w_z            -0.062 (0.144)
#> book_equity_to_asset_w_z       -0.053 (0.046)
#> roa_w_z                        -0.003 (0.035)
#> fhlb_to_asset_w_z           -0.490*** (0.049)
#> delta_fhlb_w_z                1.56*** (0.055)
#> ___________________________ _________________
#> S.E. type                                 IID
#> Observations                            4,282
#> Log-Likelihood                       -1,214.9
#> AIC                                   2,457.8
#> BIC                                   2,546.9
#> ---
#> Signif. codes: 0 '***' 0.01 '**' 0.05 '*' 0.1 ' ' 1
# 4. Calculate residual correlations (fixest supports residuals())
cat("\nCalculating residual correlations...\n")
#> 
#> Calculating residual correlations...
# type = "response" gives raw residuals (y - p_hat)
resid_btfp <- residuals(probit_btfp, type = "response")
resid_dw   <- residuals(probit_dw,   type = "response")
resid_fhlb <- residuals(probit_fhlb, type = "response")

cor_matrix_resid <- cor(data.frame(
  BTFP = resid_btfp,
  DW   = resid_dw,
  FHLB = resid_fhlb
), use = "pairwise.complete.obs")

cat("\nResidual correlations (proxy for error correlations):\n")
#> 
#> Residual correlations (proxy for error correlations):
print(round(cor_matrix_resid, 3))
#>       BTFP     DW   FHLB
#> BTFP 1.000  0.073  0.017
#> DW   0.073  1.000 -0.020
#> FHLB 0.017 -0.020  1.000
cat("\n")
cat("Interpretation:\n")
#> Interpretation:
cat("  ρ(BTFP, DW):", sprintf("%.3f", cor_matrix_resid[1,2]), 
    "- Correlation in unobserved factors affecting both\n")
#>   ρ(BTFP, DW): 0.073 - Correlation in unobserved factors affecting both
cat("  ρ(BTFP, FHLB):", sprintf("%.3f", cor_matrix_resid[1,3]), 
    "- Potential complementarity/substitution\n")
#>   ρ(BTFP, FHLB): 0.017 - Potential complementarity/substitution
cat("  ρ(DW, FHLB):", sprintf("%.3f", cor_matrix_resid[2,3]), 
    "- Potential complementarity/substitution\n")
#>   ρ(DW, FHLB): -0.020 - Potential complementarity/substitution
cat("\n✓ Trivariate probit (separate estimation) completed\n")
#> 
#> ✓ Trivariate probit (separate estimation) completed

10 Robustness Checks

################################################################################
# SECTION 14: SUBSAMPLE ANALYSIS
################################################################################

cat("\n")
cat(strrep("=", 80), "\n", sep = "")
#> ================================================================================
cat("SUBSAMPLE ANALYSIS\n")
#> SUBSAMPLE ANALYSIS
cat(strrep("=", 80), "\n", sep = "")
#> ================================================================================
# Size-based subsamples
median_assets <- median(df_mlogit$log_assets_w_z, na.rm = TRUE)

cat("Estimating for small banks (below median assets)...\n")
#> Estimating for small banks (below median assets)...
df_small <- df_mlogit %>% filter(log_assets_w_z <= median_assets)
mlogit_small <- multinom(
  Y_factor ~ 
    mtm_btfp_pct_w_z + mtm_other_pct_w_z + uninsured_lev_w_z +
    mtm_btfp_x_unins_w_z +
    log_assets_w_z + pct_wholesale_liability_w_z + pct_liquidity_available_w_z +
    book_equity_to_asset_w_z + fhlb_to_asset_w_z,
  data = df_small,
  trace = FALSE
)

cat("Estimating for large banks (above median assets)...\n")
#> Estimating for large banks (above median assets)...
df_large <- df_mlogit %>% filter(log_assets_w_z > median_assets)
mlogit_large <- multinom(
  Y_factor ~ 
    mtm_btfp_pct_w_z + mtm_other_pct_w_z + uninsured_lev_w_z +
    mtm_btfp_x_unins_w_z +
    log_assets_w_z + pct_wholesale_liability_w_z + pct_liquidity_available_w_z +
    book_equity_to_asset_w_z + fhlb_to_asset_w_z,
  data = df_large,
  trace = FALSE
)

cat("\n✓ Size-based subsample analysis completed\n")
#> 
#> ✓ Size-based subsample analysis completed
# Compare key coefficients across subsamples
cat("\nComparing MTM BTFP coefficient (BTFP_Only outcome) across subsamples:\n")
#> 
#> Comparing MTM BTFP coefficient (BTFP_Only outcome) across subsamples:
cat("  Full sample:", 
    sprintf("%.4f", coef(mlogit_2)["BTFP_Only", "mtm_btfp_pct_w_z"]), "\n")
#>   Full sample: 0.1730
cat("  Small banks:", 
    sprintf("%.4f", coef(mlogit_small)["BTFP_Only", "mtm_btfp_pct_w_z"]), "\n")
#>   Small banks: 0.5619
cat("  Large banks:", 
    sprintf("%.4f", coef(mlogit_large)["BTFP_Only", "mtm_btfp_pct_w_z"]), "\n")
#>   Large banks: 0.0328

11 Visualizations

################################################################################
# SECTION 15: VISUALIZATIONS
################################################################################

cat("\n")
cat(strrep("=", 80), "\n", sep = "")
#> ================================================================================
cat("CREATING VISUALIZATIONS\n")
#> CREATING VISUALIZATIONS
cat(strrep("=", 80), "\n", sep = "")
#> ================================================================================
# Calculate predicted probabilities
pred_probs <- predict(mlogit_2, newdata = df_mlogit, type = "probs")
df_mlogit$pred_no_part <- pred_probs[, "No_Participation"]
df_mlogit$pred_btfp <- pred_probs[, "BTFP_Only"]
df_mlogit$pred_dw <- pred_probs[, "DW_Only"]
df_mlogit$pred_both <- pred_probs[, "Both"]

# Plot 1: Distribution of predicted probabilities by actual outcome
plot_data <- df_mlogit %>%
  select(Y_factor, starts_with("pred_")) %>%
  pivot_longer(starts_with("pred_"), 
               names_to = "Predicted", 
               values_to = "Probability") %>%
  mutate(
    Predicted = gsub("pred_", "", Predicted),
    Predicted = case_when(
      Predicted == "no_part" ~ "No Participation",
      Predicted == "btfp" ~ "BTFP Only",
      Predicted == "dw" ~ "DW Only",
      Predicted == "both" ~ "Both",
      TRUE ~ Predicted
    )
  )

p1 <- ggplot(plot_data, aes(x = Probability, fill = Y_factor)) +
  geom_density(alpha = 0.5) +
  facet_wrap(~Predicted, scales = "free") +
  theme_minimal() +
  labs(
    title = "Distribution of Predicted Probabilities by Actual Outcome",
    x = "Predicted Probability",
    y = "Density",
    fill = "Actual Outcome"
  ) +
  theme(legend.position = "bottom",
        plot.title = element_text(hjust = 0.5, face = "bold"))

print(p1)

ggsave(file.path(FIG_PATH, "predicted_probabilities_distribution.png"), 
       p1, width = 12, height = 8, dpi = 300)

cat("\n✓ Predicted probability plots created\n")
#> 
#> ✓ Predicted probability plots created
################################################################################
# PLOT MARGINAL EFFECTS
################################################################################

# Create plot of marginal effects
plot_me <- ame_mlogit %>%
  pivot_longer(-Variable, names_to = "Outcome", values_to = "Effect") %>%
  mutate(
    Outcome = factor(Outcome, 
                    levels = c("No_Participation", "BTFP_Only", "DW_Only", "Both"),
                    labels = c("No Participation", "BTFP Only", "DW Only", "Both"))
  )

p2 <- ggplot(plot_me, aes(x = Variable, y = Effect, fill = Outcome)) +
  geom_col(position = "dodge") +
  geom_hline(yintercept = 0, linetype = "dashed", color = "gray50") +
  coord_flip() +
  theme_minimal() +
  labs(
    title = "Average Marginal Effects on Choice Probabilities",
    subtitle = "Effect of one standard deviation increase (percentage points)",
    x = NULL,
    y = "Marginal Effect (percentage points)",
    fill = "Outcome"
  ) +
  theme(legend.position = "bottom",
        plot.title = element_text(hjust = 0.5, face = "bold"),
        plot.subtitle = element_text(hjust = 0.5))

print(p2)

ggsave(file.path(FIG_PATH, "marginal_effects.png"), 
       p2, width = 10, height = 8, dpi = 300)

cat("\n✓ Marginal effects plot created\n")
#> 
#> ✓ Marginal effects plot created
################################################################################
# PLOT MTM EFFECTS BY OUTCOME
################################################################################

# Create grid of MTM values
mtm_grid <- seq(
  min(df_mlogit$mtm_btfp_pct_w_z, na.rm = TRUE),
  max(df_mlogit$mtm_btfp_pct_w_z, na.rm = TRUE),
  length.out = 50
)

# Create counterfactual data (hold other variables at mean = 0)
data_cf <- df_mlogit[rep(1, 50), ]
for (i in 1:50) {
  data_cf[i, "mtm_btfp_pct_w_z"] <- mtm_grid[i]
  # Set other standardized variables to mean (= 0)
  for (v in setdiff(key_vars_mlogit, "mtm_btfp_pct_w_z")) {
    if (v %in% names(data_cf)) {
      data_cf[i, v] <- 0
    }
  }
}

# Predict probabilities
pred_mtm <- predict(mlogit_2, newdata = data_cf, type = "probs")

plot_data_mtm <- data.frame(
  mtm_btfp = mtm_grid,
  No_Participation = pred_mtm[, "No_Participation"],
  BTFP_Only = pred_mtm[, "BTFP_Only"],
  DW_Only = pred_mtm[, "DW_Only"],
  Both = pred_mtm[, "Both"]
) %>%
  pivot_longer(-mtm_btfp, names_to = "Outcome", values_to = "Probability")

p3 <- ggplot(plot_data_mtm, aes(x = mtm_btfp, y = Probability, color = Outcome)) +
  geom_line(size = 1.2) +
  theme_minimal() +
  labs(
    title = "Predicted Probability by MTM Loss on BTFP-Eligible Assets",
    subtitle = "All other variables held at mean",
    x = "MTM Loss on BTFP-Eligible Assets (standardized)",
    y = "Predicted Probability",
    color = "Outcome"
  ) +
  scale_y_continuous(labels = percent_format()) +
  theme(legend.position = "bottom",
        plot.title = element_text(hjust = 0.5, face = "bold"),
        plot.subtitle = element_text(hjust = 0.5))

print(p3)

ggsave(file.path(FIG_PATH, "mtm_effects.png"), 
       p3, width = 10, height = 6, dpi = 300)

cat("\n✓ MTM effects plot created\n")
#> 
#> ✓ MTM effects plot created

12 Export Results

################################################################################
# SECTION 16: EXPORT RESULTS
################################################################################

cat("\n")
cat(strrep("=", 80), "\n", sep = "")
#> ================================================================================
cat("EXPORTING RESULTS\n")
#> EXPORTING RESULTS
cat(strrep("=", 80), "\n", sep = "")
#> ================================================================================
# Save regression tables
modelsummary(
  list(
    "LPM (2)" = lpm_2,
    "Logit (2)" = logit_2,
    "MLogit BTFP" = mlogit_2,
    "MLogit DW" = mlogit_2,
    "MLogit Both" = mlogit_2
  ),
  output = file.path(TABLE_PATH, "all_models_comparison.html"),
  estimate = "{estimate}{stars}",
  statistic = "std.error",
  stars = c('*' = 0.10, '**' = 0.05, '***' = 0.01)
)

# Save marginal effects
write.csv(
  ame_logit,
  file.path(TABLE_PATH, "marginal_effects_logit.csv"),
  row.names = FALSE
)

write.csv(
  ame_mlogit,
  file.path(TABLE_PATH, "marginal_effects_mlogit.csv"),
  row.names = FALSE
)

# Save summary statistics
write.csv(
  summ_overall,
  file.path(TABLE_PATH, "summary_statistics_overall.csv"),
  row.names = FALSE
)

write.csv(
  summ_by_outcome,
  file.path(TABLE_PATH, "summary_statistics_by_outcome.csv"),
  row.names = FALSE
)

# Save model objects for later use
saveRDS(lpm_2, file.path(TABLE_PATH, "lpm_main.rds"))
saveRDS(logit_2, file.path(TABLE_PATH, "logit_main.rds"))
saveRDS(mlogit_2, file.path(TABLE_PATH, "mlogit_main.rds"))
saveRDS(list(probit_btfp, probit_dw, probit_fhlb), 
        file.path(TABLE_PATH, "probit_models.rds"))

cat("\n✓ Results exported to:", TABLE_PATH, "\n")
#> 
#> ✓ Results exported to: C:/Users/mferdo2/OneDrive - Louisiana State University/Finance_PhD/DW_Stigma_paper/Liquidity_project_2025/03_documentation/regression_tables/multinomial_analysis
cat("  Tables:\n")
#>   Tables:
cat("    - all_models_comparison.html\n")
#>     - all_models_comparison.html
cat("    - marginal_effects_logit.csv\n")
#>     - marginal_effects_logit.csv
cat("    - marginal_effects_mlogit.csv\n")
#>     - marginal_effects_mlogit.csv
cat("    - summary_statistics_*.csv\n")
#>     - summary_statistics_*.csv
cat("  Model objects:\n")
#>   Model objects:
cat("    - lpm_main.rds\n")
#>     - lpm_main.rds
cat("    - logit_main.rds\n")
#>     - logit_main.rds
cat("    - mlogit_main.rds\n")
#>     - mlogit_main.rds
cat("    - probit_models.rds\n")
#>     - probit_models.rds
cat("  Figures:\n")
#>   Figures:
cat("    - predicted_probabilities_distribution.png\n")
#>     - predicted_probabilities_distribution.png
cat("    - marginal_effects.png\n")
#>     - marginal_effects.png
cat("    - mtm_effects.png\n")
#>     - mtm_effects.png

13 Key Findings Summary

################################################################################
# SECTION 17: KEY FINDINGS SUMMARY
################################################################################

cat("\n")
cat(strrep("=", 80), "\n", sep = "")
#> ================================================================================
cat("KEY FINDINGS SUMMARY\n")
#> KEY FINDINGS SUMMARY
cat(strrep("=", 80), "\n", sep = "")
#> ================================================================================
cat("\n1. CHOICE PATTERNS:\n")
#> 
#> 1. CHOICE PATTERNS:
cat(strrep("-", 80), "\n")
#> --------------------------------------------------------------------------------
cat("  - Most banks did not access Fed facilities during crisis\n")
#>   - Most banks did not access Fed facilities during crisis
cat("  - Among borrowers, BTFP was preferred over DW\n")
#>   - Among borrowers, BTFP was preferred over DW
cat("  - Small fraction used both facilities simultaneously\n")
#>   - Small fraction used both facilities simultaneously
cat("\n2. MTM LOSSES AND BTFP-ELIGIBLE SECURITIES:\n")
#> 
#> 2. MTM LOSSES AND BTFP-ELIGIBLE SECURITIES:
cat(strrep("-", 80), "\n")
#> --------------------------------------------------------------------------------
cat("  - Banks with greater MTM losses on BTFP-eligible securities\n")
#>   - Banks with greater MTM losses on BTFP-eligible securities
cat("    were MORE likely to use BTFP vs DW\n")
#>     were MORE likely to use BTFP vs DW
cat("  - This reflects the par value pricing subsidy\n")
#>   - This reflects the par value pricing subsidy
cat("  - MTM losses on other securities also matter but less so\n")
#>   - MTM losses on other securities also matter but less so
cat("\n3. UNINSURED DEPOSITS:\n")
#> 
#> 3. UNINSURED DEPOSITS:
cat(strrep("-", 80), "\n")
#> --------------------------------------------------------------------------------
cat("  - Higher uninsured deposit ratios increase use of Fed facilities\n")
#>   - Higher uninsured deposit ratios increase use of Fed facilities
cat("  - Run risk (interaction of uninsured deposits × MTM losses)\n")
#>   - Run risk (interaction of uninsured deposits × MTM losses)
cat("    is a key predictor of facility choice\n")
#>     is a key predictor of facility choice
cat("\n4. BANK SIZE:\n")
#> 
#> 4. BANK SIZE:
cat(strrep("-", 80), "\n")
#> --------------------------------------------------------------------------------
cat("  - Larger banks more likely to access facilities\n")
#>   - Larger banks more likely to access facilities
cat("  - Potentially reflects lower stigma and better relationships\n")
#>   - Potentially reflects lower stigma and better relationships
cat("  - Size effects differ between BTFP and DW\n")
#>   - Size effects differ between BTFP and DW
cat("\n5. FHLB AS ALTERNATIVE:\n")
#> 
#> 5. FHLB AS ALTERNATIVE:
cat(strrep("-", 80), "\n")
#> --------------------------------------------------------------------------------
cat("  - Banks with baseline FHLB relationships used it during crisis\n")
#>   - Banks with baseline FHLB relationships used it during crisis
cat("  - Positive correlation between FHLB and Fed facility use\n")
#>   - Positive correlation between FHLB and Fed facility use
cat("  - Suggests complementarity rather than substitution\n")
#>   - Suggests complementarity rather than substitution
cat("\n6. CAPITAL AND LIQUIDITY:\n")
#> 
#> 6. CAPITAL AND LIQUIDITY:
cat(strrep("-", 80), "\n")
#> --------------------------------------------------------------------------------
cat("  - Better-capitalized banks less likely to borrow\n")
#>   - Better-capitalized banks less likely to borrow
cat("  - Banks with more liquid assets less likely to use facilities\n")
#>   - Banks with more liquid assets less likely to use facilities
cat("  - Consistent with these being liquidity backstops\n")
#>   - Consistent with these being liquidity backstops
cat("\n✓ Key findings summarized\n")
#> 
#> ✓ Key findings summarized

14 Session Information

################################################################################
# SESSION INFO
################################################################################

cat("\n")
cat(strrep("=", 80), "\n", sep = "")
#> ================================================================================
cat("SESSION INFORMATION\n")
#> SESSION INFORMATION
cat(strrep("=", 80), "\n", sep = "")
#> ================================================================================
sessionInfo()
#> R version 4.3.1 (2023-06-16 ucrt)
#> Platform: x86_64-w64-mingw32/x64 (64-bit)
#> Running under: Windows 11 x64 (build 26100)
#> 
#> Matrix products: default
#> 
#> 
#> locale:
#> [1] LC_COLLATE=English_United States.utf8 
#> [2] LC_CTYPE=English_United States.utf8   
#> [3] LC_MONETARY=English_United States.utf8
#> [4] LC_NUMERIC=C                          
#> [5] LC_TIME=English_United States.utf8    
#> 
#> time zone: America/Chicago
#> tzcode source: internal
#> 
#> attached base packages:
#> [1] stats     graphics  grDevices utils     datasets  methods   base     
#> 
#> other attached packages:
#>  [1] psych_2.5.6        moments_0.14.1     DescTools_0.99.60  modelsummary_2.3.0
#>  [5] stargazer_5.2.3    kableExtra_1.4.0   knitr_1.50         gridExtra_2.3     
#>  [9] patchwork_1.3.0    scales_1.3.0       ggthemes_5.1.0     ggplot2_3.5.1     
#> [13] broom_1.0.8        lmtest_0.9-40      zoo_1.8-12         sandwich_3.1-1    
#> [17] mvtnorm_1.3-3      mlogit_1.1-3       dfidx_0.2-0        nnet_7.3-19       
#> [21] fixest_0.12.1      readr_2.1.5        stringr_1.5.1      lubridate_1.9.4   
#> [25] tibble_3.2.1       tidyr_1.3.1        dplyr_1.1.4        data.table_1.17.0 
#> 
#> loaded via a namespace (and not attached):
#>  [1] Rdpack_2.6          mnormt_2.1.1        gld_2.6.7          
#>  [4] readxl_1.4.3        rlang_1.1.2         magrittr_2.0.3     
#>  [7] dreamerr_1.4.0      e1071_1.7-14        compiler_4.3.1     
#> [10] systemfonts_1.0.6   vctrs_0.6.4         pkgconfig_2.0.3    
#> [13] crayon_1.5.2        fastmap_1.1.1       backports_1.4.1    
#> [16] labeling_0.4.3      utf8_1.2.4          rmarkdown_2.29     
#> [19] tzdb_0.4.0          haven_2.5.4         ragg_1.3.0         
#> [22] purrr_1.0.2         bit_4.0.5           xfun_0.54          
#> [25] cachem_1.0.8        jsonlite_1.8.7      tinytable_0.15.1   
#> [28] stringmagic_1.1.2   parallel_4.3.1      R6_2.5.1           
#> [31] bslib_0.5.1         tables_0.9.31       stringi_1.7.12     
#> [34] boot_1.3-28.1       jquerylib_0.1.4     cellranger_1.1.0   
#> [37] numDeriv_2016.8-1.1 Rcpp_1.0.12         parameters_0.28.3  
#> [40] Matrix_1.5-4.1      timechange_0.3.0    tidyselect_1.2.1   
#> [43] rstudioapi_0.16.0   yaml_2.3.7          lattice_0.21-8     
#> [46] bayestestR_0.17.0   withr_2.5.2         evaluate_0.23      
#> [49] proxy_0.4-27        xml2_1.3.6          pillar_1.9.0       
#> [52] checkmate_2.3.1     insight_1.4.3       generics_0.1.3     
#> [55] vroom_1.6.5         hms_1.1.3           munsell_0.5.0      
#> [58] rootSolve_1.8.2.4   class_7.3-22        glue_1.6.2         
#> [61] lmom_3.2            tools_4.3.1         forcats_1.0.0      
#> [64] Exact_3.3           fs_1.6.3            grid_4.3.1         
#> [67] rbibutils_2.2.16    datawizard_1.3.0    colorspace_2.1-0   
#> [70] nlme_3.1-162        performance_0.15.3  Formula_1.2-5      
#> [73] cli_3.6.1           textshaping_0.3.7   fansi_1.0.5        
#> [76] expm_1.0-0          viridisLite_0.4.2   svglite_2.1.3      
#> [79] gtable_0.3.6        sass_0.4.9          digest_0.6.33      
#> [82] farver_2.1.1        htmltools_0.5.7     lifecycle_1.0.4    
#> [85] httr_1.4.7          statmod_1.5.0       bit64_4.0.5        
#> [88] MASS_7.3-60

15 Appendix

15.1 Variable Definitions

15.1.1 Dependent Variables

Variable Description
Y / Y_factor Multinomial outcome: 0=No participation, 1=BTFP only, 2=DW only, 3=Both
btfp_user Binary: 1 if borrowed from BTFP during acute crisis
dw_user Binary: 1 if borrowed from DW during acute crisis
btfp_vs_dw Binary (borrowers only): 1 if used BTFP, 0 if DW only
fhlb_crisis Binary: 1 if FHLB borrowing > mean + 2SD

15.1.2 Key Independent Variables

Variable Description Source
mtm_btfp_pct MTM loss on BTFP-eligible securities / Assets (%) Python cleaning
mtm_other_pct MTM loss on other securities / Assets (%) Python cleaning
borrowing_subsidy MTM loss on eligible / Eligible securities (%) Calculated
uninsured_lev Uninsured deposits / Assets (%) Call Reports
pct_uninsured Uninsured deposits / Total deposits (%) Call Reports
run_risk_1 % Uninsured × % MTM loss Calculated
run_risk_1_dummy 1 if both > median Calculated
idcr_1 Coverage ratio (s=0.5) (MV assets - s×Uninsured - Insured) / Insured
idcr_2 Coverage ratio (s=1.0) (MV assets - s×Uninsured - Insured) / Insured
insolvency_1 Equity-based coverage (s=0.5) (Total assets - Total Liability - s×Uninsured×(Total assets/MV Asset) -1)) / Total assets
insolvency_2 Equity-based coverage (s=0.5) (Total assets - Total Liability - s×Uninsured×(Total assets/MV Asset) -1)) / Total assets

15.1.3 Control Variables

Variable Description
log_assets Log(Total assets)
pct_wholesale_liability (Fed funds + Repo + Other borrowed < 1 year) / Liabilities (%)
pct_liquidity_available (Cash + Reverse repo + Fed funds sold) / Assets (%)
securities_ratio Total securities / Assets (%)
loan_to_deposit Total loans / Total deposits (%)
book_equity_to_asset Book equity / Assets (%)
roa Net income (annualized) / Avg assets (%)
fhlb_to_asset FHLB advances / Assets (%)
delta_fhlb Change in FHLB from baseline to crisis

15.2 Model Specifications

15.2.1 Linear Probability Model (LPM)

\[P(BTFP = 1 | X) = X'\beta + \epsilon\]

15.2.2 Logit Model

\[P(BTFP = 1 | X) = \frac{e^{X'\beta}}{1 + e^{X'\beta}}\]

15.2.3 Multinomial Logit

\[P(Y = j | X) = \frac{e^{X'\beta_j}}{\sum_{k=0}^{3} e^{X'\beta_k}}\]

Base category: No participation (\(\beta_0 = 0\))

15.2.4 Trivariate Probit

Latent variables: \[BTFP^* = X'\beta_1 + \epsilon_1\] \[DW^* = X'\beta_2 + \epsilon_2\] \[FHLB^* = X'\beta_3 + \epsilon_3\]

Error correlation: \((\epsilon_1, \epsilon_2, \epsilon_3)' \sim N(0, \Sigma)\)

15.3 Sample Selection

  1. Baseline: 2022Q4 call reports
  2. Exclude: G-SIB banks, failed banks
  3. Require: omo_eligible > 0 (BTFP-eligible collateral)
  4. Crisis period: March 13 - April 30, 2023

End of Analysis