Introduction
With the recent news of major bank collapses it seems like a good time to investigate the performance of US banks. We will start by examining data from the Federal Reserve and then take a look at stock performance where applicable.
The most recent US bank collapses are from Silicon Valley Bank (SVB) ranked 16th in our data and Signature Bank ranked 29th. We will be certain to examine their stock values leading up to their collapse.
As is standard with my R projects we will load the relevant R packages.
library(here)
library(readODS)
library(quantmod)
library(magrittr)
library(plotly)
We will go ahead and load up the Federal reserve banking data now and get the stock data later.
fp <- here("csv", "banks", "large_commercial_banks20221231.ods")
if (!file.exists(here::here("csv", "banks", "lcb_temp.RData")))
{
banks <- readODS::read_ods(fp)
save(banks, file = here::here("csv", "banks", "lcb_temp.RData"))
} else {
load(here::here("csv", "banks", "lcb_temp.RData"))
}
Bank Dataset
Let’s get some statistics about these banks. Note that according to the data source these are “insured U.S.-chartered commercial banks that have consolidated assets of $300 million or more.” Let’s take a look at the data structure below.
str(banks)
## 'data.frame': 2135 obs. of 12 variables:
## $ Bank Name / Holding Co Name: chr "JPMORGAN CHASE BK NA/JPMORGAN CHASE & CO" "BANK OF AMER NA/BANK OF AMER CORP" "CITIBANK NA/CITIGROUP" "WELLS FARGO BK NA/WELLS FARGO & CO" ...
## $ Nat'l Rank : num 1 2 3 4 5 6 7 8 9 10 ...
## $ Bank ID : num 852218 480228 476810 451965 504713 ...
## $ Bank Location : chr "COLUMBUS, OH" "CHARLOTTE, NC" "SIOUX FALLS, SD" "SIOUX FALLS, SD" ...
## $ Charter : chr "NAT" "NAT" "NAT" "NAT" ...
## $ Consol Assets (Mil $) : num 3201942 2418508 1766752 1717531 585136 ...
## $ Domestic Assets (Mil $) : num 2480688 2291312 1069311 1693335 574872 ...
## $ Pct Domestic Assets : num 77 95 61 99 98 100 100 90 100 100 ...
## $ Pct Cumulative Assets : num 15 26 34 42 45 47 50 52 54 56 ...
## $ Domestic Branches : num 4791 3819 661 4670 2236 ...
## $ Foreign Branches : num 33 24 144 10 1 1 0 2 1 0 ...
## $ IBF : chr "Y" "Y" "Y" "Y" ...
From this we can see that we have a dataset of 2135 banks. Let’s see how much their total assets are worth as well as total assets in the US.
total_assets <- sum(banks$`Consol Assets (Mil $)`) / 1000000
us_assets <- sum(banks$`Domestic Assets (Mil $)`) / 1000000
Reporting these results in trillions of dollars we have total assets of $21.696593 trillion and US assets of $19.826428 trillion.
Let’s take a quick look at the top 30 banks and their total Assets
knitr::kable(banks[1:30, c("Bank Name / Holding Co Name", "Nat'l Rank", "Consol Assets (Mil $)", "Domestic Assets (Mil $)")])
Bank Name / Holding Co Name | Nat’l Rank | Consol Assets (Mil $) | Domestic Assets (Mil $) |
---|---|---|---|
JPMORGAN CHASE BK NA/JPMORGAN CHASE & CO | 1 | 3201942 | 2480688 |
BANK OF AMER NA/BANK OF AMER CORP | 2 | 2418508 | 2291312 |
CITIBANK NA/CITIGROUP | 3 | 1766752 | 1069311 |
WELLS FARGO BK NA/WELLS FARGO & CO | 4 | 1717531 | 1693335 |
U S BK NA/U S BC | 5 | 585136 | 574872 |
PNC BK NA/PNC FNCL SVC GROUP | 6 | 552307 | 550670 |
TRUIST BK/TRUIST FC | 7 | 546228 | 546148 |
GOLDMAN SACHS BK USA/GOLDMAN SACHS GROUP THE | 8 | 486967 | 439365 |
CAPITAL ONE NA/CAPITAL ONE FC | 9 | 453313 | 452784 |
T D BK NA/TD GRP US HOLDS LLC | 10 | 386799 | 386799 |
BANK OF NY MELLON/BANK OF NY MELLON CORP | 11 | 324646 | 236858 |
STATE STREET B&TC/STATE STREET CORP | 12 | 298020 | 209177 |
CITIZENS BK NA/CITIZENS FNCL GRP | 13 | 226402 | 226402 |
FIRST REPUBLIC BK/ | 14 | 212639 | 212639 |
MORGAN STANLEY PRIV BK NA/MORGAN STANLEY | 15 | 209664 | 209664 |
SILICON VALLEY BK/SVB FNCL GRP | 16 | 209026 | 194514 |
FIFTH THIRD BK NA/FIFTH THIRD BC | 17 | 206289 | 206099 |
MORGAN STANLEY BK NA/MORGAN STANLEY | 18 | 201363 | 201363 |
MANUFACTURERS & TRADERS TC/M&T BK CORP | 19 | 200263 | 200263 |
KEYBANK NA/KEYCORP | 20 | 187590 | 187588 |
HUNTINGTON NB/HUNTINGTON BSHRS | 21 | 182326 | 182326 |
ALLY BK/ALLY FNCL | 22 | 181890 | 181890 |
BMO HARRIS BK NA/BMO FNCL CORP | 23 | 176980 | 176980 |
HSBC BK USA NA/HSBC N AMER HOLDS | 24 | 162437 | 162436 |
AMERICAN EXPRESS NB/AMERICAN EXPRESS CO | 25 | 155378 | 155378 |
NORTHERN TC/NORTHERN TR CORP | 26 | 154523 | 112890 |
REGIONS BK/REGIONS FC | 27 | 154203 | 154203 |
DISCOVER BK/DISCOVER FS | 28 | 129386 | 129386 |
SIGNATURE BK/ | 29 | 110364 | 110364 |
FIRST-CITIZENS B&TC/FIRST CITIZENS BSHRS | 30 | 109180 | 109125 |
So clearly these banks have a significant amount of assets. It would be interesting to see how these assets have changed over time, but we do not have that data and are more interested in looking at stock values to use as an indicator of a possible bank collapse.
Stock prices for Failing Banks
In this section we are going to look at the stock prices of the two banks which have collapsed: SVB and Signature Bank. We will also look at First Republic Bank which has been talked about as being at risk. Using the quantmod
package we are able to get our data.
SIVB <- getSymbols("SIVB", src='yahoo', env=NULL, to="2023-03-28", periodicity = "monthly")
SBNY <- getSymbols("SBNY", src='yahoo', env=NULL, to="2023-03-28", periodicity = "monthly")
FRC <- getSymbols("FRC", src='yahoo', env=NULL, to="2023-03-28", periodicity = "monthly")
To graph our data using plotly
we need create a function that does all the hard work for us. We will use a candlestick plot since we are using OHLC data.
# Function used to take xts symbol data and plot candlestick graph
convert_and_plot <- function (symbol, title) {
# convert xts data to a dataframe
df <- data.frame(Date=index(symbol), coredata(symbol))
# create volume plot
volume <- df %>% plot_ly(x=~Date, y=~df[, 6], type='bar',
name="Volume",
colors=c('#17BECF','#7F7F7F'))
volume %<>% layout(yaxis=list(title="Volume"))
# create the main candlestick plot
main <- df %>% plot_ly(x = ~Date, type="candlestick",
open = ~df[, 2], close = ~df[, 5],
high = ~df[, 3], low = ~df[, 4])
main %<>% layout(title = title,
xaxis = list(rangeslider = list(visible = FALSE)))
# combine plots
figure <- subplot(main, volume, heights=c(0.7, 0.2), nrows=2,
shareX=TRUE, titleY=TRUE)
return(figure)
}
Below we show plots for the three banks of interest.
convert_and_plot(SIVB, "Silicon Valley Bank Stock Price")
convert_and_plot(SBNY, "Signature Bank Stock Price")
convert_and_plot(FRC, "First Republic Bank Stock Price")
The common structure we can see in these plots is a sharp price decline starting around January 2022 when the Federal reserve bank started raising interest rates.
Stock Prices for Top 5 Banks
For the sake of comparison let’s take a look at the top 5 banks. Below we collect the data.
JPM <- getSymbols("JPM", src='yahoo', env=NULL, to="2023-03-28", periodicity = "monthly")
BAC <- getSymbols("BAC", src='yahoo', env=NULL, to="2023-03-28", periodicity = "monthly")
C <- getSymbols("C", src='yahoo', env=NULL, to="2023-03-28", periodicity = "monthly")
WFC <- getSymbols("WFC", src='yahoo', env=NULL, to="2023-03-28", periodicity = "monthly")
USB <- getSymbols("USB", src='yahoo', env=NULL, to="2023-03-28", periodicity = "monthly")
Now that we have the data we utilize our function to plot them out.
convert_and_plot(JPM, "JPMorgan Chase & Co Stock Price")
convert_and_plot(BAC, "Bank of America Corp Stock Price")
convert_and_plot(C, "Citigroup Inc Stock Price")
convert_and_plot(WFC, "Wells Fargo & Co Stock Price")
convert_and_plot(USB, "US Bancorp Stock Price")
The 5 top banks do not appear to be in as much trouble as the first 3 banks we looked at. Citigroup has the worst long term trend though and US Bancorp appears to have the worst reaction to the current market.
Conclusion
Based on these graphs it appears that the three weaker banks we first examined had very fast growth followed by a harsh decline. This decline was likely started due to the Federal reserve bank raising rates. It appears that in each case these banks had some slight relief before breaking down in price even further. The major banks while appearing to drop in price as well seem to have better price support. Instead of having a short relief in price the major banks appeared to have built up some price support. Essentially the larger banks appeared to enter a trading range while the weaker banks could not find support. Of course with the recent news the larger banks are once again in some possible trouble. It could take weeks or months to determine if they can continue to hold up to the current public concern.