!pip install --upgrade quantecon !conda install -y -c plotly plotly plotly-orca import numpy as np import matplotlib.pyplot as plt from scipy.stats import norm from numba import njit, prange from quantecon.optimize import root_finding %matplotlib inline #=========== Class: BCG for complete markets ===========# class BCG_complete_markets: # init method or constructor def __init__(self, 𝜒1 = 0, 𝜒2 = 0.9, w10 = 1, w20 = 1, 𝜃10 = 0.5, 𝜃20 = 0.5, 𝜓 = 3, 𝛼 = 0.6, A = 2.5, 𝜇 = -0.025, 𝜎 = 0.4, 𝛽 = 0.96, nb_points_integ = 10): #=========== Setup ===========# # Risk parameters self.𝜒1 = 𝜒1 self.𝜒2 = 𝜒2 # Other parameters self.𝜓 = 𝜓 self.𝛼 = 𝛼 self.A = A self.𝜇 = 𝜇 self.𝜎 = 𝜎 self.𝛽 = 𝛽 # Utility self.u = lambda c: (c**(1-𝜓)) / (1-𝜓) # Production self.f = njit(lambda k: A * (k ** 𝛼)) self.Y = lambda 𝜖, k: np.exp(𝜖) * self.f(k) # Initial endowments self.w10 = w10 self.w20 = w20 self.w0 = w10 + w20 # Initial holdings self.𝜃10 = 𝜃10 self.𝜃20 = 𝜃20 # Endowments at t=1 w11 = njit(lambda 𝜖: np.exp(-𝜒1*𝜇 - 0.5*(𝜒1**2)*(𝜎**2) + 𝜒1*𝜖)) w21 = njit(lambda 𝜖: np.exp(-𝜒2*𝜇 - 0.5*(𝜒2**2)*(𝜎**2) + 𝜒2*𝜖)) self.w11 = w11 self.w21 = w21 self.w1 = njit(lambda 𝜖: w11(𝜖) + w21(𝜖)) # Normal PDF self.g = lambda x: norm.pdf(x, loc=𝜇, scale=𝜎) # Integration x, self.weights = np.polynomial.hermite.hermgauss(nb_points_integ) self.points_integral = np.sqrt(2) * 𝜎 * x + 𝜇 self.k_foc = k_foc_factory(self) #=========== Optimal k ===========# # Function: solve for optimal k def opt_k(self, plot=False): w0 = self.w0 # Grid for k kgrid = np.linspace(1e-4, w0-1e-4, 100) # get FONC values for each k in the grid kfoc_list = []; for k in kgrid: kfoc = self.k_foc(k, self.𝜒1, self.𝜒2) kfoc_list.append(kfoc) # Plot FONC for k if plot: fig, ax = plt.subplots(figsize=(8,7)) ax.plot(kgrid, kfoc_list, color='blue', label=r'FONC for k') ax.axhline(0, color='red', linestyle='--') ax.legend() ax.set_xlabel(r'k') plt.show() # Find k that solves the FONC kk = root_finding.newton_secant(self.k_foc, 1e-2, args=(self.𝜒1, self.𝜒2)).root return kk #=========== Arrow security price ===========# # Function: Compute Arrow security price def q(self,𝜖,k): 𝛽 = self.𝛽 𝜓 = self.𝜓 w0 = self.w0 w1 = self.w1 fk = self.f(k) g = self.g return 𝛽 * ((w1(𝜖) + np.exp(𝜖)*fk) / (w0 - k))**(-𝜓) #=========== Firm value V ===========# # Function: compute firm value V def V(self, k): q = self.q fk = self.f(k) weights = self.weights integ = lambda 𝜖: np.exp(𝜖) * fk * q(𝜖, k) return -k + np.sum(weights * integ(self.points_integral)) / np.sqrt(np.pi) #=========== Optimal c ===========# # Function: Compute optimal consumption choices c def opt_c(self, k=None, plot=False): w1 = self.w1 w0 = self.w0 w10 = self.w10 w11 = self.w11 𝜃10 = self.𝜃10 Y = self.Y q = self.q V = self.V weights = self.weights if k is None: k = self.opt_k() # Solve for the ratio of consumption 𝜂 from the intertemporal B.C. fk = self.f(k) c1 = lambda 𝜖: (w1(𝜖) + np.exp(𝜖)*fk)*q(𝜖,k) denom = np.sum(weights * c1(self.points_integral)) / np.sqrt(np.pi) + (w0 - k) w11q = lambda 𝜖: w11(𝜖)*q(𝜖,k) num = w10 + 𝜃10 * V(k) + np.sum(weights * w11q(self.points_integral)) / np.sqrt(np.pi) 𝜂 = num / denom # Consumption choices c10 = 𝜂 * (w0 - k) c20 = (1-𝜂) * (w0 - k) c11 = lambda 𝜖: 𝜂 * (w1(𝜖)+Y(𝜖,k)) c21 = lambda 𝜖: (1-𝜂) * (w1(𝜖)+Y(𝜖,k)) return c10, c20, c11, c21 def k_foc_factory(model): 𝜓 = model.𝜓 f = model.f 𝛽 = model.𝛽 𝛼 = model.𝛼 A = model.A 𝜓 = model.𝜓 w0 = model.w0 𝜇 = model.𝜇 𝜎 = model.𝜎 weights = model.weights points_integral = model.points_integral w11 = njit(lambda 𝜖, 𝜒1, : np.exp(-𝜒1*𝜇 - 0.5*(𝜒1**2)*(𝜎**2) + 𝜒1*𝜖)) w21 = njit(lambda 𝜖, 𝜒2: np.exp(-𝜒2*𝜇 - 0.5*(𝜒2**2)*(𝜎**2) + 𝜒2*𝜖)) w1 = njit(lambda 𝜖, 𝜒1, 𝜒2: w11(𝜖, 𝜒1) + w21(𝜖, 𝜒2)) @njit def integrand(𝜖, 𝜒1, 𝜒2, k=1e-4): fk = f(k) return (w1(𝜖, 𝜒1, 𝜒2) + np.exp(𝜖) * fk) ** (-𝜓) * np.exp(𝜖) @njit def k_foc(k, 𝜒1, 𝜒2): int_k = np.sum(weights * integrand(points_integral, 𝜒1, 𝜒2, k=k)) / np.sqrt(np.pi) mul = 𝛽 * 𝛼 * A * k ** (𝛼 - 1) / ((w0 - k) ** (-𝜓)) val = mul * int_k - 1 return val return k_foc # Example: BCG model for complete markets mdl1 = BCG_complete_markets() mdl2 = BCG_complete_markets(𝜒2=-0.9) #==== Figure 1: HH endowments and firm productivity ====# # Realizations of innovation from -3 to 3 epsgrid = np.linspace(-1,1,1000) fig, ax = plt.subplots(1,2,figsize=(14,6)) ax[0].plot(epsgrid, mdl1.w11(epsgrid), color='black', label='Agent 1\'s endowment') ax[0].plot(epsgrid, mdl1.w21(epsgrid), color='blue', label='Agent 2\'s endowment') ax[0].plot(epsgrid, mdl1.Y(epsgrid,1), color='red', label=r'Production with $k=1$') ax[0].set_xlim([-1,1]) ax[0].set_ylim([0,7]) ax[0].set_xlabel(r'$\epsilon$',fontsize=12) ax[0].set_title(r'Model with $\chi_1 = 0$, $\chi_2 = 0.9$') ax[0].legend() ax[0].grid() ax[1].plot(epsgrid, mdl2.w11(epsgrid), color='black', label='Agent 1\'s endowment') ax[1].plot(epsgrid, mdl2.w21(epsgrid), color='blue', label='Agent 2\'s endowment') ax[1].plot(epsgrid, mdl2.Y(epsgrid,1), color='red', label=r'Production with $k=1$') ax[1].set_xlim([-1,1]) ax[1].set_ylim([0,7]) ax[1].set_xlabel(r'$\epsilon$',fontsize=12) ax[1].set_title(r'Model with $\chi_1 = 0$, $\chi_2 = -0.9$') ax[1].legend() ax[1].grid() plt.show() # Print optimal k kk_1 = mdl1.opt_k() kk_2 = mdl2.opt_k() print('The optimal k for model 1: {:.5f}'.format(kk_1)) print('The optimal k for model 2: {:.5f}'.format(kk_2)) # Print optimal time-0 consumption for agent 2 c20_1 = mdl1.opt_c(k=kk_1)[1] c20_2 = mdl2.opt_c(k=kk_2)[1] print('The optimal c20 for model 1: {:.5f}'.format(c20_1)) print('The optimal c20 for model 2: {:.5f}'.format(c20_2)) # Mesh grid of 𝜒 N = 30 𝜒1grid, 𝜒2grid = np.meshgrid(np.linspace(-1,1,N), np.linspace(-1,1,N)) k_foc = k_foc_factory(mdl1) # Create grid for k kgrid = np.zeros_like(𝜒1grid) w0 = mdl1.w0 @njit(parallel=True) def fill_k_grid(kgrid): # Loop: Compute optimal k and for i in prange(N): for j in prange(N): X1 = 𝜒1grid[i, j] X2 = 𝜒2grid[i, j] k = root_finding.newton_secant(k_foc, 1e-2, args=(X1, X2)).root kgrid[i, j] = k %%time fill_k_grid(kgrid) %%time # Second-run fill_k_grid(kgrid) #=== Example: Plot optimal k with different correlations ===# from IPython.display import Image # Import plotly import plotly.graph_objs as go # Plot optimal k fig = go.Figure(data=[go.Surface(x=𝜒1grid, y=𝜒2grid, z=kgrid)]) fig.update_layout(scene = dict(xaxis_title='x - 𝜒1', yaxis_title='y - 𝜒2', zaxis_title='z - k', aspectratio=dict(x=1,y=1,z=1))) fig.update_layout(width=500, height=500, margin=dict(l=50, r=50, b=65, t=90)) fig.update_layout(scene_camera=dict(eye=dict(x=2, y=-2, z=1.5))) # Export to PNG file Image(fig.to_image(format="png")) # fig.show() will provide interactive plot when running # notebook locally