SigmaField
Mathematical Foundations for Quant Finance
0 of 256 lessons
      1. 2.5.1 Area and Riemann sumsConcept · 30 min
      2. 2.5.2 AntiderivativesConcept · 25 min
      3. 2.5.3 The fundamental theorem of calculusConcept · 30 min
      4. 2.5.4 Practice set: integrationPractice set · 25 min
      5. 2.5.5 Case study: present value of a continuous cash flowCase study · 35 min

Level 2, Single-variable calculus 2.5 Integration Lesson 5 of 5

Case studyLesson 2.5.5 in Level 2, Single-variable calculus. About 35 minutes.

Case study: present value of a continuous cash flow

A stream of cash as an integral

Say money arrives at a rate of c(t)c(t) dollars per year at time tt, measured in years. In a short time Δt\Delta t, about c(t) Δtc(t)\,\Delta t dollars arrive. Discounted continuously at the rate rr (case study 1.4.6), they are worth c(t) e−rt Δtc(t)\,e^{-rt}\,\Delta t today.

Adding these pieces over [0,T][0, T] is a Riemann sum (lesson 2.5.1). As Δt→0\Delta t \to 0, it becomes an integral.

Rule: Present value of a continuous stream

PV=∫0Tc(t) e−rt dtPV = \int_0^T c(t)\,e^{-rt}\,dt

c(t) e−rtc(t)\,e^{-rt} is the discounted rate: what the cash arriving at time tt is worth today, per year. The present value is the area under it.

For a constant rate cc, an antiderivative of e−rte^{-rt} is −e−rtr-\frac{e^{-rt}}{r}: divide by k=−rk = -r, as in lesson 2.5.2. The fundamental theorem (lesson 2.5.3) then gives a closed form.

PV=c[−e−rtr]0T=c 1−e−rTr\begin{aligned} PV &= c\left[-\frac{e^{-rt}}{r}\right]_0^T \\ &= c\,\frac{1 - e^{-rT}}{r} \end{aligned}

For the toll road, c=10,000c = 10{,}000, r=0.05r = 0.05 and T=10T = 10, so PVPV = $78,693.87. Undiscounted, the same 10 years pay $100,000.

Units on a desk

The formula needs one unit of time throughout: cc in dollars per year, rr per year and TT in years. Then rTrT is a pure number, as an exponent must be.

  • Convert cash flows first. $850 a month is c=10,200c = 10{,}200 dollars a year.
  • Rates enter as decimals. Typing r=5r = 5 for 5% gives $2,000, nonsense for ten years of $10,000.
  • Time is in years. Typing T=120T = 120 months with a yearly rate gives $199,504.25, almost the value of tolls forever.

Try it

The closed form and SciPy's quad agree on $78,693.87. Then the two unit mistakes above: a rate typed as 5, and the term typed in months.

⌘/Ctrl + Enter runs the cell

Continuous against yearly payments

At the same discount rate, a schedule of separate payments is a Riemann sum of the discounted rate. So lesson 2.5.1 says which way it errs.

Ten payments of $10,000 at the year-ends are worth ∑k=11010,000 e−0.05k\sum_{k=1}^{10} 10{,}000\,e^{-0.05k} today. That is the right sum of 10,000 e−0.05t10{,}000\,e^{-0.05t} with Δt=1\Delta t = 1. The discounted rate falls, so the right sum is too small: $76,742.92, short by $1,950.95.

The area under the discounted rate is the present value of continuous tolls, $78,694. Ten year-end payments are right-end rectangles under the falling curve, so they come to less: $76,743.

Payments at the start of each year form the left sum, which is too large: $80,677.61. The two schedules differ by Δt (f(0)−f(10))=10,000 (1−e−0.5)\Delta t\,\big(f(0) - f(10)\big) = 10{,}000\,(1 - e^{-0.5}), or $3,934.69: the gap rule of lesson 2.5.1, with ff the discounted rate.

paymentsRiemann sumvalue today
at year-endsright, Δt=1\Delta t = 1$76,742.92
at month-endsright, Δt=112\Delta t = \frac{1}{12}$78,530.04
at mid-yearmidpoint, Δt=1\Delta t = 1$78,685.67
continuouslythe integral$78,693.87
at year-startsleft, Δt=1\Delta t = 1$80,677.61

Monthly payments close most of the gap, and mid-year payments nearly all of it, because midpoint sums are accurate. That is why valuations often treat a year's cash as arriving at mid-year.

Same rate, same convention

A comparison is fair only when both sides use the same rate. A rate of 5% compounded once a year is not a continuous 5%.

