FXMasterCourse

Trading Order Out of Chaos

  • Facebook
  • LinkedIn
  • RSS
  • Twitter
  • About
  • Trading Approach
  • Resources
  • Forex Tools
    • MT4 Code
    • Tick Data
    • Useful Tools
  • In the Media
  • Testimonials
  • Contact
  • Member Login
You are here: Home / Market Dynamics / Calculating Bond Index Prices: Analyzing the Bond Bear Market

October 2, 2018 by Corvin Codirla Leave a Comment

Calculating Bond Index Prices: Analyzing the Bond Bear Market

Calculating Bond Index Prices: Analyzing the Bond Bear Market

In the previous article we set out to cover a new asset class: Bond investments.  We saw how by including bonds together with stocks we could improve on our portfolio performance.  Is this mixture still good given that we are now shifting in the interest rate cycle to a Bond Bear Market?  In this article we go about calculating the Bond Index going back 120 years to answer this question.

Here is a chart since 1960 of US 1 and 10 year rates:

Current Interest Rate Cycle and Rising Rates
Current Interest Rate Cycle and Rising Rates

With rates starting to normalize and go higher, bond prices are entering a bear market.  Is it still advisable to hold bonds?

These are tricky questions, in particular because easily accessible bond data is lacking, and so, performing any back testing or forward simulations is difficult.

This article sets out to rectify that.  We will:

  • Introduce you to a simple way to get decades worth of good quality data
  • Determine how to create a reliable index of bond prices showing total return going back decades
  • Figure out what bonds can actually do for us in this cycle.

Interest Rates and Bond Prices

Bonds are finite maturity instruments.  Unlike a stock that you can hold for decades, a bond matures after a certain amount of time.

Bonds are also tricky for retail traders to trade; they’re not easily accessible.  As we saw previously, this is where ETFs come to the rescue.  Bond ETFs are like shares.  You buy them and receive an income stream from the bond coupons.  ETFs also don’t have a finite maturity.

So how is that we can buy a bond ETF, which like a share seems to hang around forever?  And more importantly, given that these ETF bond prices only go back to 2002, how can we work out our own ETF proxies, extending them back far enough to produce some meaningful backtests.

To do this we have to break up our bond instrument into its parts and cover some basic bond maths.

Bond Background

A bond is made up of two components.

There is the underlying principal, which you as the bond buyer are lending to the bond seller.  Since you are buying the bond, the money goes to the seller, who at maturity of the bond will give you the money back.  So, buying a bond is just like lending money.

In the meantime, however, you will receive periodic payments.  These are the bond coupon payments.  Let’s have a look at an example.

Bond Cash Flows
Bond Cash Flows

You start out by paying for the bond.  That’s the red bar.  Seen another way: you’re making a loan and in return you’re receiving a piece of paper that entitles you to regular (in this case semi-annual) interest payments, and a repayment at the end of the life of the bond.  The income stream forms your annuity.  The final payment is the principal re-payment on the loan you’ve given.

Ultimately what you care about is, how much am I lending and what am I getting in return for it.  The series of repayments represents the amount you’re earning on your loan.  In essence you can say that the stream of all these future cashflows is equal to the amount you are lending today.

I.e. your loan is the price of today’s bond.

And as you can see this amount (the red bar) is directly related to the interest rates in the market.

So let’s follow this up by looking at some real world bond prices.

Bond Quotes and Bond Prices

One thing you will find, is that getting individual bond data on the internet is more difficult than for equities.

One such source of data is the Frankfurt Stock exchange for various European bonds.  One such example is the German government bond maturing in 2024, which is in six years from now.  (Note that each bond has a unique identification number, called the ISIN number.  In this case it is DE0001134922.  Google it!)

Now its coupon is at 6.25%.  This means that for every bond, with a face value of EUR 10,000, I would get EUR 625 annually (on the 4th of January).  Note that unlike US Government Bonds, German bonds pay annually rather than semi-annually.

But hang on, you say.  Interest rates in Germany are low right now.  In fact 6 year rates are at -0.08% (you can check that over at marketwatch.com).

So what’s going on?  Is this money for free?

