Bond valuation tutorial#

This is a tutorial describing the functions in the functions.py module. These functions are tailored to understanding the valuation of currently listed, investment grade Australian Government Treasury Bonds (eTBs).

Note. The payment periods for all eTBs are half-yearly. All figures are expressed, where relevant, in annulaused form.

Bond list#

The function etbList_AU() in module functions.py returns a pandas dataframe comprising the current list of exchange traded Australian Government Treasury Bonds (eTBs). These are obtained from the government website here.

from functions import etbList_AU

etblist = etbList_AU()
etblist = etblist.reset_index(drop=True)

etblist
maturity coupon ASX_code payDates
0 21-Apr-2023 5.50% GSBG23 21-Apr, 21-Oct
1 21-Apr-2024 2.75% GSBG24 21-Apr, 21-Oct
2 21-Nov-2024 0.25% GSBU24 21-May, 21-Nov
3 21-Apr-2025 3.25% GSBG25 21-Apr, 21-Oct
4 21-Nov-2025 0.25% GSBU25 21-May, 21-Nov
5 21-Apr-2026 4.25% GSBG26 21-Apr, 21-Oct
6 21-Sep-2026 0.50% GSBQ26 21-Sep, 21-Mar
7 21-Apr-2027 4.75% GSBG27 21-Apr, 21-Oct
8 21-Nov-2027 2.75% GSBU27 21-Nov, 21-May
9 21-May-2028 2.25% GSBI28 21-May, 21-Nov
10 21-Nov-2028 2.75% GSBU28 21-Nov, 21-May
11 21-Apr-2029 3.25% GSBG29 21-Apr, 21-Oct
12 21-Nov-2029 2.75% GSBU29 21-Nov, 21-May
13 21-May-2030 2.50% GSBI30 21-May, 21-Nov
14 21-Dec-2030 1.00% GSBW30 21-Dec, 21-Jun
15 21-Jun-2031 1.50% GSBK31 21-Jun, 21-Dec
16 21-Nov-2031 1.00% GSBU31 21-Nov, 21-May
17 21-May-2032 1.25% GSBI32 21-May, 21-Nov
18 21-Nov-2032 1.75% GSBU32 21-May, 21-Nov
19 21-Apr-2033 4.50% GSBG33 21-Apr, 21-Oct
20 21-Nov-2033 3.00% GSBU33 21-Nov, 21-May
21 21-May-2034 3.75% GSBI34 21-May, 21-Nov
22 21-Jun-2035 2.75% GSBK35 21-Jun, 21-Dec
23 21-Apr-2037 3.75% GSBG37 21-Apr, 21-Oct
24 21-Jun-2039 3.25% GSBK39 21-Jun, 21-Dec
25 21-May-2041 2.75% GSBI41 21-May, 21-Nov
26 21-Mar-2047 3.00% GSBE47 21-Mar, 21-Sep
27 21-Jun-2051 1.75% GSBK51 21-Jun, 21-Dec

At the time of writing there are 28 eTBs currently issued by the Australian Government.

Bond Value#

The function etbListWithValueYield_AU() returns the same dataframe with the following columns added:

  • bond_value;

  • bond_value_yields;

  • bond_yields;

  • netReturnOn_AUD1000

Each entry depends on the bond’s current market price. The bond’s value and value yields and net return on AUD1000 assume the bond holder buys the bond at the current market price and holds it to maturity.

This function passes no arguments and uses Python’s web scraper package BeautifulSoup to retrieve the bond’s current market price from Yahoo Finance. If values in any entry is is nan, it means Yahoo Finance did not have a record of this bond.

from functions import etbListWithValueYield_AU

etblist_value_yield = etbListWithValueYield_AU()

