Tutorials › Exam FM - Financial Mathematics › Implementing a Bootstrap with Pseudocode

Exam FM · Bootstrapping the Curve · Tutorial 749 of 998

Implementing a Bootstrap with Pseudocode

Learn to translate sequential discount-factor bootstrapping into pseudocode, including when an instrument equation is usable and how to validate each stored factor.

Advanced 12 min read

What You'll Learn

  • Define the inputs and assumptions for a sequential discount-factor bootstrap
  • Sort instruments by maturity and aggregate net cash flows by payment date
  • Calculate each terminal factor from the instrument price and known earlier factors
  • Distinguish missing factors at nonzero cash flows from dates with zero net cash flow
  • Flag unusable equations and check solved factors by repricing the input instrument

Why Write the Bootstrap as an Algorithm?

A bootstrap is a sequence of linked calculations. Each instrument supplies an equation for its price; once earlier discount factors are known, that equation may determine the factor at the instrument’s maturity. Writing the process as an algorithm makes the order of operations explicit and helps prevent a spreadsheet or manual calculation from silently using an unavailable factor.

The key decision is not merely whether an earlier payment date appears in an instrument’s schedule. The algorithm needs a stored factor for an earlier date only when the instrument has a nonzero net cash flow on that date. A zero cash flow contributes nothing to price, even if no factor has been stored for its date.

Definition: Let \(D(t)\) denote the discount factor from the valuation date to time \(t\), with \(D(0)=1\). For an instrument with price \(P\) and net cash flows \(C(t)\) at payment times \(t\), its pricing equation is \(P=\sum_t C(t)D(t)\). In a sequential bootstrap, an instrument maturing at \(T\) is used to solve for \(D(T)\) when its terminal net cash flow is nonzero and all earlier nonzero cash flows in its equation have known discount factors.

The model assumes that each quoted price and cash-flow schedule refers to the same valuation date, that the cash flows and their times are known, and that the price is represented by discounting those cash flows using one factor \(D(t)\) for each payment time. Cash flows occurring at the same time must be netted before the equation is tested. The procedure below does not decide whether quoted market inputs are reliable; it identifies whether the equations can be solved sequentially and checks the resulting arithmetic.

From the Pricing Equation to the Bootstrap Step

Suppose an instrument matures at \(T\), and its terminal net cash flow is \(C(T)\). Separate the terminal payment from all earlier payments:

$$ P=\sum_{t<T}C(t)D(t)+C(T)D(T). $$

If \(C(T)\ne 0\), and every earlier date with \(C(t)\ne 0\) has a stored factor, the earlier terms are known numbers. Subtract their total from the price and divide by the terminal cash flow:

$$ D(T)=\frac{P-\sum_{t<T}C(t)D(t)}{C(T)}. $$

This rearrangement explains both the calculation and the usability checks. If \(C(T)=0\), division is impossible and the equation contains no \(D(T)\) term, so it cannot determine the terminal factor. If an earlier nonzero cash flow has no stored factor, its present value is unknown, so the right-hand side cannot yet be calculated. By contrast, when \(C(t)=0\), the term \(C(t)D(t)\) equals zero; there is no need to look up \(D(t)\).

Theorem: An instrument with maturity \(T\) can directly supply a sequential bootstrap value for \(D(T)\) if (1) its terminal net cash flow is nonzero, (2) every earlier date with a nonzero net cash flow has a known discount factor, and (3) the resulting value is acceptable under the model’s discount-factor assumptions. A positive discount-factor model requires \(D(T)>0\). A factor above 1 is not rejected solely for being above 1.

A Maturity-Sorted Procedure

The algorithm stores factors by payment time. It processes instruments in increasing order of maturity so that a factor can be used only after it has been established. Each instrument should first be represented as a price, a maturity, and a list of payment-time/net-cash-flow pairs. If multiple contractual flows occur at the same time, combine them into one net amount before applying the checks.

1
Prepare the input.
For each instrument, record its price \(P\), maturity \(T\), and net cash flows \(C(t)\). Combine flows at identical dates. Reject or investigate records whose dates are inconsistent with the valuation date or whose cash flows extend beyond the stated maturity.
2
Sort by maturity.
Order the instruments from earliest to latest maturity. Initialize a factor table with \(D(0)=1\). If instruments share a maturity, treat each equation as a candidate for that same terminal factor and compare the implied values rather than treating one as a later maturity.
3
Check the terminal cash flow.
For the current instrument, find its net cash flow \(C(T)\). If \(C(T)=0\), flag the equation as unable to solve for \(D(T)\) and continue without storing a factor from it.
4
Accumulate known earlier values.
Set the known earlier present-value total to zero. For every earlier payment date \(t<T\), ignore the date if \(C(t)=0\). If \(C(t)\ne0\) and \(D(t)\) is stored, add \(C(t)D(t)\) to the total. If \(C(t)\ne0\) and \(D(t)\) is not stored, flag this instrument as not currently solvable; do not substitute zero for the missing factor.
5
Solve and validate.
If all required earlier factors are available, calculate \(D(T)=[P-\text{known earlier total}]/C(T)\). Check the result against the model assumptions. Store an acceptable factor and retain the instrument’s repricing residual as a diagnostic.
6
Report the outcome.
For every instrument, report whether it produced a factor, was blocked by a missing required factor, had zero terminal cash flow, or produced an unacceptable result. Do not quietly omit a failed equation.