Actually the quoted price on the exchange for this bond was at 136.20 on Monday September 10, 2018.  So to own that EUR 10,000 of bond I would have to fork over EUR 13,420 right now.  Now remember, that in 2024, I get the original EUR 10,000 back, plus a series of annual coupons (worth EUR 625 every 4th of January), I’m actually looking to get back EUR 13,750 (just naively adding up all the cash-flows), which is more or less in line with the current price of money invested, and equates to roughly 0% return over these six  years.  Exactly where the market puts 6 year German yields.

In essence because everybody asked the same bright question: “Money for free?” they rushed in and pushed that bond price up, until the rate of return equaled to other interest rate instruments in the market.  Hence the concept of no free lunch in economics.  People tend to rush in and equalize prices so that such anomalies disappear quickly.  This is also known as arbitrage trading: exploiting mismatches in prices between equivalent instruments.

To put the above example into context, this bond was issued back in 1994, when 30 year rates were roughly at 6.25%, and hence its coupon wasn’t so out of whack.  At that time the bond most likely trade at “par,” meaning it’s market price was equal to it’s face value.  That is the EUR 10,000 bond actually traded for a price of EUR 10,000.

Bond Prices and Interest Rates

So as interest rates decrease, the bond price trades above par.  The capital loss you make on receiving par value at redemption counteracts the yield gain on the high coupons during the lifetime of the bond.

This simple example drives the point home, that interest rates determine price and vice versa.

However, the relationship isn’t one-for-one.  I.e. in technical jargon: the relationship isn’t linear.  The actual relationship between a bond price and interest rates is non-linear.

If I were to plot the relationship it wouldn’t be a straight line.  Here’s the behavior of a 30 Yr bond’s price as interest rates change.  The blue line shows the price / interest rate relationship, the orange line shows what a linear relationship would look like.

Bond / Interest Rate Relationship
Bond / Interest Rate Relationship

Two things stand out here:

  1. The actual price – rate relationship is upward curving
  2. The curvature for low rates is higher than for higher rates

This curvature is called convexity.  And we can reformulate the relationship thus: high coupon bonds have a higher convexity than low coupon bonds (compared to current rate levels).  And furthermore, higher convexity means that bonds are more sensitive to rate movements.  You will also find that longer maturity bonds tend to have higher convexity than shorter maturity bonds.

From this chart you can see that in a falling rate environment people tend to want to hold higher convexity bonds, as it affords them a more levered position with respect to the underlying interest rates.  Vice versa in a rising rate environment the opposite is true.

So how did we get this chart up?  For the more mathematically savvy here is the relationship we are using

\(\text{P}= \text{Annuity} + \text{Capital Repayment}\)

 

The Annuity here is the value of the future coupons you receive and the Capital Repayment is today’s value of the loan repayment to be made at the bond’s maturity.

If

  • the yield on the bond today is \(r%\),
  • your coupon is \(C\),
  • your time to maturity is \(T\),
  • your loan Notional is \(N\),
  • and you make semi-annual payments the formula reduces to:

\(\begin{align}P(r,C) & = \displaystyle\sum_{i=1}^{2T}\frac{\frac{C}{2}N}{\left(1+\frac{r}{2}\right)^i} + \frac{N}{\left(1 + \frac{r}{2}\right)^{2T}} \\\\ & = \frac{CN}{r} \left(1 – \left(1 + \frac{r}{2}\right)^{-2T}\right) + N\left(1 + \frac{r}{2}\right)^{-2T}\end{align}\)

 

On a technical note: this formula is true on Coupon payment day. In between coupons we need to take into account the accrual. The correction can be stated as:

\(P(r,C,t) = \left( 1 + \frac{r}{2}\right)^{t}\times P(r,C)\),

where \(t\) is the time from the previous coupon date as a year fraction.

This part becomes really important when we want to account for any money that we’ve made on the bond index as time passes, i.e. it allows us to take account of the coupon we are being paid.

This relationship between bond prices and interest rates will allow us to extrapolate price series into the past giving us a synthetic ETF for our backtesting and regime analysis.

And the good thing is we have interest rate data galore!  Going back far enough that we can perform some useful analysis of what the future might bring!

Two sources we can look at are:

  1. Prof. Schiller’s website (which goes back to 1871).
  2. The US Treasury’s website (though we will be using Python and Quandl for this)

Our Bond Index in Action

In this section we’ll use the formula for bond prices above to create our own bond index.  We’ll also check that our bond index makes sense, by comparing it to the current Bond ETFs and making sure our bond index tracks them appropriately.

