SkillAgentSearch skills...

NetworkRiskMeasures

Implements risk measures for (financial) networks, such as DebtRank, Impact Susceptibility, Impact Diffusion and Impact Fluidity.

Install / Use

/learn @carloscinelli/NetworkRiskMeasures
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

<!-- README.md is generated from README.Rmd. Please edit that file -->

Travis-CI Build
Status Build
status CRAN_Status_Badge Coverage
Status

The Network Risk Measures (NetworkRiskMeasures) package implements a set of tools to analyze systemic risk in (financial) networks in a unified framework. We currently have implemented:

  • matrix reconstruction methods such as the maximum entropy (Upper, 2004) and minimum density estimation (Anand et al, 2015);
  • a flexible contagion algorithm with: (i) threshold propagation (traditional default cascades), (ii) linear propagation (aka DebtRank – Battiston et al (2012) and Bardoscia et al (2105)), (iii) a combination of threshold and linear propagation (iv) as well as any other custom propagation function provided by the user.
  • network risk measures based on the communicability matrix such as: impact susceptibility, impact diffusion and impact fluidity (Silva et al 2015a and 2015b).

CRAN

To install the CRAN version run:

install.packages("NetworkRiskMeasures")

How to install the development version from GitHub

To install the GitHub version you need to have the package devtools installed. Make sure to set the option build_vignettes = TRUE to compile the package vignette (not available yet).

# install.packages("devtools") # run this to install the devtools package
devtools::install_github("carloscinelli/NetworkRiskMeasures", build_vignettes = TRUE)

We are looking for interesting public datasets!

Most bilateral exposures data are confidential and can’t be used as examples on the package. So we are looking for interesting, public datasets on bilateral exposures for that purpose. If you have any suggestions, please let us know!

Example usage

Filling in the blanks: estimating the adjacency matrix

Many regulators have data on total interbank exposures but do not observe the network of bilateral exposures. That is, they only know the marginals of the interbank adjacency matrix. Consider the example below with 7 fictitious banks – banks A through G (Anand et al, 2015, p.628):

<!-- </br> --> <!-- <center> -->

<!-- </center> --> <!-- </br> -->

We know how much each bank has in the interbank market in the form of assets and liabilities (row and column sums)–but we do not know how each bank is related to each other. In those cases, if one wants to run contagion simulations or assess other risk measures, it is necessary to estimate the interbank network.

Two popular methods for this task are the maximum entropy (Upper, 2004) and minimum density estimation (Anand et al, 2015). These two methods are already implemented on the package. So, let’s build the interbank assets and liabilities vectors of our example (which are the row and column sums of the interbank network) to see how the estimation function works:

# Example from Anand, Craig and Von Peter (2015, p.628)
# Total Liabilities
L <- c(a = 4, b = 5, c = 5, d = 0, e = 0, f = 2, g = 4)

# Total Assets
A <- c(a = 7, b = 5, c = 3, d = 1, e = 3, f = 0, g = 1)

For the maximum entropy estimation we can use the matrix_estimation() function by providing the row (assets) sums, column (liabilities) sums and the parameter method = "me". The maximum entropy estimate of the interbank network assumes that each bank tries to diversify its exposures as evenly as possible, given the restrictions.

# Loads the package
library(NetworkRiskMeasures)
#> Loading required package: Matrix

# Maximum Entropy Estimation
ME <- matrix_estimation(rowsums = A, colsums = L, method = "me")
#> Starting Maximum Entropy estimation.
#> 
#> - Iteration number: 1 -- abs error: 2.0356 
#> - Iteration number: 2 -- abs error: 0.0555 
#> - Iteration number: 3 -- abs error: 0.004 
#> - Iteration number: 4 -- abs error: 3e-04 
#> 
#> Maximum Entropy estimation finished.
#>  * Total Number of Iterations: 4
#>  * Absolute Error: 3e-04

The resulting adjacency matrix is:

ME <- round(ME, 2)
ME
#>      a    b    c d e    f    g
#> a 0.00 2.53 2.18 0 0 0.74 1.55
#> b 1.72 0.00 1.60 0 0 0.54 1.14
#> c 0.98 1.06 0.00 0 0 0.31 0.65
#> d 0.25 0.27 0.23 0 0 0.08 0.17
#> e 0.75 0.81 0.70 0 0 0.24 0.50
#> f 0.00 0.00 0.00 0 0 0.00 0.00
#> g 0.30 0.32 0.28 0 0 0.09 0.00

This solution may work well in some cases, but it does not mimic some properties of interbank networks, which are known to be sparse and disassortative. Therefore, one proposed alternative to the maximum entropy is the “minimum density” estimation by Anand et al (2015). To do that in R, just change the parameter method to "md" in the matrix_estimation() function:

