9 min read

The Tale of the TALF (2.0)

Yet another week and yet another TALF update. While I haven’t been posting to the blog, rest assured attention has been paid to this slice of fixed income esoterica. Never one to bury the lede, readers of this post are rewarded with a summary of who’s who in the land of TALF.

The TALF Backstory

For those unaware, and in so few words, TALF–the Fed’s Term Asset-Backed Securities Loan Facility–is a program which first appeared on planet Earth in 2008 as a means to support the seizing consumer and small business (and latterly, the commercial real estate) credit markets.

The facility provides very cheap financing for investors to leverage their purchases of TALF-eligible securities (mostly securities backed by consumer, commercial real estate, or small business loans). The theory is that cheap borrowing costs incentivize investors to buy a lot of these securities, thereby lowering the borrowing costs borne by end borrowers.

TALF 2.0

In the wake of the coronavirus fallout, the Fed restarted the program. Unlike TALF 1.0, TALF 2.0 has been decidedly less necessary as securitized spreads have largely tightened to levels which make even the Fed’s cheap lending rates uneconomic. It has other minor differences from TALF 1.0, but the terms are largely the same.

As the program winds down (no new TALF loans will be made after 2020-12-31), it is worth looking at what’s happened.

Take a look at 3Y Prime Auto Spreads. In March, these AAA stalwarts offered ~200 bps over LIBOR. Today? I’ve seen some shorter paper clear ~ 10 bps. The point is, one must presume a bunch of folks got all dressed up and ready to go for TALF 2.0…but there’s been nowhere to go.

The first subscription date was 2020-06-17. Spreads had already ratcheted in substantially from the March wides.

Who’s doing what to whom?

But, lest you think our investment manager friends who paid out of pocket for TALF fund set up costs & gallivanted around the globe (on Zoom) raising money, would be stopped at the prospect of meager returns!

Here is the breakdown of those investment managers who’ve actually taken down TALF loans.

Summary of TALF Lending By Investment Manager
Millions of USD | Data Through 2020-11-09
Manager CLO CMBS Insurance SBA 504 SBA 7(a) Student Loan CUSIPs Avg Loan Total
BELSTAR $328 $251 $152 $1,327 $24 114 $18.3 $2,081
MACKAY SHIELDS $298 $56 $143 $221 $102 40 $20.5 $819
PALMER SQUARE $212 24 $8.8 $212
PIMCO $26 $19 $78 5 $24.4 $122
BLACKROCK $24 $82 7 $15.1 $106
VOYA $87 4 $21.8 $87
BARINGS $71 15 $4.7 $71
TORTOISE CAPITAL $38 $5 $17 9 $6.7 $60
NUVERSE $7 $34 9 $4.6 $41
WELLINGTON $39 4 $9.8 $39
INVESCO $34 5 $6.8 $34
SCHRODERS $12 2 $6.0 $12
JENNISON ASSOCIATES $10 1 $10.0 $10
Total $328 $1,085 $74 $415 $1,565 $226 239 $15.5 $3,693

WOW! Revealing. Recall, all data is in millions of USD. Here are the key lessons to draw:

  • Total TALF lending is ~$3.7B, a paltry sum compared to the $71B lend over ~1.5 years in TALF 1.0
  • Two managers, Belstar & Mackay Shields, account for nearly 80% of the borrowing
    • These two have taken different strategies with Belstar loading the boat with SBA 7(a) loans & Mackay Shields building a well diversified portfolio
    • Belstar’s avg loan size was $18.3MM and Mackay Shields’ avg loan was $20.5MM. The overall avg loan size is $15.5, and the avg ex. Belstar is $13MM
  • CMBS has been the fading death star of the show, with nearly all TALF funds (who’ve subscribed at all) allocating to this sector. I have it on good authority that the expected levered IRRs for these bonds, even in June, were ~5%. Today, most are closer to ~3%.

So long as returns are reasonably positive, Belstar and Mackay Shields appear to be have good stories for their investors. Unlike Schroders, who tied up $12MM of investor capital for minuscule returns and no diversification, the two heavy weights have done an impressive job of building diversified portfolios.

For those interested, the code to reproduce this post is below.

library(tidyverse)
library(readxl)
library(gt)
library(janitor)

# function for downloads

xl_download <- function(link) {
  temp <- tempfile()
  download.file(link, destfile = temp, mode = "wb")
  out_df <- read_excel(temp, sheet = "TALF Loan Level Data") %>% 
    clean_names()
  
  #clean up
  file.remove(temp)
  return(out_df)
}

