1 Theoretical Framework & Model Map

Four-model identification strategy for emergency lending facility selection.

Model 1 — Main Results (Crisis Period, DSSW Solvency Split)

Solvency is defined using the Drechsler, Savov, Schnabl & Wang (2023, 2025) deposit franchise value (DFV) framework. The DFV captures the present value of below-market deposit funding. In cross-section, the bank-specific DFV per dollar of assets is:

\[\text{DFV}_i = (1 - \beta_i) \times \frac{D_i}{TA_i}\]

where \(\beta_i\) is the bank’s deposit beta (sensitivity of deposit rate to the Fed Funds rate). The full DSSW formula is \(D \times [(1 - \beta) - c/r] \times [1 - 1/(1+r)^T]\) where \(c\) is operating cost (\(\approx 2\%\)), \(r\) is the long rate, and \(T\) is the deposit runoff horizon. Since \(c\), \(r\), and \(T\) are approximately constant in cross-section, all variation comes from \(\beta_i\) and \(D_i/TA_i\), justifying our simplification.

DSSW Adjusted Equity = Book Equity/TA \(-\) MTM Loss/TA \(+\) DFV/TA

A bank is DSSW-solvent if DSSW Adjusted Equity \(\geq 0\), DSSW-insolvent otherwise.

For each borrower type \(\in \{\text{AnyFed, BTFP, DW, FHLB}\}\) and each solvency class \(\in \{\text{Solvent, Insolvent}\}\) (8 regressions):

\[\text{Borrower}_i = \alpha + \beta_1 \text{MTM}_i + \beta_2 \text{Uninsured}_i + \beta_3 (\text{MTM}_i \times \text{Uninsured}_i) + \gamma \mathbf{X}_i + \varepsilon_i\]

Model 2 — BTFP & DW: Crisis vs. Arbitrage (DSSW Solvency Split)

Same specification, estimated separately for BTFP and DW across Crisis and Arbitrage periods, split by DSSW solvency. This tests whether the panic mechanism (MTM \(\times\) Uninsured) operates only during the crisis window.

Model 3 — Deposit Beta Channel

Introduce uninsured_beta (\(\beta^U_i\) from DSSW estimation) and a triple interaction:

\[\text{Borrower}_i = \alpha + \beta_1 \text{MTM}_i + \beta_2 \text{Uninsured}_i + \beta_3 \text{Unins\_Beta}_i + \beta_4 (\text{MTM}_i \times \text{Uninsured}_i) + \beta_5 (\text{MTM}_i \times \text{Uninsured}_i \times \text{Unins\_Beta}_i) + \gamma \mathbf{X}_i + \varepsilon_i\]

Banks with low uninsured beta have stickier (less rate-sensitive) uninsured deposits. The triple interaction tests whether the panic mechanism is amplified when uninsured deposits are also “flighty” (high \(\beta^U\)).

Model 4 — BTFP Complementarity with DW

All BTFP borrowers are DW-eligible by definition. The DW accepts broader collateral but lends at market value; the BTFP lends at par but only against OMO-eligible securities. BTFP complements DW by: (a) removing fire-sale pressure on liquid securities, (b) longer term (up to 1 year vs. overnight), (c) reduced stigma.

Modeling approach: - 4a. Facility Choice (Multinomial): Among all emergency borrowers during Crisis, model the choice \(\{\)BTFP Only, DW Only, Both\(\}\) as a function of bank characteristics. - 4b. Complementarity Test: Among DW borrowers, model additional BTFP usage (\(\text{Both} = 1\) vs. \(\text{DW\_Only} = 0\)). Prediction: banks with larger OMO MTM losses (higher par benefit) choose BTFP as complement. - 4c. Substitution Test: Among all emergency borrowers, model BTFP-only (\(= 1\)) vs. DW-only (\(= 0\)). Prediction: banks with more OMO-eligible collateral and larger par subsidy choose BTFP over DW.


2 SETUP

2.1 Packages

rm(list = ls())

# Core
library(data.table)
library(dplyr)
library(tidyr)
library(stringr)
library(lubridate)
library(purrr)
library(tibble)
library(ggrepel)

# Econometrics
library(fixest)
library(marginaleffects)
library(nnet)
library(broom)

# Tables
library(modelsummary)
library(knitr)
library(kableExtra)

# Statistics
library(DescTools)

# Visualization
library(ggplot2)
library(gridExtra)
library(scales)
library(patchwork)

# I/O
library(readr)
library(readxl)

cat("All packages loaded.\n")
## All packages loaded.

2.2 Helper Functions

# ==============================================================================
# CORE HELPERS
# ==============================================================================

winsorize <- function(x, probs = c(0.025, 0.975)) {
  if (all(is.na(x))) return(x)
  q <- quantile(x, probs = probs, na.rm = TRUE, names = FALSE)
  pmax(pmin(x, q[2]), q[1])
}

standardize_z <- function(x) {
  if (all(is.na(x))) return(x)
  (x - mean(x, na.rm = TRUE)) / sd(x, na.rm = TRUE)
}

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

create_size_category_3 <- function(assets_thousands) {
  assets_millions <- assets_thousands / 1000
  case_when(
    assets_millions >= 100000 ~ "Large (>$100B)",
    assets_millions >= 1000   ~ "Medium ($1B-$100B)",
    TRUE                      ~ "Small (<$1B)"
  )
}
size_levels_3 <- c("Small (<$1B)", "Medium ($1B-$100B)", "Large (>$100B)")

format_pval <- function(p) {
  case_when(is.na(p) ~ "", p < 0.01 ~ "***", p < 0.05 ~ "**", p < 0.10 ~ "*", TRUE ~ "")
}

# ==============================================================================
# FILE I/O
# ==============================================================================

safe_writeLines <- function(text, con, max_retries = 5, wait_sec = 2) {
  for (i in seq_len(max_retries)) {
    result <- tryCatch(
      { writeLines(text, con); TRUE },
      error = function(e) {
        if (i < max_retries) Sys.sleep(wait_sec)
        FALSE
      }
    )
    if (isTRUE(result)) return(invisible(NULL))
  }
  warning("Failed to write ", con, " after ", max_retries, " attempts.")
}

save_table <- function(tbl, filename, caption_text = "") {
  latex_file <- file.path(TABLE_PATH, paste0(filename, ".tex"))
  latex_content <- knitr::kable(
    tbl, format = "latex", caption = caption_text, booktabs = TRUE
  )
  safe_writeLines(as.character(latex_content), latex_file)
  message("Saved: ", filename, ".tex")
}

save_figure <- function(plot_obj, filename, width = 12, height = 8) {
  ggsave(
    file.path(FIG_PATH, paste0(filename, ".pdf")),
    plot = plot_obj, width = width, height = height, device = "pdf"
  )
  message("Saved: ", filename, ".pdf")
}

2.3 Paths

BASE_PATH   <- "C:/Users/mferdo2/OneDrive - Louisiana State University/Finance_PhD/DW_Stigma_paper/Liquidity_project_2025"
DATA_PROC   <- file.path(BASE_PATH, "01_data/processed")
OUTPUT_PATH <- file.path(BASE_PATH, "03_documentation/Four_Model_Analysis")
TABLE_PATH  <- file.path(OUTPUT_PATH, "tables")
FIG_PATH    <- file.path(OUTPUT_PATH, "figures")

for (path in c(TABLE_PATH, FIG_PATH)) {
  if (!dir.exists(path)) dir.create(path, recursive = TRUE)
}

2.4 Key Dates

BASELINE_MAIN <- "2022Q4"
BASELINE_ARB  <- "2023Q3"
BASELINE_WIND <- "2023Q4"

# Analysis windows
CRISIS_START     <- as.Date("2023-03-08")
CRISIS_END       <- as.Date("2023-05-04")
ARB_START        <- as.Date("2023-11-15")
ARB_END          <- as.Date("2024-01-24")
WIND_START       <- as.Date("2024-01-25")
WIND_END         <- as.Date("2024-03-11")
DW_DATA_END      <- as.Date("2023-12-31")

cat("=== DATE CONSTANTS SET ===\n")
## === DATE CONSTANTS SET ===
cat("Crisis window:     ", format(CRISIS_START), "to", format(CRISIS_END), "\n")
## Crisis window:      2023-03-08 to 2023-05-04
cat("Arbitrage window:  ", format(ARB_START), "to", format(ARB_END), "\n")
## Arbitrage window:   2023-11-15 to 2024-01-24

3 DATA LOADING

# --- Call Reports ---
call_q <- read_csv(
  file.path(DATA_PROC, "final_call_gsib.csv"),
  show_col_types = FALSE
) %>%
  mutate(idrssd = as.character(idrssd))

# --- BTFP Loan-Level ---
btfp_loans_raw <- read_csv(
  file.path(DATA_PROC, "btfp_loan_bank_only.csv"),
  show_col_types = FALSE
) %>%
  mutate(
    rssd_id        = as.character(rssd_id),
    btfp_loan_date = mdy(btfp_loan_date)
  )

# --- Discount Window Loan-Level ---
dw_loans_raw <- read_csv(
  file.path(DATA_PROC, "dw_loan_bank_2023.csv"),
  show_col_types = FALSE
) %>%
  mutate(
    rssd_id      = as.character(rssd_id),
    dw_loan_date = ymd(dw_loan_date)
  )

# --- DSSW Deposit Betas ---
dssw_betas <- read_csv(
  file.path(DATA_PROC, "dssw_deposit_betas.csv"),
  show_col_types = FALSE
) %>%
  mutate(idrssd = as.character(idrssd))

# Pre-split betas by estimation period
dssw_beta_2022q4 <- dssw_betas %>% filter(estimation_date == "2022Q4") %>%
  select(idrssd, beta_overall, beta_insured_w, beta_uninsured_w,
         gamma_hat, alpha_hat)
dssw_beta_2023q4 <- dssw_betas %>% filter(estimation_date == "2023Q4") %>%
  select(idrssd, beta_overall, beta_insured_w, beta_uninsured_w,
         gamma_hat, alpha_hat)

cat("=== DATA LOADED ===\n")
## === DATA LOADED ===
cat("Call Report:      ", nrow(call_q), "obs |",
    n_distinct(call_q$idrssd), "banks\n")
## Call Report:       75989 obs | 5074 banks
cat("DSSW Betas:       ", nrow(dssw_betas), "obs |",
    n_distinct(dssw_betas$idrssd), "banks\n")
## DSSW Betas:        13588 obs | 4660 banks
cat("BTFP Loans:       ", nrow(btfp_loans_raw), "loans\n")
## BTFP Loans:        6734 loans
cat("DW Loans:         ", nrow(dw_loans_raw), "loans\n")
## DW Loans:          10008 loans

3.1 Exclusions

excluded_banks <- call_q %>%
  filter(period == BASELINE_MAIN, failed_bank == 1 | gsib == 1) %>%
  pull(idrssd)

cat("Excluded banks (failed + G-SIBs):", length(excluded_banks), "\n")
## Excluded banks (failed + G-SIBs): 41
btfp_loans <- btfp_loans_raw %>% filter(!rssd_id %in% excluded_banks)
dw_loans   <- dw_loans_raw   %>% filter(!rssd_id %in% excluded_banks)

4 BORROWER INDICATOR FACTORY

create_borrower_indicator <- function(loans_df, date_col, id_col, amount_col,
                                      start_date, end_date, prefix) {
  loans_df %>%
    filter(
      !!sym(date_col) >= start_date,
      !!sym(date_col) <= end_date
    ) %>%
    group_by(!!sym(id_col)) %>%
    summarise(
      "{prefix}"       := 1L,
      "{prefix}_amt"   := sum(!!sym(amount_col), na.rm = TRUE),
      "{prefix}_first" := min(!!sym(date_col)),
      .groups = "drop"
    ) %>%
    rename(idrssd = !!sym(id_col))
}

# --- BTFP ---
btfp_crisis <- create_borrower_indicator(
  btfp_loans, "btfp_loan_date", "rssd_id", "btfp_loan_amount",
  CRISIS_START, CRISIS_END, "btfp_crisis"
)
btfp_arb <- create_borrower_indicator(
  btfp_loans, "btfp_loan_date", "rssd_id", "btfp_loan_amount",
  ARB_START, ARB_END, "btfp_arb"
)

# --- DW ---
dw_crisis <- create_borrower_indicator(
  dw_loans, "dw_loan_date", "rssd_id", "dw_loan_amount",
  CRISIS_START, min(CRISIS_END, DW_DATA_END), "dw_crisis"
)
dw_arb <- create_borrower_indicator(
  dw_loans, "dw_loan_date", "rssd_id", "dw_loan_amount",
  ARB_START, DW_DATA_END, "dw_arb"
)