etblist_value_yield = etblist_value_yield.reset_index(drop=True)
etblist_value_yield
maturity coupon ASX_code payDates bond_value bond_value_yield bond_yields netReturnOn_AUD1000
0 21-Apr-2023 5.50% GSBG23 21-Apr, 21-Oct -1.910 -1.87% 5.4% -17.190
1 21-Apr-2024 2.75% GSBG24 21-Apr, 21-Oct 1.275 1.27% 2.75% 11.475
2 21-Nov-2024 0.25% GSBU24 21-May, 21-Nov 5.650 5.97% 0.26% 56.500
3 21-Apr-2025 3.25% GSBG25 21-Apr, 21-Oct 2.550 2.53% 3.23% 22.950
4 21-Nov-2025 0.25% GSBU25 21-May, 21-Nov 8.375 9.1% 0.27% 83.750
5 21-Apr-2026 4.25% GSBG26 21-Apr, 21-Oct 2.955 2.86% 4.11% 26.595
6 21-Sep-2026 0.50% GSBQ26 21-Sep, 21-Mar 9.820 10.8% 0.55% 98.200
7 21-Apr-2027 4.75% GSBG27 21-Apr, 21-Oct 2.910 2.73% 4.46% 26.190
8 21-Nov-2027 2.75% GSBU27 21-Nov, 21-May 9.455 9.71% 2.82% 94.550
9 21-May-2028 2.25% GSBI28 21-May, 21-Nov 10.855 11.45% 2.37% 108.550
10 21-Nov-2028 2.75% GSBU28 21-Nov, 21-May 11.480 11.86% 2.84% 114.800
11 21-Apr-2029 3.25% GSBG29 21-Apr, 21-Oct 10.300 10.36% 3.27% 103.000
12 21-Nov-2029 2.75% GSBU29 21-Nov, 21-May 14.275 14.97% 2.88% 142.750
13 21-May-2030 2.50% GSBI30 21-May, 21-Nov 16.830 18.31% 2.72% 168.300
14 21-Dec-2030 1.00% GSBW30 21-Dec, 21-Jun 22.250 27.22% 1.22% 267.000
15 21-Jun-2031 1.50% GSBK31 21-Jun, 21-Dec 19.610 22.7% 1.74% 215.710
16 21-Nov-2031 1.00% GSBU31 21-Nov, 21-May 24.690 30.94% 1.25% 296.280
17 21-May-2032 1.25% GSBI32 21-May, 21-Nov 24.385 30.02% 1.54% 292.620
18 21-Nov-2032 1.75% GSBU32 21-May, 21-Nov 24.330 28.82% 2.07% 267.630
19 21-Apr-2033 4.50% GSBG33 21-Apr, 21-Oct 16.100 15.13% 4.23% 144.900
20 21-Nov-2033 3.00% GSBU33 21-Nov, 21-May 22.140 23.46% 3.18% 221.400
21 21-May-2034 3.75% GSBI34 21-May, 21-Nov 22.855 23.38% 3.84% 228.550
22 21-Jun-2035 2.75% GSBK35 21-Jun, 21-Dec 26.830 29.92% 3.07% 295.130
23 21-Apr-2037 3.75% GSBG37 21-Apr, 21-Oct 26.990 27.19% 3.78% 269.900
24 21-Jun-2039 3.25% GSBK39 21-Jun, 21-Dec 35.320 38.95% 3.58% 388.520
25 21-May-2041 2.75% GSBI41 21-May, 21-Nov 41.840 50.46% 3.32% 502.080
26 21-Mar-2047 3.00% GSBE47 21-Mar, 21-Sep 51.360 60.68% 3.54% 564.960
27 21-Jun-2051 1.75% GSBK51 21-Jun, 21-Dec 62.460 100.68% 2.82% 999.360

Note. If a value in the bond_value column is negative, it means the corresponding bond is overpriced in the market. One expects to lose money if one buys at the current market price and holdis it to maturity. This can also be seen in the column netReturnOn_AUD1000.

Note. The bond value yield is a means of comparing bonds with differing maturities. It is used in calculating stock RROI.

