On this page
  • 56.1. Overview
    • 56.1.1. Model Features
  • 56.2. Model
    • 56.2.1. Parameterization
    • 56.2.2. Back-of-the-Envelope Calculations
  • 56.3. Implementation
  • 56.4. Solving for Policies
  • 56.5. Exercises

logo

Powered by Jupyter Book

↑ Top

Intermediate Quantitative Economics with Python

Thomas J. Sargent and John Stachurski

Changelog (full history)

  • 2f1eead John Stachurski 20 hours ago [jv] Convert to JAX using nested vmap (#984)
  • 74949c4 John Stachurski 8 months ago Standardize Job Search lecture titles to consistent I-IX numbering (#681)
  • 3a05315 Humphrey Yang 11 months ago [FIX] Remove Syntax Warning from Cache Rebuild (#508)
  • f4d7a8d Matt McKay 1 year ago FIX: pass quantecon logo through to download notebooks (#432)
  • 9ec9e13 Matt McKay 1 year ago MAINT: update @jit(nopython=True) to @jit with numba>=0.59 (#395)
  • db29a24 kp992 2 years ago Use np.interp instead of interpolation.interp
  • dd9fd01 Smit Lunagariya 2 years ago MAINT: Fix small typos (#362)
  • bab7a8e Smit Lunagariya 2 years ago Remove unused imports (#357)
  • 338a4a4 Humphrey Yang 3 years ago Reformat the Exercise and Solution (#271)
  • 6f29c33 Smit-create 3 years ago Print only when convergence is successful

56. Job Search VII: On-the-Job Search#

Contents

  • Job Search VII: On-the-Job Search

    • Overview

    • Model

    • Implementation

    • Solving for Policies

    • Exercises

GPU

This lecture was built using a machine with access to a GPU — although it will also run without one.

Google Colab has a free tier with GPUs that you can access as follows:

  1. Click on the “play” icon top right

  2. Select Colab

  3. Set the runtime environment to include a GPU

56.1. Overview#

In this section, we solve a simple on-the-job search model

  • based on [Ljungqvist and Sargent, 2018], exercise 6.18, and [Jovanovic, 1979]

Let’s start with some imports:

from typing import NamedTuple

import matplotlib.pyplot as plt
import scipy.stats as stats
import jax
import jax.numpy as jnp
import jax.random as jr

56.1.1. Model Features#

  • job-specific human capital accumulation combined with on-the-job search

  • infinite-horizon dynamic programming with one state variable and two controls

56.2. Model#

Let \(x_t\) denote the time-\(t\) job-specific human capital of a worker employed at a given firm and let \(w_t\) denote current wages.

Let \(w_t = x_t(1 - s_t - \phi_t)\), where

  • \(\phi_t\) is investment in job-specific human capital for the current role and

  • \(s_t\) is search effort, devoted to obtaining new offers from other firms.

For as long as the worker remains in the current job, evolution of \(\{x_t\}\) is given by \(x_{t+1} = g(x_t, \phi_t)\).

When search effort at \(t\) is \(s_t\), the worker receives a new job offer with probability \(\pi(s_t) \in [0, 1]\).

The value of the offer, measured in job-specific human capital, is \(u_{t+1}\), where \(\{u_t\}\) is IID with common distribution \(f\).

The worker can reject the current offer and continue with existing job.

Hence \(x_{t+1} = u_{t+1}\) if he/she accepts and \(x_{t+1} = g(x_t, \phi_t)\) otherwise.

Let \(b_{t+1} \in \{0,1\}\) be a binary random variable, where \(b_{t+1} = 1\) indicates that the worker receives an offer at the end of time \(t\).

We can write

(56.1)#\[x_{t+1} = (1 - b_{t+1}) g(x_t, \phi_t) + b_{t+1} \max \{ g(x_t, \phi_t), u_{t+1}\}\]

Agent’s objective: maximize expected discounted sum of wages via controls \(\{s_t\}\) and \(\{\phi_t\}\).

Taking the expectation of \(v(x_{t+1})\) and using (56.1), the Bellman equation for this problem can be written as

(56.2)#\[v(x) = \max_{s + \phi \leq 1} \left\{ x (1 - s - \phi) + \beta (1 - \pi(s)) v[g(x, \phi)] + \beta \pi(s) \int v[g(x, \phi) \vee u] f(du) \right\}\]

Here nonnegativity of \(s\) and \(\phi\) is understood, while \(a \vee b := \max\{a, b\}\).

56.2.1. Parameterization#

In the implementation below, we will focus on the parameterization

\[ g(x, \phi) = A (x \phi)^{\alpha}, \quad \pi(s) = \sqrt s \quad \text{and} \quad f = \text{Beta}(2, 2) \]

with default parameter values

  • \(A = 1.4\)

  • \(\alpha = 0.6\)

  • \(\beta = 0.96\)

The \(\text{Beta}(2,2)\) distribution is supported on \((0,1)\) - it has a unimodal, symmetric density peaked at 0.5.

56.2.2. Back-of-the-Envelope Calculations#

Before we solve the model, let’s make some quick calculations that provide intuition on what the solution should look like.

To begin, observe that the worker has two instruments to build capital and hence wages:

  1. invest in capital specific to the current job via \(\phi\)

  2. search for a new job with better job-specific capital match via \(s\)

Since wages are \(x (1 - s - \phi)\), marginal cost of investment via either \(\phi\) or \(s\) is identical.

Our risk-neutral worker should focus on whatever instrument has the highest expected return.

The relative expected return will depend on \(x\).

For example, suppose first that \(x = 0.05\)

  • If \(s=1\) and \(\phi = 0\), then since \(g(x,\phi) = 0\), taking expectations of (56.1) gives expected next period capital equal to \(\pi(s) \mathbb{E} u = \mathbb{E} u = 0.5\).

  • If \(s=0\) and \(\phi=1\), then next period capital is \(g(x, \phi) = g(0.05, 1) \approx 0.23\).

Both rates of return are good, but the return from search is better.

Next, suppose that \(x = 0.4\)

  • If \(s=1\) and \(\phi = 0\), then expected next period capital is again \(0.5\)

  • If \(s=0\) and \(\phi = 1\), then \(g(x, \phi) = g(0.4, 1) \approx 0.8\)

Return from investment via \(\phi\) dominates expected return from search.

Combining these observations gives us two informal predictions:

  1. At any given state \(x\), the two controls \(\phi\) and \(s\) will function primarily as substitutes — worker will focus on whichever instrument has the higher expected return.

  2. For sufficiently small \(x\), search will be preferable to investment in job-specific human capital. For larger \(x\), the reverse will be true.

Now let’s turn to implementation, and see if we can match our predictions.

56.3. Implementation#

We solve the model with JAX, using a NamedTuple to hold the parameters and grids.

class JVWorker(NamedTuple):
    A: float                # Scale parameter in g
    α: float                # Curvature parameter in g
    β: float                # Discount factor
    x_grid: jnp.ndarray     # Grid of human capital values
    s_grid: jnp.ndarray     # Grid of search effort values
    ϕ_grid: jnp.ndarray     # Grid of investment values
    f_rvs: jnp.ndarray      # Draws from f, for Monte Carlo integration


def create_jv_worker(A=1.4,               # Scale parameter in g
                     α=0.6,               # Curvature parameter in g
                     β=0.96,              # Discount factor
                     a=2,                 # Parameter of f
                     b=2,                 # Parameter of f
                     grid_size=50,        # Size of the state grid
                     mc_size=100,         # Number of draws from f
                     search_grid_size=15, # Size of each action grid
                     ɛ=1e-4,
                     seed=1234):
    """
    Create an instance of the on-the-job search model.
    """
    f_rvs = jr.beta(jr.key(seed), a, b, (mc_size,))

    # Max of grid is the max of a large quantile value for f and the
    # fixed point y = g(y, 1)
    grid_max = max(A**(1 / (1 - α)), stats.beta(a, b).ppf(1 - ɛ))

    x_grid = jnp.linspace(ɛ, grid_max, grid_size)
    s_grid = jnp.linspace(ɛ, 1, search_grid_size)
    ϕ_grid = jnp.linspace(ɛ, 1, search_grid_size)

    return JVWorker(A=A, α=α, β=β, x_grid=x_grid, s_grid=s_grid,
                    ϕ_grid=ϕ_grid, f_rvs=f_rvs)

Here are the transition function \(g\) and the offer probability \(\pi\).

@jax.jit
def g(jv, x, ϕ):
    "Transition function for job-specific human capital."
    return jv.A * (x * ϕ)**jv.α


@jax.jit
def π(s):
    "Probability of receiving an offer when search effort is s."
    return jnp.sqrt(s)

Next we write the right-hand side of the Bellman equation (56.2), before maximization:

(56.3)#\[B(x, s, \phi) := x (1 - s - \phi) + \beta (1 - \pi(s)) v[g(x, \phi)] + \beta \pi(s) \int v[g(x, \phi) \vee u] f(du)\]

We represent \(v\) by an array giving its values on x_grid, and recover a function from it by linear interpolation.

The integral is replaced by a Monte Carlo average over the draws in f_rvs.

The function below is written for a single state \(x\) and a single action pair \((s, \phi)\) — so it reads much like (56.3) itself.

def _B(v, jv, x, s, ϕ):
    """
    The right-hand side of the Bellman equation before maximization, for one
    state x and one action pair (s, ϕ).

    Infeasible pairs, where s + ϕ > 1, are given value -∞ so that they are
    never selected by the maximization step.
    """
    v_func = lambda z: jnp.interp(z, jv.x_grid, v)
    gxϕ = g(jv, x, ϕ)

    # Monte Carlo estimate of ∫ v[g(x, ϕ) ∨ u] f(du)
    integral = jnp.mean(v_func(jnp.maximum(gxϕ, jv.f_rvs)))

    q = π(s) * integral + (1 - π(s)) * v_func(gxϕ)
    return jnp.where(s + ϕ <= 1, x * (1 - s - ϕ) + jv.β * q, -jnp.inf)

Now we evaluate _B at every combination of state and action.

Rather than write three nested loops, we apply jax.vmap three times.

Each application vectorizes over one argument, so the stack below plays the role of a triple loop — but the whole thing compiles to code that runs in parallel.

In in_axes, a 0 marks the argument being mapped over, while None holds an argument fixed.

# The argument order of _B is    (v,    jv,   x,    s,    ϕ)
_B_ϕ   = jax.vmap(_B,    in_axes=(None, None, None, None, 0))     # over ϕ
_B_sϕ  = jax.vmap(_B_ϕ,  in_axes=(None, None, None, 0,    None))  # then over s
_B_xsϕ = jax.vmap(_B_sϕ, in_axes=(None, None, 0,    None, None))  # then over x

The result is a fully vectorized version of \(B\).

@jax.jit
def B(v, jv):
    """
    Evaluate B at every (state, action) combination.

    Returns an array of shape (len(x_grid), len(s_grid), len(ϕ_grid)) where
    entry [i, j, k] holds the value of choosing (s_j, ϕ_k) in state x_i.
    """
    return _B_xsϕ(v, jv, jv.x_grid, jv.s_grid, jv.ϕ_grid)

With B in hand, the Bellman operator and the greedy policy are both one-liners — we maximize over the two action axes, taking the maximum in one case and the maximizer in the other.

@jax.jit
def T(v, jv):
    "The Bellman operator."
    return jnp.max(B(v, jv), axis=(1, 2))


@jax.jit
def get_greedy(v, jv):
    "Compute the v-greedy policy, returned as a pair (s_policy, ϕ_policy)."
    vals = B(v, jv)

    # Flatten the two action axes so that a single argmax picks out the best
    # pair at each state, then convert the flat index back to a (s, ϕ) pair
    n_s, n_ϕ = len(jv.s_grid), len(jv.ϕ_grid)
    best = jnp.argmax(vals.reshape(len(jv.x_grid), n_s * n_ϕ), axis=1)
    j, k = jnp.unravel_index(best, (n_s, n_ϕ))

    return jv.s_grid[j], jv.ϕ_grid[k]

To solve the model we iterate \(T\) to convergence.

We use jax.lax.while_loop so that the entire iteration compiles into a single operation, and bound the number of steps so that the loop always terminates.

@jax.jit
def solve_model(jv, tol=1e-4, max_iter=1_000):
    """
    Solve the model by value function iteration.

    Returns the value function, the number of iterations taken, and the final
    error, so that the caller can check convergence.
    """
    def condition(loop_state):
        i, v, error = loop_state
        return (error > tol) & (i < max_iter)

    def update(loop_state):
        i, v, error = loop_state
        v_new = T(v, jv)
        return i + 1, v_new, jnp.max(jnp.abs(v_new - v))

    v_init = jv.x_grid * 0.5
    i, v, error = jax.lax.while_loop(condition, update, (0, v_init, tol + 1))
    return v, i, error

Note

The grids here are small, and this model would also run perfectly well in NumPy.

We use JAX because the code is almost as readable as the NumPy equivalent, while scaling far better — to finer grids, or to richer versions of the model with additional state variables, where the same code will make full use of a GPU.

56.4. Solving for Policies#

Let’s generate the optimal policies and see what they look like.

jv = create_jv_worker()
v_star, num_iter, error = solve_model(jv)
s_star, ϕ_star = get_greedy(v_star, jv)

print(f"Converged in {num_iter} iterations with error {error:.2e}.")
Converged in 205 iterations with error 9.92e-05.

Here are the plots:

plots = [s_star, ϕ_star, v_star]
titles = ["s policy", "ϕ policy",  "value function"]

fig, axes = plt.subplots(3, 1, figsize=(12, 12))

for ax, plot, title in zip(axes, plots, titles):
    ax.plot(jv.x_grid, plot)
    ax.set(title=title)
    ax.grid()

axes[-1].set_xlabel("x")
plt.show()
_images/a6b078eb240a11a91e2a72ab368bc06e65eadaa31d05a2fc9769a924ef36063d.png

The horizontal axis is the state \(x\), while the vertical axis gives \(s(x)\) and \(\phi(x)\).

Overall, the policies match well with our predictions from above

  • Worker switches from one investment strategy to the other depending on relative return.

  • For low values of \(x\), the best option is to search for a new job.

  • Once \(x\) is larger, worker does better by investing in human capital specific to the current position.

56.5. Exercises#

Exercise 56.1

Let’s look at the dynamics for the state process \(\{x_t\}\) associated with these policies.

The dynamics are given by (56.1) when \(\phi_t\) and \(s_t\) are chosen according to the optimal policies, and \(\mathbb{P}\{b_{t+1} = 1\} = \pi(s_t)\).

Since the dynamics are random, analysis is a bit subtle.

One way to do it is to plot, for each \(x\) in a relatively fine grid called plot_grid, a large number \(K\) of realizations of \(x_{t+1}\) given \(x_t = x\).

Plot this with one dot for each realization, in the form of a 45 degree diagram, setting

jv = create_jv_worker(grid_size=25, mc_size=50)
plot_grid_max, plot_grid_size = 1.2, 100
plot_grid = jnp.linspace(0, plot_grid_max, plot_grid_size)
fig, ax = plt.subplots()
ax.set_xlim(0, plot_grid_max)
ax.set_ylim(0, plot_grid_max)

By examining the plot, argue that under the optimal policies, the state \(x_t\) will converge to a constant value \(\bar x\) close to unity.

Argue that at the steady state, \(s_t \approx 0\) and \(\phi_t \approx 0.6\).

Solution

Here’s code to produce the 45 degree diagram.

Note that we draw all of the realizations at once, rather than looping over states and draws.

jv = create_jv_worker(grid_size=25, mc_size=50)
v_star, _, _ = solve_model(jv)
s_policy, ϕ_policy = get_greedy(v_star, jv)

# Turn the policy function arrays into actual functions
s = lambda y: jnp.interp(y, jv.x_grid, s_policy)
ϕ = lambda y: jnp.interp(y, jv.x_grid, ϕ_policy)

plot_grid_max, plot_grid_size = 1.2, 100
plot_grid = jnp.linspace(0, plot_grid_max, plot_grid_size)


@jax.jit
def simulate_next(key, plot_grid):
    """
    Draw realizations of next period capital for every x in plot_grid,
    following the law of motion for x_{t+1} given above.  Returns an array of shape (len(plot_grid), mc_size).
    """
    K = len(jv.f_rvs)
    gxϕ = g(jv, plot_grid, ϕ(plot_grid))[:, jnp.newaxis]   # Shape (n, 1)
    u = jv.f_rvs[jnp.newaxis, :]                           # Shape (1, K)

    # An offer arrives with probability π(s(x)), independently across draws
    b = jr.uniform(key, (len(plot_grid), K)) < π(s(plot_grid))[:, jnp.newaxis]

    return jnp.where(b, jnp.maximum(gxϕ, u), gxϕ)


x_next = simulate_next(jr.key(1234), plot_grid)

fig, ax = plt.subplots(figsize=(8, 8))
ticks = (0.25, 0.5, 0.75, 1.0)
ax.set(xticks=ticks, yticks=ticks,
       xlim=(0, plot_grid_max),
       ylim=(0, plot_grid_max),
       xlabel='$x_t$', ylabel='$x_{t+1}$')

ax.plot(plot_grid, plot_grid, 'k--', alpha=0.6)  # 45 degree line
ax.plot(jnp.repeat(plot_grid, x_next.shape[1]), x_next.ravel(),
        'go', alpha=0.25)

plt.show()
_images/bde840006b3842f97f48813ff622a2dd570a87b1461c5531ee4faff49bbef933.png

Looking at the dynamics, we can see that

  • If \(x_t\) is below about 0.2 the dynamics are random, but \(x_{t+1} > x_t\) is very likely.

  • As \(x_t\) increases the dynamics become deterministic, and \(x_t\) converges to a steady state value close to 1.

Referring back to the figure here we see that \(x_t \approx 1\) means that \(s_t = s(x_t) \approx 0\) and \(\phi_t = \phi(x_t) \approx 0.6\).

Exercise 56.2

In Exercise 56.1, we found that \(s_t\) converges to zero and \(\phi_t\) converges to about 0.6.

Since these results were calculated at a value of \(\beta\) close to one, let’s compare them to the best choice for an infinitely patient worker.

Intuitively, an infinitely patient worker would like to maximize steady state wages, which are a function of steady state capital.

You can take it as given—it’s certainly true—that the infinitely patient worker does not search in the long run (i.e., \(s_t = 0\) for large \(t\)).

Thus, given \(\phi\), steady state capital is the positive fixed point \(x^*(\phi)\) of the map \(x \mapsto g(x, \phi)\).

Steady state wages can be written as \(w^*(\phi) = x^*(\phi) (1 - \phi)\).

Graph \(w^*(\phi)\) with respect to \(\phi\), and examine the best choice of \(\phi\).

Can you give a rough interpretation for the value that you see?

Solution

The figure can be produced as follows

jv = create_jv_worker()

def xbar(ϕ):
    return (jv.A * ϕ**jv.α)**(1 / (1 - jv.α))

ϕ_grid = jnp.linspace(0, 1, 100)

fig, ax = plt.subplots(figsize=(9, 7))
ax.set(xlabel=r'$\phi$')
ax.plot(ϕ_grid, xbar(ϕ_grid) * (1 - ϕ_grid), label=r'$w^*(\phi)$')
ax.legend()

plt.show()
_images/7eae2d986ec5e3b46dc4d8675267839fbd7162f3a8ffa7d6a58f57c1049c4517.png

Observe that the maximizer is around 0.6.

This is similar to the long-run value for \(\phi\) obtained in Exercise 56.1.

Hence the behavior of the infinitely patent worker is similar to that of the worker with \(\beta = 0.96\).

This seems reasonable and helps us confirm that our dynamic programming solutions are probably correct.

Creative Commons License – This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International.

A theme by QuantEcon

Contents

Tools and Techniques

  • 1. Modeling COVID 19
  • 2. Linear Algebra
  • 3. QR Decomposition
  • 4. Circulant Matrices
  • 5. Singular Value Decomposition (SVD)
  • 6. VARs and DMDs
  • 7. Using Newton’s Method to Solve Economic Models

Elementary Statistics

  • 8. Elementary Probability with Matrices
  • 9. Some Probability Distributions
  • 10. LLN and CLT
  • 11. Two Meanings of Probability
  • 12. Multivariate Hypergeometric Distribution
  • 13. Multivariate Normal Distribution
  • 14. Fault Tree Uncertainties
  • 15. Introduction to Artificial Neural Networks
  • 16. Randomized Response Surveys
  • 17. Expected Utilities of Random Responses

Bayes Law

  • 18. Non-Conjugate Priors
  • 19. Posterior Distributions for AR(1) Parameters
  • 20. Forecasting an AR(1) Process

Statistics and Information

  • 21. Statistical Divergence Measures
  • 22. Likelihood Ratio Processes
  • 23. Heterogeneous Beliefs and Financial Markets
  • 24. Likelihood Processes For VAR Models
  • 25. Mean of a Likelihood Ratio Process
  • 26. A Problem that Stumped Milton Friedman
  • 27. A Bayesian Formulation of Friedman and Wald’s Problem
  • 28. Exchangeability and Bayesian Updating
  • 29. Likelihood Ratio Processes and Bayesian Learning
  • 30. Blackwell’s Theorem on Comparing Experiments
  • 31. Information and Market Equilibrium
  • 32. Incorrect Models
  • 33. Bayesian versus Frequentist Decision Rules
  • 34. Merging of Opinions: The Blackwell–Dubins Theorem
  • 35. Survival and Long-Run Dynamics under Recursive Preferences

Linear Programming

  • 36. Optimal Transport
  • 37. Von Neumann Growth Model (and a Generalization)

Introduction to Dynamics

  • 38. Finite Markov Chains
  • 39. Inventory Dynamics
  • 40. Linear State Space Models
  • 41. Samuelson Multiplier-Accelerator
  • 42. The Acceleration Principle and the Nature of Business Cycles
  • 43. Kesten Processes and Firm Dynamics
  • 44. Wealth Distribution Dynamics
  • 45. A First Look at the Kalman Filter
  • 46. Another Look at the Kalman Filter
  • 47. The Kalman Filter and Vector Autoregressions
  • 48. Organization Capital
  • 49. Two Models of Measurements and the Investment Accelerator

Search

  • 50. Job Search I: The McCall Search Model
  • 51. Job Search II: Search and Separation
  • 52. Job Search III: Search with Separation and Markov Wages
  • 53. Job Search IV: Fitted Value Function Iteration
  • 54. Job Search V: Persistent and Transitory Wage Shocks
  • 55. Job Search VI: Modeling Career Choice
  • 56. Job Search VII: On-the-Job Search
  • 57. Job Search VIII: Search with Learning

Reinforcement Learning

  • 58. Inventory Management via Q-Learning
  • 59. Risk-Sensitive Inventory Management via Q-Learning
  • 60. Job Search IX: Search with Q-Learning

Introduction to Optimal Savings

  • 61. Optimal Savings I: Cake Eating
  • 62. Optimal Savings II: Numerical Cake Eating
  • 63. Optimal Savings III: Stochastic Returns
  • 64. Optimal Savings IV: Time Iteration
  • 65. Optimal Savings V: The Endogenous Grid Method
  • 66. Optimal Savings VI: EGM with JAX

Household Problems

  • 67. The Income Fluctuation Problem I: Discretization and VFI
  • 68. The Income Fluctuation Problem II: Optimistic Policy Iteration
  • 69. The Income Fluctuation Problem III: The Endogenous Grid Method
  • 70. The Income Fluctuation Problem IV: Transient Income Shocks
  • 71. The Income Fluctuation Problem V: Stochastic Returns on Assets

LQ Control

  • 72. LQ Control: Foundations
  • 73. Lagrangian for LQ Control
  • 74. Eliminating Cross Products
  • 75. The Permanent Income Model
  • 76. Permanent Income II: LQ Techniques
  • 77. Robust Permanent Income and Pricing
  • 78. Certainty Equivalence
  • 79. Certainty Equivalence and Model Uncertainty
  • 80. The LQ Permanent Income Model
  • 81. Consumption Smoothing with Incomplete and Complete Markets
  • 82. Robust Consumption Smoothing and Precautionary Savings
  • 83. Production Smoothing via Inventories

Optimal Growth

  • 84. Cass-Koopmans Model
  • 85. Cass-Koopmans Competitive Equilibrium
  • 86. Cass-Koopmans Model with Distorting Taxes
  • 87. Two-Country Model with Distorting Taxes

Multiple Agent Models

  • 88. A Lake Model of Employment and Unemployment
  • 89. Lake Model with an Endogenous Job Finding Rate
  • 90. Rational Expectations Equilibrium
  • 91. Stability in Linear Rational Expectations Models
  • 92. Markov Perfect Equilibrium
  • 93. Uncertainty Traps
  • 94. The Aiyagari Model
  • 95. The Aiyagari Model with Endogenous Grid Method
  • 96. Transitions in an Overlapping Generations Model
  • 97. A Long-Lived, Heterogeneous Agents, Overlapping Generations Model
  • 98. Two Computations to Fund Social Security

Asset Pricing and Finance

  • 99. Asset Pricing: Finite State Models
  • 100. Stochastic Consumption, Risk Aversion, and the Temporal Behavior of Asset Returns
  • 101. Estimating Euler Equations by Generalized Method of Moments
  • 102. Competitive Equilibria with Arrow Securities
  • 103. Heterogeneous Beliefs and Bubbles
  • 104. Speculative Behavior with Bayesian Learning
  • 105. Rational Learning and Rational Expectations
  • 106. Least Squares Learning in Self-Referential Models
  • 107. Affine Models of Asset Prices
  • 108. The Recovery Theorem
  • 109. Long-term Risk: An Operator Approach
  • 110. Misspecified Recovery

Data and Empirics

  • 111. Pandas for Panel Data
  • 112. Linear Regression in Python
  • 113. Maximum Likelihood Estimation
  • 114. A Linear Model of Unemployment
  • 115. Unemployment Dynamics with Asymmetric Shocks

Auctions

  • 116. First-Price and Second-Price Auctions
  • 117. Multiple Good Allocation Mechanisms

Other

  • 118. Troubleshooting
  • 119. References
  • 120. Execution Statistics
  • QuantEcon
  • Lecture (PDF)

  • Book (PDF)

Notebook Launcher

Choose public or private cloud service for "Launch" button.

Select a server

  • Public
  • Private

Launch Notebook