---
title: "Chapter 2. Time Value of Money and Discounting"
---
::: {.chapter-objectives}
## Learning Goals
By the end of this chapter, students should be able to:
- explain the time value of money using accumulation and discount functions;
- convert between simple interest, periodic compounding, effective annual rates, and continuous compounding;
- price deterministic cash-flow streams using discount factors;
- derive zero-coupon bond prices, spot rates, and forward rates from no-arbitrage arguments;
- compute present value, future value, annuity value, perpetuity value, duration, and convexity;
- interpret discounting as a linear pricing functional on deterministic cash flows;
- implement discounting formulas in Python and test them numerically;
- use AI tools responsibly to check algebra, units, assumptions, and edge cases.
:::
::: {.hero-box}
The first law of mathematical finance is that **a dollar today is not the same mathematical object as a dollar tomorrow**.
A cash flow has a date. Discounting is the operation that converts cash flows at different dates into a common unit of value.
:::
## 2.1 The Time Value of Money
Suppose one dollar invested at time $0$ grows to more than one dollar at time $T$. The increase may reflect compensation for delayed consumption, inflation, credit risk, liquidity, or opportunity cost. In the idealized mathematical models of this chapter, we ignore risky default and assume a riskless bank account.
Let $B_t$ denote the value at time $t$ of one dollar invested in the bank account at time $0$. The process
$$
B_0 = 1, \qquad B_t > 0
$$
is called the **accumulation factor** or **bank-account value**. If $B_T=1.05$, then one dollar at time $0$ becomes $1.05$ dollars at time $T$.
The reciprocal
$$
D(0,T) = \frac{1}{B_T}
$$
is the **discount factor** from time $T$ back to time $0$. A deterministic cash flow $X_T$ paid at time $T$ has time-$0$ present value
$$
PV_0(X_T) = D(0,T)X_T.
$$
::: {.definition}
**Definition 2.1 (Accumulation and discount factors).** The accumulation factor $B_T$ is the time-$T$ value of one dollar invested at time $0$. The discount factor $D(0,T)$ is the time-$0$ value of one dollar paid at time $T$:
$$
D(0,T)=\frac{1}{B_T}.
$$
:::
The notation $D(0,T)$ emphasizes that discounting depends on two dates: the valuation date $0$ and the payment date $T$. Later, for time-dependent rates, we will write $D(s,T)$ for the time-$s$ value of one dollar paid at time $T$.
## 2.2 Simple Interest
Under **simple interest**, interest is earned only on the original principal, not on accumulated interest. If the annual simple interest rate is $r$ and the time horizon is $T$ years, then
$$
B_T = 1+rT.
$$
Thus the future value of principal $P$ is
$$
FV = P(1+rT),
$$
and the present value of a deterministic future payment $X_T$ is
$$
PV = \frac{X_T}{1+rT}.
$$
::: {.example}
**Example 2.1 (Simple interest).** Suppose $P=1000$, $r=0.06$, and $T=2$. Then
$$
FV = 1000(1+0.06\cdot 2)=1120.
$$
If a contract pays $1120$ in two years, its present value under this simple-interest model is
$$
PV = \frac{1120}{1.12}=1000.
$$
:::
Simple interest is useful for short-term instruments and introductory calculations. However, for multi-period mathematical finance, compound interest is more natural because it has a multiplicative structure.
## 2.3 Compound Interest
Under **annual compound interest**, interest earned in one period is added to the account and earns interest in future periods. If the annual interest rate is $r$, then
$$
B_n = (1+r)^n
$$
for integer $n\ge 0$. Therefore
$$
FV = P(1+r)^n,
\qquad
PV = \frac{FV}{(1+r)^n}.
$$
The multiplicative property is central:
$$
B_{m+n}=B_mB_n
$$
when the same rate $r$ applies in every period. This is why compounded gross returns multiply.
::: {.definition}
**Definition 2.2 (Gross risk-free return).** If the risk-free rate per period is $r$, the gross risk-free return is
$$
R_f = 1+r.
$$
One dollar becomes $R_f$ dollars after one period and $R_f^n$ dollars after $n$ periods.
:::
::: {.remark}
In finance, the word **return** is sometimes used for the net return $r$ and sometimes for the gross return $1+r$. In mathematical writing, it is safest to state explicitly whether $r$ or $1+r$ is being used.
:::
## 2.4 Periodic Compounding
If an annual nominal rate $r^{(m)}$ is compounded $m$ times per year, then each compounding period has rate $r^{(m)}/m$. Over $T$ years, there are $mT$ periods, so
$$
B_T = \left(1+\frac{r^{(m)}}{m}\right)^{mT}.
$$
The corresponding effective annual rate $r_{\mathrm{eff}}$ is defined by matching one-year growth:
$$
1+r_{\mathrm{eff}}
=
\left(1+\frac{r^{(m)}}{m}\right)^m.
$$
Thus
$$
r_{\mathrm{eff}}
=
\left(1+\frac{r^{(m)}}{m}\right)^m-1.
$$
::: {.example}
**Example 2.2 (Nominal versus effective rate).** A nominal annual rate of $6\%$ compounded monthly has effective annual rate
$$
r_{\mathrm{eff}}
=
\left(1+\frac{0.06}{12}\right)^{12}-1
\approx 0.06168.
$$
The effective annual rate is about $6.168\%$, not $6\%$.
:::
## 2.5 Continuous Compounding
Continuous compounding is obtained as a limit. For fixed $r$ and $T$,
$$
\lim_{m\to\infty}\left(1+\frac{r}{m}\right)^{mT}=e^{rT}.
$$
Thus under continuous compounding,
$$
B_T=e^{rT},
\qquad
D(0,T)=e^{-rT}.
$$
A deterministic payment $X_T$ at time $T$ has present value
$$
PV_0(X_T)=e^{-rT}X_T.
$$
The continuously compounded rate is especially convenient because exponents add:
$$
e^{r(T+s)}=e^{rT}e^{rs}.
$$
This algebra is one reason continuous compounding appears naturally in Black--Scholes theory, stochastic calculus, and term-structure modeling.
::: {.theorem}
**Theorem 2.1 (Limit from periodic to continuous compounding).** For any real $r$ and $T\ge 0$,
$$
\lim_{m\to\infty}\left(1+\frac{r}{m}\right)^{mT}=e^{rT}.
$$
:::
::: {.proof}
Let $x_m=r/m$. Since $\log(1+x_m)=x_m-x_m^2/2+O(x_m^3)$ as $m\to\infty$,
$$
mT\log\left(1+\frac{r}{m}\right)
=mT\left(\frac{r}{m}+O\left(\frac{1}{m^2}\right)\right)
=rT+O\left(\frac{1}{m}\right).
$$
Exponentiating gives the result.
:::
## 2.6 Interactive: Growth Under Different Compounding Rules
The following Plotly.js example compares simple, annual, monthly, and continuous compounding. It is designed to reinforce the difference between linear growth and exponential growth.
```{=html}
<div class="interactive-card">
<h3>Interactive 2.1: Compounding Comparison</h3>
<p>Move the rate and horizon controls to compare simple, periodic, and continuous compounding for one dollar invested today.</p>
<label for="mf2-rate"><strong>Annual rate:</strong> <span id="mf2-rate-label">5.0%</span></label>
<input id="mf2-rate" type="range" min="0" max="15" step="0.25" value="5" style="width:100%;">
<label for="mf2-years"><strong>Horizon:</strong> <span id="mf2-years-label">30 years</span></label>
<input id="mf2-years" type="range" min="1" max="50" step="1" value="30" style="width:100%;">
<div id="mf2-compounding-plot" class="plotly-demo"></div>
</div>
<script>
function mf2UpdateCompoundingPlot() {
const rateSlider = document.getElementById('mf2-rate');
const yearSlider = document.getElementById('mf2-years');
const r = Number(rateSlider.value) / 100;
const T = Number(yearSlider.value);
document.getElementById('mf2-rate-label').innerText = (100*r).toFixed(2) + '%';
document.getElementById('mf2-years-label').innerText = T + ' years';
const t = Array.from({length: 301}, (_, i) => T * i / 300);
const simple = t.map(x => 1 + r*x);
const annual = t.map(x => Math.pow(1 + r, x));
const monthly = t.map(x => Math.pow(1 + r/12, 12*x));
const continuous = t.map(x => Math.exp(r*x));
const traces = [
{x: t, y: simple, mode: 'lines', name: 'simple: 1 + rt'},
{x: t, y: annual, mode: 'lines', name: 'annual: (1+r)^t'},
{x: t, y: monthly, mode: 'lines', name: 'monthly: (1+r/12)^(12t)'},
{x: t, y: continuous, mode: 'lines', name: 'continuous: exp(rt)'}
];
Plotly.react('mf2-compounding-plot', traces, {
title: 'Growth of $1 Under Different Compounding Rules',
xaxis: {title: 'Years'},
yaxis: {title: 'Future value'},
margin: {l: 60, r: 25, t: 55, b: 55},
legend: {orientation: 'h'}
}, {responsive: true});
}
document.addEventListener('DOMContentLoaded', function() {
if (typeof Plotly !== 'undefined' && document.getElementById('mf2-compounding-plot')) {
mf2UpdateCompoundingPlot();
document.getElementById('mf2-rate').addEventListener('input', mf2UpdateCompoundingPlot);
document.getElementById('mf2-years').addEventListener('input', mf2UpdateCompoundingPlot);
}
});
</script>
```
## 2.7 Rate Conversions
Different financial markets quote rates in different forms. A mathematically clean approach is to convert all rates to an accumulation factor.
Suppose the horizon is $T$ years.
| Quotation | Accumulation factor $B_T$ |
|---|---:|
| Simple rate $r_s$ | $1+r_sT$ |
| Annual effective rate $r$ | $(1+r)^T$ |
| Nominal rate $r^{(m)}$, compounded $m$ times per year | $\left(1+\frac{r^{(m)}}{m}\right)^{mT}$ |
| Continuous rate $r_c$ | $e^{r_cT}$ |
Two quoted rates are equivalent over the same horizon if they generate the same $B_T$.
For example, an annual effective rate $r$ and a continuously compounded rate $r_c$ are equivalent over one year if
$$
1+r=e^{r_c}.
$$
Thus
$$
r_c=\log(1+r),
\qquad
r=e^{r_c}-1.
$$
::: {.example}
**Example 2.3 (Effective and continuous rates).** If the annual effective rate is $8\%$, then the equivalent continuously compounded rate is
$$
r_c=\log(1.08)\approx 0.07696.
$$
Conversely, if the continuously compounded rate is $7\%$, then the annual effective rate is
$$
r=e^{0.07}-1\approx 0.07251.
$$
:::
## 2.8 Time-Dependent Deterministic Interest Rates
A constant interest rate is mathematically convenient but often unrealistic. Let $r(t)$ be a deterministic continuously compounded short rate. The bank account evolves according to the ordinary differential equation
$$
\frac{dB_t}{dt}=r(t)B_t,
\qquad
B_0=1.
$$
Solving gives
$$
B_T=\exp\left(\int_0^T r(u)\,du\right).
$$
Therefore the discount factor is
$$
D(0,T)=\exp\left(-\int_0^T r(u)\,du\right).
$$
More generally, the discount factor from time $s$ to time $T$ is
$$
D(s,T)=\exp\left(-\int_s^T r(u)\,du\right),
\qquad 0\le s\le T.
$$
::: {.definition}
**Definition 2.3 (Deterministic short rate).** A deterministic short-rate function $r(t)$ gives the instantaneous continuously compounded risk-free rate at time $t$. Its associated discount factor is
$$
D(s,T)=\exp\left(-\int_s^T r(u)\,du\right).
$$
:::
The multiplicative property of discount factors is
$$
D(s,T)=D(s,u)D(u,T),
\qquad s\le u\le T.
$$
This follows immediately from additivity of the integral.
## 2.9 Present Value of a Cash-Flow Stream
A deterministic cash-flow stream consists of payments $C_1,\ldots,C_n$ at dates $t_1,\ldots,t_n$. Its present value is
$$
PV_0=\sum_{i=1}^n D(0,t_i)C_i.
$$
This formula shows that deterministic pricing is a **linear operation** on cash flows. If $X=(C_1,\ldots,C_n)$ and $Y=(H_1,\ldots,H_n)$ are cash-flow vectors, then
$$
PV(aX+bY)=aPV(X)+bPV(Y).
$$
::: {.definition}
**Definition 2.4 (Present-value functional).** Fix payment dates $t_1,\ldots,t_n$ and discount factors $D(0,t_i)$. The present-value functional is the linear map
$$
\Pi:\mathbb R^n\to\mathbb R,
\qquad
\Pi(C_1,\ldots,C_n)=\sum_{i=1}^n D(0,t_i)C_i.
$$
:::
This linear-algebra viewpoint is important. The vector $D=(D(0,t_1),\ldots,D(0,t_n))$ is a vector of prices of one-dollar cash flows. Then
$$
PV_0 = D^\top C.
$$
A deterministic bond is therefore just a vector of promised cash flows, and its price is the dot product of the cash-flow vector with the discount-factor vector.
## 2.10 Zero-Coupon Bonds and Spot Rates
A **zero-coupon bond** with maturity $T$ pays exactly one dollar at time $T$ and nothing before then. Its time-$0$ price is denoted by $P(0,T)$. In a default-free deterministic model,
$$
P(0,T)=D(0,T).
$$
Thus zero-coupon bond prices are discount factors.
If the continuously compounded spot rate for maturity $T$ is $R(0,T)$, then
$$
P(0,T)=e^{-R(0,T)T}.
$$
Solving for $R(0,T)$ gives
$$
R(0,T)=-\frac{1}{T}\log P(0,T).
$$
If rates are annually compounded instead, then
$$
P(0,T)=\frac{1}{(1+R_{\mathrm{ann}}(0,T))^T},
$$
so
$$
R_{\mathrm{ann}}(0,T)=P(0,T)^{-1/T}-1.
$$
::: {.definition}
**Definition 2.5 (Spot rate).** The spot rate for maturity $T$ is the constant rate that prices a zero-coupon bond maturing at $T$. Under continuous compounding,
$$
R(0,T)=-\frac{1}{T}\log P(0,T).
$$
:::
## 2.11 No-Arbitrage Restrictions on Discount Factors
Discount factors cannot be arbitrary. In the simplest deterministic riskless setting, several no-arbitrage restrictions must hold.
First,
$$
P(0,T)>0.
$$
If $P(0,T)<0$, an investor could receive money today and receive one dollar at time $T$, which is an arbitrage. If $P(0,T)=0$, an investor could acquire a positive future payoff for free.
Second, if interest rates are nonnegative, then
$$
P(0,T)\le 1.
$$
This says one dollar tomorrow is worth no more than one dollar today when the riskless rate is nonnegative.
Third, if $0<S<T$ and deterministic rates are nonnegative, then
$$
P(0,T)\le P(0,S).
$$
Longer-maturity one-dollar payments are worth weakly less than shorter-maturity one-dollar payments.
::: {.remark}
In modern markets, interest rates can be negative. Then some monotonicity statements need adjustment. The essential no-arbitrage requirement is positivity and consistency across maturities, not necessarily that every discount factor is below one.
:::
## 2.12 Forward Rates
A forward rate is a rate agreed today for borrowing or lending over a future interval. Let $0<S<T$. Suppose $P(0,S)$ and $P(0,T)$ are zero-coupon bond prices. The no-arbitrage forward discount factor from $S$ to $T$ is
$$
D(0;S,T)=\frac{P(0,T)}{P(0,S)}.
$$
Why? A strategy that buys a $T$-maturity zero-coupon bond and finances it using an $S$-maturity zero-coupon bond locks in a future exchange of cash flows. The ratio $P(0,T)/P(0,S)$ is the time-$S$ price, agreed at time $0$, of one dollar at time $T$.
The continuously compounded forward rate $F(0;S,T)$ over $[S,T]$ is defined by
$$
\frac{P(0,T)}{P(0,S)}=e^{-F(0;S,T)(T-S)}.
$$
Therefore
$$
F(0;S,T)=\frac{\log P(0,S)-\log P(0,T)}{T-S}.
$$
::: {.theorem}
**Theorem 2.2 (No-arbitrage forward rate).** Given positive zero-coupon prices $P(0,S)$ and $P(0,T)$ with $0<S<T$, the continuously compounded forward rate over $[S,T]$ is
$$
F(0;S,T)=\frac{\log P(0,S)-\log P(0,T)}{T-S}.
$$
:::
::: {.proof}
The forward discount factor from $S$ to $T$ must satisfy
$$
P(0,T)=P(0,S)e^{-F(0;S,T)(T-S)}.
$$
Dividing by $P(0,S)$ and taking logarithms gives
$$
\log P(0,T)-\log P(0,S)=-F(0;S,T)(T-S).
$$
Solving yields the formula.
:::
## 2.13 Coupon Bonds
A coupon bond pays a sequence of coupons and a final principal payment. Suppose a bond has face value $F$, coupon rate $c$, annual coupon payments, and maturity $n$ years. If coupons are paid once per year, the annual coupon is $cF$. The cash flows are
$$
C_i=cF, \quad i=1,\ldots,n-1,
$$
and
$$
C_n=F+cF.
$$
Using discount factors $D(0,i)$, the bond price is
$$
B_0=\sum_{i=1}^{n-1}D(0,i)cF+D(0,n)(F+cF).
$$
Equivalently,
$$
B_0=\sum_{i=1}^n D(0,i)C_i.
$$
If the yield to maturity $y$ is used as a single annual effective discount rate, then
$$
B_0=\sum_{i=1}^n \frac{C_i}{(1+y)^i}.
$$
Yield to maturity is therefore the internal rate of return that makes the discounted cash flows equal to the observed bond price.
::: {.warning}
Yield to maturity summarizes a bond using one number, but it is not the same as the full term structure. Pricing with the full zero-coupon curve is mathematically cleaner because each cash flow is discounted at the rate appropriate for its maturity.
:::
## 2.14 Annuities and Perpetuities
An **annuity** pays a fixed amount $C$ at regular dates. If the discount rate per period is $r>0$ and there are $n$ payments, then
$$
PV=C\sum_{k=1}^n \frac{1}{(1+r)^k}.
$$
This is a finite geometric series:
$$
PV=C\frac{1-(1+r)^{-n}}{r}.
$$
A **perpetuity** pays $C$ forever. If $r>0$, then
$$
PV=C\sum_{k=1}^{\infty}\frac{1}{(1+r)^k}=\frac{C}{r}.
$$
A growing perpetuity with payment $C$ next period and growth rate $g$ has present value
$$
PV=\sum_{k=1}^{\infty}\frac{C(1+g)^{k-1}}{(1+r)^k}.
$$
If $r>g$, this equals
$$
PV=\frac{C}{r-g}.
$$
The condition $r>g$ is not a technical detail. It is exactly the condition that the infinite geometric series converges.
## 2.15 Interactive: Present Value Surface
The next Plotly.js visualization shows how the present value of a fixed future payment changes with the interest rate and time horizon.
```{=html}
<div class="interactive-card">
<h3>Interactive 2.2: Present Value Surface</h3>
<p>The surface plots <code>PV = FV exp(-rT)</code> for a future payment of <code>FV = 100</code>.</p>
<div id="mf2-pv-surface" class="plotly-demo"></div>
</div>
<script>
function mf2PresentValueSurface() {
const el = document.getElementById('mf2-pv-surface');
if (!el || typeof Plotly === 'undefined') return;
const rates = Array.from({length: 41}, (_, i) => i * 0.0025);
const times = Array.from({length: 41}, (_, i) => i * 0.25);
const FV = 100;
const z = times.map(T => rates.map(r => FV * Math.exp(-r*T)));
Plotly.newPlot(el, [{
x: rates.map(r => 100*r),
y: times,
z: z,
type: 'surface',
colorscale: 'Viridis',
showscale: true
}], {
title: 'Present Value of a $100 Future Payment',
scene: {
xaxis: {title: 'Rate (%)'},
yaxis: {title: 'Time'},
zaxis: {title: 'Present value'}
},
margin: {l: 0, r: 0, t: 55, b: 0}
}, {responsive: true});
}
document.addEventListener('DOMContentLoaded', mf2PresentValueSurface);
</script>
```
## 2.16 Duration and Convexity
A bond price changes when interest rates change. Duration and convexity quantify this sensitivity.
Consider deterministic cash flows $C_1,\ldots,C_n$ at times $t_1,\ldots,t_n$. Under a flat continuously compounded yield $y$, the bond price is
$$
P(y)=\sum_{i=1}^n C_i e^{-yt_i}.
$$
Differentiating,
$$
P'(y)=-\sum_{i=1}^n t_i C_i e^{-yt_i}.
$$
The **Macaulay duration** is
$$
D_M(y)=\frac{\sum_{i=1}^n t_i C_i e^{-yt_i}}{P(y)}.
$$
Thus
$$
\frac{P'(y)}{P(y)}=-D_M(y).
$$
For a small yield change $\Delta y$,
$$
\frac{\Delta P}{P}\approx -D_M\Delta y.
$$
The **convexity** is
$$
C(y)=\frac{P''(y)}{P(y)}
=
\frac{\sum_{i=1}^n t_i^2 C_i e^{-yt_i}}{P(y)}.
$$
A second-order approximation gives
$$
\frac{\Delta P}{P}
\approx
-D_M\Delta y+\frac12 C(y)(\Delta y)^2.
$$
::: {.remark}
Duration is a weighted average time of cash flows. The weights are present-value weights:
$$
w_i=\frac{C_i e^{-yt_i}}{P(y)},
\qquad
\sum_{i=1}^n w_i=1.
$$
Therefore
$$
D_M=\sum_{i=1}^n w_it_i.
$$
:::
## 2.17 Interactive: Bond Price, Duration, and Convexity
```{=html}
<div class="interactive-card">
<h3>Interactive 2.3: Coupon Bond Price-Yield Curve</h3>
<p>This plot shows the nonlinear relationship between yield and bond price. The tangent line at the selected yield is the duration approximation.</p>
<label for="mf2-coupon"><strong>Coupon rate:</strong> <span id="mf2-coupon-label">5.0%</span></label>
<input id="mf2-coupon" type="range" min="0" max="12" step="0.25" value="5" style="width:100%;">
<label for="mf2-maturity"><strong>Maturity:</strong> <span id="mf2-maturity-label">10 years</span></label>
<input id="mf2-maturity" type="range" min="1" max="30" step="1" value="10" style="width:100%;">
<label for="mf2-yield"><strong>Selected yield:</strong> <span id="mf2-yield-label">5.0%</span></label>
<input id="mf2-yield" type="range" min="0" max="15" step="0.25" value="5" style="width:100%;">
<div id="mf2-bond-plot" class="plotly-demo"></div>
<p id="mf2-bond-stats"></p>
</div>
<script>
function mf2BondPrice(y, couponRate, maturity) {
const F = 100;
let price = 0;
for (let i = 1; i <= maturity; i++) {
const cash = (i === maturity) ? F * (1 + couponRate) : F * couponRate;
price += cash * Math.exp(-y * i);
}
return price;
}
function mf2BondDuration(y, couponRate, maturity) {
const F = 100;
const P = mf2BondPrice(y, couponRate, maturity);
let weighted = 0;
let convexityNumerator = 0;
for (let i = 1; i <= maturity; i++) {
const cash = (i === maturity) ? F * (1 + couponRate) : F * couponRate;
const pv = cash * Math.exp(-y * i);
weighted += i * pv;
convexityNumerator += i * i * pv;
}
return {duration: weighted / P, convexity: convexityNumerator / P};
}
function mf2UpdateBondPlot() {
const couponRate = Number(document.getElementById('mf2-coupon').value) / 100;
const maturity = Number(document.getElementById('mf2-maturity').value);
const y0 = Number(document.getElementById('mf2-yield').value) / 100;
document.getElementById('mf2-coupon-label').innerText = (100*couponRate).toFixed(2) + '%';
document.getElementById('mf2-maturity-label').innerText = maturity + ' years';
document.getElementById('mf2-yield-label').innerText = (100*y0).toFixed(2) + '%';
const yields = Array.from({length: 151}, (_, i) => i * 0.001);
const prices = yields.map(y => mf2BondPrice(y, couponRate, maturity));
const P0 = mf2BondPrice(y0, couponRate, maturity);
const sens = mf2BondDuration(y0, couponRate, maturity);
const tangent = yields.map(y => P0 * (1 - sens.duration * (y - y0)));
Plotly.react('mf2-bond-plot', [
{x: yields.map(y => 100*y), y: prices, mode: 'lines', name: 'bond price'},
{x: yields.map(y => 100*y), y: tangent, mode: 'lines', name: 'duration tangent'},
{x: [100*y0], y: [P0], mode: 'markers', name: 'selected yield', marker: {size: 10}}
], {
title: 'Bond Price as a Function of Yield',
xaxis: {title: 'Continuously compounded yield (%)'},
yaxis: {title: 'Price per $100 face value'},
margin: {l: 65, r: 25, t: 55, b: 55},
legend: {orientation: 'h'}
}, {responsive: true});
document.getElementById('mf2-bond-stats').innerText =
'Price = ' + P0.toFixed(2) +
', Macaulay duration = ' + sens.duration.toFixed(2) +
', convexity = ' + sens.convexity.toFixed(2) + '.';
}
document.addEventListener('DOMContentLoaded', function() {
if (typeof Plotly !== 'undefined' && document.getElementById('mf2-bond-plot')) {
mf2UpdateBondPlot();
['mf2-coupon', 'mf2-maturity', 'mf2-yield'].forEach(id => {
document.getElementById(id).addEventListener('input', mf2UpdateBondPlot);
});
}
});
</script>
```
## 2.18 Discounting as a Linear Algebra Problem
Let the payment dates be fixed. A deterministic cash-flow stream is a vector
$$
C=\begin{pmatrix}C_1\\ C_2\\ \vdots\\ C_n\end{pmatrix}\in\mathbb R^n.
$$
The discount-factor vector is
$$
d=\begin{pmatrix}D(0,t_1)\\D(0,t_2)\\ \vdots\\ D(0,t_n)\end{pmatrix}\in\mathbb R^n.
$$
The present value is the inner product
$$
PV=d^\top C.
$$
This formula looks elementary, but it is a model of a pricing operator. It has three important properties.
1. **Additivity:** the value of a sum of cash flows is the sum of values.
2. **Homogeneity:** scaling all cash flows scales the price by the same amount.
3. **Positivity:** if all cash flows are nonnegative and at least one is positive, then the price is positive.
A pricing map satisfying these properties is the deterministic analogue of the state-price and risk-neutral valuation maps in later chapters.
::: {.theorem}
**Theorem 2.3 (Positive linear pricing of deterministic cash flows).** Suppose $D(0,t_i)>0$ for all $i$. The map
$$
\Pi(C)=\sum_{i=1}^n D(0,t_i)C_i
$$
is linear and strictly positive: if $C_i\ge 0$ for all $i$ and $C_j>0$ for at least one $j$, then $\Pi(C)>0$.
:::
::: {.proof}
Linearity follows from distributivity of scalar multiplication and addition:
$$
\Pi(aC+bH)
=\sum_i D(0,t_i)(aC_i+bH_i)
=a\Pi(C)+b\Pi(H).
$$
If $C_i\ge 0$ and at least one $C_j>0$, then each term $D(0,t_i)C_i$ is nonnegative and the $j$th term is positive because $D(0,t_j)>0$. Hence the sum is positive.
:::
## 2.19 Python Example: Rate Conversions
The following Python code converts between common rate conventions. The goal is not only to compute numbers but also to make the compounding convention explicit.
```{python}
import numpy as np
r_eff = 0.08
r_cont = np.log(1 + r_eff)
print("continuous rate equivalent to 8% effective:", r_cont)
r_cont = 0.07
r_eff = np.exp(r_cont) - 1
print("effective annual rate equivalent to 7% continuous:", r_eff)
r_nominal = 0.06
m = 12
r_eff_monthly = (1 + r_nominal / m)**m - 1
print("effective annual rate for 6% nominal monthly:", r_eff_monthly)
```
## 2.20 Python Example: Present Value of Cash Flows
```{python}
import numpy as np
import pandas as pd
cash_flows = np.array([50, 50, 50, 1050], dtype=float)
times = np.array([1, 2, 3, 4], dtype=float)
y = 0.045
discount_factors = np.exp(-y * times)
present_values = discount_factors * cash_flows
price = present_values.sum()
bond_table = pd.DataFrame({
"time": times,
"cash_flow": cash_flows,
"discount_factor": discount_factors,
"present_value": present_values
})
print(bond_table)
print("Bond price:", price)
```
This example uses continuous discounting with a flat yield $y=4.5\%$. Each row is a dated cash flow. The bond price is the sum of the row-level present values.
## 2.21 Python Example: Zero Rates and Forward Rates
Suppose we observe zero-coupon bond prices for several maturities. We can compute continuously compounded spot rates and forward rates.
```{python}
import numpy as np
import pandas as pd
maturities = np.array([0.5, 1.0, 2.0, 3.0, 5.0])
zero_prices = np.array([0.9802, 0.9589, 0.9120, 0.8607, 0.7548])
spot_rates = -np.log(zero_prices) / maturities
forward_rates = []
intervals = []
for i in range(len(maturities) - 1):
S = maturities[i]
T = maturities[i + 1]
P_S = zero_prices[i]
P_T = zero_prices[i + 1]
F_ST = (np.log(P_S) - np.log(P_T)) / (T - S)
forward_rates.append(F_ST)
intervals.append(f"{S:g} to {T:g}")
spot_table = pd.DataFrame({
"maturity": maturities,
"zero_price": zero_prices,
"spot_rate_cont": spot_rates
})
forward_table = pd.DataFrame({
"interval": intervals,
"forward_rate_cont": forward_rates
})
print(spot_table)
print(forward_table)
```
## 2.22 Python Example: Duration and Convexity
```{python}
import numpy as np
def bond_price_duration_convexity(cash_flows, times, y):
cash_flows = np.asarray(cash_flows, dtype=float)
times = np.asarray(times, dtype=float)
pv = cash_flows * np.exp(-y * times)
price = pv.sum()
weights = pv / price
duration = np.sum(weights * times)
convexity = np.sum(weights * times**2)
return price, duration, convexity
cash_flows = [40, 40, 40, 1040]
times = [1, 2, 3, 4]
y = 0.05
price, duration, convexity = bond_price_duration_convexity(cash_flows, times, y)
print("price:", price)
print("Macaulay duration:", duration)
print("convexity:", convexity)
# First- and second-order approximation for a 1% increase in yield.
dy = 0.01
price_approx_1 = price * (1 - duration * dy)
price_approx_2 = price * (1 - duration * dy + 0.5 * convexity * dy**2)
price_exact = bond_price_duration_convexity(cash_flows, times, y + dy)[0]
print("first-order approximation:", price_approx_1)
print("second-order approximation:", price_approx_2)
print("exact new price:", price_exact)
```
## 2.23 AI Component: Algebra Audit for Discounting
AI tools can be useful for checking algebra, but they should not replace definitions. In this chapter, the most common errors are unit errors, compounding-convention errors, and confusing a rate with a discount factor.
::: {.example}
**AI prompt for checking a calculation.**
> I am valuing deterministic cash flows $C_i$ at dates $t_i$ using continuous compounding. My formula is $PV=\sum_i C_i e^{-rt_i}$. Check whether my units and compounding convention are consistent. Do not solve numerically until you verify the formula.
:::
A good AI-assisted workflow is:
1. State the cash-flow dates and units.
2. State the compounding convention.
3. Write the discount factor.
4. Apply the discount factor to each cash flow.
5. Check limiting cases: $r=0$, $T=0$, and positive versus negative rates.
::: {.warning}
AI systems often mix compounding conventions. For example, they may use $e^{-rT}$ after saying the rate is annually compounded. Always check whether the discount factor matches the stated rate convention.
:::
## 2.24 AI Component: Build a Formula Checker
A simple AI-supported programming task is to build a function that receives a list of cash flows and returns a present value. Before trusting the function, ask the AI assistant to generate tests.
Useful tests include:
- If all cash flows are zero, present value should be zero.
- If $r=0$, present value should be the sum of cash flows.
- If all cash flows are nonnegative and the discount factors are positive, present value should be nonnegative.
- A later positive cash flow should have lower present value than an equal earlier cash flow when rates are positive.
- Under continuous compounding, $D(0,S)D(S,T)=D(0,T)$ for constant rates.
```{python}
def present_value_continuous(cash_flows, times, r):
cash_flows = np.asarray(cash_flows, dtype=float)
times = np.asarray(times, dtype=float)
if cash_flows.shape != times.shape:
raise ValueError("cash_flows and times must have the same shape")
if np.any(times < 0):
raise ValueError("payment times must be nonnegative")
return np.sum(cash_flows * np.exp(-r * times))
# Basic tests
assert np.isclose(present_value_continuous([0, 0], [1, 2], 0.05), 0.0)
assert np.isclose(present_value_continuous([10, 20], [1, 2], 0.0), 30.0)
assert present_value_continuous([100], [2], 0.05) < present_value_continuous([100], [1], 0.05)
print("All basic tests passed.")
```
## 2.25 Common Mistakes
### Mistake 1: Forgetting the payment date
A dollar amount alone is not a complete financial object. The statement “the payoff is $100$” is incomplete unless we know when the $100$ is paid.
### Mistake 2: Mixing rate conventions
The formula
$$
PV=\frac{FV}{(1+r)^T}
$$
uses annual effective compounding, while
$$
PV=FVe^{-rT}
$$
uses continuous compounding. The same symbol $r$ should not be used for both unless a conversion has been made.
### Mistake 3: Treating yield as the term structure
A single yield to maturity is a summary number. A full zero-coupon curve gives one discount factor for each maturity.
### Mistake 4: Ignoring units
A rate quoted annually must be matched with time measured in years. If a rate is monthly, the time index must reflect months or be converted.
### Mistake 5: Thinking discounting removes risk
Discounting deterministic cash flows is not the same as pricing risky cash flows. For risky payoffs, we need risk-neutral probabilities, stochastic discount factors, or equilibrium assumptions.
## 2.26 Chapter Summary
This chapter developed the mathematical foundation for valuing deterministic cash flows.
- An accumulation factor $B_T$ converts dollars today into dollars at time $T$.
- A discount factor $D(0,T)=1/B_T$ converts dollars at time $T$ into dollars today.
- Simple, periodic, and continuous compounding are different ways to specify $B_T$.
- Continuous compounding gives $B_T=e^{rT}$ and $D(0,T)=e^{-rT}$.
- A deterministic cash-flow stream has present value
$$
PV_0=\sum_i D(0,t_i)C_i.
$$
- Zero-coupon bond prices are discount factors.
- Spot rates and forward rates are derived from zero-coupon prices.
- Duration and convexity measure sensitivity of bond prices to yield changes.
- Discounting is a positive linear functional on deterministic cash-flow vectors.
The next chapter moves from deterministic cash flows to uncertain payoffs in a one-period market. The discount factor remains essential, but uncertainty requires a new ingredient: state prices and risk-neutral probabilities.
## Exercises
### Conceptual Exercises
1. Explain why $100$ dollars today and $100$ dollars in two years should not be represented by the same financial object.
2. What is the difference between an accumulation factor and a discount factor?
3. Why is continuous compounding mathematically convenient in stochastic calculus?
4. Explain the difference between a zero-coupon bond price and a spot rate.
5. Why is yield to maturity not the same as the full term structure of interest rates?
### Computational Exercises
6. Compute the future value of $1000$ dollars after $5$ years at an annual effective rate of $4\%$.
7. Compute the future value of $1000$ dollars after $5$ years at a nominal annual rate of $4\%$ compounded monthly.
8. Compute the future value of $1000$ dollars after $5$ years at a continuously compounded rate of $4\%$.
9. A contract pays $500$ in one year, $500$ in two years, and $1500$ in three years. Compute the present value using a continuously compounded rate of $5\%$.
10. A zero-coupon bond maturing in three years has price $0.86$. Compute the continuously compounded spot rate.
### Mathematical Exercises
11. Prove that if $r>0$, then
$$
\sum_{k=1}^{\infty}\frac{C}{(1+r)^k}=\frac{C}{r}.
$$
12. Derive the present value formula for an $n$-period annuity:
$$
PV=C\frac{1-(1+r)^{-n}}{r}.
$$
13. Suppose $P(0,T)=e^{-aT-bT^2}$ for constants $a,b$. Compute the continuously compounded spot rate $R(0,T)$.
14. For the same zero-coupon curve $P(0,T)=e^{-aT-bT^2}$, compute the forward rate $F(0;S,T)$.
15. Let $P(y)=\sum_{i=1}^n C_i e^{-yt_i}$. Prove that
$$
\frac{P'(y)}{P(y)}=-D_M(y),
$$
where $D_M(y)$ is Macaulay duration.
16. Prove that the present-value functional $\Pi(C)=d^\top C$ is linear.
17. Suppose all discount factors are positive. Prove that a deterministic cash flow with nonnegative payments and at least one positive payment must have positive present value.
### Python Exercises
18. Write a Python function that converts an annual effective rate to a continuously compounded rate.
19. Write a Python function that computes discount factors from a list of maturities and a flat continuously compounded rate.
20. Given zero-coupon prices, compute spot rates and adjacent forward rates.
21. Write a Python function that computes the price, duration, and convexity of a coupon bond.
22. Numerically compare the exact bond price change after a yield shock with the first-order duration approximation and the second-order duration-convexity approximation.
### AI-Assisted Exercises
23. Ask an AI assistant to explain the difference between simple and compound interest. Then identify whether its explanation correctly distinguishes linear growth from exponential growth.
24. Ask an AI assistant to generate a present-value formula for cash flows under continuous compounding. Check whether the formula uses the correct sign in the exponential.
25. Ask an AI assistant to produce tests for a present-value function. Add at least three additional tests that check edge cases.
26. Ask an AI assistant to explain yield to maturity. Revise the answer so that it clearly states the limitation of using one yield instead of the full zero-coupon curve.