At time of writing the value of the longest maturity bond on the list, GSBK51 is 62.46. This means if we buy 100 units of GSBK51at the current market price, we will earn 62.46 * 100 = 6246 at maturity, being 21-Jun-2051. Alternatively, if we invest AUD1000, this allows us to buy AUD1000 // current_market_price many units. At time of writing, we see that net return will be 999.360. So, by 21-Jun-2051, the value of our investment in GSBK51 will have (almost) doubled.

Lastly, while the coupon on this bond is 1.75% per year, it is trading at below face value. Its yield is therefore higher. We see it is 2.82%.

Bond list with Run Rate#

A crucial component in the valuations above is the assumption the bond holder holds to maturity. Bonds which are closer to maturity ought to have lower value since their market price will tend to converge to face value at maturity. A better means of comparing bonds with differing maturities is then to simply correct for maturity, yielding a bond’s “run-rate”. That is, dividing their value by their time to maturity. A bond’s run rate is equivalently its net value per unit time, which we have annualised to net value per year.

Note. *While the value yield in the bond_value_yield column is another means of comparing bonds, we propose it is not as intuitive a measure as the run rate.

The function etbListWithValueYieldRunRate() in functions.py returns the same data as etbListWithValueYield_AU() with an extra column recording the bond’s run rate. It does not pass any arguments.

from functions import etbListWithValueYieldRunRate_AU

etblistvalue_yield_runrate = etbListWithValueYieldRunRate_AU()

etblistvalue_yield_runrate = etblistvalue_yield_runrate.reset_index(drop=True)
etblistvalue_yield_runrate[['ASX_code', 'runRate_annualised']] # displaying only the bond code and run rate
ASX_code runRate_annualised
0 GSBG23 0.000000
1 GSBG24 2.550000
2 GSBU24 5.650000
3 GSBG25 2.550000
4 GSBU25 5.583333
5 GSBG26 1.970000
6 GSBQ26 6.546667
7 GSBG27 1.455000
8 GSBU27 3.782000
9 GSBI28 4.342000
10 GSBU28 3.826667
11 GSBG29 3.433333
12 GSBU29 4.078571
13 GSBI30 4.808571
14 GSBW30 5.562500
15 GSBK31 4.902500
16 GSBU31 5.486667
17 GSBI32 5.418889
18 GSBU32 4.866000
19 GSBG33 3.220000
20 GSBU33 4.025455
21 GSBI34 4.155455
22 GSBK35 4.471667
23 GSBG37 3.855714
24 GSBK39 4.415000
25 GSBI41 4.648889
26 GSBE47 4.280000
27 GSBK51 4.461429

Since the above is a pandas dataframe we can call the method sort_values() to reorder by run_rate. The highest value-per-unit-time bond is at the top; while the lowest is at the bottom.