cat("=== BORROWER COUNTS ===\n")
## === BORROWER COUNTS ===
cat("BTFP:  Crisis=", nrow(btfp_crisis), " Arb=", nrow(btfp_arb), "\n")
## BTFP:  Crisis= 526  Arb= 780
cat("DW:    Crisis=", nrow(dw_crisis), " Arb=", nrow(dw_arb), "\n")
## DW:    Crisis= 459  Arb= 389

5 VARIABLE CONSTRUCTION

# ==============================================================================
# Variable naming convention:
#   *_raw  — original scale (for descriptive tables)
#   *_w    — winsorized at [2.5%, 97.5%]
#   *      — z-standardized (mean 0, SD 1) — used in all regressions
# ==============================================================================
construct_analysis_vars <- function(baseline_data) {
  baseline_data %>%
    mutate(

      # ======================================================================
      # 1. RAW VARIABLES
      # ======================================================================
      mtm_total_raw         = mtm_loss_to_total_asset,
      mtm_btfp_raw          = mtm_loss_omo_eligible_to_total_asset,
      mtm_other_raw         = mtm_loss_non_omo_eligible_to_total_asset,
      uninsured_lev_raw     = uninsured_deposit_to_total_asset,
      insured_lev_raw       = r_insured_deposit,
      uninsured_share_raw   = uninsured_to_deposit,

      ln_assets_raw         = log(total_asset),
      cash_ratio_raw        = cash_to_total_asset,
      securities_ratio_raw  = security_to_total_asset,
      loan_ratio_raw        = total_loan_to_total_asset,
      book_equity_ratio_raw = book_equity_to_total_asset,
      tier1_ratio_raw       = tier1cap_to_total_asset,
      roa_raw               = roa,
      fhlb_ratio_raw        = fhlb_to_total_asset,
      loan_to_deposit_raw   = loan_to_deposit,
      wholesale_raw         = safe_div(
        fed_fund_purchase + repo +
          replace_na(other_borrowed_less_than_1yr, 0),
        total_liability, 0
      ) * 100,

      uninsured_outflow_raw = change_uninsured_fwd_q,
      insured_outflow_raw   = change_insured_deposit_fwd_q,
      total_outflow_raw     = change_total_deposit_fwd_q,

      # ======================================================================
      # 2. SOLVENCY MEASURES
      # ======================================================================

      # Jiang-style Adjusted Equity
      adjusted_equity_raw = book_equity_to_total_asset - mtm_loss_to_total_asset,

      # IDCR measures
      mv_assets = total_asset * (1 - mtm_loss_to_total_asset / 100),
      idcr_1 = safe_div(
        mv_assets - 0.5 * uninsured_deposit - insured_deposit,
        insured_deposit, NA_real_
      ),
      idcr_2 = safe_div(
        mv_assets - uninsured_deposit - insured_deposit,
        insured_deposit, NA_real_
      ),

      # Binary solvency indicators (Jiang-style)
      mtm_insolvent       = as.integer(adjusted_equity_raw < 0),
      mtm_solvent         = as.integer(adjusted_equity_raw >= 0),
      insolvent_idcr_s50  = as.integer(idcr_1 < 0),
      insolvent_idcr_s100 = as.integer(idcr_2 < 0),

      # ======================================================================
      # 2b. DSSW DEPOSIT FRANCHISE VALUE
      #
      # Full DSSW (2023/2025) formula:
      #   F = D × [(1-β) - c/r] × [1 - 1/(1+r)^T]
      #
      # Cross-sectional simplification (c, r, T constant across banks):
      #   DFV_i ∝ (1 - β_i) × D_i / TA_i
      #
      # This captures all bank-specific variation for regressions.
      # DSSW Adjusted Equity = Book Equity/TA - MTM Loss/TA + DFV/TA
      # ======================================================================

      dfv_raw = ifelse(
        !is.na(beta_overall),
        (1 - beta_overall) * (dom_deposit / total_asset) * 100,
        NA_real_
      ),

      adjusted_equity_dssw_raw = ifelse(
        !is.na(dfv_raw),
        book_equity_to_total_asset - mtm_loss_to_total_asset + dfv_raw,
        NA_real_
      ),

      # DSSW solvency indicators
      dssw_insolvent = as.integer(!is.na(adjusted_equity_dssw_raw) &
                                   adjusted_equity_dssw_raw < 0),
      dssw_solvent   = as.integer(!is.na(adjusted_equity_dssw_raw) &
                                   adjusted_equity_dssw_raw >= 0),

      # ======================================================================
      # 2c. UNINSURED DEPOSIT BETA (for Model 3)
      # ======================================================================

      uninsured_beta_raw = ifelse(
        !is.na(beta_uninsured_w), beta_uninsured_w, NA_real_
      ),

      # ======================================================================
      # 3. WINSORIZED VARIABLES
      # ======================================================================

      mtm_total_w         = winsorize(mtm_total_raw),
      mtm_btfp_w          = winsorize(mtm_btfp_raw),
      mtm_other_w         = winsorize(mtm_other_raw),
      uninsured_lev_w     = winsorize(uninsured_lev_raw),
      insured_lev_w       = winsorize(r_insured_deposit),
      adjusted_equity_w   = winsorize(adjusted_equity_raw),

      dfv_w                  = winsorize(dfv_raw),
      adjusted_equity_dssw_w = winsorize(adjusted_equity_dssw_raw),
      uninsured_beta_w       = winsorize(uninsured_beta_raw),

      ln_assets_w           = winsorize(ln_assets_raw),
      cash_ratio_w          = winsorize(cash_ratio_raw),
      book_equity_ratio_w   = winsorize(book_equity_ratio_raw),
      roa_w                 = winsorize(roa_raw),
      loan_to_deposit_w     = winsorize(loan_to_deposit_raw),
      wholesale_w           = winsorize(wholesale_raw),

      uninsured_outflow_w   = winsorize(uninsured_outflow_raw),
      insured_outflow_w     = winsorize(insured_outflow_raw),
      total_outflow_w       = winsorize(total_outflow_raw),

      # ======================================================================
      # 4. Z-STANDARDIZED VARIABLES
      # ======================================================================

      mtm_total           = standardize_z(mtm_total_w),
      mtm_btfp            = standardize_z(mtm_btfp_w),
      mtm_other           = standardize_z(mtm_other_w),
      uninsured_lev       = standardize_z(uninsured_lev_w),
      insured_lev         = standardize_z(insured_lev_w),
      adjusted_equity     = standardize_z(adjusted_equity_w),

      dfv                    = standardize_z(dfv_w),
      adjusted_equity_dssw   = standardize_z(adjusted_equity_dssw_w),
      uninsured_beta         = standardize_z(uninsured_beta_w),

      ln_assets           = standardize_z(ln_assets_w),
      cash_ratio          = standardize_z(cash_ratio_w),
      book_equity_ratio   = standardize_z(book_equity_ratio_w),
      roa                 = standardize_z(roa_w),
      loan_to_deposit     = standardize_z(loan_to_deposit_w),
      wholesale           = standardize_z(wholesale_w),

      uninsured_outflow   = standardize_z(uninsured_outflow_w),
      insured_outflow     = standardize_z(insured_outflow_w),
      total_outflow       = standardize_z(total_outflow_w),

      # ======================================================================
      # 5. INTERACTION TERMS
      # ======================================================================

      # Base: MTM × Uninsured
      mtm_x_uninsured          = mtm_total * uninsured_lev,
      mtm_x_insured            = mtm_total * insured_lev,

      # DSSW: DSSW AE × Uninsured
      dssw_ae_x_uninsured = adjusted_equity_dssw * uninsured_lev,

      # Model 3: Deposit beta interactions
      mtm_x_unins_beta         = mtm_total * uninsured_beta,
      unins_x_unins_beta       = uninsured_lev * uninsured_beta,
      mtm_x_unins_x_beta      = mtm_total * uninsured_lev * uninsured_beta,

      # ======================================================================
      # 6. PAR BENEFIT AND COLLATERAL CAPACITY
      # ======================================================================

      par_benefit_raw = safe_div(
        mtm_btfp_raw,
        mtm_btfp_raw + 100 * safe_div(omo_eligible, total_asset * 1000, 0),
        NA_real_
      ),
      collateral_capacity_raw = safe_div(
        omo_eligible, total_asset * 1000, 0
      ) * 100,

      # ======================================================================
      # 7. CATEGORICAL VARIABLES
      # ======================================================================

      size_cat = factor(
        create_size_category_3(total_asset),
        levels = size_levels_3
      ),

      state        = if ("state"        %in% names(.)) state        else NA_character_,
      fed_district = if ("fed_district" %in% names(.)) fed_district else NA_character_

    ) %>%
    mutate(
      par_benefit_w   = winsorize(par_benefit_raw),
      par_benefit     = standardize_z(par_benefit_w),
      par_x_uninsured = par_benefit * uninsured_lev,

      collateral_capacity_w = winsorize(collateral_capacity_raw),
      collateral_capacity   = standardize_z(collateral_capacity_w)
    )
}

6 BUILD BASELINE DATASETS

# --- 2022Q4 Baseline (Crisis analysis) ---
df_2022q4 <- call_q %>%
  filter(
    period  == BASELINE_MAIN,
    !idrssd %in% excluded_banks,
    !is.na(omo_eligible) & omo_eligible > 0
  ) %>%
  left_join(dssw_beta_2022q4, by = "idrssd") %>%
  construct_analysis_vars()

# --- 2023Q3 Baseline (Arbitrage period) ---
df_2023q3 <- call_q %>%
  filter(
    period  == BASELINE_ARB,
    !idrssd %in% excluded_banks,
    !is.na(omo_eligible) & omo_eligible > 0
  ) %>%
  left_join(dssw_beta_2022q4, by = "idrssd") %>%
  construct_analysis_vars()

cat("=== BASELINE DATASETS ===\n")
## === BASELINE DATASETS ===
cat("2022Q4:", nrow(df_2022q4), "banks |",
    "DSSW Insolvent:", sum(df_2022q4$dssw_insolvent, na.rm = TRUE),
    "| Beta coverage:", sum(!is.na(df_2022q4$beta_overall)),
    "| Uninsured Beta coverage:", sum(!is.na(df_2022q4$uninsured_beta_raw)), "\n")
## 2022Q4: 4292 banks | DSSW Insolvent: 0 | Beta coverage: 4226 | Uninsured Beta coverage: 4226
cat("2023Q3:", nrow(df_2023q3), "banks\n")
## 2023Q3: 4214 banks

7 BUILD PERIOD DATASETS

# ==============================================================================
# JOIN_ALL_BORROWERS HELPER
# ==============================================================================

join_all_borrowers <- function(df_base, btfp_df, dw_df, btfp_var, dw_var) {
  df_base %>%
    left_join(btfp_df %>% select(idrssd, starts_with(btfp_var)), by = "idrssd") %>%
    left_join(dw_df   %>% select(idrssd, starts_with(dw_var)),   by = "idrssd") %>%
    mutate(
      "{btfp_var}" := replace_na(!!sym(btfp_var), 0L),
      "{dw_var}"   := replace_na(!!sym(dw_var),   0L),
      fhlb_user = as.integer(abnormal_fhlb_borrowing_10pct == 1),

      any_fed  = as.integer(!!sym(btfp_var) == 1 | !!sym(dw_var) == 1),
      both_fed = as.integer(!!sym(btfp_var) == 1 & !!sym(dw_var) == 1),

      user_group = factor(
        case_when(
          both_fed == 1 ~ "Both",
          !!sym(btfp_var) == 1 ~ "BTFP_Only",
          !!sym(dw_var)   == 1 ~ "DW_Only",
          TRUE                 ~ "Neither"
        ),
        levels = c("Neither", "BTFP_Only", "DW_Only", "Both")
      ),
      non_user = as.integer(any_fed == 0 & fhlb_user == 0)
    )
}

# ==============================================================================
# CRISIS PERIOD
# ==============================================================================

df_crisis <- join_all_borrowers(
  df_2022q4, btfp_crisis, dw_crisis, "btfp_crisis", "dw_crisis"
) %>%
  mutate(
    btfp_pct = ifelse(
      btfp_crisis == 1 & btfp_crisis_amt > 0,
      100 * btfp_crisis_amt / (total_asset * 1000), NA_real_
    ),
    dw_pct = ifelse(
      dw_crisis == 1 & dw_crisis_amt > 0,
      100 * dw_crisis_amt / (total_asset * 1000), NA_real_
    ),
    log_btfp_amt = ifelse(
      btfp_crisis == 1 & btfp_crisis_amt > 0, log(btfp_crisis_amt), NA_real_
    ),
    log_dw_amt = ifelse(
      dw_crisis == 1 & dw_crisis_amt > 0, log(dw_crisis_amt), NA_real_
    )
  )

