Chapter 5 - Nonlinear Interactions (Python Code)#

! pip install --upgrade quantecon_book_networks
Hide code cell output
Collecting quantecon_book_networks
  Obtaining dependency information for quantecon_book_networks from https://files.pythonhosted.org/packages/29/6e/3eaac581e7cf7b71e4b20ad018c035e602891cf16ab373a57859f4495cf6/quantecon_book_networks-1.1-py2.py3-none-any.whl.metadata
  Downloading quantecon_book_networks-1.1-py2.py3-none-any.whl.metadata (1.3 kB)
Requirement already satisfied: numpy in /usr/share/miniconda3/envs/networks/lib/python3.11/site-packages (from quantecon_book_networks) (1.24.3)
Requirement already satisfied: scipy in /usr/share/miniconda3/envs/networks/lib/python3.11/site-packages (from quantecon_book_networks) (1.11.1)
Requirement already satisfied: pandas in /usr/share/miniconda3/envs/networks/lib/python3.11/site-packages (from quantecon_book_networks) (2.0.3)
Requirement already satisfied: matplotlib in /usr/share/miniconda3/envs/networks/lib/python3.11/site-packages (from quantecon_book_networks) (3.7.2)
Collecting pandas-datareader (from quantecon_book_networks)
  Downloading pandas_datareader-0.10.0-py3-none-any.whl (109 kB)
?25l     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 0.0/109.5 kB ? eta -:--:--
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 109.5/109.5 kB 7.6 MB/s eta 0:00:00
?25h
Requirement already satisfied: networkx in /usr/share/miniconda3/envs/networks/lib/python3.11/site-packages (from quantecon_book_networks) (3.1)
Collecting quantecon (from quantecon_book_networks)
  Obtaining dependency information for quantecon from https://files.pythonhosted.org/packages/33/ea/e64e1be90daf370f5b190ceb298b9ac92105b3672775dce77acde8ccf603/quantecon-0.7.1-py3-none-any.whl.metadata
  Downloading quantecon-0.7.1-py3-none-any.whl.metadata (4.0 kB)
Collecting POT (from quantecon_book_networks)
  Obtaining dependency information for POT from https://files.pythonhosted.org/packages/66/62/e6107249236383a5e6c015bf2ec13b2b8e1c4abeb59a2915f754c2182990/POT-0.9.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata
  Downloading POT-0.9.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (30 kB)