Once we’ve covered that we’ll use a great property of interest rates that will allow us to make some educated estimates of future behaviour, allowing us to peek into the future.

Let’s start out by listing the ETFs we could compare our bond index to:

Bond ETFMaturities CoveredDate available fromCAGRSharpe RatioMax D/D
SHY1 - 3 yrs2002-07-301.9%1.35-2.2%
IEI3 - 7 yrs2007-01-113.5%0.87-6.0%
TLH10 - 20 yrs2007-01-115.4%0.58-14.3%
TLT> 20 yrs2002-07-306.9%0.51-26.6%
AGG>1 yr2003-09-293.6%0.76-12.8%

As we saw previously, the longer dated bond ETFs have a higher volatility, and hence a lower Share Ratio.

Now let’s try to replicate some these ETFs by using the rates available from the US Treasury’s website.

The simplest one to replicate is the TLT, as it is primarily driven by long rates, which have been relatively flat in recent history, unlike the other ETFs which span sections of the yield curve with more curvature.

We’ll track the history back to 2008.  Primarily because the 30yr bond issuance has been patchy.  The US government started selling 30yr bonds regularly in 1977, but discontinued them in October 2001.  They then restarted issuing them in February of 2006.

The result is:

Simulated 30Yr Bond Index vs TLT ETF
Simulated 30Yr Bond Index vs TLT ETF

The replication methodology is very simple.  At the start of every month we buy a par bond.  At the end of the month we check our returns.  These are made up of the accrued coupon and a change in price due to the change in rates

\(\begin{align}\Delta A &=\frac{r_{t-1}}{12}, \\\\ \Delta P &=\frac{Nr_{t-1}}{r_t}\left(1-\left(1+\frac{r_t}{2}\right)^{-2T}\right) + \left(1+\frac{r_t}{2}\right)^{-2T} – 1\end{align}\).

The assumptions here are that our bond notional is $1, and the yield of the bond we buy at the start of every month is the same as its coupon, which means its price is at par, i.e. equal to face value, which is the $1.  This is a good approximation since the most recent bonds issued by governments tend to have coupons very close to the current yield.

So the total monthly change in value is the sum of these two components \(\Delta A + \Delta P\).

These two components give us two income streams which we can plot out for the same time period as the chart above:

Capital and Coupon Component of 3o Yr Bond Index
Capital and Coupon Component of 30 Yr Bond Index

The take-away point here is that we make money both on the coupons we are receiving (the red line) as well as the capital appreciation due to declining rates, which result in rising bond prices.

We’ll have more to say about this when we try to predict possible outcomes: rising rates don’t necessarily mean losing money.  It’s also the speed with which they rise, since if they rise too quickly it could be that our income doesn’t make up for the loss caused due to interest rate movements.

We can also create our bond indices for the interest rates available from the US Treasury website and create an equally weighted portfolio, to compare it to the AGG ETF, which is an aggregate of all bonds with maturity greater than one year.  The result is:

Aggregate Bond Index Simulation
Aggregate Bond Index Simulation

Looking at returns, our proxy tracks AGG movements closely, with a correlation on monthly returns of 97.8%. However, the AGG covers a universe of bonds larger than just government bonds. Government bonds make up 38%. 28% of the AGG are made up of mortgage backed securities (residential and commercial), 25% are corporate bonds, the remainder is made up of Sovereign / Supranational / Agency, and other bonds. Here sovereign means USD denominated foreign bonds, e.g. Hungary, Colombia, etc. This kind of discrepancy explains the difference in performance between our proxy and AGG.

Interest Rate History

So we are now in a position to start conducting backtests as well as present a possible future outcome given the current rise in rates.

Let’s start out by looking at 10 year rates going back to 1871, using Schiller’s data:

10 Year US Treasury Yield
10 Year US Treasury Yield

From the chart you can see that the data starts to become more granular from the start of 1953 onwards.  Prior to that the observation periods are annual, with averaged values in between.  Hence the smoothed nature of rates prior to 1953.

Regardless, let’s have a look at the relative behavior between the 10 year proxy we can construct from this yield series and the S&P 500 data from the same source. (Note we use log prices in these charts)

S&P500 vs 10 Year Bonds since 1871, Log Scale
S&P500 vs 10 Year Bonds since 1871, Log Scale

At first glance, the results are quite striking: over the last 150 years bonds and equities have performed nearly in sync.  There are some structural differences, however, throughout the time period.  Since the 1930s it’s clear that equities have significantly outperformed bonds: they start from a complete low point, and yet reach the current highs of our bond index.

