Integral Calculus and Differential Equations › Ordinary Differential Equations in Finance
Quantitative FinanceAll chapters Integral Calculus and Differential Equations › Ordinary Differential Equations in FinanceOne section · Sections in this chapter6 / 14 ↓
Reading tools Definitions & inline links
Choose your expertise level to adjust how many terms are explained. Beginners see more tooltips, experts see fewer to maintain reading flow. Hover over underlined terms for instant definitions.
Article links
Make inline references clickable
Differential equations describe relationships between quantities and their rates of change. Algebraic equations relate values directly, while differential equations relate a function to its derivatives and state the rules its path must satisfy. In finance, they model how portfolios, prices, and economic variables evolve over time, capturing the dynamic nature of markets and economies.
Differential equations encode rules of change that, when solved, reveal the trajectory of a system. If we know that interest rates revert toward a long-term mean, or that a portfolio grows proportionally to its value plus deposits, we can express these dynamics as differential equations and solve for the resulting paths.
First-Order Linear ODEs
A first-order linear ordinary differential equation has the form:
The term "first-order" means the equation involves only the first derivative of , not higher derivatives. "Linear" means and its derivative appear only to the first power and are not multiplied together. On an interval where and are continuous (or satisfy suitable integrability conditions), an integrating factor gives the general solution.
The general solution uses an integrating factor :
where:
- : the unknown function we are solving for
- : coefficient function multiplying
- : forcing function (the non-homogeneous term)
- : integrating factor that makes the left side a perfect derivative
- : constant of integration, determined by initial conditions
The integrating factor works because multiplying by converts the left side into , allowing direct integration. This technique appears frequently in differential equations. By multiplying through by just the right function, we transform a seemingly intractable equation into one we can solve by straightforward integration.
Example: Portfolio Growth with Continuous Deposits
Suppose you have a portfolio earning continuous return and you make continuous deposits at rate per year. This models a retirement account where you contribute regularly while earning investment returns. The portfolio value satisfies:
This equation says: the rate of change of your portfolio equals the investment return (, proportional to what you have) plus your deposits (, a constant flow). This is a first-order linear ODE with and . The integrating factor is .
Multiplying both sides by :
The left side is the derivative of :
This is the key insight: what looked like two separate terms is a single derivative. For , we can integrate directly:
With initial condition :
For , the solution is:
The first term represents growth of the initial investment, while the second represents accumulated deposits with their earned interest. This decomposition is intuitive. Your wealth at any time is the sum of what your original stake has grown to, plus what your contributions have accumulated.
For , is the time-zero value of a perpetual continuous cash-flow rate discounted continuously at rate . In the finite-horizon accumulation formula, the stable term is . Its continuous limit at is , so the zero-rate solution is rather than a division by zero.
import numpy as np
def portfolio_value(t, V0, r, D):
"""Analytical solution for portfolio with continuous deposits."""
return V0 + D * t if r == 0 else V0 * np.exp(r * t) + D * np.expm1(r * t) / r
# Parameters
V0 = 10000 # Initial investment
r = 0.07 # 7% annual return
D = 6000 # $6,000 annual deposits
t = np.linspace(0, 30, 300)
V = portfolio_value(t, V0, r, D)
# Components
growth_component = V0 * np.exp(r * t)
deposit_component = portfolio_value(t, 0, r, D)
After 30 years: Initial investment: $10,000 Total deposits: $180,000 Final portfolio value: $695,904.83 Investment gain: $505,904.83
The power of compounding is evident: starting with $10,000 and depositing $6,000 per year, the portfolio grows to over $600,000 after 30 years, with investment gains far exceeding the total contributions.
Numerical Solution of ODEs
Numerical methods can compute trajectories when a convenient known closed form is unavailable. Time-varying coefficients and nonlinearity do not automatically prevent analytical solutions. The examples below also use numerical evaluation when a benchmark formula is known. The SciPy function odeint wraps LSODA and uses requested local-error tolerances; success does not guarantee a chosen global error. SciPy recommends solve_ivp for new code.
Example: Mean-Reverting Interest Rates
The constant-parameter Vasicek model is the stochastic differential equation . Assume for mean reversion. The ODE below retains only its drift and also governs the conditional mean :
where:
- : deterministic drift trajectory, equivalently the conditional mean rate at time
- : speed of mean reversion (larger positive values mean faster reversion)
- : long-term mean interest rate
- : short-rate volatility in the full SDE; is a Brownian increment
Mean reversion is a modeling assumption, not a claim that central banks or arbitrage impose hard bounds. In the drift ODE, gives a negative derivative and gives a positive derivative; larger means faster convergence of the conditional mean. For positive elapsed time and nonzero volatility, the constant-parameter Vasicek rate has a nondegenerate Gaussian law with support on the entire real line. At time zero or zero volatility, its conditional law is degenerate instead.
This conditional-mean ODE has the analytical solution , but we solve it numerically to demonstrate the technique:
import numpy as np
from scipy.integrate import odeint
def vasicek_drift(r, t, kappa, theta):
"""Drift term of Vasicek model (deterministic part)."""
return kappa * (theta - r)
# Model parameters
kappa = 0.5 # Mean reversion speed
theta = 0.05 # Long-term mean (5%)
# Solve for different starting rates
t = np.linspace(0, 10, 100)
r0_values = [0.02, 0.05, 0.08] # Starting rates
solutions = {}
for r0 in r0_values:
solutions[r0] = odeint(vasicek_drift, r0, t, args=(kappa, theta)).flatten()
The mean reversion parameter implies a half-life of years: after about 1.4 years, the conditional mean's deviation has halved, not every individual stochastic path's deviation.
Mean reversion speed (kappa): 0.5 Long-term mean (theta): 5.0% Half-life of deviation: 1.39 years