Requirement already satisfied: contourpy>=1.0.1 in /usr/share/miniconda3/envs/networks/lib/python3.11/site-packages (from matplotlib->quantecon_book_networks) (1.0.5)
Requirement already satisfied: cycler>=0.10 in /usr/share/miniconda3/envs/networks/lib/python3.11/site-packages (from matplotlib->quantecon_book_networks) (0.11.0)
Requirement already satisfied: fonttools>=4.22.0 in /usr/share/miniconda3/envs/networks/lib/python3.11/site-packages (from matplotlib->quantecon_book_networks) (4.25.0)
Requirement already satisfied: kiwisolver>=1.0.1 in /usr/share/miniconda3/envs/networks/lib/python3.11/site-packages (from matplotlib->quantecon_book_networks) (1.4.4)
Requirement already satisfied: packaging>=20.0 in /usr/share/miniconda3/envs/networks/lib/python3.11/site-packages (from matplotlib->quantecon_book_networks) (23.1)
Requirement already satisfied: pillow>=6.2.0 in /usr/share/miniconda3/envs/networks/lib/python3.11/site-packages (from matplotlib->quantecon_book_networks) (9.4.0)
Requirement already satisfied: pyparsing<3.1,>=2.3.1 in /usr/share/miniconda3/envs/networks/lib/python3.11/site-packages (from matplotlib->quantecon_book_networks) (3.0.9)
Requirement already satisfied: python-dateutil>=2.7 in /usr/share/miniconda3/envs/networks/lib/python3.11/site-packages (from matplotlib->quantecon_book_networks) (2.8.2)
Requirement already satisfied: pytz>=2020.1 in /usr/share/miniconda3/envs/networks/lib/python3.11/site-packages (from pandas->quantecon_book_networks) (2023.3.post1)
Requirement already satisfied: tzdata>=2022.1 in /usr/share/miniconda3/envs/networks/lib/python3.11/site-packages (from pandas->quantecon_book_networks) (2023.3)
Requirement already satisfied: lxml in /usr/share/miniconda3/envs/networks/lib/python3.11/site-packages (from pandas-datareader->quantecon_book_networks) (4.9.3)
Requirement already satisfied: requests>=2.19.0 in /usr/share/miniconda3/envs/networks/lib/python3.11/site-packages (from pandas-datareader->quantecon_book_networks) (2.31.0)
Requirement already satisfied: numba>=0.49.0 in /usr/share/miniconda3/envs/networks/lib/python3.11/site-packages (from quantecon->quantecon_book_networks) (0.57.1)
Requirement already satisfied: sympy in /usr/share/miniconda3/envs/networks/lib/python3.11/site-packages (from quantecon->quantecon_book_networks) (1.11.1)
Requirement already satisfied: llvmlite<0.41,>=0.40.0dev0 in /usr/share/miniconda3/envs/networks/lib/python3.11/site-packages (from numba>=0.49.0->quantecon->quantecon_book_networks) (0.40.0)
Requirement already satisfied: six>=1.5 in /usr/share/miniconda3/envs/networks/lib/python3.11/site-packages (from python-dateutil>=2.7->matplotlib->quantecon_book_networks) (1.16.0)
Requirement already satisfied: charset-normalizer<4,>=2 in /usr/share/miniconda3/envs/networks/lib/python3.11/site-packages (from requests>=2.19.0->pandas-datareader->quantecon_book_networks) (2.0.4)
Requirement already satisfied: idna<4,>=2.5 in /usr/share/miniconda3/envs/networks/lib/python3.11/site-packages (from requests>=2.19.0->pandas-datareader->quantecon_book_networks) (3.4)
Requirement already satisfied: urllib3<3,>=1.21.1 in /usr/share/miniconda3/envs/networks/lib/python3.11/site-packages (from requests>=2.19.0->pandas-datareader->quantecon_book_networks) (1.26.16)
Requirement already satisfied: certifi>=2017.4.17 in /usr/share/miniconda3/envs/networks/lib/python3.11/site-packages (from requests>=2.19.0->pandas-datareader->quantecon_book_networks) (2023.7.22)
Requirement already satisfied: mpmath>=0.19 in /usr/share/miniconda3/envs/networks/lib/python3.11/site-packages (from sympy->quantecon->quantecon_book_networks) (1.3.0)
Downloading quantecon_book_networks-1.1-py2.py3-none-any.whl (364 kB)
?25l   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 0.0/364.8 kB ? eta -:--:--
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 364.8/364.8 kB 60.4 MB/s eta 0:00:00
?25h
Downloading POT-0.9.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (858 kB)
?25l   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 0.0/858.2 kB ? eta -:--:--
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 858.2/858.2 kB 49.6 MB/s eta 0:00:00
?25hDownloading quantecon-0.7.1-py3-none-any.whl (214 kB)
?25l   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 0.0/214.8 kB ? eta -:--:--
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 214.8/214.8 kB 75.7 MB/s eta 0:00:00
?25h
Installing collected packages: quantecon, POT, pandas-datareader, quantecon_book_networks
Successfully installed POT-0.9.3 pandas-datareader-0.10.0 quantecon-0.7.1 quantecon_book_networks-1.1

We begin with some imports

import quantecon as qe
import quantecon_book_networks
import quantecon_book_networks.input_output as qbn_io
import quantecon_book_networks.plotting as qbn_plt
import quantecon_book_networks.data as qbn_data
export_figures = False
import numpy as np
import networkx as nx
import matplotlib.pyplot as plt
from matplotlib import cm
quantecon_book_networks.config("matplotlib")

Financial Networks#

Equity-Cross Holdings#

Here we define a class for modelling a financial network where firms are linked by share cross-holdings, and there are failure costs as described by Elliott et al. (2014).

