Simple modeling with pythonΒΆ

IntroductionΒΆ

In this lecture, we will explore how to create a simple, non-optimization model using Python. We will define variables, parameters, and constraints to represent a basic problem scenario that we have previously discussed in this course. In particular, we will illustrate the new keynesian IS-LM-FX model using python.

Python is the preferred language of choice for this lecture due to its simplicity and readability. It allows us to focus on the modeling aspects without getting bogged down by complex syntax. It is also very popular, which may increase your chance of landing jobs and PhD programs. Matlab is also popular in economics, but it is proprietary software and can be expensive. R is another open-source option, but it is less commonly used for economic modeling compared to Python. Nevertheless, the concepts we will cover can be easily translated to other programming languages.

More on pythonΒΆ

Some resourcesΒΆ

My main resources for learning python for economics is QuantEcon Lab led by John Stachurski and Thomas Sargent. Materials in the website covers everything from the absolute basic to the very advance ones. They have a YouTube channel with many useful videos. Lots of my codes are copied from them.

There is also macrosimulation.org that you can follow. Their codes are clean but not as extensive as QuantEcon. They also provide R codes, so if you prefer to use R, you can check them out. This particular lecture is using their IS-LM-FX model (called New Keynesian 3-equation model).

ToolsΒΆ

Most of the time, I write my python codes in Jupyter Notebook. It is an open-source web application that allows you to create and share documents that contain live code, equations, visualizations, and narrative text. It is very popular in data science and scientific computing communities.

To install Jupyter Notebook, you can use Anaconda, which is a free and open-source distribution of Python. You can download it from here. After installing Anaconda, you can launch Jupyter Notebook from the Anaconda prompt. Yes, you will get a new prompt besides the regular command prompt. Open windows search bar and type "Anaconda Prompt" to find it. You then can type jupyter lab to launch Jupyter Lab, which is an enhanced version of Jupyter Notebook. the jupyter notebook have .ipynb extension.

These days, though, I typically use VS Code with the Jupyter extension installed. VS Code is a free code editor developed by Microsoft. It is lightweight and has many useful features for coding, including syntax highlighting, code completion, and debugging. More importantly, running R, python, quarto and other language is more seamless in vscode. I often switch languages (depends on projects and who works with me), so vscode is my go-to tool.

In the end, IDE is more on personal preference really. For this class, though, jupyter lab is already very powerful, so you can just stick to it. You will find your preferred IDE later on.

Next, let me review a bit on the model.

IS-LM modelΒΆ

The IS-LM model that I use is adopted from Carlin and Soskice (2016). It is a closed economy model suitable for a relatively close country of big open country. It is useful to run the model to understand the mechanism. The model implemented in this notebook is trimmed to the absolute basic to avoid complex optimization.

The main equations are as follows:

yt=Aβˆ’a1rtβˆ’1yt=Aβˆ’a1rtβˆ’1

Ο€t=Ο€tβˆ’1+a2(ytβˆ’ye)Ο€t=Ο€tβˆ’1+a2(ytβˆ’ye)

rs=Aβˆ’ye+betβˆ’1a1rs=Aβˆ’ye+betβˆ’1a1

rt=rs+a3(Ο€tβˆ’Ο€T)rt=rs+a3(Ο€tβˆ’Ο€T)

These sets of equations are also called three equation model because it consists of IS equation (y=IS(r))(y=IS(r)), philips curve aka the adaptive expectation (Ο€t=PC(Ο€tβˆ’1,(ytβˆ’ye)))(Ο€t=PC(Ο€tβˆ’1,(ytβˆ’ye))) and the central bank reaction function.

Basically, central bank balance output gap and inflation targeting by setting interest rate. When the economy is too hot amid shocks (yt>ye)(yt>ye), inflation will go up and the central bank must control it by hiking interest rate. The opposite is true for negative output shock.

IS-LM-FX modelΒΆ

The IS-LM-FX model is a macroeconomic model that describes the interaction between the goods market (IS curve), the money market (LM curve), and the foreign exchange market (FX curve). The model is a bit different than what we teached in class, so we will sharae a bit of the theory here.

Home is small, and foreign is large. It is a short-run model so prices are fixed. The model assumes perfect capital mobility, which means that domestic and foreign interest rates are equalized through capital flows. Government spending and taxes are exogenous, and the money supply is controlled by the central bank. Moreover, foreign output and interest rates are also exogenous.

This is also called 3-equation model because it consists of three main equations: IS curve, Philips curve, and central bank rule. We then add UIP condition because of the open economy setting.

