Department of Statistics, The Chinese University of Hong Kong
RMSC 2001 Introduction to Risk Management (Term 2, 2023-24)
Solution to Assignment 3
1. Recall that a zero-coupon bond, also called a pure discount bond and sometimes known as a “zero”, pays no principal
or interest until maturity. A “zero” has a par value or face value, which is the payment made to the bondholder at
maturity. The zero sells for less than the par value, which is the reason it is a discount bond. This problem studies the
relation between a zero price with the interest rate movement. Let’s consider a 20-year zero with a par value of $1,000
and 6% interest compounded semiannually.
a. What is the fair price of this zero coupon bond at time 0?
b. Suppose that you bought the zero for the amount that you just computed in part (a.) at time zero, and then six
months later the interest rate increases to 7%. What will be the fair price at time 0.5? If you sell the bond at t = 0.5,
what is your return per year? (Hint: A return is defined as Profit or Loss / Initial investment. Notice that for this
question, the investment horizon is just 0.5 year.)
c. What conclusion can you draw from the above example on the relation between a zero price with the underlying
interest rate? What is your intuition?
Solution: Let P (t) be the fair price at time t.
a. The fair price of this zero coupon bond at time 0 is
1000
P (0) = = $306.56.
(1 + 6%/2)20×2
b. The fair price of this zero coupon bond at time 0.5 is
1000
P (0.5) = = $261.41.
(1 + 7%/2)20×2−1
If we sell the bond at t = 0.5, the return per year is
P (0.5) − P (0)
× 2 = −29.45%.
P (0)
c. The zero price decreases when interest rate increase. Future money worth less at present due to higher interest rate.
2. A coupon bond with a par value of $1,000 and a 10-year maturity pays semi-annual coupons of $22.
a. Suppose the current interest rate for this bond is 4% per year compounded semi-annually. What is the fair price of
the bond?
b. Is the bond selling above or below par value?
Solution:
20
X 22 1000
a. The fair price is + = $1032.70 .
1.02t 1.0220
t=1
b. It is selling above par.
3. A 10-year loan of $3,000 is arranged to be settled by payments at the end of each year. It can be repaid under the
following two options:
1
i. Equal annual payments at an annual effective rate of 5.50%.
ii. Installments of $300 each year plus interest on the unpaid balance at an annual effective rate of i.
The sum of the payments under option (i) equals the sum of the payments under option (ii). Find i.
Solution: By direct derivation,
Sum of payments under option (i) = sum of the payments under option (ii)
3000
10 × P10 1
= 300 × 10 + 3000i + 2700i + . . . + 300i
t=1 1.055
3980 = 3000 + 16500i
i = 5.94%
4. Misato deposited $2,000 twice in her bank account on 1st January 2011 and on 1st January 2014. If there were no other
deposits or withdrawals and the amount of money in the account at the end of 31st Decemeber 2015 is $7,100, find the
effective rate of interest that Misato earned.
Solution: The effective rate of interest is 16.9% by solving the following equation:
2000(1 + r)5 + 2000(1 + r)2 = 7100.
Equivalently, 1 + r is the root of the polynomial f (x) = 2000x5 + 2000x2 − 7100. The root of any polynomial can
be computed by Numpy function in Python:
1 print ( np . roots ([2000 , 0 , 0 , 2000 , 0 , -7100]) )
2 # - - - - - - - - - Output in console
3 [ 1.1690295 +0. j 0.49478517+1.29665999 j 0.49478517 -1.29665999 j
4 -1.07929992+0.64162959 j -1.07929992 -0.64162959 j ]
where the result shows the only real root to the target polynomial is 1.169.
5. A bond is trading at a price of 100 with a yield of 8%. If the yield increases by 1 basis point, the price of the bond
will decrease to 99.95. If the yield decreases by 1 basis point, the price of the bond will increase to 100.04. What is the
modified duration of the bond?
Solution: The change of price w.r.t. 1 basis point is approximated as
∆P = {(99.95 − 100) + (100 − 100.04)}/2 = −0.27.
Hence the modified duration of the bond is
′ 0.27
MD = −P (0.08)/P (0.08) = 100 = 4.5 .
0.0001
6. (a) Compare the total amount of interest that would be paid on a $1000 loan over 10-year period, if the effective rate
of interest is 9% per annum, under the following three repayment methods: (1) The entire loan plus accumulated
interest is paid in one lump-sum at end of 10 years. (2) Interest is paid each each year as accrued and the principal
is repaid at the end of 10 years. (3) The loan is repaid by level payments over the 10-years. Which payment scheme
incurs the least amount of interest payment? Show your calculations clearly.
2
(b) Ms Katsuragi wishes to accumulate $1000 in a fund at end of 12 years. To accomplish this, Ms Katsuragi plans to
make deposits at the end of each year, the final payment to be made one year prior to the end of the investment
period. How large should each deposit be if the fund earns 7% effective.
Solution:
(a) (1) Interest I1 = 1000 · 1.0910 − 1000 = $1367.
(2) Interest I2 = 1000 · 0.09 · 10 = $900.
(3) Interest I3 = 10c − 1000 = $558.20 where c is the annual payment s.t.
10
X c cv(1 − v 10 ) 1
= = 1000 where v= .
1.09t 1−v 1.09
t=1
Payment scheme (3) incurs the least amount of interest payment.
(b) Each deposit is c = $59.21 by solving the following equation:
11
X c · 1.09(1 − 1.0910 )
c · 1.07t = = 1000.
1 − 1.09
t=1
Bonus Programming Questions:
P1. a. Write a function to approximate the change of an arbitrary function f (·) with respect to a small change in x,
say δx, via its Taylor’s series expansion: For any infinitely differentiable functionf (·), one can write
df (x) 1 d2 f (x)
f (x + ∆x) = f (x) + ∆x + (∆x)2 + . . . .
dx 2 dx2
Comment on the differences between the true and the approximation values as a function of the number of
terms included in the expansion.
b. Using Taylor’s series expansion, or otherwise, justify the following approximation:
P (y) − P (y + δy) ≈ −D(δy), and
P (y + δy) ≈ P (y){1 − D∗ (δy)},
where D and D∗ denote the dollar duration and the modified duration for a bond P (y) with yield y. You should
also argue why the bond price can be infinitely differentiable with respect to y if you make use of the result in (a)
to support your claim. Illustrate the approximation via a figure that is similar to Slide #69 with R and/or Python.
Solution:
a. We write a function delta_approx that takes the attributes of
• f_list: a list containing the arbitray function and its derivatives. For example, f_list[0](1) = f (1),
f_list[1](2) = f ′ (2) and f_list[5](0) = f (5) (0).
• x: point of evaluation x;
• dx: size of the small change δx.
and output the approximated change δbf via Taylor’s series expansion:
n−1
X 1 (m)
δf = f (x + δx) − f (x) ≈ f (x) · (δx)m ≜ δbf ,
m!
m=1
where n is the number of terms in the expansion, i.e., size of f_list and δx is a small value, say 0.01.
3
1 def delta_approx ( f_list , x , dx ) :
2 output = 0
3 for m in list ( range (1 , len ( f_list ) ) ) : # m running from 1 , 2 , to n -1
4 output += 1 / np . math . factorial ( m ) * f_list [ m ]( x ) * dx ** m
5 return output
Take f (x) = ex as an example, note that f (m) (x) = ex for all x. To see the differences between the true and
the approximation values as a function of the number of terms included in the expansion, we may plot |δbf − δf |
against n:
Approximation error against number of terms in expansion
0.007
0.006
f|
0.005
f
Approximation error |
0.004
0.003
0.002
0.001
0.000
2 3 4 5 6 7 8 9
Number of terms in expansion n
We can see that as number of terms increase, the approximated value is closer to the true value. Note that the
approximation error for f (x) = ex is very close to zero even the number of terms is as small as 3.
The Python code for generating the graph is shown here:
1 # Note that exp ( x ) has all its derivative equals itself
2 def f ( x ) :
3 return np . exp ( x ) # f ( x ) = exp ( x )
4 # Compute a list of approximation error against number of terms
5 n = 10 # number of terms in expansion
6 f_list = [ f for i in range ( n ) ] # a list containing arbitray function and its
derivatives
7 x , dx = 5 , .01
8 delta_true = f ( x + dx ) - f ( x ) # true delta
9 k_all = [ k for k in range (2 , n ) ] # list containing 2 , 3 , ... , n -1
10 error_list = [ abs ( delta_approx ( f_list [0: k ] , x , dx ) - delta_true ) for k in k_all ]
11 print ( error_list ) # list containing approximation errors
12 >>> [0.007445455444303972 , 2 . 4 7 9 7 4 8 9 1 7 5 1 6 5 6 6 6 e -05 , 6 . 1 9 6 2 6 5 8 1 1 5 5 3 3 0 3 e -08 ,
1 . 2 3 8 4 1 8 2 5 6 8 3 2 5 7 4 e -10 , 1 . 6 4 0 9 0 9 6 3 0 3 9 5 9 8 1 4 e -13 , 4 . 1 9 6 6 4 3 0 3 3 0 8 3 0 9 2 e -14 ,
4 . 2 1 8 8 4 7 4 9 3 5 7 5 5 9 5 e -14 , 4 . 2 1 8 8 4 7 4 9 3 5 7 5 5 9 5 e -14]
13 # Plot approximation error against number of terms
14 plt . plot ( k_all , error_list )
15 plt . title ( r ’ Approximation error against number of terms in expansion ’)
16 plt . ylabel ( r ’ Approximation error $ |\ hat {\ delta } _f - \ delta_f | $ ’)
17 plt . xlabel ( r ’ Number of terms in expansion $n$ ’)
18 plt . show ()
b. • (Bond price is infinitely differentiable). Note that
n n
X CFti X
P (y) = = CFti × gti (y)
(1 + y)ti
i=1 i=1
where gt (y) = (1 + y)−t is infinitely differentiable for all t.
Since P (y) is a linear combination of [gt1 (y), . . . , gtn (y)], P (y) is also infinitely differentiable.
4
• (Justification of approximation). By definition, D = P ′ (y). By the result in (a), we have
′ 1 ′′ 2
P (y) − P (y + δy) = P (y) − P (y) + P (y)δy + P (y)(δy) + . . .
2
′
≈ P (y) − P (y) + P (y)δy = −D(δy),
where the approximation is based on the fact that (δy)2 , (δy)3 , . . . goes to zero faster than δy.
Next, by definition, D⋆ = −D/P (y). It follows that
P (y + δy) ≈ P (y){1 − D⋆ (δy)}.
• (Illustration of the approximation). Consider a 50-year bond with principal $100 and coupon rate 10%. We
have
50 50
X 10 100 X 10t 1000
P (y) = t
+ and P ′ (y) = − − .
(1 + y) (1 + y)50 (1 + y)t+1 (1 + y)51
t=1 t=1
Consider y = 0.05 with δy = 0.01, we have the following plot:
Illustration of the approximation
P(y)
Taylor Approximation
400
300
200
P(y + y)
100
0 y+ y
0.000 0.025 0.050 0.075 0.100 0.125 0.150 0.175 0.200
y
We can see that the actual value of P (y + δy) is close to the approximation at y + δy. The python code
for generating the plot can be found here:
1 def P ( y ) :
2 output = 0
3 for t in range (1 , 50 + 1) :
4 output += 10 / (1 + y ) ** t
5 output += 100 / (1 + y ) ** 50
6 return output
7 def P_prime ( y ) :
8 output = 0
9 for t in range (1 , 50 + 1) :
10 output += 10 * -t / (1 + y ) ** ( t + 1)
11 output += 100 * -30 / (1 + y ) ** 51
12 return output # return P ’( y )
13 np . vectorize ( P ) ; np . vectorize ( P_prime )
14 y_all = np . arange (.01 , .21 , step =.01)
15 y , dy = .05 , .01
16 plt . plot ( y_all , P ( y_all ) , label = r " $P ( y ) $ " )
17 plt . axline (( y , P ( y ) ) , slope = P_prime ( y ) , color = ’ red ’ , label = r " Taylor Approximation " )
5
18 plt . hlines ( y = P ( y + dy ) , xmin =0 , xmax = y + dy , colors = ’ blue ’ , linestyles = ’ dashed ’)
19 plt . text ( -.01 , P ( y + dy ) +10 , r " $P ( y + \ delta y ) $ " , color = ’ blue ’)
20 plt . vlines ( x = y + dy , ymin =0 , ymax = P ( y + dy ) , colors = ’ blue ’ , linestyles = ’ dashed ’)
21 plt . text ( y + dy -.01 , -15 , r " $y + \ delta y$ " , color = ’ blue ’)
22 plt . title ( r ’ Illustration of the approximation ’) ; plt . xlabel ( r ’y ’) ; plt . legend ()
23 plt . show ()
P2. We consider the following zero-coupon curve:
Maturity (years) 1 2 3 4 5
Zero-coupon rate (%) 4.00 4.25 4.75 4.90 5.00
a. What is the yield to maturity (YTM) of this bond? You are required to solve this problem using R and/or Python
via Newton-Raphson/bisection method.
b. Suppose that the zero-coupon curve increases uniformly by 0.25% immediately after the bond specified in (a) is
purchased. What should be the new price and the new YTM of this bond? Using the results obtained in X1 or
otherwise, calculate also the unrealised profit/loss due to this sudden change in the zero-coupon curve.
Solution:
a. Consider a 5-year bond with $100 par value and 5% annual coupon rate.
The price is given by
5
X
P = 5 · B(0, t) + 100 · B(0, 5) = $100.16 where B(0, t) is the zero bond price at maturity t.
t=1
using the following Python code.
1 rate = [4 , 4.25 , 4.75 , 4.9 , 5]
2 zero_price = [1 for i in range (5) ]
3 bond_price = 0
4 for i in range (5) :
5 zero_price [ i ] /= (1 + rate [ i ] / 100) **( i +1)
6 bond_price += 5 * zero_price [ i ]
7 bond_price += 100 * zero_price [4]
8 print ( bond_price )
9 # - - - - - - - - - Output in console
10 1 0 0 . 1 57 9 8 2 9 3 5 7 4 6 2
The YTM is 4.96% by finding the root of the following function using bisection method:
5
X 5 100
f (y) = + − 100.16.
(1 + y)t (1 + y)5
t=1
The implementation of bisection method in Python is attachd here:
1 # Bisection algorithm
2 def bisection (f , a , b , tol ) :
3 # f is the function we aim to find the root in [a , b ]
4 # tol is a small enough tolerance
5 root = ( a + b ) / 2
6 while abs ( a - b ) > tol :
7 if f ( root ) == 0:
8 break
9 elif f ( root ) * f ( a ) < 0:
10 b = root
11 else :
12 a = root
6
13 root = ( a + b ) / 2
14 return root
15
16 def f ( y ) :
17 YTM_price = 0
18 for i in range (5) :
19 YTM_price += 5 / (1 + y ) ** ( i + 1)
20 return YTM_price + 100 / (1 + y ) ** 5 - bond_price
21
22 print ( bisection (f , .01 , .1 , 10 ** -6) )
23 # - - - - - - - - - Output in console
24 0.04963558197021484
b. The new price is $99.08 and the new YTM is 5.21%, using the following Python code:
1 rate_new = [ rate [ i ] + .25 for i in range (5) ] # rate increases by 0.25\%
2 zero_price = [1 for i in range (5) ]
3 price_new = 0
4 for i in range (5) :
5 zero_price [ i ] /= (1 + rate_new [ i ] / 100) **( i +1)
6 price_new += 5 * zero_price [ i ]
7 price_new += 100 * zero_price [4]
8
9 def f_new ( y ) :
10 YTM_price = 0
11 for i in range (5) :
12 YTM_price += 5 / (1 + y ) ** ( i + 1)
13 return YTM_price + 100 / (1 + y ) ** 5 - price_new
14
15 print ( price_new ) # impl ementa tion of finding price is identical to P2a
16 print ( bisection ( f_new , .01 , .1 , 10 ** -6) )
17 # - - - - - - - - - Output in console
18 9 9 . 0 8 18 8 7 9 7 6 6 7 3 5 3
19 0.0521329116821289
The change in price is 99.08 − 100.16 = −$1.08, i.e., the unrealised loss is $1.08.