# ==============================================================================
# ARBITRAGE PERIOD
# ==============================================================================

df_arb <- df_2023q3 %>%
  left_join(btfp_arb %>% select(idrssd, btfp_arb, btfp_arb_amt), by = "idrssd") %>%
  left_join(dw_arb   %>% select(idrssd, dw_arb),                 by = "idrssd") %>%
  mutate(
    btfp_arb   = replace_na(btfp_arb, 0L),
    dw_arb     = replace_na(dw_arb,   0L),
    fhlb_user  = as.integer(abnormal_fhlb_borrowing_10pct == 1),
    any_fed    = as.integer(btfp_arb == 1 | dw_arb == 1),
    both_fed   = as.integer(btfp_arb == 1 & dw_arb == 1),
    non_user   = as.integer(any_fed == 0 & fhlb_user == 0),
    user_group = factor(
      case_when(
        both_fed == 1  ~ "Both",
        btfp_arb == 1  ~ "BTFP_Only",
        dw_arb   == 1  ~ "DW_Only",
        TRUE           ~ "Neither"
      ),
      levels = c("Neither", "BTFP_Only", "DW_Only", "Both")
    )
  )

cat("=== PERIOD DATASET COUNTS ===\n")
## === PERIOD DATASET COUNTS ===
cat("Crisis:    ", nrow(df_crisis),
    " | BTFP=1:", sum(df_crisis$btfp_crisis),
    " | DW=1:",   sum(df_crisis$dw_crisis),
    " | Both:",   sum(df_crisis$both_fed),
    " | AnyFed:", sum(df_crisis$any_fed), "\n")
## Crisis:     4292  | BTFP=1: 501  | DW=1: 433  | Both: 106  | AnyFed: 828
cat("Arb:       ", nrow(df_arb),
    " | BTFP=1:", sum(df_arb$btfp_arb),
    " | DW=1:",   sum(df_arb$dw_arb), "\n")
## Arb:        4214  | BTFP=1: 749  | DW=1: 362

8 REGRESSION SAMPLES

# ==============================================================================
# PURE COMPARISON SAMPLES (Borrower vs. Pure Non-Borrower)
# ==============================================================================

# --- Crisis Period ---
df_btfp_s   <- df_crisis %>% filter(btfp_crisis == 1 | non_user == 1)
df_dw_s     <- df_crisis %>% filter(dw_crisis   == 1 | non_user == 1)
df_anyfed_s <- df_crisis %>% filter(any_fed     == 1 | non_user == 1)
df_fhlb_s   <- df_crisis %>% filter(fhlb_user   == 1 | non_user == 1)

# --- DSSW Solvency Splits: Crisis (for Model 1) ---
df_dssw_btfp_sol <- df_btfp_s   %>% filter(dssw_solvent   == 1)
df_dssw_btfp_ins <- df_btfp_s   %>% filter(dssw_insolvent == 1)
df_dssw_dw_sol   <- df_dw_s     %>% filter(dssw_solvent   == 1)
df_dssw_dw_ins   <- df_dw_s     %>% filter(dssw_insolvent == 1)
df_dssw_any_sol  <- df_anyfed_s %>% filter(dssw_solvent   == 1)
df_dssw_any_ins  <- df_anyfed_s %>% filter(dssw_insolvent == 1)
df_dssw_fhlb_sol <- df_fhlb_s   %>% filter(dssw_solvent   == 1)
df_dssw_fhlb_ins <- df_fhlb_s   %>% filter(dssw_insolvent == 1)

# --- Arbitrage Period (for Model 2) ---
df_btfp_arb_s <- df_arb %>% filter(btfp_arb == 1 | non_user == 1)
df_dw_arb_s   <- df_arb %>% filter(dw_arb   == 1 | non_user == 1)

df_dssw_btfp_arb_sol <- df_btfp_arb_s %>% filter(dssw_solvent   == 1)
df_dssw_btfp_arb_ins <- df_btfp_arb_s %>% filter(dssw_insolvent == 1)
df_dssw_dw_arb_sol   <- df_dw_arb_s   %>% filter(dssw_solvent   == 1)
df_dssw_dw_arb_ins   <- df_dw_arb_s   %>% filter(dssw_insolvent == 1)

# --- Model 3: Deposit Beta samples (need non-missing uninsured_beta) ---
df_beta_btfp_s   <- df_btfp_s   %>% filter(!is.na(uninsured_beta_w))
df_beta_dw_s     <- df_dw_s     %>% filter(!is.na(uninsured_beta_w))
df_beta_anyfed_s <- df_anyfed_s %>% filter(!is.na(uninsured_beta_w))
df_beta_fhlb_s   <- df_fhlb_s   %>% filter(!is.na(uninsured_beta_w))

# --- Model 4: Facility Choice samples (Crisis emergency borrowers only) ---
# 4a. Multinomial: Among all emergency borrowers
df_emerg_borrowers <- df_crisis %>%
  filter(any_fed == 1) %>%
  mutate(
    facility_choice = factor(
      case_when(
        both_fed == 1       ~ "Both",
        btfp_crisis == 1    ~ "BTFP_Only",
        dw_crisis == 1      ~ "DW_Only"
      ),
      levels = c("DW_Only", "BTFP_Only", "Both")
    )
  )

# 4b. Complementarity: Among DW borrowers, did they ALSO use BTFP?
df_dw_complement <- df_crisis %>%
  filter(dw_crisis == 1) %>%
  mutate(also_btfp = as.integer(btfp_crisis == 1))

# 4c. Substitution: BTFP-only vs. DW-only
df_substitution <- df_crisis %>%
  filter(user_group %in% c("BTFP_Only", "DW_Only")) %>%
  mutate(chose_btfp = as.integer(user_group == "BTFP_Only"))

cat("=== REGRESSION SAMPLES ===\n")
## === REGRESSION SAMPLES ===
cat("Model 1 (Crisis DSSW splits):\n")
## Model 1 (Crisis DSSW splits):
cat("  BTFP — Sol:", nrow(df_dssw_btfp_sol), "| Ins:", nrow(df_dssw_btfp_ins), "\n")
##   BTFP — Sol: 3665 | Ins: 0
cat("  DW   — Sol:", nrow(df_dssw_dw_sol),   "| Ins:", nrow(df_dssw_dw_ins), "\n")
##   DW   — Sol: 3599 | Ins: 0
cat("  Any  — Sol:", nrow(df_dssw_any_sol),   "| Ins:", nrow(df_dssw_any_ins), "\n")
##   Any  — Sol: 3991 | Ins: 0
cat("  FHLB — Sol:", nrow(df_dssw_fhlb_sol),  "| Ins:", nrow(df_dssw_fhlb_ins), "\n")
##   FHLB — Sol: 3468 | Ins: 0
cat("\nModel 2 (Arb DSSW splits):\n")
## 
## Model 2 (Arb DSSW splits):
cat("  BTFP Arb — Sol:", nrow(df_dssw_btfp_arb_sol), "| Ins:", nrow(df_dssw_btfp_arb_ins), "\n")
##   BTFP Arb — Sol: 3748 | Ins: 0
cat("  DW Arb   — Sol:", nrow(df_dssw_dw_arb_sol),   "| Ins:", nrow(df_dssw_dw_arb_ins), "\n")
##   DW Arb   — Sol: 3364 | Ins: 0
cat("\nModel 3 (Beta coverage):\n")
## 
## Model 3 (Beta coverage):
cat("  BTFP:", nrow(df_beta_btfp_s), "| DW:", nrow(df_beta_dw_s),
    "| Any:", nrow(df_beta_anyfed_s), "| FHLB:", nrow(df_beta_fhlb_s), "\n")
##   BTFP: 3665 | DW: 3599 | Any: 3991 | FHLB: 3468
cat("\nModel 4 (Facility choice):\n")
## 
## Model 4 (Facility choice):
cat("  Emergency borrowers:", nrow(df_emerg_borrowers), "\n")
##   Emergency borrowers: 828
cat("  DW borrowers (complement test):", nrow(df_dw_complement), "\n")
##   DW borrowers (complement test): 433
cat("  BTFP-only vs DW-only (substitution):", nrow(df_substitution), "\n")
##   BTFP-only vs DW-only (substitution): 722

9 MODEL INFRASTRUCTURE

# ==============================================================================
# CONTROLS
# ==============================================================================

CONTROLS <- "ln_assets + cash_ratio + loan_to_deposit + book_equity_ratio + wholesale + roa"

# ==============================================================================
# FORMULA STRINGS
# ==============================================================================

# Model 1: Base specification (same for all 4 models, varies by sample)
EXPL_BASE <- "mtm_total + uninsured_lev + mtm_x_uninsured"

# Model 3: Deposit beta channel (triple interaction)
EXPL_BETA_FULL <- paste0(
  "mtm_total + uninsured_lev + uninsured_beta + ",
  "mtm_x_uninsured + mtm_x_unins_beta + unins_x_unins_beta + ",
  "mtm_x_unins_x_beta"
)

# Model 3 nested: without triple (for comparison)
EXPL_BETA_NOINT <- paste0(
  "mtm_total + uninsured_lev + uninsured_beta + ",
  "mtm_x_uninsured + mtm_x_unins_beta + unins_x_unins_beta"
)

# Model 4: Facility choice — par benefit + collateral capacity
EXPL_FACILITY <- "mtm_total + uninsured_lev + mtm_x_uninsured + par_benefit + collateral_capacity"

# ==============================================================================
# FIXEST VARIABLE DICTIONARY
# ==============================================================================

setFixest_dict(c(
  mtm_total             = "MTM Loss (z)",
  uninsured_lev         = "Uninsured Leverage (z)",
  insured_lev           = "Insured Leverage (z)",
  adjusted_equity_dssw  = "DSSW Adj.\\ Equity (z)",
  dfv                   = "Deposit Franchise Value (z)",
  dssw_ae_x_uninsured   = "DSSW AE $\\times$ Uninsured",
  uninsured_beta        = "Uninsured $\\beta$ (z)",
  mtm_x_uninsured       = "MTM $\\times$ Uninsured",
  mtm_x_insured         = "MTM $\\times$ Insured",
  mtm_x_unins_beta      = "MTM $\\times$ Unins. $\\beta$",
  unins_x_unins_beta    = "Uninsured $\\times$ Unins. $\\beta$",
  mtm_x_unins_x_beta   = "MTM $\\times$ Uninsured $\\times$ Unins. $\\beta$",
  par_benefit           = "Par Benefit (z)",
  collateral_capacity   = "OMO Collateral (z)",
  par_x_uninsured       = "Par $\\times$ Uninsured",
  ln_assets             = "Log(Assets)",
  cash_ratio            = "Cash Ratio",
  loan_to_deposit       = "Loan-to-Deposit",
  book_equity_ratio     = "Book Equity Ratio",
  wholesale             = "Wholesale Funding",
  roa                   = "ROA"
))

COEF_ORDER <- c(
  "Constant",
  "MTM Loss",
  "Uninsured Leverage",
  "Uninsured.*beta",
  "MTM.*Uninsured",
  "MTM.*Unins.*beta",
  "Uninsured.*Unins.*beta",
  "MTM.*Uninsured.*Unins",
  "Par Benefit",
  "OMO Collateral",
  "DSSW Adj.*Equity",
  "Deposit Franchise"
)

# ==============================================================================
# GENERIC MODEL RUNNER
# ==============================================================================

run_model <- function(data, dv, explanatory,
                      family_type = "lpm", controls = CONTROLS) {
  ff <- as.formula(paste(dv, "~", explanatory, "+", controls))
  if (family_type == "lpm") {
    feols(ff, data = data, vcov = "hetero")
  } else if (family_type == "logit") {
    feglm(ff, data = data, family = binomial("logit"), vcov = "hetero")
  } else {
    stop("family_type must be either 'lpm' or 'logit'")
  }
}

# ==============================================================================
# SAFE MODEL RUNNER (catches errors for small samples)
# ==============================================================================

safe_run_model <- function(data, dv, explanatory, family_type = "lpm",
                           controls = CONTROLS, min_n = 30) {
  n_obs <- sum(!is.na(data[[dv]]))
  n_dv1 <- sum(data[[dv]] == 1, na.rm = TRUE)

  if (n_obs < min_n || n_dv1 < 5) {
    message("  ⚠ Skipping: N=", n_obs, ", DV=1 count=", n_dv1,
            " (below threshold for ", dv, ")")
    return(NULL)
  }

  tryCatch(
    run_model(data, dv, explanatory, family_type, controls),
    error = function(e) {
      message("  ⚠ Model failed for ", dv, ": ", e$message)
      return(NULL)
    }
  )
}

