Last active
September 16, 2022 15:06
-
-
Save alastairparagas/d5e30d64252ff9e49bc4e77308c4f3b5 to your computer and use it in GitHub Desktop.
Treasury, TIPS and I-bonds: Playing with bonds
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import numpy as np | |
import matplotlib.pyplot as plt | |
np.seterr(all="ignore") | |
import matplotlib.ticker as ticker | |
import numpy_financial | |
# Treasury, TIPS and I-bonds - these are all bonds, which allows you to lend | |
# a $ amount (principal) to the US government. The US government promises to pay | |
# you back in time (years). | |
# They also give you interest payments every so often to compensate you for | |
# lending the US government money. Every year, this $ in interest payment profit | |
# amounts to principal*coupon rate. | |
# The government in turn uses investors paying for bonds, to fund projects like | |
# build infrastructure and grow the US economy by allocating capital to industries | |
# that may not be as profitable but the government has an incentive | |
# to direct American society to. For ex: renewable energy, state-side semiconductor | |
# manufacturing, etc (industries where companies have relatively small profit | |
# margins, but the US government wants to keep them afloat until they mature) | |
# In turn, US taxpayers are the ones essentially paying the principal + coupons | |
# (interest payments) owed to investors, who lent money to the US government. | |
def calculate_tbond_return(years, principal, coupon_rate): | |
return numpy_financial.fv(0, np.arange(years+1), -1*principal*coupon_rate, -1*principal) | |
def calculate_ibond_return(years, principal, inflation): | |
return numpy_financial.fv(inflation, np.arange(years+1), 0, -1*principal) | |
def calculate_tips_return(years, principal, coupon_rate, inflation): | |
# TIPS guarantees principal/par stays constant - even in deflation | |
inflation = max(inflation, 0) | |
tips_bond_principal = numpy_financial.fv(inflation, np.arange(years+1), 0, -1*principal) | |
tips_bond_coupons = tips_bond_principal * coupon_rate | |
return tips_bond_principal + tips_bond_coupons | |
# These calculations assume you hold to maturity (you don't sell for the duration | |
# of the bond, which is 10 years in this example) | |
principal = 1000 | |
# Treasury bonds selling at discount - $97.25~ for $100 of debt, repayment in 10 years | |
# In essence, you are lending the US government $100 using only $97.25. | |
# In 10 years, they will pay you back the $100. | |
# To add, they will make annual fixed interest payments of 1.0282% of $100 (aka coupon rate) | |
# or roughly $1.02 a year, to compensate you lending out $100 to them. | |
tbond_initial_value = principal*1.0282 | |
# TIPS selling at premium - $111.18~ for $100 of debt, repayment in 10 years | |
# In essence, you are lending the US government $100 for $111.18! | |
# In 10 years, they will pay you back $100 OR the inflation adjusted equivalent of $100 in | |
# 10 years - whichever is higher - your $100 will grow to match inflation! | |
# To add, they will make annual fixed interest payments of 0.125% of $100 (aka coupon rate) | |
# or roughly $0.125 a year, to compensate you lending out $100 to them | |
tips_initial_value = principal*0.8994 | |
# In the real world, the "yield" of a Treasury or TIPS bond combines the coupon rate | |
# and the premium/discount pricing of bonds. The difference in yield between the | |
# 10-year Treasury bond and the TIPS bond is the CURRENT (for the given day) | |
# market's estimate for the average annual inflation for the next 10 years. | |
# Currently (Sept 12 2022), 10 year Treasury yield is at 3.343% and 10 year TIPS yield | |
# is at 0.942%. As such market is assuming a 10 year average inflation rate of 2.401%. | |
# If 10 years into the future, the average inflation is above 2.401%, investing | |
# into TIPS would have made more money. If the average inflation is below 2.401%, | |
# investing into a 10-year Treasury would have made more money. | |
# US government bond yields also bleed into the stock market. The higher yields | |
# go, the more investors are likely to choose investing a "safe" US government | |
# bond over stocks (less risk, more assured profit). The lower bond yields go, the | |
# more investors are likely to choose investing into stocks (as there are not much | |
# profit to be made from bonds, investors flock to riskier assets) | |
# In the real world, when interest rates go up, companies find it harder to | |
# borrow money. Companies that depend on borrowing money to grow and increase their | |
# net profit (growth companies) will typically see their valuations (stock price) | |
# re-adjusted by the market. Mature companies that depend less on borrowed money | |
# (but may also not have the capability to increase net profits), see more stable | |
# valuations (stock price) as they can better weather the environment. | |
# 10-year Treasury coupon rate of 1.125% | |
treasury_bond = calculate_tbond_return( | |
years=10, principal=tbond_initial_value, coupon_rate=0.0125 | |
) | |
# 10-year TIPS coupon rate of 0.125% | |
# TIPS 1% annual deflation, TIPS guarantees principal never dips even with deflation if held to maturity | |
tips_bond_1pctdeflation = calculate_tips_return( | |
years=10, principal=tips_initial_value, coupon_rate=0.00125, | |
inflation=-0.01 | |
) | |
# TIPS 1% annual inflation | |
tips_bond_1pctinflation = calculate_tips_return( | |
years=10, principal=tips_initial_value, coupon_rate=0.00125, | |
inflation=0.01 | |
) | |
# TIPS 2% annual inflation | |
tips_bond_2pctinflation = calculate_tips_return( | |
years=10, principal=tips_initial_value, coupon_rate=0.00125, | |
inflation=0.02 | |
) | |
# TIPS 4% annual inflation | |
tips_bond_4pctinflation = calculate_tips_return( | |
years=10, principal=tips_initial_value, coupon_rate=0.00125, | |
inflation=0.04 | |
) | |
# I-bond, 4% annual inflation | |
ibond_4pctinflation = calculate_ibond_return( | |
years=10, principal=principal, | |
inflation=0.04 | |
) | |
fig3, fig3_ax1 = plt.subplots() | |
fig3_ax1.plot(treasury_bond, label='Treasury Bond') | |
fig3_ax1.plot(tips_bond_1pctdeflation, label='TIPS, 1% deflation') | |
fig3_ax1.plot(tips_bond_1pctinflation, label='TIPS, 1% inflation') | |
fig3_ax1.plot(tips_bond_2pctinflation, label='TIPS, 2% inflation') | |
fig3_ax1.plot(tips_bond_4pctinflation, label='TIPS, 4% inflation') | |
fig3_ax1.plot(ibond_4pctinflation, label='I-bond, 4% inflation') | |
fig3_ax1.set_xlabel('Years') | |
fig3_ax1.set_ylabel('Total Return, $') | |
fig3_ax1.set_title('10-year Treasury Bonds vs TIPS, Bought at $1k \n(TIPS at premium, Treasury at discount), Held to Maturity') | |
fig3_ax1.legend() | |
fig3_ax1.yaxis.set_major_formatter(ticker.FormatStrFormatter('$%.0f')) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment