Defining Functions

It is useful when programming in Python to reuse computations. In mathematics, we call this a function. Given a certain number of inputs, a function gives an output.

Introduction

For example, imagine that we want to define the following function: \[ f(x) = x^{3} + 3 x - 5 \]

def f(x):
    return x**3 + 3 * x - 5

We can now call this function for different values of \(x\). For example, if we want to compute \(f(3)\), we can type:

f(3)
31

The keyword def allows us to define a function called f that takes one argument, in this case x. Note that this statement is followed by a colon :. It is also important to know that in Python indentation matters. All code that is indented after the definition is part of the function. For example, we could have also written the previous function as:

def g(x):
    y = x**3 + 3 * x - 5
    return y

The value returned by the function is defined by the keyword return.

Computing the Present Value of an Annuity

Functions can have more than one argument. For example, consider an annuity that pays a fixed cash flow \(C\) once per period starting in period 1 until year \(N\). If the discount rate is \(r\) expressed per period compounded once per period, then the present value of this annuity is given by: \[ \mathit{PV} = \frac{C}{r} \left( 1 - \frac{1}{(1 + r)^{N}} \right) \]

The function \(\mathit{PV}\) has three arguments:

  • the periodic cash flow \(C\)
  • the discount rate \(r\)
  • the number of periods \(N\)

The following function implements this computation.

def pv_annuity(C, r, N):
    pv = (C / r) * (1 - 1 / (1 + r)**N)
    return round(pv, 2)

The first argument of the function is the periodic cash flow, the second is the discount rate and the third argument is the number of periods. Note that we are rounding the result to two decimals. The function round allows us to round the output of the function to express the result with a fixed number of decimals.

We can now use our function to compute the present value of an annuity that pays $100 every year for 10 years if the discount rate is 8%.

pv_annuity(100, 0.08, 10)
671.01

Valuing a Coupon Bond

We can now adapt our previous formula to value a coupon bond. In the United States, a coupon bond pays a certain amount of interest every six months until the bond expires, at which moment the bond also pays its face or principal value. The semi-annual coupon is determined by the annual coupon rate which is a percentage of the face value of the bond.

For example, consider a 5-year bond that pays a 5% per year coupon rate semi-annually over a principal of $1,000. The bond then pays a coupon of 2.5% every six months, or $25. The cash flows of the bond can be computed as follows:

Year 0.5 1.0 1.5 2.0 2.5 3.0 3.5 4.0 4.5 5.0
Payments 25 25 25 25 25 25 25 25 25 1,025

The discount rate or yield-to-maturity (YTM) of the bond \(y\) is defined as the rate per year compounded semi-annually that prices the bond correctly. This means that the bond can be seen as an annuity that pays $25 every six months for 10 periods plus an additional cash flow of $1,000 at the end.

Therefore, we can value this bond as: \[ B = \frac{F \times c / 2}{y / 2} \left( 1 - \frac{1}{(1 + y / 2)^{2 T}} \right) + \frac{F}{(1 + y/2)^{2 T}}, \] where \(c\) is the annual coupon rate, \(y\) is the annual YTM, \(F\) is the face value, and \(T\) is the maturity of the bond in years.

def pv_bond(c, y, F, T):
    pv = (F * (c/2) / (y/2)) * (1 - 1 / (1 + (y/2))**(2*T)) + F / (1 + y/2)**(2*T)
    return round(pv, 2)

This is the same bond from the example above — a 5% coupon, $1,000 face value, 5-year bond. Say the YTM is 6% per year with semi-annual compounding. Then:

pv_bond(0.05, 0.06, 1000, 5)
957.35

Since the coupon rate (5%) is below the YTM (6%), we expect the bond to trade at a discount — that is, below its $1,000 face value. The result should confirm this.

Note that we can also call the function by specifying its arguments explicitly by name, which makes the code easier to read:

pv_bond(c=0.05, y=0.06, F=1000, T=5)
957.35

Practice Problems

Problem 1 Write a function that computes \(x^{4} - 2x^{3} + 3x^{2} + 6x - 8\). Evaluate the function at \(x = -2\).

Solution

You can call the function anyway you want. If we call the function \(h(x)\) we have that:

def h(x):
    y = x**4 - 2*x**3 + 3*x**2 + 6*x - 8
    return y

h(-2)
24

Problem 2 Compute the present value of an annuity that pays $5,000 for 20 years if the discount rate is 6% per year.

Solution

We can use the function pv_annuity defined earlier, where \(C = 5000\), \(r = 6\%\) and \(N = 20\).

pv_annuity(5000, 0.06, 20)
57349.61

Problem 3 Compute the price of a 30-year bond paying semi-annual coupons if the yield-to-maturity is 3.88% per year with semi-annual compounding. The coupon rate is 3.63% per year over a principal of $100.

Solution

We can use the same function pv_bond defined earlier where \(c = 3.63\%\), \(y = 3.88\%\), \(F = 100\) and \(T = 30\).

pv_bond(0.0363, 0.0388, 100, 30)
95.59