In pseudocode, the central loop can be written compactly as follows. The conditional test on the earlier cash flow is essential: it ensures that zero-flow dates do not create false failures.

$$ \begin{aligned} &\text{sort instruments by }T;\quad \text{set factors}[0]\leftarrow 1\\ &\text{for each instrument }(P,T,\{(t,C(t))\}):\\ &\quad \text{if }C(T)=0,\ \text{flag zero terminal flow; continue}\\ &\quad K\leftarrow 0;\quad \text{usable}\leftarrow \text{true}\\ &\quad \text{for each }t<T:\\ &\qquad \text{if }C(t)=0,\ \text{continue}\\ &\qquad \text{if }D(t)\text{ is not stored, usable}\leftarrow \text{false}\\ &\qquad \text{otherwise }K\leftarrow K+C(t)D(t)\\ &\quad \text{if not usable, flag missing required factor; continue}\\ &\quad D(T)\leftarrow [P-K]/C(T);\ \text{validate and store} \end{aligned} $$

An implementation must also avoid storing a factor if validation fails. In particular, under the positive discount-factor model, a calculated \(D(T)\le 0\) signals inconsistent inputs or an unsuitable model and should be investigated. A factor \(D(T)>1\) is not automatically invalid: negative spot rates can produce discount factors above 1.

Worked Example: Solving Two Successive Maturities

A valuation date is time 0. A one-year zero-coupon instrument costs \$90 and pays \$100 at time 1. A second instrument costs \$97 and pays \$10 at time 1 and \$110 at time 2. Use the maturity-sorted procedure to find the available factors and check the second price.

Method. Process the one-year instrument first. Its only cash flow is the terminal payment, so

$$ 90=100D(1),\qquad D(1)=\frac{90}{100}=0.9. $$

The stored factor table now contains \(D(0)=1\) and \(D(1)=0.9\). For the instrument maturing at time 2, the earlier present value is \(10D(1)=10(0.9)=9\). Its terminal cash flow is \$110, which is nonzero, so

$$ \begin{aligned} 97&=10(0.9)+110D(2),\\ D(2)&=\frac{97-9}{110} =\frac{88}{110}=0.8. \end{aligned} $$

Check. Repricing the second instrument gives \(10(0.9)+110(0.8)=9+88=97\), exactly its quoted price. The procedure stores \(D(1)=0.9\) and \(D(2)=0.8\). The common mistake to avoid is using the two-year instrument before establishing \(D(1)\), or subtracting the \$10 coupon without discounting it.

Worked Example: A Zero Cash Flow at an Unstored Date

A one-year instrument costs \$94.50 and pays \$105 at time 1. A separate instrument maturing at time 3 costs \$97.20 and has net cash flows of \$4 at time 1, \$0 at time 2, and \$104 at time 3. No instrument supplies a factor at time 2. Determine whether the time-3 equation is usable and calculate its implied factor.

Method. First establish the one-year factor:

$$ D(1)=\frac{94.50}{105}=0.9. $$

For the time-3 instrument, the time-1 cash flow is nonzero and its factor is stored. Its contribution is \(4(0.9)=3.60\). At time 2 the cash flow is zero, so its contribution is \(0D(2)=0\), regardless of whether \(D(2)\) is stored. The earlier known total is therefore \$3.60, not an unknown amount requiring a time-2 factor. The terminal cash flow is nonzero, so the equation can be solved:

$$ \begin{aligned} 97.20&=4(0.9)+0D(2)+104D(3),\\ D(3)&=\frac{97.20-3.60}{104} =\frac{93.60}{104}=0.9. \end{aligned} $$

Check. The repriced amount is \(3.60+0+104(0.9)=3.60+93.60=97.20\). Thus the time-3 equation is usable even though \(D(2)\) is absent. The common mistake is to flag the instrument merely because its schedule lists an earlier date without a stored factor. The correct test asks whether that date’s net cash flow is nonzero.

When the Algorithm Must Flag an Equation

A robust implementation distinguishes a solvability problem from a numerical result. The following example shows why an equation with a missing required factor must be flagged, while an equation with zero earlier cash flows can still provide a terminal factor.

Worked Example: Missing Required Factor Versus Zero Terminal-Date Dependencies