Previous Bond Bear Markets: How Bad Does it Get?

The whole point of this exercise of constructing a price index from bond yields was to answer the question of what happened during previous bond bear markets.

The conventional wisdom is that fixed income securities decrease in price when yields go up.  However, as we saw previously, it’s not only the value of the notional of the bond that contributes to the value of the bond.  It’s also the coupon that you earn during the life-time of the bond.

The caveat here, is the speed with which rates start to increase.  The rate of change will influence the decline of bond prices, and if it’s too fast, the coupon might not make up for it.

To get a better picture of the relationship between rising and declining interest rate regimes, let’s plot the bond index versus the underlying 10 year rate:

Bond Index vs 10 Yr Rate, 1871 - 2018
Bond Index vs 10 Yr Rate, 1871 – 2018

The part we naturally want to focus on for this article is the section which experienced the previous big updraft in rates: 1953 to 1982.

Bond Index vs Yields 1953 to 1982
Bond Index vs Yields 1953 to 1982

And this is really the punch-line: bond prices appreciated… a bit. Coming back to coupon income vs capital appreciation, let’s plot out the two components during this time period:

Coupon Income vs Capital Income during Bond Bear Market 1953/82
Coupon Income vs Capital Income during Bond Bear Market 1953/82

The high rates covered for the capital losses.

However, most importantly, volatility was contained during most time periods:

Yearly Standard Deviation of Bond Index
Yearly Standard Deviation of Bond Index

Looking Forward to Part 2

This has been a pretty lengthy article, so we’ll take a break here…

To summarize: in this article we’ve covered the nature of bonds, and the relationship between their prices and current yields.

Most importantly we’ve formulated a framework to help us navigate bond price behavior over a longer time horizon, so that we can create a historical lab for testing how bonds and their inclusion in equity portfolios will impact returns.

The relevant points here are:

  • Bonds make money both on the the interest payments they receive
  • They also are make or lose money on the appreciation of the capital depending on how interest rates move
  • Falling rates don’t always mean losing money.  It depends how quickly they fall with respect to the income the bond generates

So where do we go with this?

Now that we have a lab setup we can ask questions as to how an equity / bond portfolio did perform in the past.  And equally exciting: since interest rates mean revert, we can project their behavior into the future and figure out how a rising rate environment might affect our equity / bond portfolio.

Recall that the main focus of the article series is to understand how each asset can contribute to our portfolio.  So gaining an insight into the future by performing simulations is quite exciting!

In the meantime, the Python Code for all the diagrams in this article is included here, so that you can go ahead and conduct your own experiments.

So, until next time,

Happy Trading.

If you have enjoyed this post follow me on Twitter and sign-up to my Newsletter for weekly updates on trading strategies and other market insights below!

Get Your Action Guide Here:

7 Steps To Trading Success – 7 Steps that will increase your trading Success TODAY

Quick Review of the Last Six Months

It’s been six months since I wrote the last article, and with time flying it’s always a good exercise to review how systems have performed.  These walk forward tests tend to satisfy two important points

  • Re-affirm that the initial principles were valid
  • Keep your eyes open for any regime shifts

And with such a turbulent market environment (from trade wars, domestic US issues, to European Brexit, as well as tech stock problems) it’s good to see that principles still hold.  Here is the 60% Equity – 40% Bond portfolio holding as it has fared since the start of 2008 as well as the recovery after the Volatility shakes in February:

60-40 Equity Bond Portfolio since 2008
60-40 Equity Bond Portfolio since 2008

Python Code

Here is the Python Code that produces the diagrams in this post.

You might not have some of the modules which are used here, and so you will have to pip install them.

In particular:

  • Quandl (for which you should get an API key for free here: Quandl API Key).  This module enables you to grab lots of free market data, in particular the FRED Treasury Rate series going back to the 60s
  • requests, which will allow you easy access and downloads from the internet
  • numpy and pandas, which are standard numerical analysis and data manipulation modules
  • matplotlib which is the de facto plotting module in Python
  • fix_yahoo_finance, which bypasses the issue in pandas for obtaining Yahoo Finance data

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
'''
Script for accessing Quandl and Schiller data as well as Bond ETF data and generating
Bond indexes going back to 1871 and comparing them to the ETF data.
'''