Compounded yearly, 5% discounts year kk by 1.05−k=e−0.04879k1.05^{-k} = e^{-0.04879k}: a continuous rate of ln⁡1.05=4.879%\ln 1.05 = 4.879\% (case study 1.4.6). Valued that way, the year-end payments are worth $77,217.35, not $76,742.92. Convert both sides to one convention before you compare them.

Try it

Each schedule is a sum of discounted payments, all at a continuous 5%. Each line prints its value and its gap from the integral.

The last line discounts the year-end payments with 1.05−k1.05^{-k} instead: a different rate, so a different value.

⌘/Ctrl + Enter runs the cell

A growing stream

If the tolls grow at a continuous rate gg, then c(t)=c0 egtc(t) = c_0\,e^{gt}, where c0c_0 is the rate now. The discounted rate becomes c0 e−(r−g)tc_0\,e^{-(r - g)t}, and the same antiderivative, with r−gr - g in place of rr, gives the present value.

Rule: Growing stream

PV=c0 1−e−(r−g)Tr−g(r≠g)PV = c_0\,\frac{1 - e^{-(r - g)T}}{r - g} \quad (r \neq g)

Growth acts like a lower discount rate, r−gr - g. With c0=10,000c_0 = 10{,}000 and g=3%g = 3\%, the toll road is worth $90,634.62.

When the formula breaks

  • g=rg = r. The formula reads 00\frac{0}{0}. But then the discounted rate is the constant c0c_0, so the present value is c0Tc_0 T: $100,000 here.
  • gg almost equal to rr. Rates often come out of other sums. 0.15−0.10.15 - 0.1 is stored as 0.04999999999999999, so a test g == r against r=0.05r = 0.05 fails. The formula then divides two tiny numbers, 1−e−x1 - e^{-x} loses its digits, and it returns $80,000 instead of $100,000.
  • T→∞T \to \infty. If r>gr > g, then e−(r−g)T→0e^{-(r - g)T} \to 0 and PV→c0r−gPV \to \frac{c_0}{r - g}: the growing perpetuity behind dividend-discount models. If g≥rg \ge r, the area grows without limit and there is no finite value; lesson 2.6.3 treats such integrals.

math.expm1(x) computes ex−1e^x - 1 accurately even for tiny xx. Writing the top of the fraction as −expm1(−(r−g)T)-\text{expm1}\big(-(r - g)T\big) repairs the second case.

The perpetuity also shows how sensitive values are when gg is close to rr. At r=5%r = 5\% it is $500,000 with g=3%g = 3\%, $1,000,000 with 4% and $2,000,000 with 4.5%. A half-point change in a growth guess can double the answer.

Try it

The closed form, quad and a midpoint sum with only 100 strips agree to within 1 cent for 3% growth.

Then the float trap: the plain formula against the expm1 version, with g=0.15−0.1g = 0.15 - 0.1. Last, the perpetuity for three growth rates.

⌘/Ctrl + Enter runs the cell
Check yourself
An income stream of $10,000 a year lasts forever, at a continuous rate of 5% and no growth. What is it worth today?

Default intensity

Credit desks model a borrower's default with a hazard rate λ\lambda (lambda), also called a default intensity. It is a rate per year: over a short time Δt\Delta t, a borrower who has not yet defaulted defaults with probability about λ Δt\lambda\,\Delta t.

With a constant λ\lambda, the probability of surviving to time tt is e−λte^{-\lambda t}. The default time then has density λe−λt\lambda e^{-\lambda t}: a rate of probability, per year. Integrating that rate over the years gives a total probability (lesson 2.5.3):

P(default by T)=∫0Tλe−λt dt=[−e−λt]0T=1−e−λT\begin{aligned} P(\text{default by } T) &= \int_0^T \lambda e^{-\lambda t}\,dt \\ &= \big[-e^{-\lambda t}\big]_0^T = 1 - e^{-\lambda T} \end{aligned}

At λ=2%\lambda = 2\% a year, that is 9.52% within 5 years and 18.13% within 10. The shortcut λT\lambda T gives 10% and 20%: close while λT\lambda T is small, worse as it grows. Level 5 develops densities properly.

A stream that stops at default

Suppose the tolls stop for good if the operator defaults, with nothing recovered. Cash at time tt arrives only if there has been no default by then, which has probability e−λte^{-\lambda t}. So each moment's discounted cash is weighted by it.

Rule: Stream with a hazard rate

PV=∫0Tc e−rt e−λt dt=c 1−e−(r+λ)Tr+λ\begin{gathered} PV = \int_0^T c\,e^{-rt}\,e^{-\lambda t}\,dt \\ = c\,\frac{1 - e^{-(r + \lambda)T}}{r + \lambda} \end{gathered}

