0

I'm trying to simulate a fairly standard RBC model. The equations used in the code are all correct based on the chosen specification, so my question relates more to the implementation side.

Specifically, I want to use the technology shock generated in z_hat:

# Generate the autoregressive process for the technology shock:
for t in range(1, T):
    # Each period the shock decays by the factor rho_z, mimicking an AR(1) process.
    z_hat[t] = rho_z * z_hat[t - 1]

to influence the other model equations recursively. The responses of the model variables are captured in the for loop that follows.

The issue is this: when I run the code as it is, the impulse response functions (IRFs) appear to be flipped. I only get the expected graph if I reverse the order of the calculated IRFs for each variable.

Has anyone encountered a similar issue or can spot what might be going wrong in how the IRFs are being generated or stored? I attached the code which created the IRFs and the full code.

Thanks in advance!

Important part of the code:

# Generate the autoregressive process for the technology shock:
for t in range(1, T):
    # Each period the shock decays by the factor rho_z, mimicking an AR(1) process.
    z_hat[t] = rho_z * z_hat[t - 1]

# Initialize arrays to store the log-deviations from steady state for various variables.
# The deviations represent percentage deviations from the benchmark steady state.
c_hat = np.zeros(T+1)  # Consumption log-deviation, extra period for terminal condition.
i_hat = np.zeros(T)    # Investment log-deviation.
k_hat = np.zeros(T+1)  # Capital log-deviation, extra period due to accumulation.
y_hat = np.zeros(T)    # Output log-deviation.
r_hat = np.zeros(T)    # Interest rate log-deviation.
w_hat = np.zeros(T)    # Wage log-deviation.
l_hat = np.zeros(T)    # Labor log-deviation.

# Terminal condition is assumed for consumption: c_T = 0 (i.e., no deviation at the final period).

# Set initial conditions: assume no deviation in capital and consumption at time t = 0.
k_hat[0] = 0
c_hat[0] = 0

# Loop over each time period to simulate the dynamic responses (Impulse Response Functions - IRFs)
for t in range(T):

    # 1. Factor Prices from Marginal Products:
    # The wage (w_hat) is determined as the sum of the technology shock and contributions from
    # capital and labor deviations scaled by the capital share.
    w_hat[t] = z_hat[t] + alpha * k_hat[t] - alpha * l_hat[t]
    # The rental rate (r_hat) is calculated using the marginal product conditions;
    # it is affected by the deviation of capital and labor.
    r_hat[t] = (alpha - 1) * k_hat[t] + z_hat[t] + (1 - alpha) * l_hat[t]

    # 2. Labor Supply from the Intratemporal Condition:
    # The log-deviation of labor (l_hat) is updated based on the difference between wages and consumption,
    # scaled by the ratio ((1-L_ss)/L_ss), which captures the elasticity in this specification.
    l_hat[t] = (w_hat[t] - c_hat[t]) * ((1 - L_ss) / L_ss)

    # 3. Output Computation:
    # Output is determined by combining the contributions of capital and labor deviations weighted by alpha and
    # (1-alpha), respectively, then adding the technology shock.
    # This update is performed after updating the labor deviation.
    y_hat[t] = alpha * k_hat[t] + (1 - alpha) * l_hat[t] + z_hat[t]

    # 4. Investment from the Resource Constraint:
    # Investment log-deviation is calculated using the resource constraint where output minus the scaled consumption
    # is divided by the share of investment in output.
    i_hat[t] = (y_hat[t] - phi_c * c_hat[t]) / phi_i

    # 5. Capital Accumulation:
    # The next period's capital log-deviation is determined by the current capital after depreciation and the
    # new investment weighted by delta, representing the adjustment process.
    k_hat[t + 1] = (1 - delta) * k_hat[t] + delta * i_hat[t]

    # 6. Euler Equation (Consumption Dynamics):
    # According to the Euler equation in a log-linearized setting, the change in the consumption deviation
    # equals the product of the steady state return factor (beta*q_ss) and the rental rate deviation.
    c_hat[t + 1] = c_hat[t] + (beta * q_ss) * r_hat[t]

Full code:

###############################################################################
# Loading Required Packages
###############################################################################
# Import the numpy package for efficient numerical computing and array manipulation.
import numpy as np
# Import sympy for symbolic mathematics (e.g., symbolic algebra, calculus).
import sympy as sp
# Import matplotlib's pyplot for plotting and creating visualizations.
import matplotlib.pyplot as plt
# Set the seed for NumPy's random number generator to ensure that any random processes produce
# the same output every time the code is run (this aids in reproducibility).
np.random.seed(42)  # optional, for reproducibility
# Import the math module for accessing standard mathematical functions.
import math

###############################################################################
# End of package loading
###############################################################################


###############################################################################
###############################################################################
# 1% Shock in Technology: Set up the DSGE model environment and steady state.
###############################################################################
###############################################################################

# Starting parameter values for our DSGE model:

# beta: Discount factor, reflecting how future payoffs are weighted relative to present ones.
beta = 0.96
# delta: Depreciation rate of capital per period.
delta = 0.1
# p: Capital's share of output (alternatively represented as alpha in many models).
p = 0.36
# Lss: Steady-state (or initial) labor input; here, representing a small fraction for the population.
Lss = 0.01  # Population starting value
# z: Technology level; initially set to a small value (here equivalent to a 1% initial shock).
z = 0.01

# Define functions to compute steady state values using the model's equations.
# These functions calculate key economic quantities as functions of the parameters and z.

def K_fun(beta, delta, p, Lss, z):
    """
    Computes the steady state level of Capital (K) using the model's formula.
    The expression is derived from equating marginal products and other steady state conditions.
    """
    global K_expr
    # The expression involves the technology term z, labor Lss and other parameters.
    K_expr = (p * Lss**(1 - p) * z / (1/beta - 1 + delta))**(1/(1 - p))
    return K_expr

def q_fun(beta, delta, p, Lss, z):
    """
    Computes the steady state marginal product of capital (q) which is related 
    to the return on capital.
    """
    global q_expr
    # The function inverts part of the K_fun expression and rescales it by z, p and Lss.
    q_expr = z * p * (p * Lss**(1 - p) * z / (1/beta - 1 + delta))**(-1) * Lss**(1 - p)
    return q_expr

def w_fun(beta, delta, p, Lss, z):
    """
    Computes the steady state wage (w) as given by the marginal product of labor.
    """
    global w_expr
    # Note the use of the exponent p/(1-p) in the wage formula, capturing the relative power
    # of capital’s effect adjusted by the labor share.
    w_expr = z * (1 - p) * Lss**(-p) * (p * Lss**(1 - p) * z / (1/beta - 1 + delta))**(p/(1 - p))
    return w_expr

def Y_fun(beta, delta, p, Lss, z):
    """
    Computes the steady state level of Output (Y) using the production function.
    This function assumes a Cobb-Douglas production function depending on K and L.
    """
    global Y_expr
    # K_expr is used here, and it is assumed to be computed before using K_fun.
    Y_expr = z * (K_expr)**p * Lss**(1 - p)
    return Y_expr

def I_fun(beta, delta, p, Lss, z):
    """
    Computes the level of Investment (I) in the steady state.
    Investment is proportional to the capital stock through the depreciation rate.
    """
    global I_expr
    I_expr = delta * K_expr
    return I_expr

def C_fun(beta, delta, p, Lss, z):
    """
    Computes steady state Consumption (C) as the residual of output after investment.
    """
    global C_expr
    C_expr = Y_expr - I_expr
    return C_expr

def L_fun(beta, delta, p, Lss, z):
    """
    Provides the value of steady state labor. Here it is set to L_ss (previously defined),
    implying fixed labor input in the model.
    """
    global L_expr
    L_expr = Lss
    return L_expr

# ---------------------------
# 2. Define the steady state equations (as expressions) in terms of z
# ---------------------------
# Compute the steady state values using the defined functions.
# These are the benchmark values around which log-linearized deviations are computed.
K_val = K_fun(beta, delta, p, Lss, z)
q_val = q_fun(beta, delta, p, Lss, z)
w_val = w_fun(beta, delta, p, Lss, z)
Y_val = Y_fun(beta, delta, p, Lss, z)
I_val = I_fun(beta, delta, p, Lss, z)
C_val = C_fun(beta, delta, p, Lss, z)
L_val = L_fun(beta, delta, p, Lss, z)

# The above assignments are immediately repeated to store the steady state as "_ss" variables,
# which might be used later to make the notation clearer that these are steady-state benchmarks.
K_ss = K_fun(beta, delta, p, Lss, z)
q_ss = q_fun(beta, delta, p, Lss, z)
w_ss = w_fun(beta, delta, p, Lss, z)
Y_ss = Y_fun(beta, delta, p, Lss, z)
I_ss = I_fun(beta, delta, p, Lss, z)
C_ss = C_fun(beta, delta, p, Lss, z)
L_ss = L_fun(beta, delta, p, Lss, z)

# Print the steady state values to verify the baseline of the model. These are calculated at z=1.
print("Steady State Values (at z=1):")
print("K_ss =", K_val)
print("q_ss =", q_val)
print("w_ss =", w_val)
print("Y_ss =", Y_val)
print("I_ss =", I_val)
print("C_ss =", C_val)
print("L_ss =", L_val)

# Define additional parameters for the simulation:
alpha = p         # alpha is set equal to capital share, which in some literature uses alpha.
T = 20            # T defines the total number of time periods for the IRF simulation.
rho_z = 0.95      # Autoregressive parameter for the technology shock process.

# From the steady state, compute additional model parameters:
# r_ss is the steady state real interest rate derived from the Euler equation.
r_ss = 1 / beta - 1 + delta
# phi_c and phi_i are ratios of consumption and investment to output in the steady state,
# and are used to scale the IRF responses.
phi_c = C_ss / Y_ss
phi_i = I_ss / Y_ss

# Initialize the technology shock process:
# z_hat is an array representing the shock process over T periods.
z_hat = np.zeros(T)
z_hat[0] = 1  # At time 0, we introduce a 1% technology shock.