# Minimum Density Estimation
set.seed(192) # seed for reproducibility
MD <- matrix_estimation(A, L, method = "md")
#> Starting Minimum Density estimation.
#> 
#> - Iteration number: 1 -- total alocated: 0 % 
#> - Iteration number: 2 -- total alocated: 20 % 
#> - Iteration number: 3 -- total alocated: 25 % 
#> - Iteration number: 4 -- total alocated: 30 % 
#> - Iteration number: 5 -- total alocated: 30 % 
#> - Iteration number: 6 -- total alocated: 30 % 
#> - Iteration number: 7 -- total alocated: 30 % 
#> - Iteration number: 8 -- total alocated: 30 % 
#> - Iteration number: 9 -- total alocated: 30 % 
#> - Iteration number: 10 -- total alocated: 30 % 
#> - Iteration number: 11 -- total alocated: 45 % 
#> - Iteration number: 12 -- total alocated: 45 % 
#> - Iteration number: 13 -- total alocated: 55 % 
#> - Iteration number: 14 -- total alocated: 60 % 
#> - Iteration number: 15 -- total alocated: 60 % 
#> - Iteration number: 16 -- total alocated: 60 % 
#> - Iteration number: 17 -- total alocated: 75 % 
#> - Iteration number: 18 -- total alocated: 90 % 
#> - Iteration number: 19 -- total alocated: 90 % 
#> - Iteration number: 20 -- total alocated: 90 % 
#> - Iteration number: 21 -- total alocated: 90 % 
#> - Iteration number: 22 -- total alocated: 100 % 
#> 
#> Minimum Density estimation finished.
#>  * Total Number of Iterations: 22
#>  * Total Alocated: 100 %

The resulting adjacency matrix is:

MD
#>   a b c d e f g
#> a 0 3 0 0 0 0 4
#> b 3 0 2 0 0 0 0
#> c 0 2 0 0 0 1 0
#> d 0 0 0 0 0 1 0
#> e 0 0 3 0 0 0 0
#> f 0 0 0 0 0 0 0
#> g 1 0 0 0 0 0 0

We intend to implement other estimation methods used in the literature. For an overview of current proposed methods and how well they fit known networks, you may watch Anand’s presentation below:

<!-- </br> --> <!-- <center> --> <iframe src="https://player.vimeo.com/video/145290048" width="640" height="360" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen> </iframe> <p> <a href="https://vimeo.com/145290048">The missing links: a global study on uncovering financial network structure from partial data</a> from <a href="https://vimeo.com/cambridgejbs">Cambridge Judge Business School</a> on <a href="https://vimeo.com">Vimeo</a>. </p> <!-- </center> --> </br>

Measuring risk: finding systemically important institutions and simulating scenarios

Two important questions:

  • How can we find important or systemic institutions?
  • How can we estimate the impact of shock scenarios, considering possible contagion effects?

The example data: simulated interbank network

For illustration purposes, the NetworkRiskMeasures package comes with a simulated dataset of interbank assets, liabilities, capital buffer and weights for 125 nodes. Let’s use it for our analysis:

# See the code to generate the dataset in the help files: ?sim_data.
data("sim_data")
head(sim_data)
#>   bank     assets liabilities   buffer   weights
#> 1   b1 0.37490927   9.6317127 5.628295 17.119551
#> 2   b2 0.66805904   0.7126552 2.847072  6.004475
#> 3   b3 0.79064804   0.3089983 3.983451  6.777531
#> 4   b4 0.02420156   0.6562193 5.657779  7.787618
#> 5   b5 0.65294261   0.9153901 4.446595  8.673730
#> 6   b6 0.60766835   0.3007373 2.252369  4.708805

In this example, we do not observe the real network, only the marginals (total assets and liabilities). Thus, we must estimate the adjacency matrix before running the contagion simulations or calculating other network measures. For now, we will use the minimum density estimation:

# seed - min. dens. estimation is stochastic
set.seed(15) 

# minimum density estimation
# verbose = F to prevent printing
md_mat <- matrix_estimation(sim_data$assets, sim_data$liabilities, method = "md", verbose = F)

# rownames and colnames for the matrix
rownames(md_mat) <- colnames(md_mat) <- sim_data$bank

Once we have our network, we can visualize it either using igraph or ggplot2 along with the ggnetwork package. Below we give an example with ggplot2 – it’s useful to remember that we have an assets matrix, so a → b means that node a has an asset with node b:

library(ggplot2)
library(ggnetwork)
library(igraph)

# converting our network to an igraph object
gmd <- graph_from_adjacency_matrix(md_mat, weighted = T)

# adding other node attributes to the network
V(gmd)$buffer <- sim_data$buffer
V(gmd)$weights <- sim_data$weights/sum(sim_data$weights)
V(gmd)$assets  <- sim_data$assets
V(gmd)$liabilities <- sim_data$lia
View on GitHub
GitHub Stars76
CategoryDevelopment
Updated7d ago
Forks33

Languages

R

Security Score

80/100

Audited on Mar 29, 2026

No findings