# ==============================================================================
# ETABLE SAVER
# ==============================================================================

save_etable <- function(models, filename, title_text, notes_text,
                        fitstat_use = ~ n + r2,
                        extra_lines = NULL) {
  # Remove NULLs from model list
  models <- models[!sapply(models, is.null)]
  if (length(models) == 0) {
    message("  ⚠ No valid models for ", filename, ". Skipping save.")
    return(invisible(NULL))
  }

  etable(
    models,
    title      = title_text,
    notes      = notes_text,
    fitstat    = fitstat_use,
    order      = COEF_ORDER,
    extralines = extra_lines,
    se.below   = TRUE,
    tex        = TRUE,
    file       = file.path(TABLE_PATH, paste0(filename, ".tex")),
    replace    = TRUE,
    style.tex  = style.tex("aer")
  )
  message("Saved: ", filename, ".tex")
}

# ==============================================================================
# THEME
# ==============================================================================

theme_paper <- theme_minimal(base_size = 12) +
  theme(
    plot.title       = element_text(face = "bold", size = 13, hjust = 0),
    plot.subtitle    = element_text(size = 10, color = "grey40", hjust = 0),
    legend.position  = "bottom",
    panel.grid.minor = element_blank(),
    strip.text       = element_text(face = "bold", size = 11)
  )

pal_user <- c(
  "DW"                = "#D62828",
  "BTFP"              = "#003049",
  "FHLB"              = "#F77F00",
  "Pure Non-Borrower" = "grey70",
  "Both"              = "#7209B7",
  "AnyFed"            = "#2A9D8F"
)

cat("=== MODEL INFRASTRUCTURE READY ===\n")
## === MODEL INFRASTRUCTURE READY ===

10 MODEL 1: Main Results — DSSW Solvency Split (Crisis Period)

10.1 8 Regressions: Solvent vs. Insolvent × 4 Borrower Types

# ==============================================================================
# MODEL 1: EXTENSIVE MARGIN — CRISIS PERIOD
# 8 regressions: {AnyFed, BTFP, DW, FHLB} × {DSSW Solvent, DSSW Insolvent}
#
# Specification: Borrower = MTM + Uninsured + (MTM × Uninsured) + Controls
# Solvency: DSSW Adjusted Equity = Book Equity/TA - MTM/TA + DFV/TA ≥ 0
# ==============================================================================

cat("=== MODEL 1: MAIN RESULTS (CRISIS, DSSW SOLVENCY) ===\n\n")
## === MODEL 1: MAIN RESULTS (CRISIS, DSSW SOLVENCY) ===
# --- AnyFed ---
mod1_any_sol <- safe_run_model(df_dssw_any_sol,  "any_fed",     EXPL_BASE)
mod1_any_ins <- safe_run_model(df_dssw_any_ins,  "any_fed",     EXPL_BASE)

# --- BTFP ---
mod1_btfp_sol <- safe_run_model(df_dssw_btfp_sol, "btfp_crisis", EXPL_BASE)
mod1_btfp_ins <- safe_run_model(df_dssw_btfp_ins, "btfp_crisis", EXPL_BASE)

# --- DW ---
mod1_dw_sol <- safe_run_model(df_dssw_dw_sol, "dw_crisis", EXPL_BASE)
mod1_dw_ins <- safe_run_model(df_dssw_dw_ins, "dw_crisis", EXPL_BASE)

# --- FHLB ---
mod1_fhlb_sol <- safe_run_model(df_dssw_fhlb_sol, "fhlb_user", EXPL_BASE)
mod1_fhlb_ins <- safe_run_model(df_dssw_fhlb_ins, "fhlb_user", EXPL_BASE)

models_m1 <- list(
  "Any (Sol)"  = mod1_any_sol,
  "Any (Ins)"  = mod1_any_ins,
  "BTFP (Sol)" = mod1_btfp_sol,
  "BTFP (Ins)" = mod1_btfp_ins,
  "DW (Sol)"   = mod1_dw_sol,
  "DW (Ins)"   = mod1_dw_ins,
  "FHLB (Sol)" = mod1_fhlb_sol,
  "FHLB (Ins)" = mod1_fhlb_ins
)

# DV means
calc_dv_mean <- function(df, dv) round(mean(df[[dv]], na.rm = TRUE), 3)

save_etable(
  models     = models_m1,
  filename   = "M1_main_dssw_solvency_crisis",
  title_text = "Model 1: Emergency Facility Selection by DSSW Solvency (Crisis Period)",
  notes_text = paste0(
    "LPM. DV = 1 if bank borrowed from the facility during the Crisis Period ",
    "(Mar 8--May 4, 2023), 0 if pure non-borrower. ",
    "Solvency: DSSW Adjusted Equity = Book Equity/TA $-$ MTM Loss/TA ",
    "$+$ DFV/TA, where DFV $= (1 - \\beta_i) \\times$ Deposits/TA ",
    "following Drechsler, Savov, Schnabl \\& Wang (2023/2025). ",
    "Solvent: DSSW AE $\\geq 0$; Insolvent: DSSW AE $< 0$. ",
    "Robust SEs. z-standardized regressors."
  ),
  extra_lines = list(
    c("Solvency", "Solvent", "Insolvent", "Solvent", "Insolvent",
      "Solvent", "Insolvent", "Solvent", "Insolvent")
  )
)

cat("=== MODEL 1 RESULTS ===\n")
## === MODEL 1 RESULTS ===
etable(models_m1[!sapply(models_m1, is.null)],
       fitstat = ~ n + r2, se.below = TRUE)
##                         Any (Sol)  BTFP (Sol)   DW (Sol) FHLB (Sol)
## Dependent Var.:           any_fed btfp_crisis  dw_crisis  fhlb_user
##                                                                    
## Constant                0.2071***   0.1423***  0.1267***  0.0897***
##                        (0.0061)    (0.0056)   (0.0054)   (0.0050)  
## MTM Loss (z)            0.0295***   0.0243***  0.0151*    0.0042   
##                        (0.0070)    (0.0062)   (0.0061)   (0.0056)  
## Uninsured Leverage (z)  0.0199**    0.0219**   0.0119     0.0065   
##                        (0.0077)    (0.0071)   (0.0068)   (0.0052)  
## MTM $\times$ Uninsured  0.0189**    0.0181***  0.0165**  -0.0052   
##                        (0.0059)    (0.0054)   (0.0052)   (0.0045)  
## Log(Assets)             0.1078***   0.0724***  0.0934***  0.0277***
##                        (0.0083)    (0.0078)   (0.0078)   (0.0065)  
## Cash Ratio             -0.0241***  -0.0283*** -0.0036    -0.0207***
##                        (0.0063)    (0.0050)   (0.0055)   (0.0040)  
## Loan-to-Deposit        -0.0016     -0.0085     2.01e-5    0.0256***
##                        (0.0071)    (0.0062)   (0.0061)   (0.0054)  
## Book Equity Ratio      -0.0150*    -0.0136**  -0.0012     0.0082   
##                        (0.0059)    (0.0051)   (0.0048)   (0.0045)  
## Wholesale Funding       0.0295***   0.0265***  0.0202**   0.0024   
##                        (0.0069)    (0.0066)   (0.0064)   (0.0052)  
## ROA                    -0.0033     -0.0075    -0.0033    -0.0103*  
##                        (0.0060)    (0.0052)   (0.0051)   (0.0045)  
## ______________________ __________ ___________ __________ __________
## S.E. type              Hete.-rob. Heter.-rob. Hete.-rob. Hete.-rob.
## Observations                3,991       3,665      3,599      3,468
## R2                        0.11987     0.09589    0.10258    0.04088
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

11 MODEL 2: BTFP & DW — Crisis vs. Arbitrage (DSSW Solvency Split)

11.1 Crisis Period

# ==============================================================================
# MODEL 2a: CRISIS PERIOD — BTFP and DW × {Solvent, Insolvent}
# ==============================================================================

cat("=== MODEL 2: BTFP & DW TEMPORAL (DSSW SOLVENCY) ===\n\n")
## === MODEL 2: BTFP & DW TEMPORAL (DSSW SOLVENCY) ===
# BTFP Crisis (already built above, reuse)
mod2_btfp_cr_sol <- mod1_btfp_sol
mod2_btfp_cr_ins <- mod1_btfp_ins

# DW Crisis (already built above, reuse)
mod2_dw_cr_sol   <- mod1_dw_sol
mod2_dw_cr_ins   <- mod1_dw_ins

models_m2_crisis <- list(
  "BTFP Crisis (Sol)" = mod2_btfp_cr_sol,
  "BTFP Crisis (Ins)" = mod2_btfp_cr_ins,
  "DW Crisis (Sol)"   = mod2_dw_cr_sol,
  "DW Crisis (Ins)"   = mod2_dw_cr_ins
)

save_etable(
  models     = models_m2_crisis,
  filename   = "M2a_btfp_dw_crisis_solvency",
  title_text = "Model 2a: BTFP \\& DW Selection by DSSW Solvency (Crisis Period)",
  notes_text = paste0(
    "LPM. DV = 1 if bank borrowed from the respective facility during the Crisis Period ",
    "(Mar 8--May 4, 2023). Solvency defined by DSSW Adjusted Equity. ",
    "Robust SEs. z-standardized regressors."
  ),
  extra_lines = list(
    c("Facility", "BTFP", "BTFP", "DW", "DW"),
    c("Solvency", "Solvent", "Insolvent", "Solvent", "Insolvent")
  )
)

cat("=== MODEL 2a: CRISIS ===\n")
## === MODEL 2a: CRISIS ===
etable(models_m2_crisis[!sapply(models_m2_crisis, is.null)],
       fitstat = ~ n + r2, se.below = TRUE)
##                        BTFP Cris.. DW Crisi..
## Dependent Var.:        btfp_crisis  dw_crisis
##                                              
## Constant                 0.1423***  0.1267***
##                         (0.0056)   (0.0054)  
## MTM Loss (z)             0.0243***  0.0151*  
##                         (0.0062)   (0.0061)  
## Uninsured Leverage (z)   0.0219**   0.0119   
##                         (0.0071)   (0.0068)  
## MTM $\times$ Uninsured   0.0181***  0.0165** 
##                         (0.0054)   (0.0052)  
## Log(Assets)              0.0724***  0.0934***
##                         (0.0078)   (0.0078)  
## Cash Ratio              -0.0283*** -0.0036   
##                         (0.0050)   (0.0055)  
## Loan-to-Deposit         -0.0085     2.01e-5  
##                         (0.0062)   (0.0061)  
## Book Equity Ratio       -0.0136**  -0.0012   
##                         (0.0051)   (0.0048)  
## Wholesale Funding        0.0265***  0.0202** 
##                         (0.0066)   (0.0064)  
## ROA                     -0.0075    -0.0033   
##                         (0.0052)   (0.0051)  
## ______________________ ___________ __________
## S.E. type              Heter.-rob. Hete.-rob.
## Observations                 3,665      3,599
## R2                         0.09589    0.10258
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

11.2 Arbitrage Period

# ==============================================================================
# MODEL 2b: ARBITRAGE PERIOD — BTFP and DW × {Solvent, Insolvent}
# Note: DW data extends to 2023-12-31, arbitrage starts Nov 15.
#       DW arbitrage sample may be small.
# ==============================================================================

mod2_btfp_arb_sol <- safe_run_model(df_dssw_btfp_arb_sol, "btfp_arb", EXPL_BASE)
mod2_btfp_arb_ins <- safe_run_model(df_dssw_btfp_arb_ins, "btfp_arb", EXPL_BASE)
mod2_dw_arb_sol   <- safe_run_model(df_dssw_dw_arb_sol,   "dw_arb",   EXPL_BASE)
mod2_dw_arb_ins   <- safe_run_model(df_dssw_dw_arb_ins,   "dw_arb",   EXPL_BASE)

models_m2_arb <- list(
  "BTFP Arb (Sol)" = mod2_btfp_arb_sol,
  "BTFP Arb (Ins)" = mod2_btfp_arb_ins,
  "DW Arb (Sol)"   = mod2_dw_arb_sol,
  "DW Arb (Ins)"   = mod2_dw_arb_ins
)