The hazard rate adds to the discount rate. That is why a riskier borrower's cash is discounted at a higher rate: the extra λ\lambda acts as a credit spread.

At λ=2%\lambda = 2\%, the toll road's 10 years are worth $71,916.39, which is $6,777.48 less than without default risk.

Try it

The default probabilities from the closed form, and from quad of the density for 5 years. Then the risky stream, by formula and by quad.

⌘/Ctrl + Enter runs the cell
Check yourself
The toll road pays $10,000 a year for 10 years, at a continuous 5%, with a 2% hazard rate. Which gives its present value?
Exercise

Present value of a continuous stream

Write two functions.

  1. pv_stream(c, r, T, g=0.0, hazard=0.0) returns the present value of income at rate c egtc\,e^{gt} per year for TT years. It discounts at the continuous rate r and stops at a default with hazard rate hazard. Use the closed form with the net rate k=r+λ−gk = r + \lambda - g, written with math.expm1 so that a tiny kk keeps its digits. When k=0k = 0 the answer is cTcT. Raise ValueError if T or hazard is negative.
  2. default_probability(hazard, T) returns 1−e−λT1 - e^{-\lambda T}.

All rates are per year, as decimals, and T is in years.

See the tests
import math

from scipy.integrate import quad


def test_constant_stream():
    """$10,000 a year for 10 years at 5% is worth about $78,693.87"""
    expect_close(pv_stream(10_000, 0.05, 10), 78693.86805747332, what="pv_stream(10000, 0.05, 10)")


def test_growing_stream():
    """Growing at 3%, it is worth about $90,634.62"""
    expect_close(pv_stream(10_000, 0.05, 10, g=0.03), 90634.62346100906, what="pv_stream(..., g=0.03)")


def test_risky_stream():
    """With a 2% hazard rate, it is worth about $71,916.39"""
    expect_close(pv_stream(10_000, 0.05, 10, hazard=0.02), 71916.38517265576, what="pv_stream(..., hazard=0.02)")


def test_matches_quad():
    """It matches numerical integration for a growing, risky stream"""
    expected = quad(lambda t: 2500 * math.exp(0.01 * t) * math.exp(-0.07 * t) * math.exp(-0.015 * t), 0, 25)[0]
    expect_close(pv_stream(2500, 0.07, 25, g=0.01, hazard=0.015), expected, what="pv_stream(2500, 0.07, 25, g=0.01, hazard=0.015)")


def test_growth_equals_rate():
    """When g equals r the answer is c × T"""
    expect_close(pv_stream(1000, 0.04, 8, g=0.04), 8000.0, what="pv_stream(1000, 0.04, 8, g=0.04)")


def test_growth_almost_equals_rate():
    """g = 0.15 − 0.1 is stored as 0.04999999999999999; at r = 0.05 the answer is still c × T"""
    expect_close(pv_stream(10_000, 0.05, 10, g=0.15 - 0.1), 100_000.0, what="pv_stream(10000, 0.05, 10, g=0.15 - 0.1)", rel=1e-9)


def test_bad_inputs():
    """A negative term or a negative hazard rate raises ValueError"""
    for args in [dict(T=-1), dict(T=10, hazard=-0.01)]:
        try:
            pv_stream(10_000, 0.05, **args)
        except ValueError:
            continue
        raise AssertionError(f"expected ValueError for {args}")


def test_default_probability():
    """A 2% hazard rate gives a 9.52% chance of default within 5 years"""
    expect_close(default_probability(0.02, 5), 0.09516258196404048, what="default_probability(0.02, 5)")

Summary card

  • A continuous cash flow at rate c(t)c(t) dollars per year is worth ∫0Tc(t) e−rt dt\int_0^T c(t)\,e^{-rt}\,dt today: the area under the discounted rate.
  • Constant rate: c 1−e−rTrc\,\frac{1 - e^{-rT}}{r}, and cr\frac{c}{r} forever. Keep cc, rr and TT in per-year units.
  • Discrete payments are Riemann sums of the discounted rate: year-end payments are too small, year-start ones too large, mid-year ones close. Compare values only at the same rate convention.
  • Growing at gg: c0 1−e−(r−g)Tr−gc_0\,\frac{1 - e^{-(r - g)T}}{r - g}, which is c0Tc_0 T when g=rg = r; use math.expm1 when r−gr - g is tiny. Forever, c0r−g\frac{c_0}{r - g} if r>gr > g.
  • A hazard rate λ\lambda gives P(default by T)=1−e−λTP(\text{default by } T) = 1 - e^{-\lambda T}, and adds to the discount rate of a stream that stops at default.

Free further reading

Optional. This lesson covers what you need; these add more examples and practice. All are free to read.