import math
import io
import quandl
import requests
import datetime as dt
import numpy as np
import pandas as pd
import fix_yahoo_finance as yf
import matplotlib.pyplot as plt

from collections import OrderedDict
from pandas_datareader import data as pdr

yf.pdr_override()

ak = XXXXX  # INSERT FREE QUANDL KEY HERE from here: https://help.quandl.com/article/320-where-can-i-find-my-api-key

TRS = OrderedDict([('M01', 'FED/RIFLGFCM01_N_B'),
                   ('M03', 'FED/RIFLGFCM03_N_B'),
                   ('M06', 'FED/RIFLGFCM06_N_B'),
                   ('Y01', 'FED/RIFLGFCY01_N_B'),
                   ('Y02', 'FED/RIFLGFCY02_N_B'),
                   ('Y03', 'FED/RIFLGFCY03_N_B'),
                   ('Y05', 'FED/RIFLGFCY05_N_B'),
                   ('Y07', 'FED/RIFLGFCY07_N_B'),
                   ('Y10', 'FED/RIFLGFCY10_N_B'),
                   ('Y20', 'FED/RIFLGFCY20_N_B'),
                   ('Y30', 'FED/RIFLGFCY30_N_B'),
                   ])


def plot_yld(df, yld='M03'):
    '''
    Plots a column from the dataframe f, which contains the Quandl Treasury Rates labelled by the columns above
    :param df:   Quandl Treasury Rates
    :param yld:  Labelling which column to plot, can be a list of strings for multiple rate series
    '''

    if type(yld) == list:
        for i in yld:
            plt.plot(df[i], label=i)
    else:
        plt.plot(df[yld], label=yld)
        plt.title('Chart of ' + yld + ' government bond yield')

    plt.title('Chart of  government bond yield')
    plt.grid()
    plt.legend()
    plt.show()


def get_trs(cache=True):
    '''
    Function to download the Quandl Treasury Rates
    :param cache:  If False will download and store rates in a pkl file.  If True will load pickle file
    :return:       Resulting DataFrame with Treasury rates from Quandl
    '''

    if cache:
        try:
            df = pd.read_pickle("rates.pkl")
        except:
            pass
        else:
            return df

    df = pd.DataFrame()
    for k, v in TRS.items():
        s = quandl.get(v, api_key=ak)
        s.rename(columns={'Value': k}, inplace=True)
        df = df.join(s, how='outer')

    df = df.replace(0, pd.np.nan).ffill()

    df.to_pickle("rates.pkl")
    return df


def simulate_bond(df, yld='Y01', mat=1, freq=360, pfreq=2):
    '''
    Bond Index price simulation
    :param df:    DataFrame with Treasury Rates from Quandl
    :param yld:   Identifies which Rate in the DataFrame to use
    :param mat:   Maturity of bond considered, e.g. for Y01, mat = 1
    :param freq:  Frequency of rate observations, e.g. for monthly observations freq = 12
    :param pfreq: Payment frequency. E.g. for US Bonds pfreq=2, for German bonds pfreq = 1
    :return:      A dataframe containing the various components of the Bond Index Series
    '''

    if not type(yld) == list:
        yld = [yld]
    rates = df[yld]
    rates.columns = ['rate']
    rates['rate'] = rates.rate / 100.0
    rates['capital'] = (1 + rates.rate / pfreq).pow(-pfreq * mat)
    rates['annuity'] = rates.rate.shift(1) / rates.rate * (1 - rates.capital)
    rates['coupon'] = rates.rate.shift(1) / freq
    rates['ret'] = rates.capital + rates.annuity + rates.coupon - 1
    rates['p_c'] = np.exp((rates.capital + rates.annuity - 1).cumsum())
    rates['c_c'] = np.exp(rates.coupon.cumsum())
    rates['px'] = (1 + rates.ret).cumprod()
    return rates


def resample_ylds(df: pd.DataFrame):
    '''
    Simple function to resample rates to monthly observations.  Assumption is that DataFrame index contains time.
    '''

    df = df.resample('M').last()
    return df


def get_symbol(sym):
    '''
    Wrapper for getting tickers from Yahoo
    :param sym: Yahoo ticker.  E.g. AGG for AGG ETF
    :return: DataFrame with Yahoo Finance price data
    '''

    df = pdr.get_data_yahoo(sym, start='1990-01-01', end=dt.date.today().strftime('%Y-%m-%d'))
    print(df.shape)
    return df