save_etable(
  models     = models_m2_arb,
  filename   = "M2b_btfp_dw_arb_solvency",
  title_text = "Model 2b: BTFP \\& DW Selection by DSSW Solvency (Arbitrage Period)",
  notes_text = paste0(
    "LPM. DV = 1 if bank borrowed during the Arbitrage Period ",
    "(Nov 15, 2023--Jan 24, 2024). DW data available through Dec 31, 2023. ",
    "Solvency defined by DSSW Adjusted Equity (2023Q3 baseline for BTFP, 2022Q4 betas). ",
    "Prediction: MTM $\\times$ Uninsured should be weak/insignificant in arbitrage. ",
    "Robust SEs. z-standardized regressors."
  ),
  extra_lines = list(
    c("Facility", "BTFP", "BTFP", "DW", "DW"),
    c("Solvency", "Solvent", "Insolvent", "Solvent", "Insolvent")
  )
)

cat("=== MODEL 2b: ARBITRAGE ===\n")
## === MODEL 2b: ARBITRAGE ===
etable(models_m2_arb[!sapply(models_m2_arb, is.null)],
       fitstat = ~ n + r2, se.below = TRUE)
##                        BTFP Arb.. DW Arb (..
## Dependent Var.:          btfp_arb     dw_arb
##                                             
## Constant                0.2006***  0.1165***
##                        (0.0060)   (0.0056)  
## MTM Loss (z)            0.0227**  -0.0036   
##                        (0.0072)   (0.0065)  
## Uninsured Leverage (z)  0.0124    -0.0094   
##                        (0.0071)   (0.0064)  
## MTM $\times$ Uninsured  0.0054     0.0007   
##                        (0.0057)   (0.0054)  
## Log(Assets)             0.0650***  0.0780***
##                        (0.0078)   (0.0075)  
## Cash Ratio             -0.0365*** -0.0098   
##                        (0.0061)   (0.0053)  
## Loan-to-Deposit        -0.0004    -0.0002   
##                        (0.0068)   (0.0055)  
## Book Equity Ratio      -0.0089    -0.0063   
##                        (0.0061)   (0.0049)  
## Wholesale Funding       0.1089***  0.0326***
##                        (0.0079)   (0.0072)  
## ROA                    -0.0265*** -0.0089   
##                        (0.0060)   (0.0050)  
## ______________________ __________ __________
## S.E. type              Hete.-rob. Hete.-rob.
## Observations                3,748      3,364
## R2                        0.16390    0.08042
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

11.3 Combined Table: Crisis vs. Arbitrage

# ==============================================================================
# MODEL 2 COMBINED: Side-by-side Crisis vs Arbitrage
# ==============================================================================

models_m2_combined <- list(
  "BTFP Crisis (Sol)" = mod2_btfp_cr_sol,
  "BTFP Crisis (Ins)" = mod2_btfp_cr_ins,
  "BTFP Arb (Sol)"    = mod2_btfp_arb_sol,
  "BTFP Arb (Ins)"    = mod2_btfp_arb_ins,
  "DW Crisis (Sol)"   = mod2_dw_cr_sol,
  "DW Crisis (Ins)"   = mod2_dw_cr_ins,
  "DW Arb (Sol)"      = mod2_dw_arb_sol,
  "DW Arb (Ins)"      = mod2_dw_arb_ins
)

save_etable(
  models     = models_m2_combined,
  filename   = "M2_combined_temporal_solvency",
  title_text = "Model 2: Crisis vs. Arbitrage by Facility and DSSW Solvency",
  notes_text = paste0(
    "LPM. Columns 1--4: BTFP; Columns 5--8: DW. ",
    "Crisis = Mar 8--May 4, 2023; Arbitrage = Nov 15, 2023--Jan 24, 2024. ",
    "Solvency defined by DSSW Adjusted Equity. ",
    "Robust SEs. z-standardized regressors."
  ),
  extra_lines = list(
    c("Period", "Crisis", "Crisis", "Arb", "Arb",
      "Crisis", "Crisis", "Arb", "Arb"),
    c("Solvency", "Sol", "Ins", "Sol", "Ins",
      "Sol", "Ins", "Sol", "Ins")
  )
)

cat("=== MODEL 2 COMBINED TABLE ===\n")
## === MODEL 2 COMBINED TABLE ===
etable(models_m2_combined[!sapply(models_m2_combined, is.null)],
       fitstat = ~ n + r2, se.below = TRUE)
##                        BTFP Cris.. BTFP Arb.. DW Crisi.. DW Arb (..
## Dependent Var.:        btfp_crisis   btfp_arb  dw_crisis     dw_arb
##                                                                    
## Constant                 0.1423***  0.2006***  0.1267***  0.1165***
##                         (0.0056)   (0.0060)   (0.0054)   (0.0056)  
## MTM Loss (z)             0.0243***  0.0227**   0.0151*   -0.0036   
##                         (0.0062)   (0.0072)   (0.0061)   (0.0065)  
## Uninsured Leverage (z)   0.0219**   0.0124     0.0119    -0.0094   
##                         (0.0071)   (0.0071)   (0.0068)   (0.0064)  
## MTM $\times$ Uninsured   0.0181***  0.0054     0.0165**   0.0007   
##                         (0.0054)   (0.0057)   (0.0052)   (0.0054)  
## Log(Assets)              0.0724***  0.0650***  0.0934***  0.0780***
##                         (0.0078)   (0.0078)   (0.0078)   (0.0075)  
## Cash Ratio              -0.0283*** -0.0365*** -0.0036    -0.0098   
##                         (0.0050)   (0.0061)   (0.0055)   (0.0053)  
## Loan-to-Deposit         -0.0085    -0.0004     2.01e-5   -0.0002   
##                         (0.0062)   (0.0068)   (0.0061)   (0.0055)  
## Book Equity Ratio       -0.0136**  -0.0089    -0.0012    -0.0063   
##                         (0.0051)   (0.0061)   (0.0048)   (0.0049)  
## Wholesale Funding        0.0265***  0.1089***  0.0202**   0.0326***
##                         (0.0066)   (0.0079)   (0.0064)   (0.0072)  
## ROA                     -0.0075    -0.0265*** -0.0033    -0.0089   
##                         (0.0052)   (0.0060)   (0.0051)   (0.0050)  
## ______________________ ___________ __________ __________ __________
## S.E. type              Heter.-rob. Hete.-rob. Hete.-rob. Hete.-rob.
## Observations                 3,665      3,748      3,599      3,364
## R2                         0.09589    0.16390    0.10258    0.08042
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

12 MODEL 3: Deposit Beta Channel — Triple Interaction

12.1 Main Specification

# ==============================================================================
# MODEL 3: DEPOSIT BETA ON UNINSURED
#
# Introduces uninsured_beta (β^U from DSSW estimation) and tests whether the
# panic mechanism (MTM × Uninsured) is amplified for banks whose uninsured
# deposits are more rate-sensitive (high β^U).
#
# Full specification:
#   Borrower = MTM + Uninsured + Unins_Beta + (MTM × Uninsured)
#            + (MTM × Unins_Beta) + (Uninsured × Unins_Beta)
#            + (MTM × Uninsured × Unins_Beta) + Controls
#
# Key prediction: β_7 (triple interaction) > 0
#   → Banks with higher uninsured beta (flightier deposits) see a stronger
#     panic amplification from MTM × Uninsured.
# ==============================================================================

cat("=== MODEL 3: DEPOSIT BETA CHANNEL ===\n\n")
## === MODEL 3: DEPOSIT BETA CHANNEL ===
# --- AnyFed ---
mod3_any_full    <- safe_run_model(df_beta_anyfed_s, "any_fed",     EXPL_BETA_FULL)
mod3_any_noint   <- safe_run_model(df_beta_anyfed_s, "any_fed",     EXPL_BETA_NOINT)

# --- BTFP ---
mod3_btfp_full   <- safe_run_model(df_beta_btfp_s, "btfp_crisis", EXPL_BETA_FULL)
mod3_btfp_noint  <- safe_run_model(df_beta_btfp_s, "btfp_crisis", EXPL_BETA_NOINT)

# --- DW ---
mod3_dw_full     <- safe_run_model(df_beta_dw_s, "dw_crisis",     EXPL_BETA_FULL)
mod3_dw_noint    <- safe_run_model(df_beta_dw_s, "dw_crisis",     EXPL_BETA_NOINT)

# --- FHLB (falsification) ---
mod3_fhlb_full   <- safe_run_model(df_beta_fhlb_s, "fhlb_user",   EXPL_BETA_FULL)

models_m3 <- list(
  "Any (no triple)"   = mod3_any_noint,
  "Any (full)"        = mod3_any_full,
  "BTFP (no triple)"  = mod3_btfp_noint,
  "BTFP (full)"       = mod3_btfp_full,
  "DW (no triple)"    = mod3_dw_noint,
  "DW (full)"         = mod3_dw_full,
  "FHLB (full)"       = mod3_fhlb_full
)

save_etable(
  models     = models_m3,
  filename   = "M3_deposit_beta_channel",
  title_text = "Model 3: Deposit Beta Channel — Triple Interaction",
  notes_text = paste0(
    "LPM. DV = 1 if bank borrowed during Crisis Period, 0 if pure non-borrower. ",
    "Uninsured $\\beta$ is the bank-specific deposit beta on uninsured deposits ",
    "estimated following DSSW (2017/2021). The triple interaction ",
    "MTM $\\times$ Uninsured $\\times$ Unins.\\\\ $\\beta$ tests whether the ",
    "panic mechanism is stronger for banks with flightier (higher-$\\beta$) ",
    "uninsured deposits. FHLB serves as falsification. ",
    "Robust SEs. z-standardized regressors."
  ),
  extra_lines = list(
    c("Triple interaction", "No", "Yes", "No", "Yes", "No", "Yes", "Yes")
  )
)

cat("=== MODEL 3 RESULTS ===\n")
## === MODEL 3 RESULTS ===
etable(models_m3[!sapply(models_m3, is.null)],
       fitstat = ~ n + r2, se.below = TRUE)
