Time Value of Money and Interest Rates › Valuing Cash Flow Streams
Quantitative FinanceAll chapters Time Value of Money and Interest Rates › Valuing Cash Flow StreamsOne section · Sections in this chapter5 / 9 ↓
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
Financial instruments and investments can involve multiple cash flows over time:
- A fixed-coupon bond pays periodic coupons.
- An amortizing loan may require monthly payments.
- A business valuation can use forecast operating cash flows, which are not the same as accounting profits.
The time value of money framework values a stream by treating each cash flow separately and summing the results.
Net Present Value
The Net Present Value (NPV) is the sum of all discounted cash flows. It takes each future cash flow, discounts it back to today using the appropriate discount factor, and adds up all these present values. This single number captures the total value of an entire cash flow stream in today's dollars:
where:
- : net present value (total value in today's dollars)
- : cash flow occurring at time (negative for outflows, positive for inflows)
- : discount rate (required rate of return)
- : final period of the cash flow stream
- : discount factor for period
- : summation over all periods from 0 (today) to (final period)
Here the periods are years and is a constant effective annual rate with . The code also accepts fractional times measured in years. Each cash-flow amount must have a corresponding time. Both inputs must be one-dimensional arrays with the same shape; the function rejects mismatches rather than allowing NumPy to broadcast them. At , discount factors are one and NPV is simply the signed sum of the cash flows.
A positive NPV indicates the investment creates value; a negative NPV indicates it destroys value. NPV answers the question of net benefit in today's dollars by converting all future cash flows to a common time reference. The discount rate represents your opportunity cost, meaning what you could earn on alternative investments of similar risk. By using this rate to discount future cash flows, you are implicitly comparing the investment to your next best alternative.
The NPV framework accounts for when each cash flow occurs. At a positive discount rate, an equal positive inflow has a higher present value when received earlier. An equal negative outflow has a more negative present value when paid earlier: its present cost is larger. Discount factors capture both effects, so the sign matters as well as the timing.
Net present value is the sum of all cash flows discounted to the present. It measures the total value created (or destroyed) by an investment in today's dollars.
import numpy as np
def npv(cash_flows, times, r):
"""
Calculate net present value of cash flows.
Parameters:
- cash_flows: array of cash flow amounts
- times: array of times when cash flows occur
- r: discount rate (annual)
"""
cash_flows = np.asarray(cash_flows, dtype=float)
times = np.asarray(times, dtype=float)
if cash_flows.ndim != 1 or times.ndim != 1 or cash_flows.shape != times.shape:
raise ValueError("cash_flows and times must be paired one-dimensional arrays")
discount_factors = (1.0 + r) ** (-times)
return np.sum(cash_flows * discount_factors)
# Investment example: Pay $10,000 now, receive $3,000/year for 5 years
cf = [-10000, 3000, 3000, 3000, 3000, 3000]
times = [0, 1, 2, 3, 4, 5]
r = 0.08
investment_npv = npv(cf, times, r)Investment Analysis ======================================== Initial investment: $10,000 Annual cash flows: $3,000 for 5 years Discount rate: 8% NPV: $1,978.13 Decision: Accept
The NPV is positive, indicating the investment generates value at an 8% discount rate. However, NPV is highly sensitive to the discount rate chosen. Let's examine this sensitivity:

The discount rate where NPV equals zero is called the Internal Rate of Return (IRR). For this investment, the IRR is approximately 15.2%, meaning the investment breaks even at that discount rate.
Annuities
An annuity is a series of equal payments made at regular intervals. Fixed-rate mortgages, amortizing car loans, and fixed-payment annuity products can be modeled as annuities. The defining characteristic is regularity: the same amount paid at the same interval for a fixed number of periods. This structure is common enough in finance to merit its own specialized formulas.
Rather than discounting each payment individually and summing, which would require separate calculations, we can derive a closed-form expression that computes the entire sum at once. The present value of an ordinary annuity (payments at end of each period) is:
where:
- : present value of the annuity
- : periodic payment amount
- : periodic interest rate (e.g., monthly rate for monthly payments)
- : total number of payment periods
- : the annuity factor (present value of $1 per period for periods)
Here is a nonnegative integer count of payments and . Solving for the payment needed to repay a loan requires ; an empty payment schedule cannot repay a positive principal. The zero-rate case is handled separately below.
The annuity formula comes from summing a geometric series of discount factors. The series forms a geometric progression with first term and common ratio . Applying the geometric series formula and simplifying yields the expression above. Rather than computing individually, the closed-form solution captures all terms at once.
For , the formula approaches (a perpetuity) as increases because shrinks toward zero. If , the present value is instead ; for and positive payments, it grows without a finite perpetuity limit. The intuition that very distant payments contribute negligibly therefore depends on a positive discount rate.
An annuity is a series of equal cash flows occurring at regular intervals. The annuity formula allows direct calculation of present or future value without summing each individual payment.
The term is called the annuity factor. It represents the present value of receiving $1 per period for periods. This factor depends only on the interest rate and number of periods, not on the payment amount, making it a useful building block. Once you know the annuity factor, you simply multiply by the payment amount to get the present value of any annuity with those characteristics.
def annuity_pv(payment, r, periods):
"""Present value of ordinary annuity."""
if r == 0:
return payment * periods
annuity_factor = -np.expm1(-periods * np.log1p(r)) / r
return payment * annuity_factor
def annuity_payment(pv, r, periods):
"""Calculate payment for a positive integer count of periods and r > -1."""
if periods <= 0 or int(periods) != periods:
raise ValueError("periods must be a positive integer")
if r <= -1:
raise ValueError("r must exceed -1")
if r == 0:
return pv / periods
annuity_factor = -np.expm1(-periods * np.log1p(r)) / r
return pv / annuity_factor
# Mortgage example: $300,000 loan, 6% annual rate, 30 years
loan_amount = 300000
annual_rate = 0.06
years = 30
monthly_rate = annual_rate / 12
months = years * 12
monthly_payment = annuity_payment(loan_amount, monthly_rate, months)
total_paid = monthly_payment * months
total_interest = total_paid - loan_amount
mortgage_years = 30 # Store for output displayMortgage Analysis ======================================== Loan amount: $ 300,000.00 Annual rate: 6.00% Term: 30 years Monthly payment: $ 1,798.65 Total payments: $ 647,514.57 Total interest: $ 347,514.57 Interest/Principal ratio: 1.16x
Over 30 years, this borrower pays about 2.16 times the original principal in total: roughly $647,515 of payments on a $300,000 loan. Total interest is about 116% of the original principal. Most of the early payments go toward interest, with principal reduction accelerating over time. This amortization structure has practical implications for refinancing decisions.

Perpetuities
A perpetuity is an annuity that continues indefinitely in the model. Perpetual securities have no contractual maturity, although their terms may permit redemption. A permanent endowment can be planned over an indefinite horizon. In these settings, the perpetuity formula can provide a useful approximation.
For constant positive payments beginning one period from now, and a constant positive per-period discount rate , the present value is:
where:
- : present value of the perpetuity
- : constant periodic payment
- : discount rate per period
The present value equals the principal amount that, if invested at rate , would generate exactly in interest each period forever, leaving the principal intact. If you have dollars earning rate , your interest income is per period. You can withdraw this interest forever without touching the principal, creating a perpetual income stream of per period.
This formula emerges from taking the limit of the annuity formula as :
For a fixed positive , the term tends to zero as grows without bound, leaving . A finite cutoff needs a rate-specific check. Omitting payments after period leaves a tail worth , or a fraction of the perpetuity value. At 4% per period, the fraction beyond payment 1,000 is about ; at 0.01% per period it is still about 90.48%. A positive rate alone does not make a particular finite cutoff negligible.
A perpetuity is a stream of equal payments continuing indefinitely. For positive payments beginning one period from now and a positive per-period discount rate, its present value is .
def perpetuity_pv(payment, r):
"""PV of end-period level payments under the model's positive-rate assumption."""
return payment / r
# Example: Endowment providing $50,000 annually at 4% rate
annual_payment = 50000
r = 0.04
endowment_needed = perpetuity_pv(annual_payment, r)Annual scholarship payment: $50,000 Interest rate: 4.0% Endowment required: $1,250,000
To fund a $50,000 annual scholarship in perpetuity at a constant 4% return, with the first withdrawal at year-end, the model requires $1.25 million. Each year's interest funds that year's withdrawal, leaving the nominal principal intact.
A growing perpetuity accounts for payments that change at a constant rate . For the usual nonnegative-payment model, take , , and ; if every payment must remain strictly positive, require .
where:
- : present value of the growing perpetuity
- : first payment (occurring one period from now)
- : discount rate per period, with positive discount gross factor
- : constant payment growth rate, with for nonnegative payments (strictly greater than zero for payments that remain positive forever)
- : the discount-growth spread in the closed form; under these nonnegative gross-factor assumptions, reduces to
Growth partially offsets discounting. When payments grow at 2% and the discount rate is 5%, the discount-growth spread is 3 percentage points. Successive present-value terms have ratio , so the decline per term is . The equivalent discount-rate quote is instead ; these are different quantities. With and fixed in the positive-gross-factor domain, as approaches from below, the terms barely decline and the sum grows without bound.
To see why mathematically, the -th payment is , so its present value is with . A geometric series converges exactly when . In the nonnegative-payment domain, , so this becomes and, because , is equivalent to . If , the nonnegative discounted terms do not decay to zero and the infinite sum diverges.
Applied to a constant-growth dividend stream, this formula gives the Gordon Growth Model for stock valuation.