The main equations are as follows:

yt=Aβˆ’a1rtβˆ’1+betβˆ’1yt=Aβˆ’a1rtβˆ’1+betβˆ’1

Ο€t=Ο€tβˆ’1+a2(ytβˆ’e)Ο€t=Ο€tβˆ’1+a2(ytβˆ’e)

rs=Aβˆ’ye+betβˆ’1a1rs=Aβˆ’ye+betβˆ’1a1

rt=rs+a3(Ο€tβˆ’Ο€T)rt=rs+a3(Ο€tβˆ’Ο€T)

et=etβˆ’1+Ξ³(rtβˆ’1βˆ’rβˆ—)βˆ’ΞΊ(etβˆ’1βˆ’eT)et=etβˆ’1+Ξ³(rtβˆ’1βˆ’rβˆ—)βˆ’ΞΊ(etβˆ’1βˆ’eT)

The first equation is the IS curve, which shows the relationship between output (y), aggregate demand (A), interest rate (r), and exchange rate (e). The second equation is the Phillips curve, which describes the relationship between inflation (ππ), expected inflation (Ο€tβˆ’1Ο€tβˆ’1), output (y), and potential output (e). The third equation is the central bank rule, which determines the policy interest rate (r) based on the stabilizing rate (rsrs) and the deviation of inflation from its target (Ο€TΟ€T). The last equation is the UIP condition, which relates the exchange rate (e) to the interest rate differential between domestic and foreign interest rates (rβˆ—rβˆ—).

To avoid tedious optimization with UIP, I introduced a stabilized exchange rate target eTeT that the central bank aims to achieve over time. This adjustment helps maintain exchange rate stability without the need for complex optimization techniques. When you do ended up doing a more advance course, you will learn about various optimization techniques to find proper equilibrium.

In the next section, we will implement this model in Python. I first show the original 3-equation model without UIP, then we will add UIP later on to see how it affects the dynamics.

Original 3-equation model without UIPΒΆ

In [74]:
import numpy as np

# Set number of periods
Q = 50

# Set number of scenarios
S = 3

# Set period in which shock/shift will occur
s = 5

# Create (S x Q) arrays to store simulated data
y = np.zeros((S, Q))  # Income/output
p = np.zeros((S, Q))  # Inflation rate
r = np.zeros((S, Q))  # Policy rate
rs = np.zeros((S, Q))  # Stabilizing interest rate

# Set constant parameter values
a1 = 0.3  # Sensitivity of inflation with respect to output gap
a2 = 0.7  # Sensitivity of output with respect to interest rate
b = 1.0     # Sensitivity of the central bank to inflation gap
a3 = (a1 * (1 / (b * a2) + a2)) ** (-1)

# Set parameter values for different scenarios
A = np.full((S, Q), 6.0)  # Autonomous spending
pt = np.full((S, Q), 2.0)  # Inflation target
ye = np.full((S, Q), 5.0)  # Potential output

A[0, s:Q] = 7.0  # Scenario 1: AD boost
pt[1, s:Q] = 3.0  # Scenario 2: Higher inflation target
ye[2, s:Q] = 5.5  # Scenario 3: Higher potential output

# Initialize endogenous variables at equilibrium values
y[:, 0] = ye[:, 0]
p[:, 0] = pt[:, 0]
rs[:, 0] = (A[:, 0] - ye[:, 0]) / a1
r[:, 0] = rs[:, 0]

# Simulate the model by looping over Q time periods for S different scenarios
for i in range(S):
    for t in range(1, Q):
        # (1) IS curve
        y[i, t] = A[i, t] - a1 * r[i, t - 1]
        # (2) Phillips Curve
        p[i, t] = p[i, t - 1] + a2 * (y[i, t] - ye[i, t])
        # (3) Stabilizing interest rate
        rs[i, t] = (A[i, t] - ye[i, t]) / a1
        # (4) Monetary policy rule, solved for r
        r[i, t] = rs[i, t] + a3 * (p[i, t] - pt[i, t])
In [75]:
import matplotlib.pyplot as plt

# Set maximum period for plots
Tmax = 15

# Plot output under different scenarios
plt.figure(figsize=(8, 6))
plt.plot(y[0, :Tmax + 1], label="Scenario 1: aggregate demand boost",
         color='k', linestyle='solid', linewidth=2)
plt.plot(y[1, :Tmax + 1], label="Scenario 2: Rise inflation target",
         color='k', linestyle='dashed', linewidth=2)
