US Treasuries#
…
#> Libraries
import numpy as np
import pandas as pd
# from IPython.display import display # import not required, maybe
import plotly.express as px
import plotly.graph_objects as go
import plotly.io as pio
from plotly.subplots import make_subplots
import yfinance as yf
#> Mount GDrive if required - for Colab editing
from pathlib import Path
# Detect Colab and mount Drive if needed
try:
from google.colab import drive
IN_COLAB = True
pio.renderers.default = "colab"
except ImportError:
IN_COLAB = False
pio.renderers.default = "iframe"
if IN_COLAB:
drive.mount('/content/drive')
%cd /content/drive/MyDrive/basics-books/repos/financial-edu/bbooks-financial-edu/ch/history
FILE_ROOT = Path.cwd()
print("Repo root:", FILE_ROOT)
Repo root: /home/davide/Documents/basics-books/books/bbooks-financial-edu/ch/history
#> Import Shiller data (.xls)
shiller_filen = str(FILE_ROOT) + "/../../code/data/shiller/ie_data.xlsx"
df_shiller = pd.read_excel(shiller_filen, sheet_name="Data", skiprows=7,) # engine="xlrd")
#> Clean data
#> Shiller
#> Remove non-data last row
df_shiller = df_shiller.iloc[:-1].copy()
#> Convert Data to proper datetime type
df_shiller["Date"] = df_shiller["Date"].map(lambda x: f"{x:.2f}")
df_shiller["Date"] = pd.to_datetime( df_shiller["Date"], format="%Y.%m")
#> Shiller, chapt 26 file, with yearly data
chap26_filen = str(FILE_ROOT) + "/../../code/data/shiller/chapt26.xlsx"
colnames = pd.read_excel(chap26_filen, sheet_name='Data', skiprows=2, nrows=1).columns
df_chap26 = pd.read_excel(chap26_filen, sheet_name="Data", skiprows=7, names=colnames)
df_chap26 = df_chap26.iloc[:-7].copy()
# Rename the first column to 'Year'
df_chap26.rename(columns={df_chap26.columns[0]: 'Year'}, inplace=True)
df_chap26['Year'] = df_chap26['Year'].astype(int)
df_chap26["T-Bill Return"] = ( 1. + df_chap26["R"]/100. ).shift(1).fillna(1).cumprod()
df_chap26["T-Bill Real Return"] = df_chap26["RealR"].shift(1).fillna(1).cumprod()
display(df_chap26.head())
display(df_chap26.tail())
| Year | P | D | E | R | RLONG | CPI | RealR | C | Unnamed: 9 | ... | P*C | RealD | Return | ln(1+ret) | RealE | P/E | E10 | P/E10 | T-Bill Return | T-Bill Real Return | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 1871 | 4.44 | 0.26 | 0.40 | 6.35 | 5.32 | 12.464061 | 1.047504 | Tab) | 1871.0 | ... | NaN | 4.731385 | 0.135809 | 0.127345 | 7.279054 | NaN | NaN | NaN | 1.000000 | 1.000000 |
| 1 | 1872 | 4.86 | 0.30 | 0.43 | 7.81 | 5.36 | 12.654392 | 1.054320 | in 2005 | 1872.0 | ... | NaN | 5.338874 | 0.088615 | 0.084907 | 7.652386 | 12.150000 | NaN | NaN | 1.063500 | 1.047504 |
| 2 | 1873 | 5.11 | 0.33 | 0.46 | 8.35 | 5.58 | 12.939807 | 1.133511 | dollars | 1873.0 | ... | NaN | 6.143830 | 0.021590 | 0.021360 | 8.564127 | 11.883721 | NaN | NaN | 1.146559 | 1.104405 |
| 3 | 1874 | 4.66 | 0.33 | 0.46 | 6.86 | 5.47 | 12.368896 | 1.148076 | NaN | 1874.0 | ... | NaN | 6.600773 | 0.122790 | 0.115817 | 9.201078 | 10.130435 | NaN | NaN | 1.242297 | 1.251855 |
| 4 | 1875 | 4.54 | 0.30 | 0.36 | 4.96 | 5.07 | 11.512651 | 1.114055 | NaN | 1875.0 | ... | NaN | 6.369199 | 0.112843 | 0.106918 | 7.643039 | 9.869565 | NaN | NaN | 1.327519 | 1.437225 |
5 rows × 23 columns
| Year | P | D | E | R | RLONG | CPI | RealR | C | Unnamed: 9 | ... | P*C | RealD | Return | ln(1+ret) | RealE | P/E | E10 | P/E10 | T-Bill Return | T-Bill Real Return | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 141 | 2012 | 1300.58 | 31.25 | 86.51 | NaN | 1.97 | 226.665 | 0.984302 | NaN | 2012.0 | ... | NaN | 31.25 | 0.144043 | 0.134569 | NaN | 14.957792 | 68.558322 | 20.265948 | 631.02331 | 34.699283 |
| 142 | 2013 | 1480.4 | 34.99 | 100.20 | NaN | 1.91 | 230.280 | NaN | NaN | 2013.0 | ... | NaN | NaN | NaN | NaN | NaN | NaN | 69.552621 | 21.593294 | 631.02331 | 34.154564 |
| 143 | 2014 | 1822.36 | 39.44 | 102.31 | NaN | 2.86 | 233.916 | NaN | NaN | NaN | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 631.02331 | 34.154564 |
| 144 | 2015 | 2028.18 | 43.39 | NaN | NaN | 1.88 | 233.707 | NaN | NaN | NaN | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 631.02331 | 34.154564 |
| 145 | 2016 | 1918.6 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 631.02331 | 34.154564 |
5 rows × 23 columns
Monthly total bond return. Given interest of 10-year bonds, with \(N = 10\) years
\[\begin{split}\begin{aligned}
M_n & = \underbrace{\frac{I_n}{12 \cdot 100}}_{\text{month coupon}} + \underbrace{\frac{I_n}{I_{n+1}} + \left( 1 + \frac{I_{n+1}}{12 \cdot 100} \right)^{-\frac{1}{12N-1}} \cdot \left( 1 - \frac{I_n}{I_{n+1}} \right)}_{\text{price change}} = \\
& = \underbrace{\frac{i_n}{12}}_{\text{month coupon}} + \underbrace{\frac{i_n}{i_{n+1}} + \left( 1 + \frac{i_{n+1}}{12} \right)^{-\frac{1}{12N-1}} \cdot \left( 1 - \frac{i_n}{i_{n+1}} \right)}_{\text{price change}} \ ,
\end{aligned}\end{split}\]
being \(I = 100 \cdot i\), the rates as a percentage.
Real total bond return.
\[T^R_{n+1} = T^R_n \cdot M_n \cdot \frac{\text{CPI}_n}{\text{CPI}_{n+1}} \ ,\]
being \(\frac{CPI_n}{CPI_{n+1}}\) the “realization” factor.
#> Inspection
# Rate GS10 : Interest Rate of 10Y Bond
# Returns : Monthly Total Bond Returns
# Returns.1 : Real Total Bond Returns
# Real Return : 10Y Annualized Stock Real Return
# Real Return.1: 10Y Annualized Bonds Real Return
# Real Return.2: Real 10Y Excess Annualized Returns
print(df_shiller.columns)
# display(df_shiller.head())
# display(df_shiller.tail())
Index(['Date', 'P', 'D', 'E', 'CPI', 'Fraction', 'Rate GS10', 'Price',
'Dividend', 'Price.1', 'Earnings', 'Earnings.1', 'CAPE', 'Unnamed: 13',
'TR CAPE', 'Unnamed: 15', 'Yield', 'Returns', 'Returns.1',
'Real Return', 'Real Return.1', 'Returns.2'],
dtype='object')
Return#
#> Evaluate nominal return, not contained in Shiller data
# df_shiller["10Y Bond Nominal Total Return"] = 1.
df_shiller["10Y Bond Nominal Total Return"] = df_shiller['Returns'].shift(1).fillna(1).cumprod()
display(df_shiller.head())
display(df_shiller.tail())
| Date | P | D | E | CPI | Fraction | Rate GS10 | Price | Dividend | Price.1 | ... | Unnamed: 13 | TR CAPE | Unnamed: 15 | Yield | Returns | Returns.1 | Real Return | Real Return.1 | Returns.2 | 10Y Bond Nominal Total Return | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 1871-01-01 | 4.44 | 0.26 | 0.4 | 12.464061 | 1871.041667 | 5.32 | 114.692610 | 6.716234 | 114.692610 | ... | NaN | NaN | NaN | NaN | 1.004177 | 1.000000 | 0.130609 | 0.092504 | 0.038106 | 1.000000 |
| 1 | 1871-02-01 | 4.5 | 0.26 | 0.4 | 12.844641 | 1871.125000 | 5.323333 | 112.798304 | 6.517235 | 113.341406 | ... | NaN | NaN | NaN | NaN | 1.004180 | 0.974424 | 0.130858 | 0.094635 | 0.036224 | 1.004177 |
| 2 | 1871-03-01 | 4.61 | 0.26 | 0.4 | 13.034972 | 1871.208333 | 5.326667 | 113.868307 | 6.422074 | 114.954311 | ... | NaN | NaN | NaN | NaN | 1.004183 | 0.964209 | 0.130951 | 0.096186 | 0.034765 | 1.008374 |
| 3 | 1871-04-01 | 4.74 | 0.26 | 0.4 | 12.559226 | 1871.291667 | 5.33 | 121.514327 | 6.665343 | 123.233997 | ... | NaN | NaN | NaN | NaN | 1.004185 | 1.004919 | 0.122056 | 0.090972 | 0.031084 | 1.012592 |
| 4 | 1871-05-01 | 4.86 | 0.26 | 0.4 | 12.273812 | 1871.375000 | 5.333333 | 127.487866 | 6.820339 | 129.868479 | ... | NaN | NaN | NaN | NaN | 1.004188 | 1.032591 | 0.122638 | 0.089488 | 0.033150 | 1.016830 |
5 rows × 23 columns
| Date | P | D | E | CPI | Fraction | Rate GS10 | Price | Dividend | Price.1 | ... | Unnamed: 13 | TR CAPE | Unnamed: 15 | Yield | Returns | Returns.1 | Real Return | Real Return.1 | Returns.2 | 10Y Bond Nominal Total Return | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 1850 | 2025-03-01 | 5683.983333 | 76.145301 | 216.69 | 319.799 | 2025.208333 | 4.28 | 5722.525411 | 76.661629 | 3845325.219 | ... | NaN | 37.348615 | NaN | 0.016749 | 1.003567 | 39.625790 | NaN | NaN | NaN | 1016.706201 |
| 1851 | 2025-04-01 | 5369.495714 | 76.546867 | NaN | 320.795 | 2025.291667 | 4.28 | 5389.121125 | 76.826645 | 3625591.938 | ... | NaN | 35.015341 | NaN | 0.018767 | 0.992343 | 39.643654 | NaN | NaN | NaN | 1020.332454 |
| 1852 | 2025-05-01 | 5810.919524 | 76.948434 | NaN | 321.465 | 2025.375000 | 4.42 | 5820.002899 | 77.068716 | 3919793.241 | ... | NaN | 37.769849 | NaN | 0.014834 | 1.006896 | 39.258095 | NaN | NaN | NaN | 1012.519392 |
| 1853 | 2025-06-01 | 6029.9515 | 77.350000 | NaN | 321.8 | 2025.458333 | 4.38 | 6033.090148 | 77.390261 | 4067651.835 | ... | NaN | 39.098992 | NaN | 0.014026 | 1.010099 | 39.487674 | NaN | NaN | NaN | 1019.501865 |
| 1854 | 2025-07-01 | 6279.35 | NaN | NaN | 321.9675 | 2025.541667 | 4.3 | 6279.350000 | NaN | 4233686.042 | ... | NaN | 40.590130 | NaN | 0.013847 | NaN | 39.865727 | NaN | NaN | NaN | 1029.798273 |
5 rows × 23 columns
#> Nominal and real value
fig = make_subplots(rows=2, cols=1, shared_xaxes=True, # vertical_spacing=0.1,
subplot_titles=("10Y T-Bond - Nominal Total Return", "10Y T-Bond - Real Total Return",)
)
#> 10Y T-Bonds
fig.add_trace(go.Scatter(x=df_shiller["Date"], y=df_shiller["10Y Bond Nominal Total Return"], name="10Y", line=dict(color="steelblue")),
row=1, col=1
)
fig.add_trace(go.Scatter(x=df_shiller["Date"], y=df_shiller["Returns.1"], name="10Y", line=dict(color="steelblue"), showlegend=False),
row=2, col=1
)
#> 1Y T-Bills
fig.add_trace(go.Scatter(x=df_chap26["Year"], y=df_chap26["T-Bill Return"], name="1Y", line=dict(color="orange")),
row=1, col=1
)
fig.add_trace(go.Scatter(x=df_chap26["Year"], y=df_chap26["T-Bill Real Return"], name="1Y", line=dict(color="orange"), showlegend=False),
row=2, col=1
)
fig.update_yaxes(type="log", row=1, col=1)
fig.update_yaxes(type="log", row=2, col=1)
fig.update_layout(showlegend=True,)
fig.show()