# Generate the autoregressive process for the technology shock:
for t in range(1, T):
    # Each period the shock decays by the factor rho_z, mimicking an AR(1) process.
    z_hat[t] = rho_z * z_hat[t - 1]

# Initialize arrays to store the log-deviations from steady state for various variables.
# The deviations represent percentage deviations from the benchmark steady state.
c_hat = np.zeros(T+1)  # Consumption log-deviation, extra period for terminal condition.
i_hat = np.zeros(T)    # Investment log-deviation.
k_hat = np.zeros(T+1)  # Capital log-deviation, extra period due to accumulation.
y_hat = np.zeros(T)    # Output log-deviation.
r_hat = np.zeros(T)    # Interest rate log-deviation.
w_hat = np.zeros(T)    # Wage log-deviation.
l_hat = np.zeros(T)    # Labor log-deviation.

# Terminal condition is assumed for consumption: c_T = 0 (i.e., no deviation at the final period).

# Set initial conditions: assume no deviation in capital and consumption at time t = 0.
k_hat[0] = 0
c_hat[0] = 0

# Loop over each time period to simulate the dynamic responses (Impulse Response Functions - IRFs)
for t in range(T):

    # 1. Factor Prices from Marginal Products:
    # The wage (w_hat) is determined as the sum of the technology shock and contributions from
    # capital and labor deviations scaled by the capital share.
    w_hat[t] = z_hat[t] + alpha * k_hat[t] - alpha * l_hat[t]
    # The rental rate (r_hat) is calculated using the marginal product conditions;
    # it is affected by the deviation of capital and labor.
    r_hat[t] = (alpha - 1) * k_hat[t] + z_hat[t] + (1 - alpha) * l_hat[t]

    # 2. Labor Supply from the Intratemporal Condition:
    # The log-deviation of labor (l_hat) is updated based on the difference between wages and consumption,
    # scaled by the ratio ((1-L_ss)/L_ss), which captures the elasticity in this specification.
    l_hat[t] = (w_hat[t] - c_hat[t]) * ((1 - L_ss) / L_ss)

    # 3. Output Computation:
    # Output is determined by combining the contributions of capital and labor deviations weighted by alpha and
    # (1-alpha), respectively, then adding the technology shock.
    # This update is performed after updating the labor deviation.
    y_hat[t] = alpha * k_hat[t] + (1 - alpha) * l_hat[t] + z_hat[t]

    # 4. Investment from the Resource Constraint:
    # Investment log-deviation is calculated using the resource constraint where output minus the scaled consumption
    # is divided by the share of investment in output.
    i_hat[t] = (y_hat[t] - phi_c * c_hat[t]) / phi_i

    # 5. Capital Accumulation:
    # The next period's capital log-deviation is determined by the current capital after depreciation and the
    # new investment weighted by delta, representing the adjustment process.
    k_hat[t + 1] = (1 - delta) * k_hat[t] + delta * i_hat[t]

    # 6. Euler Equation (Consumption Dynamics):
    # According to the Euler equation in a log-linearized setting, the change in the consumption deviation
    # equals the product of the steady state return factor (beta*q_ss) and the rental rate deviation.
    c_hat[t + 1] = c_hat[t] + (beta * q_ss) * r_hat[t]

# The consumption and capital paths are reversed to align the time axis for plotting,
# recognizing that c(t+1) and k(t+1) are plotted rather than c(t) and k(t).
c_hat_aligned = np.insert(c_hat[::-1][:-1], 0, 0.0)  # Insert a zero at the beginning after reversing.
k_hat_aligned = np.insert(k_hat[::-1][:-1], 0, 0.0)  # Similarly for capital.

# Prepare the variables for plotting by converting log-deviations into percentage deviations.
# The dictionary "variables" maps variable names to their corresponding reversed IRF paths.
variables = {
    'Output (Y)': y_hat[::-1],
    'Capital (K)': k_hat_aligned,
    'Investment (I)': i_hat[::-1],
    'Consumption (C)': c_hat_aligned,
    'Wage (w)': w_hat[::-1],
    'Interest Rate (r)': r_hat[::-1],
    'Labor (L)': l_hat[::-1], 
}

# Set up the plot size for the IRFs.
plt.figure(figsize=(12, 6))

# Plot each variable's deviation over time.
for name, var in variables.items():
    # Create a time array that matches the length of the variable series.
    time_var = np.arange(len(var))
    plt.plot(time_var, var, label=name)

# Also plot the technology shock (z_hat) for reference.
plt.plot(np.arange(len(z_hat)), z_hat, label='Technology (z)', linewidth=1, color='black')

# Add a horizontal reference line at zero to clearly see deviations from the steady state.
plt.axhline(0, color='gray', linestyle='--')
# Add plot title and axis labels.
plt.title("IRFs from Log-Linearized DSGE Model (Shock at t = 0)")
plt.xlabel("Time")
plt.ylabel("% Deviation from Steady State")
# Add a legend to distinguish between different variables.
plt.legend()
# Display grid lines for improved readability.
plt.grid(True)
# Adjust the layout to ensure nothing is clipped.
plt.tight_layout()
# Render the final plot.
plt.show()

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.