def simb(symb='TLH', yld='Y10', mat=10, freq=12, pfreq=2):
    '''
    Function to plot bond price simulation versus ETF Price
    :param symb:   Yahoo ETF Ticker
    :param yld:    Label of rate from Quandl Treasury Rate data
    :param mat:    Maturity of bond considered
    :param freq:   Observation frequency
    :param pfreq:  Payment frequency of bond
    '''

    ylds = get_trs(True)
    ylds = ylds[ylds.index >= dt.datetime(2008, 8, 1)]
    ylds_monthly = resample_ylds(ylds)
    bnd_px = simulate_bond(ylds_monthly, yld=yld, mat=mat, freq=freq, pfreq=pfreq)

    tlh = get_symbol(symb)
    tlh = tlh[tlh.index >= dt.datetime(2008, 8, 1)]
    tlh_monthly = tlh.resample('M').last()
    tlh_monthly['px'] = tlh_monthly['Adj Close'] / tlh_monthly.ix[dt.datetime(2008, 8, 31), 'Adj Close']

    fig = plt.figure()
    ax = fig.add_subplot(1, 1, 1)
    fig.hold(True)
    ax.plot(bnd_px.index, bnd_px.px, label="30Yr Bond Index")
    ax.plot(bnd_px.index, bnd_px.p_c, label="Capital Component")
    ax.plot(bnd_px.index, bnd_px.c_c, label="Coupon Component")
    ax.plot(tlh_monthly.index, tlh_monthly.px, label="TLT ETF")

    vals = ax.get_yticks()
    ax.set_yticklabels(['{:3.2f}'.format(x * 100.0) for x in vals])
    plt.legend()
    plt.grid()
    plt.title('TLT ETF vs 30 Yr Simulated Bond Index')
    plt.show()


def sim_agg(cached=True):
    '''
    Function to simulate AGG ETF using a weighted average of the bond indexes generated from
    Quandl Treasury Rates
    '''

    tlh = get_symbol('AGG')
    tlh = tlh[tlh.index >= dt.datetime(2008, 8, 1)]
    tlh_monthly = tlh.resample('M').last()
    tlh_monthly['px'] = tlh_monthly['Adj Close'] / tlh_monthly.ix[dt.datetime(2008, 8, 31), 'Adj Close']
    vol = (tlh_monthly.px / tlh_monthly.px.shift(1) - 1).std()

    ylds = get_trs(cached)
    ylds = ylds[ylds.index >= dt.datetime(2008, 8, 1)]
    ylds_monthly = resample_ylds(ylds)
    px_l = ['Y01', 'Y02', 'Y03', 'Y05', 'Y07', 'Y10', 'Y20', 'Y30']
    ret = 0

    fig = plt.figure()
    ax = fig.add_subplot(1, 1, 1)
    fig.hold(True)

    for y in px_l:
        bnd = simulate_bond(ylds_monthly, yld=y, mat=int(y[1:]), freq=12, pfreq=2)
        bnd.ret = bnd.ret / bnd.ret.std() * vol
        # ax.plot(bnd.index,bnd.px, label=y)
        ret = ret + bnd.ret / len(px_l)

    px = (1 + ret).cumprod()
    ax.plot(px.index, px, label='Simulation')
    ax.plot(tlh_monthly.index, tlh_monthly.px, label='AGG')
    plt.legend()
    plt.grid()
    plt.title('TLT ETF vs 30 Yr Simulated Bond Index')
    plt.show()

    print((px / px.shift(1) - 1).std())
    print(vol)

    return [px, tlh_monthly]


def makedt(x):
    '''
    Helper function to convert Date column in Schiller data to Python datetime.date object
    '''

    d = dt.datetime.strptime(x, '%Y.%m') + dt.timedelta(days=32)
    d = d.replace(day=1)
    d = d - dt.timedelta(days=1)
    return d


def get_schiller():
    '''
    Function to grab and return as a DataFrame the time series for 10Y rates and SP500 since 1871
    '''

    url = 'http://www.econ.yale.edu/~shiller/data/ie_data.xls'
    response = requests.get(url)
    f = io.BytesIO(response.content)
    names = ['Dates', 'SP500', 'Dividend', 'Earnings', 'CPI', 'DateF', 'T10Y', 'RealPrice', 'RealDiv', 'RealEarn',
             'CAPE']
    df = pd.read_excel(io=f, sheet_name='Data', skiprows=7, skip_footer=1, names=names, usecols="A:K")
    df['Dates'] = df['Dates'].apply(lambda x: "{:0.2f}".format(x)).apply(makedt)
    return df