##                                                Any (no .. Any (full)
## Dependent Var.:                                   any_fed    any_fed
##                                                                     
## Constant                                        0.2077***  0.2075***
##                                                (0.0061)   (0.0062)  
## MTM Loss (z)                                    0.0302***  0.0292***
##                                                (0.0071)   (0.0072)  
## Uninsured Leverage (z)                          0.0208**   0.0192*  
##                                                (0.0077)   (0.0078)  
## Uninsured $\beta$ (z)                           0.0067     0.0063   
##                                                (0.0073)   (0.0073)  
## MTM $\times$ Uninsured                          0.0190**   0.0190** 
##                                                (0.0059)   (0.0059)  
## MTM $\times$ Unins. $\beta$                     0.0067     0.0070   
##                                                (0.0062)   (0.0062)  
## Uninsured $\times$ Unins. $\beta$              -0.0041    -0.0089   
##                                                (0.0059)   (0.0068)  
## Log(Assets)                                     0.1072***  0.1073***
##                                                (0.0084)   (0.0084)  
## Cash Ratio                                     -0.0245*** -0.0243***
##                                                (0.0064)   (0.0064)  
## Loan-to-Deposit                                -0.0030    -0.0034   
##                                                (0.0073)   (0.0073)  
## Book Equity Ratio                              -0.0145*   -0.0143*  
##                                                (0.0059)   (0.0060)  
## Wholesale Funding                               0.0297***  0.0302***
##                                                (0.0069)   (0.0069)  
## ROA                                            -0.0032    -0.0030   
##                                                (0.0060)   (0.0060)  
## MTM $\times$ Uninsured $\times$ Unins. $\beta$            -0.0099   
##                                                           (0.0057)  
## ________________________________________       __________ __________
## S.E. type                                      Hete.-rob. Hete.-rob.
## Observations                                        3,991      3,991
## R2                                                0.12038    0.12113
## 
##                                                BTFP (no .. BTFP (full)
## Dependent Var.:                                btfp_crisis btfp_crisis
##                                                                       
## Constant                                         0.1435***   0.1433***
##                                                 (0.0057)    (0.0057)  
## MTM Loss (z)                                     0.0255***   0.0250***
##                                                 (0.0063)    (0.0063)  
## Uninsured Leverage (z)                           0.0230**    0.0223** 
##                                                 (0.0071)    (0.0072)  
## Uninsured $\beta$ (z)                            0.0101      0.0099   
##                                                 (0.0067)    (0.0067)  
## MTM $\times$ Uninsured                           0.0188***   0.0187***
##                                                 (0.0055)    (0.0055)  
## MTM $\times$ Unins. $\beta$                      0.0102      0.0101   
##                                                 (0.0056)    (0.0056)  
## Uninsured $\times$ Unins. $\beta$               -0.0033     -0.0056   
##                                                 (0.0054)    (0.0066)  
## Log(Assets)                                      0.0714***   0.0715***
##                                                 (0.0079)    (0.0079)  
## Cash Ratio                                      -0.0289***  -0.0287***
##                                                 (0.0051)    (0.0051)  
## Loan-to-Deposit                                 -0.0108     -0.0110   
##                                                 (0.0062)    (0.0062)  
## Book Equity Ratio                               -0.0128*    -0.0127*  
##                                                 (0.0051)    (0.0051)  
## Wholesale Funding                                0.0266***   0.0269***
##                                                 (0.0066)    (0.0066)  
## ROA                                             -0.0070     -0.0070   
##                                                 (0.0052)    (0.0052)  
## MTM $\times$ Uninsured $\times$ Unins. $\beta$              -0.0047   
##                                                             (0.0053)  
## ________________________________________       ___________ ___________
## S.E. type                                      Heter.-rob. Heter.-rob.
## Observations                                         3,665       3,665
## R2                                                 0.09725     0.09748
## 
##                                                DW (no t..  DW (full) FHLB (fu..
## Dependent Var.:                                 dw_crisis  dw_crisis  fhlb_user
##                                                                                
## Constant                                        0.1270***  0.1268***  0.0903***
##                                                (0.0055)   (0.0055)   (0.0051)  
## MTM Loss (z)                                    0.0153*    0.0145*    0.0065   
##                                                (0.0062)   (0.0062)   (0.0057)  
## Uninsured Leverage (z)                          0.0120     0.0105     0.0082   
##                                                (0.0068)   (0.0068)   (0.0054)  
## Uninsured $\beta$ (z)                           0.0004    -0.0002     0.0154** 
##                                                (0.0064)   (0.0064)   (0.0060)  
## MTM $\times$ Uninsured                          0.0169**   0.0168**  -0.0045   
##                                                (0.0052)   (0.0052)   (0.0045)  
## MTM $\times$ Unins. $\beta$                     0.0017     0.0018     0.0033   
##                                                (0.0055)   (0.0054)   (0.0048)  
## Uninsured $\times$ Unins. $\beta$               0.0019    -0.0030     0.0021   
##                                                (0.0053)   (0.0064)   (0.0055)  
## Log(Assets)                                     0.0935***  0.0935***  0.0245***
##                                                (0.0079)   (0.0079)   (0.0066)  
## Cash Ratio                                     -0.0036    -0.0034    -0.0195***
##                                                (0.0055)   (0.0055)   (0.0041)  
## Loan-to-Deposit                                -0.0001    -0.0003     0.0215***
##                                                (0.0063)   (0.0063)   (0.0054)  
## Book Equity Ratio                              -0.0010    -0.0008     0.0087   
##                                                (0.0048)   (0.0048)   (0.0045)  
## Wholesale Funding                               0.0202**   0.0207**   0.0032   
##                                                (0.0064)   (0.0063)   (0.0052)  
## ROA                                            -0.0032    -0.0032    -0.0092*  
##                                                (0.0052)   (0.0052)   (0.0045)  
## MTM $\times$ Uninsured $\times$ Unins. $\beta$            -0.0093    -0.0028   
##                                                           (0.0051)   (0.0047)  
## ________________________________________       __________ __________ __________
## S.E. type                                      Hete.-rob. Hete.-rob. Hete.-rob.
## Observations                                        3,599      3,599      3,468
## R2                                                0.10264    0.10362    0.04378
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

12.2 Uninsured Beta Diagnostics

# ==============================================================================
# DIAGNOSTICS: Distribution of uninsured beta and its correlates
# ==============================================================================

cat("=== UNINSURED BETA DIAGNOSTICS (2022Q4) ===\n\n")
## === UNINSURED BETA DIAGNOSTICS (2022Q4) ===
cat("--- Coverage ---\n")
## --- Coverage ---
n_total <- nrow(df_2022q4)
n_ubeta <- sum(!is.na(df_2022q4$uninsured_beta_raw))
cat(sprintf("Uninsured beta coverage: %d / %d banks (%.1f%%)\n",
            n_ubeta, n_total, 100 * n_ubeta / n_total))
## Uninsured beta coverage: 4226 / 4292 banks (98.5%)
cat("\n--- Distribution (raw) ---\n")
## 
## --- Distribution (raw) ---
print(summary(df_2022q4$uninsured_beta_raw))
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max.    NA's 
##  0.2640  0.3337  0.3895  0.4111  0.4683  0.6692      66
cat("\n--- Correlation with key variables ---\n")
## 
## --- Correlation with key variables ---
cor_vars <- df_2022q4 %>%
  select(uninsured_beta_raw, beta_overall,
         uninsured_lev_raw, mtm_total_raw,
         adjusted_equity_dssw_raw, ln_assets_raw) %>%
  drop_na()

if (nrow(cor_vars) > 10) {
  print(round(cor(cor_vars), 3))
}
##                          uninsured_beta_raw beta_overall uninsured_lev_raw
## uninsured_beta_raw                    1.000        0.873            -0.036
## beta_overall                          0.873        1.000             0.298
## uninsured_lev_raw                    -0.036        0.298             1.000
## mtm_total_raw                        -0.114       -0.190            -0.155
## adjusted_equity_dssw_raw             -0.825       -0.894            -0.237
## ln_assets_raw                         0.223        0.390             0.424
##                          mtm_total_raw adjusted_equity_dssw_raw ln_assets_raw
## uninsured_beta_raw              -0.114                   -0.825         0.223
## beta_overall                    -0.190                   -0.894         0.390
## uninsured_lev_raw               -0.155                   -0.237         0.424
## mtm_total_raw                    1.000                   -0.036         0.031
## adjusted_equity_dssw_raw        -0.036                    1.000        -0.451
## ln_assets_raw                    0.031                   -0.451         1.000
cat("\n--- Mean Uninsured Beta by DSSW Solvency ---\n")
## 
## --- Mean Uninsured Beta by DSSW Solvency ---
df_2022q4 %>%
  filter(!is.na(uninsured_beta_raw), !is.na(dssw_solvent)) %>%
  group_by(DSSW_Solvent = dssw_solvent) %>%
  summarise(
    N = n(),
    Mean_Unins_Beta = round(mean(uninsured_beta_raw, na.rm = TRUE), 4),
    SD_Unins_Beta   = round(sd(uninsured_beta_raw, na.rm = TRUE), 4),
    .groups = "drop"
  ) %>%
  print()
## # A tibble: 1 × 4
##   DSSW_Solvent     N Mean_Unins_Beta SD_Unins_Beta
##          <int> <int>           <dbl>         <dbl>
## 1            1  4226           0.411         0.105

13 MODEL 4: BTFP Complementarity with DW

13.1 4a. Multinomial Facility Choice

# ==============================================================================
# MODEL 4a: MULTINOMIAL LOGIT — FACILITY CHOICE
#
# Among all emergency borrowers (AnyFed == 1) during Crisis:
# Choice ∈ {DW_Only (base), BTFP_Only, Both}
#
# Key insight: All BTFP borrowers are DW-eligible (both are Fed facilities
# for depository institutions). BTFP complements DW through:
#   (a) Par valuation of OMO-eligible collateral (removing fire-sale pressure)
#   (b) Longer term (up to 1 year vs. typically overnight for DW)
#   (c) Less stigma (new program, Board encouraged use)
#
# Predictions:
#   - Banks with larger OMO MTM losses → prefer BTFP (higher par subsidy)
#   - Banks with broader (non-OMO) collateral → prefer DW (wider collateral)
#   - Banks with both → use Both facilities (complement)
# ==============================================================================

cat("=== MODEL 4a: MULTINOMIAL FACILITY CHOICE ===\n\n")
## === MODEL 4a: MULTINOMIAL FACILITY CHOICE ===
cat("Facility choice distribution among emergency borrowers (Crisis):\n")
## Facility choice distribution among emergency borrowers (Crisis):
print(table(df_emerg_borrowers$facility_choice))
## 
##   DW_Only BTFP_Only      Both 
##       327       395       106
# Multinomial logit: DW_Only is the reference category
# Include controls + facility-specific variables
ff_mnom <- as.formula(paste0(
  "facility_choice ~ mtm_total + uninsured_lev + mtm_x_uninsured + ",
  "par_benefit + collateral_capacity + ",
  CONTROLS
))

mod4a_mnom <- tryCatch(
  multinom(ff_mnom, data = df_emerg_borrowers, trace = FALSE),
  error = function(e) {
    message("  ⚠ Multinomial logit failed: ", e$message)
    NULL
  }
)

if (!is.null(mod4a_mnom)) {
  cat("\n--- Multinomial Logit Results (Base = DW Only) ---\n")
  cat("AIC:", AIC(mod4a_mnom), "\n\n")

  # Tidy output
  tidy_mnom <- tidy(mod4a_mnom, conf.int = TRUE)
  tidy_mnom <- tidy_mnom %>%
    mutate(
      stars = case_when(
        p.value < 0.01 ~ "***",
        p.value < 0.05 ~ "**",
        p.value < 0.10 ~ "*",
        TRUE           ~ ""
      ),
      display = sprintf("%.3f%s (%.3f)", estimate, stars, std.error)
    )

  # Print key coefficients
  key_vars <- c("mtm_total", "uninsured_lev", "mtm_x_uninsured",
                "par_benefit", "collateral_capacity")
  tidy_mnom %>%
    filter(term %in% key_vars) %>%
    select(y.level, term, display, p.value) %>%
    arrange(y.level, term) %>%
    print(n = 20)

  # Save as LaTeX
  latex_mnom <- kable(
    tidy_mnom %>%
      filter(term %in% key_vars) %>%
      select(Outcome = y.level, Variable = term, Estimate = display),
    format = "latex", booktabs = TRUE,
    caption = "Multinomial Logit: Facility Choice (Base = DW Only)"
  )
  safe_writeLines(
    as.character(latex_mnom),
    file.path(TABLE_PATH, "M4a_multinomial_facility_choice.tex")
  )
}
## 
## --- Multinomial Logit Results (Base = DW Only) ---
## AIC: 1567.913 
## 
## # A tibble: 10 × 4
##    y.level   term                display           p.value
##    <chr>     <chr>               <chr>               <dbl>
##  1 BTFP_Only collateral_capacity 0.240** (0.103)   0.0200 
##  2 BTFP_Only mtm_total           0.120 (0.103)     0.243  
##  3 BTFP_Only mtm_x_uninsured     -0.103 (0.086)    0.233  
##  4 BTFP_Only par_benefit         -0.342*** (0.131) 0.00891
##  5 BTFP_Only uninsured_lev       0.120 (0.093)     0.194  
##  6 Both      collateral_capacity 0.106 (0.149)     0.476  
##  7 Both      mtm_total           -0.196 (0.172)    0.255  
##  8 Both      mtm_x_uninsured     0.113 (0.129)     0.381  
##  9 Both      par_benefit         0.284 (0.380)     0.455  
## 10 Both      uninsured_lev       0.286** (0.134)   0.0332

13.2 4b. Complementarity Test: DW Borrowers → Also BTFP?

# ==============================================================================
# MODEL 4b: COMPLEMENTARITY TEST
#
# Sample: Banks that borrowed from DW during Crisis
# DV: also_btfp = 1 if bank ALSO borrowed from BTFP (i.e., "Both")
#
# This tests: Among DW borrowers, what drove them to additionally use BTFP?
# Prediction: Banks with larger OMO MTM losses (higher par benefit from BTFP)
# should be more likely to also use BTFP as a complement.
# ==============================================================================

cat("=== MODEL 4b: COMPLEMENTARITY (DW → ALSO BTFP?) ===\n\n")
## === MODEL 4b: COMPLEMENTARITY (DW → ALSO BTFP?) ===
cat("DW borrowers during Crisis:", nrow(df_dw_complement), "\n")
## DW borrowers during Crisis: 433
cat("  Also used BTFP:", sum(df_dw_complement$also_btfp), "\n")
##   Also used BTFP: 106
cat("  DW only:",        sum(df_dw_complement$also_btfp == 0), "\n\n")
##   DW only: 327
# Base specification
mod4b_base <- safe_run_model(
  df_dw_complement, "also_btfp", EXPL_BASE, min_n = 20
)

# With par benefit and collateral
mod4b_facility <- safe_run_model(
  df_dw_complement, "also_btfp", EXPL_FACILITY, min_n = 20
)

models_m4b <- list(
  "Complement (Base)"     = mod4b_base,
  "Complement (Facility)" = mod4b_facility
)

