Macro simulations

NOTE: The present notebook is coded in R. It relies heavily on the tidyverse ecosystem of packages. We load the tidyverse below as a prerequisite for the rest of the notebook - along with a few other libraries.

\(\rightarrow\) Don’t forget that code flows sequentially. A random chunk may not work if the previous have have not been executed.

library(tidyverse)   # Package for data wrangling
library(readxl)      # Package to import MS Excel files
library(latex2exp)   # Package for LaTeX expressions
library(quantmod)    # Package for stock data extraction
library(highcharter) # Package for reactive plots
library(patchwork)   # Package for plot layout

The content of the notebook is based on the Macro Simulation website and the neoclassical case in particular.

1 Context

Until now, we have seen a lot of theory, but limited simulations… This notebook is intended on providing some elements in this direction. And to show if the models achieve convergence - or not.

2 The model

2.1 Production & co.

We first start with a Cobb-Douglas production function: \[Y=AK^aN^{1-a}, \quad a \in(0,1), \tag{1}\] where \(N\) is labour/employment/active population. Next, the real wages \[w=(1-a)A(K/N)^a \tag{2}\] This comes from the labour demand of profit-maximizing firms. Indeed, the profit is \[\Pi(N)=AK^aN^{1-a}-wN-\text{other costs}, \tag{3}\] hence the FOC is \(\frac{\partial \Pi}{\partial N}=(1-a)A(K/N)^a-w=0\) QED.

Government expenditures are tied by: \(G=T+B\), i.e., taxes plus debt. But the future value is \(G^f=T^f-(1+r)B\) because the interest of the debt must be reimbursed (no default). Solving for \(B\) gives

\[G+\frac{G^f}{1+r}=T+\frac{T^f}{1+r}. \tag{4}\]

Labor supply is given by \[N = 1-b_1/w. \tag{5}\]

One way to come to this result is the following and stems from arbitrage with respect to leisure. We can assume that the agent in the economy has utility \[U(C,N)= C+b \log(1-N),\]

where \(1-N\) represents (properly normalized) the time dedicated to leisure. The parameter \(b\) tunes how much leisure matters for the agent. At the same time, the agent needs to work to consume: \(C=wN\). There are thus two competing effects: increase work to consume more or decrease work to spend more time on leisure. The logarithmic function is key to obtaining the desired form.

The FOC with respect to N (replacing \(C\) in the above expression) is thus \[\frac{\partial U}{\partial N}=w-\frac{b}{1-N}=0 \quad \Leftrightarrow \quad w(1-N)=b \quad \Leftrightarrow \quad N=1-b/w\]

2.2 Consumption

In fact the true utility is more complex: \[U(C)=\log(C+b_1\log(1-N))+b_2\log(C^f), \] where \(C^f\) is future consumption (expected and treated as exogenous), which is subject to a budget constraint involving future output. The current constraint is
\[C=Y-T-S,\] i.e., what is consumed is what is produced, minus taxes minus what is saved at rate \(r\). The future version is \[C^f=Y^f-T^f+(1+r)S\] Solving for \(S\),

\[C^f=Y^f-T^f+(1+r)(Y-T-C),\] where we can replace taxes by government spending thanks to Equation 4: \[C^f=Y^f-G^f+(1+r)(Y-G-C),\]

Hence the utility becomes

\[U(C,N)=\log(C+b_1\log(1-N))+b_2\log(Y^f-G^f+(1+r)(Y-G-C))\]

Then,

\[\frac{\partial U}{\partial C}=\frac{1}{C+b_1\log(1-N)}-\frac{b_2(1+r)}{Y^f-G^f+(1+r)(Y-G-C)},\] so the FOC with respect to \(C\) is

\[C^f=b_2(1+r)(C+b_1\log(1-N)) \quad \Leftrightarrow \quad C=\frac{C^f}{b_2(1+r)}-b_1\log(1-N) \tag{6}\]

Also, the derivative with respect to \(N\) requires to recall $Y= + wN $:

\[\frac{\partial U}{\partial N}=\frac{-b_1}{(1-N)(C+b_1\log(1-N))}+\frac{b_2(1+r)w}{C^f}\] where we recognize a similar term from Equation 6, which gives

\[C=w\frac{(1-N)(C+b_1\log(1-N))}{b_1}-b_1\log(1-N)\]

and rearranging \[C+b_1\log(1-N)=w\frac{(1-N)(C+b_1\log(1-N))}{b_1} \Leftrightarrow b_1/w = (1-N)\] QED (same form as before!).

3 The code

In fact, the original code has some unnecessary parts if we are only interested in production or consumption.
Below, we keep only the required rows.

3.1 Initializing variables

S <- 5            # Number of scenarios (including baseline)
nb_sim <- 20      # Number of simulations