class FinNet:
    
    def __init__(self, n=100, c=0.72, d=1, θ=0.5, β=1.0, seed=1234):
        
        self.n, self.c, self.d, self.θ, self.β = n, c, d, θ, β
        np.random.seed(seed)
        
        self.e = np.ones(n)
        self.C, self.C_hat = self.generate_primitives()
        self.A = self.C_hat @ np.linalg.inv(np.identity(n) - self.C)
        self.v_bar = self.A @ self.e
        self.t = np.full(n, θ)
        
    def generate_primitives(self):
        
        n, c, d = self.n, self.c, self.d
        B = np.zeros((n, n))
        C = np.zeros_like(B)

        for i in range(n):
            for j in range(n):
                if i != j and np.random.rand() < d/(n-1):
                    B[i,j] = 1
                
        for i in range(n):
            for j in range(n):
                k = np.sum(B[:,j])
                if k > 0:
                    C[i,j] = c * B[i,j] / k
                
        C_hat = np.identity(n) * (1 - c)
    
        return C, C_hat
        
    def T(self, v):
        Tv = self.A @ (self.e - self.β * np.where(v < self.t, 1, 0))
        return Tv
    
    def compute_equilibrium(self):
        i = 0
        v = self.v_bar
        error = 1
        while error > 1e-10:
            print(f"number of failing firms is ", np.sum(v < self.θ))
            new_v = self.T(v)
            error = np.max(np.abs(new_v - v))
            v = new_v
            i = i+1
            
        print(f"Terminated after {i} iterations")
        return v
    
    def map_values_to_colors(self, v, j):
        cols = cm.plasma(qbn_io.to_zero_one(v))
        if j != 0:
            for i in range(len(v)):
                if v[i] < self.t[i]:
                    cols[i] = 0.0
        return cols

Now we create a financial network.

fn = FinNet(n=100, c=0.72, d=1, θ=0.3, β=1.0)

And compute its equilibrium.

fn.compute_equilibrium()
number of failing firms is  31
number of failing firms is  42
number of failing firms is  49
number of failing firms is  52
number of failing firms is  55
number of failing firms is  57
number of failing firms is  59
number of failing firms is  62
number of failing firms is  64
number of failing firms is  66
number of failing firms is  69
number of failing firms is  77
number of failing firms is  81
number of failing firms is  86
number of failing firms is  93
number of failing firms is  97
number of failing firms is  99
number of failing firms is  100
number of failing firms is  100
Terminated after 19 iterations
array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
       0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
       0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
       0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
       0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
       0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.])

Waves of bankruptcies in a financial network#

Now we visualise the network after different numbers of iterations.

For convenience we will first define a function to plot the graphs of the financial network.

def plot_fin_graph(G, ax, node_color_list):
    
    n = G.number_of_nodes()

    node_pos_dict = nx.spring_layout(G, k=1.1)
    edge_colors = []

    for i in range(n):
        for j in range(n):
            edge_colors.append(node_color_list[i])

    
    nx.draw_networkx_nodes(G, 
                           node_pos_dict, 
                           node_color=node_color_list, 
                           edgecolors='grey', 
                           node_size=100,
                           linewidths=2, 
                           alpha=0.8, 
                           ax=ax)

    nx.draw_networkx_edges(G, 
                           node_pos_dict, 
                           edge_color=edge_colors, 
                           alpha=0.4,  
                           ax=ax)

Now we will iterate by applying the operator \(T\) to the vector of firm values \(v\) and produce the plots.

G = nx.from_numpy_array(np.array(fn.C), create_using=nx.DiGraph)
v = fn.v_bar

k = 15
d = 3
fig, axes = plt.subplots(int(k/d), 1, figsize=(10, 12))

for i in range(k):
    if i % d == 0:
        ax = axes[int(i/d)]
        ax.set_title(f"iteration {i}")

        plot_fin_graph(G, ax, fn.map_values_to_colors(v, i))
    v = fn.T(v)
if export_figures:
    plt.savefig("figures/fin_network_sims_1.pdf")
plt.show()
_images/92ab31b6519201d819674534fc08460a295e2e7375348fd6dc888bd441708e97.png