plt.plot(y[2, :Tmax + 1], label="Scenario 3: Rise potential output",
         color='k', linestyle='dotted', linewidth=2)

plt.title("Output under Different Scenarios")
plt.xlabel("Time")
plt.ylabel("y")
plt.xlim(1, Tmax)
#plt.ylim(np.min(y), np.max(y))
plt.legend()
plt.show()

plt.close()

## Interest rate

plt.figure(figsize=(8, 6))
plt.plot(r[0, :Tmax + 1], label="Scenario 1: aggregate demand boost",
         color='k', linestyle='solid', linewidth=2)
plt.plot(r[1, :Tmax + 1], label="Scenario 2: Rise inflation target",
         color='k', linestyle='dashed', linewidth=2)
plt.plot(r[2, :Tmax + 1], label="Scenario 3: Rise potential output",
         color='k', linestyle='dotted', linewidth=2)
plt.title("Interest rate under Different Scenarios")
plt.xlabel("Time")
plt.ylabel("r")
plt.xlim(1, Tmax)
#plt.ylim(np.min(y), np.max(y))
plt.legend()
plt.show()
plt.close()

## next fig
## Interest rate

plt.figure(figsize=(8, 6))
plt.plot(p[0, :Tmax + 1], label="Scenario 1: aggregate demand boost",
         color='k', linestyle='solid', linewidth=2)
plt.plot(p[1, :Tmax + 1], label="Scenario 2: Rise inflation target",
         color='k', linestyle='dashed', linewidth=2)
plt.plot(p[2, :Tmax + 1], label="Scenario 3: Rise potential output",
         color='k', linestyle='dotted', linewidth=2)
plt.title("Inflation rate under Different Scenarios")
plt.xlabel("Time")
plt.ylabel(r'$\pi$')
plt.xlim(1, Tmax)
#plt.ylim(np.min(y), np.max(y))
plt.legend()
plt.show()
plt.close()
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image

You can see the above.

With IUPΒΆ

WIth IUP, we have the term +be+be that adds to the output. A weak exchange rate increases output in general amid a reduction in terms of trade. bb is the elasticity of exchange rate (up means depreciation) to output. In a more advance models, this is handled a bit more complex, but for now an elasticity term should suffice.

The additional exchange rate term helps to boost the impact from interest rate decrease. When there are negative demand shock, central bank will reduce interest rate, but this also reduce exchange rate, soften the negative consequence of GDP.

Under the increased inflation target scenario, exchange rate can be weakened for a sustained period of time.

In [76]:
import numpy as np

# Set number of periods
Q = 50

# Set number of scenarios
S = 3

# Shock period
s = 5

# Create (S x Q) arrays
y = np.zeros((S, Q))   # Output
p = np.zeros((S, Q))   # Inflation
r = np.zeros((S, Q))   # Policy rate
rs = np.zeros((S, Q))  # Stabilizing rate
e = np.zeros((S, Q))   # Exchange rate

# -------------------------
# PARAMETERS
# -------------------------

a1 = 0.3     # IS sensitivity to interest rate
a2 = 0.7     # Phillips curve slope
b = 0.2      # IS sensitivity to exchange rate

phi = 1.0    # Taylor rule inflation weight
a3 = 0.5     # Softer Taylor rule

gamma = 0.01  # UIP adjustment speed 
kappa = 0.3  # Mean reversion strength in UIP


r_star = 2.0 # Foreign interest rate

# -------------------------
# EXOGENOUS VARIABLES
# -------------------------

A = np.full((S, Q), 6.0)
pt = np.full((S, Q), 2.0)
ye = np.full((S, Q), 5.0)


# Scenario shocks
A[0, s:Q] = 7.0
pt[1, s:Q] = 3.0
ye[2, s:Q] = 5.5

# -------------------------
# INITIAL CONDITIONS
# -------------------------

y[:, 0] = ye[:, 0]
p[:, 0] = pt[:, 0]
e[:, 0] = 1.2  
rs[:, 0] = (A[:, 0] - ye[:, 0]+b*e[:,0]) / a1
r[:, 0] = rs[:, 0]

# -------------------------
# SIMULATION
# -------------------------

