@ta.rodriguez
You have a neoclassical growth model (NCGM) w/ two types of debt:
-
Collateralized debt: F_{t} at interest rate f_{t} s.t. constraint F_{t} \leq q K_{t}
-
Unsecured debt: I_{t} at interest rate i_{t}
We need i_{t} > f_{t} for this problem to be interesting.
It makes sense: unsecured credit card rates (20%) are higher than mortgage rates (3%)
Without debt you have a routine NCGM w/ a known closed form solution (Brock-Mirman) w/ u(c)=log(c), \delta=1, g(k)=z k^\alpha.
This should be your starting point.
The easiest way I know how to solve this problem is to cast it in continuous time & use an Optimal Control package. I use NLOptControl.jl which can handle inequality constraints, but currently only allows finite horizon.
J = \max \int_{t=0}^{t=T} e^{-\rho t} u(c_{t}) dt
s.t.
\dot{k}_{t} = k_{t}^{\alpha} -\delta k_{t} - c_{t} - pmt_{1t} - pmt_{2t}
\dot{b}_{1t} = r_{1} \times b_{1t} - pmt_{1t}
\dot{b}_{2t} = r_{2} \times b_{2t} - pmt_{2t}
b_{1t} \leq q \times k_{t}
c_{t}, k_{t}, b_{1t}, b_{2t} \geq 0
k_{0} given, k_{T}=0
b_{i0}=0, b_{iT}=0 for i\in \{1,2\} (born w/o debt, die w/o debt)
State variables: k_t, b_{1t}, b_{2t}
Choice variables: c_t, pmt_{1t}, pmt_{2t}
Parameters: T, \rho, u(c), \alpha, \delta, r_{1}, r_{2}, q
Case 1: no borrowing
using NLOptControl
# NCGM No Borrowing
n=define(
numStates=1, numControls=1,
X0=[5.0], XF=[0.01],
XL=[0.0], XU=[NaN], # k(t) >= 0.0
CL=[0.01], CU=[NaN] # c(t) >= 0.0
)
states!(n,[:k];descriptions=["k(t)"])
controls!(n,[:c];descriptions=["c(t)"])
dx=[
:( (k[j]^(.67)) - 0.3 * k[j] - c[j] )
]
dynamics!(n,dx)
configure!(n;
(:integrationScheme=>:trapezoidal),
(:finalTimeDV=>false),(:tf=>100.0))
# @NLconstraint
obj=integrate!(n, :( exp(-.01 * j) * log(c[j]) ) );
@NLobjective(n.ocp.mdl, Max, obj)
optimize!(n)
allPlots(n)
Case 2: Collateralized Borrowing
# NCGM + Collateralized Borrowing
n=define(
numStates=2, numControls=2,
X0=[5.0,0.0], XF=[0.01,0.0],
XL=[0.0,NaN], XU=[NaN,NaN], # k(t) >= 0.0
CL=[0.01,-20.0], CU=[NaN,NaN] # c(t) >= 0.0
)
states!(n,[:k,:b1];descriptions=["k(t)","b1(t)"])
controls!(n,[:c,:pmt1];descriptions=["c(t)","pmt1(t)"])
dx=[
:( (k[j]^(.67)) - 0.3 * k[j] - c[j] - pmt1[j]),
:( 0.01 * b1[j] - pmt1[j] )
]
dynamics!(n,dx)
configure!(n;
(:integrationScheme=>:trapezoidal),
(:finalTimeDV=>false),(:tf=>100.0)
)
# @NLconstraint
obs_con = @NLconstraint(n.ocp.mdl,
[i=1:n.ocp.state.pts-1],
n.r.ocp.x[i,2] <= 0.25 * n.r.ocp.x[i,1] #b[t] <= 0.5*k[t]
)
newConstraint!(n,obs_con,:obs_con)
#
obj=integrate!(n, :( exp(-.01 * j) * log(c[j]) ) );
@NLobjective(n.ocp.mdl, Max, obj)
optimize!(n)
allPlots(n)
Case 3: Collateralized Borrowing + Unsecured debt
# NCGM + Collateralized Borrowing + Unsecured debt
n=define(
numStates=3, numControls=3,
X0=[5.0,0.0,0.0], XF=[0.01,0.0,0.0],
XL=[0.0,NaN,0.0], XU=[NaN,NaN,NaN], # k(t) >= 0.0, no saving
CL=[0.01,-20.0,-20.0], CU=[NaN,NaN,NaN] # c(t) >= 0.0
)
states!(n,[:k,:b1,:b2];descriptions=["k(t)","b1(t)","b2(t)"])
controls!(n,[:c,:pmt1,:pmt2];descriptions=["c(t)","pmt1(t)","pmt2(t)"])
dx=[
:( (k[j]^(.67)) - 0.3 * k[j] - c[j] - pmt1[j] - pmt2[j]),
:( 0.01 * b1[j] - pmt1[j] ),
:( 0.03 * b2[j] - pmt2[j] )
]
dynamics!(n,dx)
configure!(n;
(:integrationScheme=>:trapezoidal),
(:finalTimeDV=>false),(:tf=>100.0)
)
# @NLconstraint
obs_con = @NLconstraint(n.ocp.mdl,
[i=1:n.ocp.state.pts-1],
n.r.ocp.x[i,2] <= 0.25 * n.r.ocp.x[i,1] #b[t] <= 0.5*k[t]
)
newConstraint!(n,obs_con,:obs_con)
#
obj=integrate!(n, :( exp(-.01 * j) * log(c[j]) ) );
@NLobjective(n.ocp.mdl, Max, obj)
optimize!(n)
allPlots(n)
You’re gonna have to better tune the solver parameters for more precise solutions…
Good luck