There is no instrument maturing at time 1. A time-2 instrument costs \$101 and has cash flows of \$8 at time 1 and \$108 at time 2. A time-3 instrument costs \$100 and has net cash flows of \$0 at time 1, \$0 at time 2, and \$125 at time 3. Apply the algorithm in maturity order.

Time-2 instrument. Its terminal cash flow is \$108, but its earlier time-1 cash flow is nonzero and \(D(1)\) has not been stored. The equation is

$$ 101=8D(1)+108D(2). $$

There are two unknown factors in this equation. It cannot determine \(D(2)\) by the sequential procedure, so the algorithm flags it as missing required factor at time 1. It must not treat the absent \(D(1)\) as zero or calculate \(101/108\).

Time-3 instrument. Its terminal cash flow is \$125, and both earlier net cash flows are zero. Therefore the missing factors at times 1 and 2 do not enter its price equation:

$$ 100=0D(1)+0D(2)+125D(3),\qquad D(3)=\frac{100}{125}=0.8. $$

Check. Repricing gives \(0+0+125(0.8)=100\). The algorithm flags the time-2 equation and stores \(D(3)=0.8\) from the time-3 equation. The common mistake is to treat all earlier dates identically; only earlier dates with nonzero net cash flows require stored factors.

Diagnostics and Implementation Safeguards

A successful division is not, by itself, proof that the inputs are sound. A useful implementation records enough information to explain every result: instrument identifier, maturity, terminal cash flow, accumulated earlier value, missing-factor dates if any, calculated factor, and repricing residual. After calculating \(D(T)\), the residual is the observed price less the price reconstructed from the instrument’s cash flows and the stored factors.

$$ \text{residual} = P-\left(\sum_{t<T}C(t)D(t)+C(T)D(T)\right). $$

With exact arithmetic this residual is zero. With floating-point computation it may be a small nonzero number, so compare its absolute value with a stated tolerance rather than requiring exact equality. The chosen tolerance should be consistent with the precision of the input prices and calculations; rounding intermediate factors too early can make later residuals larger.

  • Do not confuse zero with missing. A missing factor is not a numerical value of zero. Conversely, a zero cash flow makes its factor irrelevant to that instrument’s pricing equation.
  • Aggregate before testing. If two flows at the same time offset one another, test their net amount. For example, equal and opposite flows at a date yield a zero net contribution.
  • Check the denominator. A zero terminal net cash flow cannot determine the terminal factor, even if all earlier terms are known.
  • Preserve the maturity order. A factor should be used only after it has been stored from a usable equation. If same-maturity instruments imply different factors beyond the chosen tolerance, report the inconsistency rather than silently overwriting one result.
  • Do not reject a factor merely for exceeding 1. The algorithm should apply the stated model checks, not an assumption that all discount factors must be at most 1.

These safeguards matter in spreadsheet-to-code translation and in review of a manual bootstrap. A clear status such as “usable,” “missing nonzero earlier factor,” or “zero terminal cash flow” is more informative than a blank cell or an unexplained error. The approach is aligned with the SOA Exam FM (Financial Mathematics) syllabus.

Key takeaway: For each maturity, subtract the present value of known earlier nonzero cash flows from the quoted price, then divide by the nonzero terminal cash flow. Require stored factors only at earlier dates with nonzero net cash flows; flag equations that fail the actual algebraic conditions.

Check Your Understanding

For each problem, decide which factors can be calculated and identify any equation that must be flagged.

  1. A zero-coupon instrument maturing at time 2 costs \$84 and pays \$100 at maturity. What factor does it imply? (Answer: \(D(2)=0.84\).)
  2. A time-1 instrument gives \(D(1)=0.96\). Another instrument costs \$90.56 and pays \$6 at time 1, \$0 at time 2, and \$106 at time 3. Does it require \(D(2)\), and what is \(D(3)\)? (Answer: It does not require \(D(2)\); \(D(3)=0.80\).)
  3. An instrument maturing at time 2 costs \$101, pays \$8 at time 1 and \$108 at time 2, and \(D(1)=0.95\). Calculate its implied terminal factor and verify the price. (Answer: \(D(2)=93.4/108\approx0.8648\); \(8(0.95)+108(0.8648148\ldots)=101\).)
  4. A time-3 instrument costs \$99 and pays \$4 at time 1, \$7 at time 2, and \$110 at time 3. \(D(1)=0.9\), but no factor is stored at time 2. Is the equation currently usable? (Answer: No; the nonzero \$7 payment requires \(D(2)\), so flag the instrument as not currently solvable.)
  5. An instrument’s net cash flows before maturity have known present value \$32, its price is \$92, and its terminal net cash flow is zero. Can it determine the maturity factor? (Answer: No; \(92=32+0D(T)\) contains no \(D(T)\) term, so flag zero terminal cash flow.)
Clinical Biostats