# get talf data

talf_data <- xl_download("https://www.federalreserve.gov/publications/files/talf-transaction-specific-disclosures-11-9-20.xlsx")

# overall manager information, lots of cleaning

overall <- talf_data %>% 
  rename(manager = investment_manager_for_the_borrower) %>%
  mutate(collat_type = case_when(
    collateral_sub_sector == "Conduit" ~ "CMBS",
    collateral_sub_sector == "Static" ~ "CLO",
    collateral_sub_sector == "Property and Casualty" ~ "Insurance",
    str_detect(collateral_sub_sector, "SBA 504") ~ "SBA 504",
    str_detect(collateral_sub_sector, "SBA 7") ~ "SBA 7(a)",
    str_detect(collateral_sub_sector, "Private") ~ "Student Loan"),
    collat_type = factor(collat_type, levels = c("CLO", "CMBS", "Insurance", "SBA 504", "SBA 7(a)", "Student Loan")),
    manager = trimws(gsub("LLC|Management Company|LLP|Advis(e|o)rs|Inc|,|L\\.L\\.C|\\.|((alternative )asset|capital|financial) management", "", manager, ignore.case = T)),
    manager = toupper(manager),
    manager = case_when(grepl("PACIFIC", manager) ~ "PIMCO", grepl("SCHROD", manager) ~ "SCHRODERS", TRUE ~ manager)
    ) %>% 
  group_by(manager, collat_type) %>% 
  summarise(loan = sum(current_loan_amount_outstanding),
            n = n()) %>% 
  arrange(-loan)

# count cusips

n_cusips <- overall %>% 
  group_by(manager) %>% 
  summarise(CUSIPs = sum(n)) %>% 
  add_row(manager = "Total", CUSIPs = sum(.$CUSIPs))

# investor data

investor_table <- overall %>% 
  filter(loan > 0) %>% 
  pivot_wider(-n, names_from = collat_type, values_from = loan) %>% 
  ungroup() %>% 
  mutate(Total = rowSums(.[, 2:ncol(.)], na.rm = T))

investor_sum <- tibble(
  col_head = colnames(investor_table),
  value = c(NA, as.numeric(colSums(investor_table[,2:ncol(investor_table)], na.rm = T)))
) %>% 
  pivot_wider(names_from = "col_head", values_from = "value") %>% 
  mutate(manager = "Total")

# put it together

summary_df <- bind_rows(investor_table, investor_sum) %>% 
  mutate(across(-c(manager), ~ scales::dollar(. / 1e6, accuracy = 1)),
         across(-c(manager), ~ replace_na(., replace = ""))) %>% 
  left_join(n_cusips, by = "manager") %>% 
  ungroup() %>% 
  rename(Manager = manager) %>% 
  mutate(`Avg Loan` = scales::dollar(parse_number(Total) / CUSIPs, accuracy = 0.1)) %>% 
  .[ c("Manager","CLO", "CMBS", "Insurance", "SBA 504", "SBA 7(a)", 
       "Student Loan", "CUSIPs", "Avg Loan","Total")] 

# gt out

summary_df %>% 
  gt() %>% 
  tab_header(
    title = md("**Summary of TALF Lending By Investment Manager**"),
    subtitle = "Millions of USD | Data Through 2020-11-09"
  ) %>% 
  cols_align(
    align = "left",
    columns = vars(Manager)
  ) %>% 
  tab_options(
    column_labels.font.weight = "bold",
    table.font.names = "Gill Sans MT"
  ) %>% 
  cols_align(
    align = "center",
    columns = 2:ncol(summary_df)
  ) %>% 
  tab_style(
    style = list(
      cell_text(weight = "bold")
    ),
    locations = cells_body(
      columns = everything(),
      rows = grepl("Total", summary_df$Manager)
      )
  ) %>% 
  tab_style(
    style = list(
      cell_text(weight = "bold")
    ),
    locations = cells_body(
      columns = vars(Total)
    )
  ) %>% 
  tab_style(
    style = list(
      cell_fill(color = "grey90")
    ),
    locations = cells_body(
      columns = everything(),
      rows = c(1, 3, 5, 7, 9, 11, 13)
    )
  ) %>% 
  tab_style(
    style = cell_borders(
      sides = c("top"),
      color = "black",
      weight = px(2),
      style = "solid"
    ),
    locations = cells_body(
      columns = everything(),
      rows = grepl("BELSTAR|Total", summary_df$Manager)
    )
  )