# Create and parameterise exogenous variables/parameters that will be shifted
G0 <- vector(length=S) # government expenditures
A <- vector(length=S)  # productivity
Yf <- vector(length=S) # expected future income
b1 <- vector(length=S) # household preference for leisure
G0[]=1
A[]=2
Yf[]=1
b1[]=0.4
# Set parameter values for different scenarios
G0[2] <- 2   # scenario 3: fiscal expansion
A[3] <- 3.5  # scenario 4: productivity boost
Yf[4] <- 0.2 # scenario 5: lower expected future income
b1[5] <- 0.8 # scenario 6: increased preference for leisure

#Set constant parameter values
a <- 0.3   # Capital elasticity of output
b2 <- 0.9  # discount rate
b3 <- 0.6  # household preference for money
K <- 5     # Exogenous capital stock
pe <- 0.02 # Expected rate of inflation
Gf <- 1    # Future government spending

# Initialise endogenous variables at arbitrary positive value
w <- matrix(1, ncol = S, nrow = nb_sim)
C = I = Y = r = N = P = w

3.2 Running the loop

#Solve this system numerically through 1000 iterations based on the initialization
for (i in 1:S){
  for (t in 2:nb_sim){
    #Model equations
    Y[t, i] <- A[i]*(K^a)*N[t-1, i]^(1-a)                 #(1) Cobb-Douglass production function  
    w[t, i] <- A[i]*(1-a)*(K^a)*N[t-1, i]^(-a)            #(2) Labor demand 
    N[t, i] <- 1 - (b1[i])/w[t-1, i]                      #(3) Labor supply
    #(4) Consumption demand
    C[t, i] <- (1/(1+b2+b3))*(Y[t-1, i] - G0[i] + (Yf[i]-Gf)/(1+r[t-1, i]) -b1[i]*(b2+b3)*log(b1[i]/w[t-1, i]))
    r[t, i] <- (I[t-1, i]^(a-1))*a*A[i]*N[t,i]^(1-a)      #(5) Investment demand, solved for r
    I[t, i] <- Y[t, i] - C[t,i] - G0[i]                   #(6) Goods market equilibrium condition, solved for I
  }
}

Let’s plot the result!

bind_cols(t = 1:nb_sim, as_tibble(Y)) |>
  pivot_longer(-t, names_to = "scenario", values_to = "production") |>
  ggplot(aes(x = t, y = production, color = scenario)) + geom_line() +
  theme_classic() + theme(legend.position.inside = c(0.5,0.5))

Some scenarios are redundant (initial choices have no impact).

Let’s have a look at consumption…

bind_cols(t = 1:nb_sim, as_tibble(C)) |>
  pivot_longer(-t, names_to = "scenario", values_to = "consumption") |>
  ggplot(aes(x = t, y = consumption, color = scenario)) + geom_line() +
  theme_classic() + theme(legend.position.inside = c(0.5,0.5))

Ok, some curves stop early… what happened? At time \(t=3\), the variable \(I\) became negative because \(G\) is too large!

What if we add a little noise on the production side? With small shocks to labor supply.

#Solve this system numerically through 1000 iterations based on the initialization
for (i in 1:S){
  for (t in 2:nb_sim){
    #Model equations
    Y[t, i] <- A[i]*(K^a)*N[t-1, i]^(1-a)                  # (1) Cobb-Douglass production function  
    w[t, i] <- A[i]*(1-a)*(K^a)*N[t-1, i]^(-a)             # (2) Labor demand 
    N[t, i] <- 1 - (b1[i])/w[t-1, i] + rnorm(1, sd = 0.02) # (3) Labor supply
  }
}
bind_cols(t = 1:nb_sim, as_tibble(Y)) |>
  pivot_longer(-t, names_to = "scenario", values_to = "production") |>
  ggplot(aes(x = t, y = production, color = scenario)) + geom_line() +
  theme_classic() + theme(legend.position.inside = c(0.5,0.5))

Ok so we still have convergence (mostly).
What if the shocks are ten times larger?

#Solve this system numerically through 1000 iterations based on the initialization
set.seed(42)
for (i in 1:S){
  for (t in 2:nb_sim){
    #Model equations
    Y[t, i] <- A[i]*(K^a)*N[t-1, i]^(1-a)                  # (1) Cobb-Douglass production function  
    w[t, i] <- A[i]*(1-a)*(K^a)*N[t-1, i]^(-a)             # (2) Labor demand 
    N[t, i] <- 1 - (b1[i])/w[t-1, i] + rnorm(1, sd = 0.2)  # (3) Labor supply
  }
}
bind_cols(t = 1:nb_sim, as_tibble(Y)) |>
  pivot_longer(-t, names_to = "scenario", values_to = "production") |>
  ggplot(aes(x = t, y = production, color = scenario)) + geom_line() +
  theme_classic() + theme(legend.position.inside = c(0.5,0.5))

Rocky, but still relatively consistent.