etblistvalue_yield_runrate.sort_values('runRate_annualised', ascending=False).reset_index(drop=True)
maturity coupon ASX_code payDates bond_value bond_value_yield bond_yields netReturnOn_AUD1000 runRate_annualised
0 21-Sep-2026 0.50% GSBQ26 21-Sep, 21-Mar 9.820 10.8% 0.55% 98.200 6.546667
1 21-Nov-2024 0.25% GSBU24 21-May, 21-Nov 5.650 5.97% 0.26% 56.500 5.650000
2 21-Nov-2025 0.25% GSBU25 21-May, 21-Nov 8.375 9.1% 0.27% 83.750 5.583333
3 21-Dec-2030 1.00% GSBW30 21-Dec, 21-Jun 22.250 27.22% 1.22% 267.000 5.562500
4 21-Nov-2031 1.00% GSBU31 21-Nov, 21-May 24.690 30.94% 1.25% 296.280 5.486667
5 21-May-2032 1.25% GSBI32 21-May, 21-Nov 24.385 30.02% 1.54% 292.620 5.418889
6 21-Jun-2031 1.50% GSBK31 21-Jun, 21-Dec 19.610 22.7% 1.74% 215.710 4.902500
7 21-Nov-2032 1.75% GSBU32 21-May, 21-Nov 24.330 28.82% 2.07% 267.630 4.866000
8 21-May-2030 2.50% GSBI30 21-May, 21-Nov 16.830 18.31% 2.72% 168.300 4.808571
9 21-May-2041 2.75% GSBI41 21-May, 21-Nov 41.840 50.46% 3.32% 502.080 4.648889
10 21-Jun-2035 2.75% GSBK35 21-Jun, 21-Dec 26.830 29.92% 3.07% 295.130 4.471667
11 21-Jun-2051 1.75% GSBK51 21-Jun, 21-Dec 62.460 100.68% 2.82% 999.360 4.461429
12 21-Jun-2039 3.25% GSBK39 21-Jun, 21-Dec 35.320 38.95% 3.58% 388.520 4.415000
13 21-May-2028 2.25% GSBI28 21-May, 21-Nov 10.855 11.45% 2.37% 108.550 4.342000
14 21-Mar-2047 3.00% GSBE47 21-Mar, 21-Sep 51.360 60.68% 3.54% 564.960 4.280000
15 21-May-2034 3.75% GSBI34 21-May, 21-Nov 22.855 23.38% 3.84% 228.550 4.155455
16 21-Nov-2029 2.75% GSBU29 21-Nov, 21-May 14.275 14.97% 2.88% 142.750 4.078571
17 21-Nov-2033 3.00% GSBU33 21-Nov, 21-May 22.140 23.46% 3.18% 221.400 4.025455
18 21-Apr-2037 3.75% GSBG37 21-Apr, 21-Oct 26.990 27.19% 3.78% 269.900 3.855714
19 21-Nov-2028 2.75% GSBU28 21-Nov, 21-May 11.480 11.86% 2.84% 114.800 3.826667
20 21-Nov-2027 2.75% GSBU27 21-Nov, 21-May 9.455 9.71% 2.82% 94.550 3.782000
21 21-Apr-2029 3.25% GSBG29 21-Apr, 21-Oct 10.300 10.36% 3.27% 103.000 3.433333
22 21-Apr-2033 4.50% GSBG33 21-Apr, 21-Oct 16.100 15.13% 4.23% 144.900 3.220000
23 21-Apr-2024 2.75% GSBG24 21-Apr, 21-Oct 1.275 1.27% 2.75% 11.475 2.550000
24 21-Apr-2025 3.25% GSBG25 21-Apr, 21-Oct 2.550 2.53% 3.23% 22.950 2.550000
25 21-Apr-2026 4.25% GSBG26 21-Apr, 21-Oct 2.955 2.86% 4.11% 26.595 1.970000
26 21-Apr-2027 4.75% GSBG27 21-Apr, 21-Oct 2.910 2.73% 4.46% 26.190 1.455000
27 21-Apr-2023 5.50% GSBG23 21-Apr, 21-Oct -1.910 -1.87% 5.4% -17.190 0.000000

At time of writing it is interesting to note, while the coupon and yield of bonds GSBU24 and GSBQ26 are quite low compared to others, they nevertheless have high run rates. This is due to these bonds currently trading at market price below face value in addition to having a relatively soons maturities.

And so, while its yields are low, the above result suggests GSBU24 and GSBQ26 are good buys when its market price, face value and maturity are considered.

Yield curve#

In the module yield_sketch.py the function sketch_yields() uses the Python plotting package matplotlib to display the yield curve graph. It is a sketch of bond yields against bonds. Superimposed on the graph is the regression line, which is sketched using the Python package scipy. The yield curve is said to be inverted if the slope of the regression line is negative, meaning yields of longer term maturity bonds are, on average, lower than the shorter term maturities.

Inverted yields are indicative of upcoming recessions, apparently.

The function sketch_yields() does not pass any arguments.

from yield_sketch import sketch_yields

sketch_yields()
_images/bonds_tutorial_13_0.png

At time of writing, the current yield curve regression slope is 0.0314. This is positive, meaning the yield curve is not inverted.