def long_term_bond():
    '''
    Function to plot S&P500 and 10Y Bond Index from Schiller Data
    '''

    df = get_schiller()
    px = simulate_bond(df, yld='T10Y', mat=10, freq=12, pfreq=2)
    a = df.SP500 / df.SP500[0]
    b = px.px / px.px[1]
    ix = df['Dates']
    plt.plot(ix, np.log(a), ix, np.log(b))
    ax = plt.gca()
    ax.xaxis.set_tick_params(labelsize=24)
    ax.yaxis.set_tick_params(labelsize=24)
    plt.grid(linewidth=2)
    plt.title('S&P500 vs 10 Year Bonds since 1871, Log Scale', fontsize=24)
    plt.show()


def px_vs_yld(stdt=None, eddt=None):
    '''
    Function to plot Bond Index price versus the corresponding Yield between a start and end date
    '''

    df = get_schiller()
    px = simulate_bond(df, yld='T10Y', mat=10, freq=12, pfreq=2)
    b = np.log(px.px / px.px[1])
    ix = df['Dates']

    if (stdt is None) or (eddt is None):
        iix = pd.Series(len(ix) * [True])
    else:
        iix = (ix > stdt) & (ix < eddt)

    fig, ax1 = plt.subplots()
    ax1.plot(ix[iix], b[iix])
    ax1.set_ylabel('bond index', fontdict={'size': 24})
    ax1.xaxis.set_tick_params(labelsize=24)
    plt.grid(linewidth=2)
    ax2 = ax1.twinx()
    ax2.plot(ix[iix], df['T10Y'][iix], color='red')
    ax2.set_ylabel('10Y Yield', color='red', fontdict={'size': 24})
    ax1.yaxis.set_tick_params(labelsize=24)
    ax2.yaxis.set_tick_params(labelsize=24)
    plt.title('10 Yr Bond Index vs Yield from 1871', fontsize=24)
    plt.show()


def bx_coup_cap(stdt=None, eddt=None):
    '''
    Function to plot Capital and Coupon contributions to Bond Index simulated from Schiller Data
    '''

    df = get_schiller()
    ix = df['Dates']
    if (stdt is None) or (eddt is None):
        iix = pd.Series(len(ix) * [True])
    else:
        iix = (ix > stdt) & (ix < eddt)

    px = simulate_bond(df[iix], yld='T10Y', mat=10, freq=12, pfreq=2)

    plt.plot(df['Dates'][iix], np.log(px.px / px.px.iloc[1]),
             df['Dates'][iix], np.log(px.p_c / px.p_c.iloc[1]),
             df['Dates'][iix], np.log(px.c_c / px.c_c.iloc[1]))
    ax = plt.gca()
    ax.yaxis.set_tick_params(labelsize=16)
    ax.xaxis.set_tick_params(labelsize=16)
    plt.legend(['Index Price', 'Index Capital Component', 'Index Coupon Component'])
    plt.grid(linewidth=2)
    plt.title('Coupon Income vs Capital Income during Bond Bear Market 1953/82',
              fontdict={'fontsize': 16, 'fontweight': 'bold'})
    plt.show()


def bx_vol(stdt=None, eddt=None):
    '''
    Function to plot the realized price volatility of a Bond Price index simulated from Schiller's Data
    '''

    df = get_schiller()
    ix = df['Dates']
    if (stdt is None) or (eddt is None):
        iix = pd.Series(len(ix) * [True])
    else:
        iix = (ix > stdt) & (ix < eddt)
    px = simulate_bond(df[iix], yld='T10Y', mat=10, freq=12, pfreq=2)
    ret = px.px / px.px.shift(1) - 1

    ss = ret.rolling(window=12).std() * math.sqrt(12)  # 2 year realized volatility
    plt.plot(df['Dates'][iix],
             ss)  # , df['Dates'][iix], ss.rolling(window=24).mean())  # 2 year vol and average over 100 months
    ax = plt.gca()
    ax.yaxis.set_tick_params(labelsize=16)
    ax.xaxis.set_tick_params(labelsize=16)
    plt.legend(['Yearly Standard Deviation of Bond Index'])
    plt.title('Yearly Standard Deviation of Bond Index', fontdict={'fontsize': 16, 'fontweight': 'bold'})
    plt.grid(linewidth=2)
    plt.show()


