Skip to content

Commit ef8b0b9

Browse files
authored
Merge pull request #4 from gusamarante/feature/FRED
Adding examples with jupyter notebooks and refining code
2 parents 8fcd997 + ec158b3 commit ef8b0b9

File tree

7 files changed

+549
-161
lines changed

7 files changed

+549
-161
lines changed

README.md

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,26 @@ carries all the relevant variables as atributes:
2727
pip install pyacm
2828
```
2929

30-
# Example
31-
The tricky part is getting the correct data format. The model works with
32-
annualized log-yields for zero-coupon bonds, observed at daily or monthly
33-
frequency. Maturities must be equally spaced in monthly frequency and start
34-
at month 1. This means that you need to construct a bootstraped curve for every
35-
date and interpolate it at fixed monthly maturities.
36-
37-
MORE SOON...
30+
31+
# Original Article
32+
> Adrian, Tobias and Crump, Richard K. and Moench, Emanuel,
33+
> Pricing the Term Structure with Linear Regressions (April 11, 2013).
34+
> FRB of New York Staff Report No. 340,
35+
> Available at SSRN: https://ssrn.com/abstract=1362586 or http://dx.doi.org/10.2139/ssrn.1362586
36+
37+
The version of the article that was published by the NY FED is not 100% explicit on how the data is being manipulated,
38+
but I found an earlier version of the paper on SSRN where the authors go deeper into the details on how everything is being estimated:
39+
- Data for zero yields uses monthly maturities starting from month 1
40+
- All principal components and model parameters are estiamted with data resampled to a monthly frequency, averaging observations in each month
41+
- To get daily / real-time estimates, the factor loadings estimated from the monthly frquency are used to transform the daily data
42+
43+
44+
# Usage
45+
The tricky part of using this model is getting the correct data format:
46+
- The model works with annualized log-yields for zero-coupon bonds
47+
- Observations (index) must be in either monthly or daily frequency
48+
- Maturities (columns) must be equally spaced in **monthly** frequency and start at month 1. This means that you need to construct a bootstraped curve for every date and interpolate it at fixed monthly maturities.
49+
- Whichever maturity you want to be the longest, your input data should have one column more. For example, if you want term premium estimate up to the 10-year yield (120 months), your input data should include maturities up to 121 months. This is needed to properly compute the returns.
3850

3951

4052
# Observations

example.py

Lines changed: 0 additions & 146 deletions
This file was deleted.

example_br.ipynb

Lines changed: 434 additions & 0 deletions
Large diffs are not rendered by default.

pit_estimates.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
"""
2-
Generate point-in-time estimates
2+
Generate point-in-time estimates.
3+
4+
For each date, rerun the model and save the latest estimate of expected return
5+
and term premium
36
"""
47
from tqdm import tqdm
58
import pandas as pd
@@ -16,7 +19,7 @@
1619
yield_curve = yield_curve.iloc[:, :121] # maturities up to 10y
1720
yield_curve = yield_curve.dropna()
1821
yield_curve.index = pd.to_datetime(yield_curve.index)
19-
yield_curve = yield_curve[yield_curve.index >= "2007-03-01"] # TODO deal with this missing data
22+
yield_curve = yield_curve[yield_curve.index >= "2007-03-01"]
2023

2124
tp = pd.DataFrame(columns=yield_curve.columns)
2225
er = pd.DataFrame(columns=yield_curve.columns)

pyacm/__init__.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
from pyacm.acm import NominalACM
22

3-
__all__ = ["NominalACM"]
3+
__all__ = [
4+
"NominalACM",
5+
]

pyacm/acm.py

Lines changed: 83 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,88 @@ class NominalACM:
2626
month.
2727
- To get daily / real-time estimates, the factor loadings estimated
2828
from the monthly frquency are used to transform the daily data.
29+
30+
Attributes
31+
----------
32+
n_factors: int
33+
number of principal components used
34+
35+
curve: pandas.DataFrame
36+
Raw data of the yield curve
37+
38+
curve_monthly: pandas.DataFrame
39+
Yield curve data resampled to a monthly frequency by averageing
40+
the observations
41+
42+
t: int
43+
Number of observations in the timeseries dimension
44+
45+
n: int
46+
Number of observations in the cross-sectional dimension. Same
47+
as number of maturities available after returns are computed
48+
49+
rx_m: pd.DataFrame
50+
Excess returns in monthly frquency
51+
52+
rf_m: pandas.Series
53+
Risk-free rate in monthly frequency
54+
55+
rf_d: pandas.Series
56+
Risk-free rate in daily frequency
57+
58+
pc_factors_m: pandas.DataFrame
59+
Principal components in monthly frequency
60+
61+
pc_loadings_m: pandas.DataFrame
62+
Factor loadings of the monthly PCs
63+
64+
pc_explained_m: pandas.Series
65+
Percent of total variance explained by each monthly principal component
66+
67+
pc_factors_d: pandas.DataFrame
68+
Principal components in daily frequency
69+
70+
pc_loadings_d: pandas.DataFrame
71+
Factor loadings of the daily PCs
72+
73+
pc_explained_d: pandas.Series
74+
Percent of total variance explained by each monthly principal component
75+
76+
mu, phi, Sigma, v: numpy.array
77+
Estimates of the VAR(1) parameters, the first stage of estimation.
78+
The names are the same as the original paper
79+
80+
a, beta, c, sigma2: numpy.array
81+
Estimates of the risk premium equation, the second stage of estimation.
82+
The names are the same as the original paper
83+
84+
lambda0, lambda1: numpy.array
85+
Estimates of the price of risk parameters, the third stage of estimation.
86+
The names are the same as the original paper
87+
88+
miy: pandas.DataFrame
89+
Model implied / fitted yields
90+
91+
rny: pandas.DataFrame
92+
Risk neutral yields
93+
94+
tp: pandas.DataFrame
95+
Term premium estimates
96+
97+
er_loadings: pandas.DataFrame
98+
Loadings of the expected reutrns on the principal components
99+
100+
er_hist_m: pandas.DataFrame
101+
Historical estimates of expected returns, computed in-sample, in monthly frequency
102+
103+
er_hist_d: pandas.DataFrame
104+
Historical estimates of expected returns, computed in-sample, in daily frequency
105+
106+
z_lambda: pandas.DataFrame
107+
Z-stat for inference on the price of risk parameters
108+
109+
z_beta: pandas.DataFrame
110+
Z-stat for inference on the loadings of expected returns
29111
"""
30112

31113
def __init__(self, curve, n_factors=5):
@@ -48,7 +130,7 @@ def __init__(self, curve, n_factors=5):
48130

49131
self.n_factors = n_factors
50132
self.curve = curve
51-
self.curve_monthly = curve.resample('M').mean()
133+
self.curve_monthly = curve.resample('ME').mean()
52134
self.t = self.curve_monthly.shape[0] - 1
53135
self.n = self.curve_monthly.shape[1]
54136
self.rx_m, self.rf_m = self._get_excess_returns()

setup.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,15 @@
2222
long_description=long_description,
2323
packages=find_packages(),
2424
install_requires=[
25+
'matplotlib',
26+
'numpy',
2527
'pandas',
2628
'scikit-learn',
27-
'numpy',
28-
'matplotlib',
29+
'tqdm',
2930
],
3031
keywords=[
3132
'asset pricing',
3233
'yield curve',
3334
'term premium',
3435
],
35-
)
36+
)

0 commit comments

Comments
 (0)