save_etable(
  models     = models_m4b,
  filename   = "M4b_dw_complementarity",
  title_text = "Model 4b: BTFP Complementarity — Among DW Borrowers",
  notes_text = paste0(
    "LPM. Sample: banks that borrowed from the DW during Crisis Period. ",
    "DV = 1 if the bank also borrowed from BTFP (Both), 0 if DW-only. ",
    "Par Benefit measures the proportional gain from BTFP's par-value lending. ",
    "OMO Collateral measures OMO-eligible securities as \\% of assets. ",
    "Robust SEs. z-standardized regressors."
  )
)

cat("=== MODEL 4b RESULTS ===\n")
## === MODEL 4b RESULTS ===
etable(models_m4b[!sapply(models_m4b, is.null)],
       fitstat = ~ n + r2, se.below = TRUE)
##                        Compleme.. Compleme...1
## Dependent Var.:         also_btfp    also_btfp
##                                               
## Constant                0.1686***    0.1668***
##                        (0.0235)     (0.0231)  
## MTM Loss (z)           -0.0219      -0.0186   
##                        (0.0242)     (0.0246)  
## Uninsured Leverage (z)  0.0490*      0.0499*  
##                        (0.0241)     (0.0243)  
## MTM $\times$ Uninsured  0.0200       0.0200   
##                        (0.0212)     (0.0214)  
## Log(Assets)             0.0590*      0.0563*  
##                        (0.0247)     (0.0253)  
## Cash Ratio             -0.0472      -0.0422   
##                        (0.0263)     (0.0266)  
## Loan-to-Deposit        -0.0270      -0.0103   
##                        (0.0285)     (0.0338)  
## Book Equity Ratio      -0.0502      -0.0517   
##                        (0.0261)     (0.0264)  
## Wholesale Funding       0.0244       0.0217   
##                        (0.0176)     (0.0177)  
## ROA                    -0.0258      -0.0215   
##                        (0.0236)     (0.0240)  
## Par Benefit (z)                      0.0132   
##                                     (0.0154)  
## OMO Collateral (z)                   0.0261   
##                                     (0.0283)  
## ______________________ __________   __________
## S.E. type              Hete.-rob.   Hete.-rob.
## Observations                  433          433
## R2                        0.08055      0.08293
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

13.3 4c. Substitution Test: BTFP-Only vs. DW-Only

# ==============================================================================
# MODEL 4c: SUBSTITUTION TEST
#
# Sample: Single-facility borrowers (BTFP-Only + DW-Only)
# DV: chose_btfp = 1 if BTFP-only, 0 if DW-only
#
# This tests: Among banks that chose only one Fed facility, what drove the
# choice of BTFP over DW?
# Predictions:
#   - Banks with larger OMO MTM losses → chose BTFP (par subsidy)
#   - Banks with more OMO collateral → chose BTFP
#   - DW stigma effect: conditional on fundamentals, banks avoid DW
# ==============================================================================

cat("=== MODEL 4c: SUBSTITUTION (BTFP-Only vs DW-Only) ===\n\n")
## === MODEL 4c: SUBSTITUTION (BTFP-Only vs DW-Only) ===
cat("Single-facility borrowers:", nrow(df_substitution), "\n")
## Single-facility borrowers: 722
cat("  BTFP-only:", sum(df_substitution$chose_btfp), "\n")
##   BTFP-only: 395
cat("  DW-only:",   sum(df_substitution$chose_btfp == 0), "\n\n")
##   DW-only: 327
# Base specification
mod4c_base <- safe_run_model(
  df_substitution, "chose_btfp", EXPL_BASE, min_n = 20
)

# With facility characteristics
mod4c_facility <- safe_run_model(
  df_substitution, "chose_btfp", EXPL_FACILITY, min_n = 20
)

# With par × uninsured interaction (stigma amplification)
EXPL_STIGMA <- paste0(EXPL_FACILITY, " + par_x_uninsured")
mod4c_stigma <- safe_run_model(
  df_substitution, "chose_btfp", EXPL_STIGMA, min_n = 20
)

models_m4c <- list(
  "Substitution (Base)"     = mod4c_base,
  "Substitution (Facility)" = mod4c_facility,
  "Substitution (Stigma)"   = mod4c_stigma
)

save_etable(
  models     = models_m4c,
  filename   = "M4c_btfp_vs_dw_substitution",
  title_text = "Model 4c: BTFP vs. DW Substitution — Single-Facility Borrowers",
  notes_text = paste0(
    "LPM. Sample: banks that borrowed from exactly one Fed facility during Crisis. ",
    "DV = 1 if BTFP-only, 0 if DW-only. ",
    "Par Benefit = proportional MTM loss on OMO-eligible securities. ",
    "OMO Collateral = OMO-eligible securities / total assets. ",
    "Par $\\times$ Uninsured tests whether the par subsidy is more valuable for banks ",
    "facing uninsured deposit pressure (stigma amplification). ",
    "Robust SEs. z-standardized regressors."
  )
)

cat("=== MODEL 4c RESULTS ===\n")
## === MODEL 4c RESULTS ===
etable(models_m4c[!sapply(models_m4c, is.null)],
       fitstat = ~ n + r2, se.below = TRUE)
##                        Substitu.. Substitu...1 Substitu...2
## Dependent Var.:        chose_btfp   chose_btfp   chose_btfp
##                                                            
## Constant                0.5364***    0.5378***    0.5341***
##                        (0.0243)     (0.0242)     (0.0245)  
## MTM Loss (z)            0.0092       0.0277       0.0239   
##                        (0.0240)     (0.0243)     (0.0245)  
## Uninsured Leverage (z)  0.0274       0.0270       0.0257   
##                        (0.0231)     (0.0223)     (0.0225)  
## MTM $\times$ Uninsured -0.0193      -0.0197      -0.0135   
##                        (0.0205)     (0.0199)     (0.0206)  
## Log(Assets)            -0.0808***   -0.0791***   -0.0739** 
##                        (0.0233)     (0.0229)     (0.0236)  
## Cash Ratio             -0.1242***   -0.1201***   -0.1228***
##                        (0.0300)     (0.0285)     (0.0287)  
## Loan-to-Deposit        -0.0466      -0.0115      -0.0174   
##                        (0.0276)     (0.0301)     (0.0304)  
## Book Equity Ratio      -0.0380      -0.0431      -0.0408   
##                        (0.0284)     (0.0287)     (0.0288)  
## Wholesale Funding       0.0058       0.0027       0.0028   
##                        (0.0156)     (0.0155)     (0.0155)  
## ROA                    -0.0080      -0.0037      -0.0005   
##                        (0.0232)     (0.0233)     (0.0234)  
## Par Benefit (z)                     -0.0675**    -0.0505   
##                                     (0.0245)     (0.0314)  
## OMO Collateral (z)                   0.0550*      0.0544*  
##                                     (0.0227)     (0.0228)  
## Par $\times$ Uninsured                           -0.0294   
##                                                  (0.0225)  
## ______________________ __________   __________   __________
## S.E. type              Hete.-rob.   Hete.-rob.   Hete.-rob.
## Observations                  722          722          722
## R2                        0.06253      0.07826      0.08051
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

13.4 4d. Descriptive Evidence: Borrower Characteristics by Facility Choice

# ==============================================================================
# MODEL 4d: DESCRIPTIVE COMPARISON OF FACILITY CHOICE GROUPS
# ==============================================================================

cat("=== MODEL 4: DESCRIPTIVE EVIDENCE ===\n\n")
## === MODEL 4: DESCRIPTIVE EVIDENCE ===
desc_vars <- c("mtm_total_raw", "mtm_btfp_raw", "mtm_other_raw",
               "uninsured_lev_raw", "insured_lev_raw",
               "book_equity_ratio_raw", "adjusted_equity_raw",
               "dfv_raw", "adjusted_equity_dssw_raw",
               "ln_assets_raw", "cash_ratio_raw",
               "par_benefit_raw", "collateral_capacity_raw")

desc_labels <- c("Total MTM Loss", "OMO MTM Loss", "Non-OMO MTM Loss",
                 "Uninsured Lev.", "Insured Lev.",
                 "Book Equity", "Adj. Equity (Jiang)",
                 "DFV", "DSSW Adj. Equity",
                 "Log(Assets)", "Cash Ratio",
                 "Par Benefit", "OMO Collateral")

# Compare across facility choice groups
facility_means <- df_emerg_borrowers %>%
  group_by(facility_choice) %>%
  summarise(
    N = n(),
    across(all_of(desc_vars), ~round(mean(., na.rm = TRUE), 3)),
    .groups = "drop"
  )

cat("--- Mean Characteristics by Facility Choice ---\n")
## --- Mean Characteristics by Facility Choice ---
print(facility_means, width = Inf)
## # A tibble: 3 × 15
##   facility_choice     N mtm_total_raw mtm_btfp_raw mtm_other_raw
##   <fct>           <int>         <dbl>        <dbl>         <dbl>
## 1 DW_Only           327          5.72        0.728          4.93
## 2 BTFP_Only         395          6.18        0.875          5.05
## 3 Both              106          5.83        0.924          4.83
##   uninsured_lev_raw insured_lev_raw book_equity_ratio_raw adjusted_equity_raw
##               <dbl>           <dbl>                 <dbl>               <dbl>
## 1              26.8            59.0                  9.10                3.38
## 2              26.2            59.9                  8.19                2.01
## 3              32.0            53.1                  8.14                2.31
##   dfv_raw adjusted_equity_dssw_raw ln_assets_raw cash_ratio_raw par_benefit_raw
##     <dbl>                    <dbl>         <dbl>          <dbl>           <dbl>
## 1    71.9                     75.3          13.8           6.15           0.962
## 2    73.0                     75.1          13.5           4.69           0.933
## 3    66.3                     68.8          14.6           4.62           0.978
##   collateral_capacity_raw
##                     <dbl>
## 1                   0.009
## 2                   0.012
## 3                   0.011
# T-tests: BTFP-only vs DW-only
cat("\n--- T-Tests: BTFP-Only vs DW-Only ---\n")
## 
## --- T-Tests: BTFP-Only vs DW-Only ---
btfp_only <- df_emerg_borrowers %>% filter(facility_choice == "BTFP_Only")
dw_only   <- df_emerg_borrowers %>% filter(facility_choice == "DW_Only")

for (i in seq_along(desc_vars)) {
  v <- desc_vars[i]
  tt <- tryCatch(
    t.test(btfp_only[[v]], dw_only[[v]]),
    error = function(e) NULL
  )
  if (!is.null(tt)) {
    stars <- case_when(
      tt$p.value < 0.01 ~ "***",
      tt$p.value < 0.05 ~ "**",
      tt$p.value < 0.10 ~ "*",
      TRUE              ~ ""
    )
    cat(sprintf("  %-25s  BTFP=%.3f  DW=%.3f  diff=%.3f  t=%.2f %s\n",
                desc_labels[i],
                mean(btfp_only[[v]], na.rm = TRUE),
                mean(dw_only[[v]], na.rm = TRUE),
                mean(btfp_only[[v]], na.rm = TRUE) - mean(dw_only[[v]], na.rm = TRUE),
                tt$statistic, stars))
  }
}
##   Total MTM Loss             BTFP=6.175  DW=5.718  diff=0.458  t=3.07 ***
##   OMO MTM Loss               BTFP=0.875  DW=0.728  diff=0.147  t=2.15 **
##   Non-OMO MTM Loss           BTFP=5.047  DW=4.935  diff=0.112  t=0.80 
##   Uninsured Lev.             BTFP=26.154  DW=26.774  diff=-0.621  t=-0.71 
##   Insured Lev.               BTFP=59.928  DW=58.986  diff=0.943  t=1.02 
##   Book Equity                BTFP=8.188  DW=9.097  diff=-0.909  t=-3.82 ***
##   Adj. Equity (Jiang)        BTFP=2.012  DW=3.379  diff=-1.367  t=-4.36 ***
##   DFV                        BTFP=73.045  DW=71.907  diff=1.138  t=1.01 
##   DSSW Adj. Equity           BTFP=75.098  DW=75.321  diff=-0.223  t=-0.21 
##   Log(Assets)                BTFP=13.486  DW=13.833  diff=-0.347  t=-3.22 ***
##   Cash Ratio                 BTFP=4.686  DW=6.151  diff=-1.465  t=-3.43 ***
##   Par Benefit                BTFP=0.933  DW=0.962  diff=-0.029  t=-2.15 **
##   OMO Collateral             BTFP=0.012  DW=0.009  diff=0.002  t=3.15 ***

14 DSSW SOLVENCY DIAGNOSTICS

# ==============================================================================
# COMPREHENSIVE DSSW DIAGNOSTICS
# ==============================================================================