for i in range(S):
    for t in range(1, Q):

        # (1) OPEN-ECONOMY IS CURVE
        y[i, t] = A[i, t] - a1 * r[i, t - 1] + b * e[i, t-1]

        # (2) PHILLIPS CURVE
        p[i, t] = p[i, t - 1] + a2 * (y[i, t] - ye[i, t])

        # (3) STABILIZING INTEREST RATE
        rs[i, t] = (A[i, t] - ye[i, t] + b*e[i,t-1]) / a1

        # (4) TAYLOR RULE
        r[i, t] = rs[i, t] + a3 * (p[i, t] - pt[i, t])
        
        # (5) UIP
        e[i,t]= e[i,t-1] + gamma * (r[i,t-1]-r_star) - kappa * (e[i,t-1]-1.1)
In [77]:
import matplotlib.pyplot as plt

# Set maximum period for plots
Tmax = 15

# Plot output under different scenarios
plt.figure(figsize=(8, 6))
plt.plot(y[0, :Tmax + 1], label="Scenario 1: aggregate demand boost",
         color='k', linestyle='solid', linewidth=2)
plt.plot(y[1, :Tmax + 1], label="Scenario 2: Rise inflation target",
         color='k', linestyle='dashed', linewidth=2)
plt.plot(y[2, :Tmax + 1], label="Scenario 3: Rise potential output",
         color='k', linestyle='dotted', linewidth=2)

plt.title("Output under Different Scenarios")
plt.xlabel("Time")
plt.ylabel("y")
plt.xlim(1, Tmax)
#plt.ylim(np.min(y), np.max(y))
plt.legend()
plt.show()

plt.close()

## Interest rate

plt.figure(figsize=(8, 6))
plt.plot(r[0, :Tmax + 1], label="Scenario 1: aggregate demand boost",
         color='k', linestyle='solid', linewidth=2)
plt.plot(r[1, :Tmax + 1], label="Scenario 2: Rise inflation target",
         color='k', linestyle='dashed', linewidth=2)
plt.plot(r[2, :Tmax + 1], label="Scenario 3: Rise potential output",
         color='k', linestyle='dotted', linewidth=2)
plt.title("Interest rate under Different Scenarios")
plt.xlabel("Time")
plt.ylabel("r")
plt.xlim(1, Tmax)
#plt.ylim(np.min(y), np.max(y))
plt.legend()
plt.show()
plt.close()

## next fig
## Interest rate

plt.figure(figsize=(8, 6))
plt.plot(p[0, :Tmax + 1], label="Scenario 1: aggregate demand boost",
         color='k', linestyle='solid', linewidth=2)
plt.plot(p[1, :Tmax + 1], label="Scenario 2: Rise inflation target",
         color='k', linestyle='dashed', linewidth=2)
plt.plot(p[2, :Tmax + 1], label="Scenario 3: Rise potential output",
         color='k', linestyle='dotted', linewidth=2)
plt.title("Inflation rate under Different Scenarios")
plt.xlabel("Time")
plt.ylabel(r'$\pi$')
plt.xlim(1, Tmax)
#plt.ylim(np.min(y), np.max(y))
plt.legend()
plt.show()
plt.close()

## exchange rate

plt.figure(figsize=(8, 6))
plt.plot(e[0, :Tmax + 1], label="Scenario 1: aggregate demand boost",
         color='k', linestyle='solid', linewidth=2)
plt.plot(e[1, :Tmax + 1], label="Scenario 2: Rise inflation target",
         color='k', linestyle='dashed', linewidth=2)
plt.plot(e[2, :Tmax + 1], label="Scenario 3: Rise potential output",
         color='k', linestyle='dotted', linewidth=2)
plt.title("Inflation rate under Different Scenarios")
plt.xlabel("Time")
plt.ylabel("e")
plt.xlim(1, Tmax)
#plt.ylim(np.min(y), np.max(y))
plt.legend()
plt.show()
plt.close()
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image

As you can see, the addition of the exchange rate term in the IS equation enhances the model's responsiveness to monetary policy changes. This is particularly important in an open economy context, where exchange rate fluctuations can significantly influence economic output. By incorporating this term, we can better capture the dynamics of how monetary policy affects both domestic output and exchange rates, leading to a more comprehensive understanding of economic behavior in an open economy setting.

ClosingΒΆ

Anyway, I really encourage you all to experiment more on structural model like this. This will make macroeconomic courses and its optimisation methods more enjoyable to learn. Check out QuantEcon to learn more about python implementation in economics.

jupyter notebook in general is also very powerful and versatile to use. You can use nbconvert to convert jupyter notebook into various formats, including HTML, PDF, and slideshows. This makes it easy to share your work with others or present your findings in a professional manner. The rabbit hole is pretty deep in this one, so explore it on your own pace. Good luck!