if __name__ == "__main__":
    run_option = 1

    if run_option == 1:
        # Figure of Treasury Rates from Quandl
        df = get_trs(False)
        plot_yld(df,yld=['Y01', 'Y10'])
    elif run_option == 2:
        # Comparison of bond index vs TLT
        simb(symb='TLT', yld='Y30', mat=30, freq=12, pfreq=2)
    elif run_option == 3:
        # AGG simulation
        sim_agg()
    elif run_option == 4:
        # Bond Index vs SP500 from Schiller data
        long_term_bond()
    elif run_option == 5:
        # Bond price index vs 10 Yr Yield from Schiller Data
        px_vs_yld()
        px_vs_yld(stdt = dt.date(1952,1,1), eddt=dt.date(1982,1,1))
    elif run_option == 6:
        # Capital and Coupon contributions for 10Yr Rate from Schiller Data
        bx_coup_cap(stdt=dt.date(1952,1,1), eddt=dt.date(1982,1,1))
    elif run_option == 7:
        # Bond Index Volatility
        bx_vol(stdt=dt.date(1949, 1, 1), eddt=dt.date(2019, 1, 1))

Filed Under: Market Dynamics Tagged With: Backtest, Bonds, Market Timing

Subscribe to Get the One Exercise which will Improve Your Foreign Exchange Trading Straight Away

  • Get rid of your fear of losing
  • Learn to stick to the rules
  • Achieve a Zen like state when you trade

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Browse Topics

Tags

ADP AUDUSD Backtest Bid Ask Bonds Breakout CHFJPY Commodities ECB Economic Indicators Economic Releases Emerging Markets Engulfing Candles Equities EURCHF EURSEK EURUSD FOMC FX G10 GBPUSD HFT Kelly Market Timing Mean Reversion Moon News Events News Trading NFP ORB Performance Measures PPP Python Range Expansion Recession Risk Parity Sharpe Ratio Slippage Solar Eclipse SP500 Trading Systems USD USDCAD USDCHF USDJPY

Subscribe to Get the One Exercise which will Improve Your Foreign Exchange Trading Straight Away

  • Get rid of your fear of losing
  • Learn to stick to the rules
  • Achieve a Zen like state when you trade

Search Site

Testimonials

Very insightful from an intelligent and talented individual. Life changing.
CASS Seminar
The bar in trader education has been set and I highly recommend anyone wishing to pursue a career in trading to invest in this program.         Jehan Jabar
One-on-One Coaching
Very well structured, interesting and insightfull
CASS Seminar
Very clear, engaging and insightful.
CASS Seminar
I really do rate everything with a “5.” Very good talk
CASS Seminar
Great teaching style. Very engaging. Material was presented in interesting manner and focused more on real life than theory.
CASS Seminar
Quick thank you for the suggestion to look at shorting the CHFJPY. Just closed at 122 pips profit. With only 9 pips Max loss. Nice.  Michele Russell
One-on-One Coaching
Excellent, funny. Very knowledgeable!
CASS Seminar

© 2023 · FXMasterCourse · Privacy Policy · Terms & Conditions · Earnings Disclaimer

This website uses cookies to improve your experience. We'll assume you're ok with this, but you can opt-out if you wish.Accept Read More
Privacy & Cookies Policy

Privacy Overview

This website uses cookies to improve your experience while you navigate through the website. Out of these, the cookies that are categorized as necessary are stored on your browser as they are essential for the working of basic functionalities of the website. We also use third-party cookies that help us analyze and understand how you use this website. These cookies will be stored in your browser only with your consent. You also have the option to opt-out of these cookies. But opting out of some of these cookies may affect your browsing experience.
Necessary
Always Enabled
Necessary cookies are absolutely essential for the website to function properly. This category only includes cookies that ensures basic functionalities and security features of the website. These cookies do not store any personal information.
Non-necessary
Any cookies that may not be particularly necessary for the website to function and is used specifically to collect user personal data via analytics, ads, other embedded contents are termed as non-necessary cookies. It is mandatory to procure user consent prior to running these cookies on your website.
SAVE & ACCEPT