Campbell–Cochrane (1999): habit formation

Campbell and Cochrane explain the equity premium with an external habit. The single state is the log surplus consumption ratio $s = \log\frac{C-X}{C}$ — how far consumption sits above the habit $X$ — which mean-reverts around $\bar s$. The price–consumption ratio $p(s)$ solves a linear second-order ODE (a special case of the HJB machinery):

\[0 = 1 + \bigl(\mu + \mu_p(s) + \sigma_p(s)\,\sigma - r(s) - \kappa(s)\,(\sigma+\sigma_p(s))\bigr)\, p(s),\]

where the drift $\mu_p$, volatility $\sigma_p$, price of risk $\kappa$, and riskless rate $r$ are all functions of $s$ through the habit.

Defining the model

The parameters live in a struct:

using EconPDEs, Plots

Base.@kwdef struct CampbellCochraneModel
    μ::Float64 = 0.0189    # mean consumption growth
    σ::Float64 = 0.015     # volatility of consumption growth
    γ::Float64 = 2.0       # utility curvature (relative risk aversion)
    ρ::Float64 = 0.116     # discount rate
    κs::Float64 = 0.138    # mean-reversion speed of log surplus consumption ratio
    b::Float64 = 0.0       # sensitivity of riskless rate to surplus ratio (b=0 ⇒ constant r)
end
Main.CampbellCochraneModel

We solve the model at its default parameters:

m = CampbellCochraneModel()
Main.CampbellCochraneModel(0.0189, 0.015, 2.0, 0.116, 0.138, 0.0)

Defining the grid

We define the grid, a NamedTuple whose key is the state variable (s, the log surplus consumption ratio). The grid concentrates points near the reflecting upper bound $s_{\max}$, where the surplus ratio is highest, and stretches far into the left tail.

function initialize_stategrid(m::CampbellCochraneModel; sn = 1000)
    (; μ, σ, γ, ρ, κs, b) = m
    Sbar = σ * sqrt(γ / (κs - b / γ))
    sbar = log(Sbar)
    smax = sbar + 0.5 * (1 - Sbar^2)
    shigh = log.(range(0.0, exp(smax), length = div(sn, 10)))
    slow = range(-300.0, shigh[2], length = sn - div(sn, 10))
    (; s = vcat(slow[1:(end-1)], shigh[2:end]))
end

stategrid = initialize_stategrid(m)
(s = [-300.0, -299.67403740931655, -299.34807481863317, -299.0221122279497, -298.69614963726633, -298.3701870465829, -298.0442244558995, -297.71826186521605, -297.39229927453266, -297.0663366838492  …  -2.4598213052744216, -2.4487714690878364, -2.4378423985556466, -2.4270314824514307, -2.4163361933346827, -2.405754084004146, -2.3952827841368505, -2.3849199971013038, -2.3746634969341147, -2.364511125470097],)

Defining an initial guess

We define the initial guess, a NamedTuple whose key is the unknown function (p, the price–consumption ratio). These names (and the finite differences of $p$, such as ps_up) are what reappear in the equation below.

guess = (; p = ones(length(stategrid[:s])))
(p = [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0  …  1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0],)

Defining the PDE

We now write the function encoding the HJB equation. Following the package convention, it takes the current state (a grid point) and u (each unknown together with its finite-difference derivatives there) and returns the time derivative of each unknown.

function (m::CampbellCochraneModel)(state::NamedTuple, u::NamedTuple)
    (; μ, σ, γ, ρ, κs, b) = m
    (; s) = state
    (; p, ps_up, ps_down, pss) = u
    Sbar = σ * sqrt(γ / (κs - b / γ))
    sbar = log(Sbar)
    λ = 1 / Sbar * sqrt(1 - 2 * (s - sbar)) - 1
    μs = -κs * (s - sbar)
    σs = λ * σ
    # pricing uses the risk-adjusted drift of surplus consumption, not the physical one
    μs_effective = μs + σs * (σ - γ * (σ + σs))
    ps = (μs_effective >= 0) ? ps_up : ps_down
    σp = ps / p * σs
    μp = ps / p * μs + 0.5 * pss / p * σs^2
    κ = γ * (σ + σs)
    r = ρ + γ * μ - (γ * κs - b) / 2 + b * (sbar - s)
    pt = -p * (1 / p + μ + μp + σp * σ - r - κ * (σ + σp))
    return (; pt)
end

Solving the model

With the grid, guess, and equation in hand, pdesolve solves the stationary system:

result = pdesolve(m, stategrid, guess)
EconPDEResult
  solution:      p (998)
  residual_norm: 3.45e-12
  converged:     true (tolerance 1.49e-08)

The solution

Plotted against the surplus consumption ratio $S = e^s$, the price–consumption ratio rises steeply in good times: as consumption pulls away from the habit, effective risk aversion falls, discount rates drop, and valuations climb.

Sbar = m.σ * sqrt(m.γ / (m.κs - m.b / m.γ))
sbar = log(Sbar)
ss = stategrid[:s]
mask = ss .>= (sbar - 4)
plot(exp.(ss[mask]), result.solution.p[mask]; xlabel = "surplus consumption ratio S = exp(s)", ylabel = "price–consumption ratio p", legend = false)
Example block output

This page was generated using Literate.jl.