cat("=== DSSW DEPOSIT FRANCHISE VALUE DIAGNOSTICS ===\n\n")
## === DSSW DEPOSIT FRANCHISE VALUE DIAGNOSTICS ===
# Coverage
n_total <- nrow(df_2022q4)
n_beta  <- sum(!is.na(df_2022q4$beta_overall))
cat(sprintf("Beta coverage: %d / %d banks (%.1f%%)\n\n",
            n_beta, n_total, 100 * n_beta / n_total))
## Beta coverage: 4226 / 4292 banks (98.5%)
# DFV distribution
cat("--- DFV Distribution (raw, % of assets) ---\n")
## --- DFV Distribution (raw, % of assets) ---
print(summary(df_2022q4$dfv_raw))
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max.    NA's 
##  -8.887  67.675  77.723  74.838  85.413 107.054      66
cat("\n--- DSSW Adjusted Equity Distribution (raw, %) ---\n")
## 
## --- DSSW Adjusted Equity Distribution (raw, %) ---
print(summary(df_2022q4$adjusted_equity_dssw_raw))
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max.    NA's 
##   1.223  71.797  81.603  78.951  88.751 112.129      66
# Solvency comparison: Jiang vs DSSW
cat("\n--- Solvency Classification Cross-Tab ---\n")
## 
## --- Solvency Classification Cross-Tab ---
tab_compare <- df_2022q4 %>%
  filter(!is.na(dssw_insolvent)) %>%
  count(mtm_insolvent, dssw_insolvent) %>%
  mutate(
    Jiang = ifelse(mtm_insolvent == 1, "Insolvent", "Solvent"),
    DSSW  = ifelse(dssw_insolvent == 1, "Insolvent", "Solvent")
  )
print(tab_compare %>% select(Jiang, DSSW, n))
## # A tibble: 3 × 3
##   Jiang     DSSW        n
##   <chr>     <chr>   <int>
## 1 Solvent   Solvent  3457
## 2 Insolvent Solvent   825
## 3 <NA>      Solvent    10
# Reclassification
n_jiang_insol <- sum(df_2022q4$mtm_insolvent == 1, na.rm = TRUE)
n_dssw_insol  <- sum(df_2022q4$dssw_insolvent == 1, na.rm = TRUE)
n_rescued     <- sum(df_2022q4$mtm_insolvent == 1 & df_2022q4$dssw_solvent == 1, na.rm = TRUE)
cat(sprintf("\nJiang insolvent: %d | DSSW insolvent: %d | Rescued by DFV: %d\n",
            n_jiang_insol, n_dssw_insol, n_rescued))
## 
## Jiang insolvent: 825 | DSSW insolvent: 0 | Rescued by DFV: 813
# Beta by solvency
cat("\n--- Mean Deposit Beta by DSSW Solvency ---\n")
## 
## --- Mean Deposit Beta by DSSW Solvency ---
df_2022q4 %>%
  filter(!is.na(beta_overall), !is.na(dssw_insolvent)) %>%
  group_by(dssw_solvent) %>%
  summarise(
    n = n(),
    mean_beta = mean(beta_overall, na.rm = TRUE),
    mean_dfv  = mean(dfv_raw, na.rm = TRUE),
    mean_ae_jiang = mean(adjusted_equity_raw, na.rm = TRUE),
    mean_ae_dssw  = mean(adjusted_equity_dssw_raw, na.rm = TRUE),
    .groups = "drop"
  ) %>%
  print()
## # A tibble: 1 × 6
##   dssw_solvent     n mean_beta mean_dfv mean_ae_jiang mean_ae_dssw
##          <int> <int>     <dbl>    <dbl>         <dbl>        <dbl>
## 1            1  4226     0.132     74.8          4.11         79.0

15 VISUALIZATION

15.1 Adjusted Equity: Jiang vs. DSSW

# ==============================================================================
# SCATTER: Jiang AE vs DSSW AE, colored by borrower status
# ==============================================================================

df_scatter <- df_crisis %>%
  filter(!is.na(adjusted_equity_dssw_raw)) %>%
  mutate(
    Borrower = case_when(
      any_fed == 1 ~ "Emergency Borrower",
      fhlb_user == 1 ~ "FHLB",
      TRUE ~ "Non-Borrower"
    )
  )

p_scatter <- ggplot(df_scatter,
       aes(x = adjusted_equity_raw, y = adjusted_equity_dssw_raw,
           color = Borrower, alpha = Borrower)) +
  geom_point(size = 1.5) +
  geom_abline(slope = 1, intercept = 0, linetype = "dashed", color = "grey50") +
  geom_hline(yintercept = 0, linetype = "dotted", color = "red") +
  geom_vline(xintercept = 0, linetype = "dotted", color = "red") +
  scale_color_manual(values = c("Emergency Borrower" = "#003049",
                                "FHLB" = "#F77F00",
                                "Non-Borrower" = "grey70")) +
  scale_alpha_manual(values = c("Emergency Borrower" = 0.8,
                                "FHLB" = 0.6,
                                "Non-Borrower" = 0.3)) +
  labs(
    title = "Jiang-Style vs. DSSW Adjusted Equity",
    subtitle = "DSSW AE adds deposit franchise value; many Jiang-insolvent banks become DSSW-solvent",
    x = "Jiang Adjusted Equity (Book Equity - MTM Loss, %)",
    y = "DSSW Adjusted Equity (Book Equity - MTM Loss + DFV, %)"
  ) +
  theme_paper +
  annotate("text", x = -5, y = 20, label = "Rescued by\nDFV", color = "darkgreen",
           fontface = "italic", size = 3.5)

p_scatter

save_figure(p_scatter, "Fig_Jiang_vs_DSSW_AE", width = 10, height = 6)

15.2 Facility Choice by Borrower Group

# ==============================================================================
# BAR CHART: Facility choice distribution by key characteristics
# ==============================================================================

df_choice_bar <- df_emerg_borrowers %>%
  group_by(facility_choice) %>%
  summarise(
    N = n(),
    Mean_MTM = mean(mtm_total_raw, na.rm = TRUE),
    Mean_ParBenefit = mean(par_benefit_raw, na.rm = TRUE),
    Mean_Uninsured = mean(uninsured_lev_raw, na.rm = TRUE),
    .groups = "drop"
  ) %>%
  pivot_longer(cols = starts_with("Mean_"),
               names_to = "Variable", values_to = "Value") %>%
  mutate(
    Variable = case_when(
      Variable == "Mean_MTM" ~ "MTM Loss (%)",
      Variable == "Mean_ParBenefit" ~ "Par Benefit",
      Variable == "Mean_Uninsured" ~ "Uninsured Lev (%)"
    )
  )

p_choice <- ggplot(df_choice_bar,
       aes(x = facility_choice, y = Value, fill = facility_choice)) +
  geom_col(width = 0.7) +
  facet_wrap(~ Variable, scales = "free_y", ncol = 3) +
  scale_fill_manual(values = c("DW_Only" = "#D62828",
                               "BTFP_Only" = "#003049",
                               "Both" = "#7209B7")) +
  labs(
    title = "Mean Characteristics by Facility Choice (Crisis Period)",
    x = NULL, y = "Mean Value", fill = "Facility"
  ) +
  theme_paper +
  theme(axis.text.x = element_text(angle = 30, hjust = 1))

p_choice

save_figure(p_choice, "Fig_Facility_Choice_Characteristics", width = 9, height = 5)

15.3 Deposit Beta Distribution by Borrower Status

# ==============================================================================
# KDE: Uninsured deposit beta by borrower status
# ==============================================================================

df_beta_kde <- df_crisis %>%
  filter(!is.na(uninsured_beta_w)) %>%
  mutate(
    Group = case_when(
      any_fed == 1 ~ "Emergency Borrower",
      fhlb_user == 1 ~ "FHLB",
      TRUE ~ "Non-Borrower"
    ),
    Group = factor(Group, levels = c("Non-Borrower", "FHLB", "Emergency Borrower"))
  )

if (nrow(df_beta_kde) > 50) {
  p_beta <- ggplot(df_beta_kde, aes(x = uninsured_beta_w, fill = Group, color = Group)) +
    geom_density(alpha = 0.4, linewidth = 0.8) +
    scale_fill_manual(values = c("Non-Borrower" = "grey70",
                                 "FHLB" = "#F77F00",
                                 "Emergency Borrower" = "#003049")) +
    scale_color_manual(values = c("Non-Borrower" = "grey70",
                                  "FHLB" = "#F77F00",
                                  "Emergency Borrower" = "#003049")) +
    labs(
      title = "Distribution of Uninsured Deposit Beta by Borrower Group",
      subtitle = "Higher beta → more rate-sensitive (flightier) uninsured deposits",
      x = "Uninsured Deposit Beta",
      y = "Density"
    ) +
    theme_paper

  # Explicitly print the plot so it shows up in RStudio/your graphics device
  print(p_beta) 
  
  save_figure(p_beta, "Fig_KDE_Uninsured_Beta", width = 8, height = 5)
} else {
  cat("Insufficient observations for uninsured beta density plot.\n")
}


16 SUMMARY OF ALL MODELS

cat("======================================================================\n")
## ======================================================================
cat("  FOUR-MODEL ANALYSIS — SUMMARY\n")
##   FOUR-MODEL ANALYSIS — SUMMARY
cat("======================================================================\n\n")
## ======================================================================
cat("MODEL 1: Main Results (Crisis, DSSW Solvency)\n")
## MODEL 1: Main Results (Crisis, DSSW Solvency)
cat("  8 regressions: 4 borrower types × (Solvent, Insolvent)\n")
##   8 regressions: 4 borrower types × (Solvent, Insolvent)
cat("  Solvency = DSSW AE = Book Equity - MTM + DFV ≥ 0\n")
##   Solvency = DSSW AE = Book Equity - MTM + DFV ≥ 0
cat("  DFV = (1-β_i) × Deposits/TA (cross-sectional DSSW approximation)\n\n")
##   DFV = (1-β_i) × Deposits/TA (cross-sectional DSSW approximation)
cat("MODEL 2: Temporal — BTFP & DW, Crisis vs. Arbitrage\n")
## MODEL 2: Temporal — BTFP & DW, Crisis vs. Arbitrage
cat("  BTFP: Crisis (Sol/Ins) + Arb (Sol/Ins) = 4 regressions\n")
##   BTFP: Crisis (Sol/Ins) + Arb (Sol/Ins) = 4 regressions
cat("  DW:   Crisis (Sol/Ins) + Arb (Sol/Ins) = 4 regressions\n")
##   DW:   Crisis (Sol/Ins) + Arb (Sol/Ins) = 4 regressions
cat("  Prediction: MTM × Uninsured strong in crisis, weak in arbitrage\n\n")
##   Prediction: MTM × Uninsured strong in crisis, weak in arbitrage
cat("MODEL 3: Deposit Beta Channel\n")
## MODEL 3: Deposit Beta Channel
cat("  Triple interaction: MTM × Uninsured × Uninsured_Beta\n")
##   Triple interaction: MTM × Uninsured × Uninsured_Beta
cat("  Tests whether panic is amplified for banks with flightier deposits\n")
##   Tests whether panic is amplified for banks with flightier deposits
cat("  7 regressions across 4 borrower types (nested + full)\n\n")
##   7 regressions across 4 borrower types (nested + full)
cat("MODEL 4: BTFP Complementarity with DW\n")
## MODEL 4: BTFP Complementarity with DW
cat("  4a. Multinomial: Facility choice {BTFP_Only, DW_Only, Both}\n")
##   4a. Multinomial: Facility choice {BTFP_Only, DW_Only, Both}
cat("  4b. Complementarity: Among DW borrowers, what drove also-BTFP?\n")
##   4b. Complementarity: Among DW borrowers, what drove also-BTFP?
cat("  4c. Substitution: BTFP-only vs DW-only, what drove the choice?\n")
##   4c. Substitution: BTFP-only vs DW-only, what drove the choice?
cat("  4d. Descriptive evidence on facility choice characteristics\n\n")
##   4d. Descriptive evidence on facility choice characteristics
cat("======================================================================\n")
## ======================================================================
cat("Tables saved to:", TABLE_PATH, "\n")
## Tables saved to: C:/Users/mferdo2/OneDrive - Louisiana State University/Finance_PhD/DW_Stigma_paper/Liquidity_project_2025/03_documentation/Four_Model_Analysis/tables
cat("Figures saved to:", FIG_PATH, "\n")
## Figures saved to: C:/Users/mferdo2/OneDrive - Louisiana State University/Finance_PhD/DW_Stigma_paper/Liquidity_project_2025/03_documentation/Four_Model_Analysis/figures
cat("======================================================================\n")
## ======================================================================