Almost there..

This commit is contained in:
jeroen
2023-02-22 16:04:53 +01:00
parent 71e4accb11
commit 05a09fda8a
6 changed files with 403 additions and 31 deletions

View File

@@ -144,7 +144,6 @@ def display_ecb_yield_curve(
export : str
Export data to csv,json,xlsx or png,jpg,pdf,svg file
"""
print(date)
rates, date_of_yield = ecb_model.get_ecb_yield_curve(
date, yield_type, True, detailed, any_rating
)

View File

@@ -47,8 +47,10 @@ class FixedIncomeController(BaseController):
"ecbycrv",
"usrates",
"icebofa",
"moody",
"cp",
"spot",
"hqm",
"icespread",
"tbffr",
]
@@ -171,7 +173,7 @@ class FixedIncomeController(BaseController):
def print_help(self):
"""Print help"""
mt = MenuText("fixedincome/")
mt = MenuText("fixedincome/", column_sources=120)
mt.add_info("_reference_rates_")
mt.add_cmd("estr")
mt.add_cmd("sofr")
@@ -193,8 +195,10 @@ class FixedIncomeController(BaseController):
mt.add_raw("\n")
mt.add_info("_corporate_bonds_")
mt.add_cmd("icebofa")
mt.add_cmd("moody")
mt.add_cmd("cp")
mt.add_cmd("spot")
mt.add_cmd("hqm")
mt.add_raw("\n")
mt.add_info("_spreads_")
mt.add_cmd("icespread")
@@ -1197,6 +1201,70 @@ class FixedIncomeController(BaseController):
if ns_parser.sheet_name
else None,
)
@log_start_end(log=logger)
def call_moody(self, other_args: List[str]):
"""Process moody command"""
parser = argparse.ArgumentParser(
add_help=False,
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
prog="moody",
description="Moody's Aaa and Baa are investment bonds that acts as an index of "
"the performance of all bonds given an Aaa or Baa rating by Moody's Investors Service respectively"
"These corporate bonds often are used in macroeconomics as an alternative to the federal ten-year "
"Treasury Bill as an indicator of the interest rate."
)
parser.add_argument(
"-t",
"--type",
dest="data_type",
type=str,
help="What type you'd like to collect data for",
default="aaa",
choices=fred_view.MOODY_TO_OPTIONS['Type'].keys()
)
parser.add_argument(
"--spread",
dest="spread",
type=str,
help="Whether you want to show the spread",
default=None,
choices=fred_view.MOODY_TO_OPTIONS['Spread']
)
parser.add_argument(
"-s",
"--start",
dest="start_date",
type=valid_date,
help="Starting date (YYYY-MM-DD) of data",
default="1980-01-01",
)
parser.add_argument(
"-e",
"--end",
dest="end_date",
type=valid_date,
help="Ending date (YYYY-MM-DD) of data",
default=None,
)
ns_parser = self.parse_known_args_and_warn(
parser, other_args, EXPORT_BOTH_RAW_DATA_AND_FIGURES, raw=True
)
if ns_parser:
fred_view.plot_moody(
data_type=ns_parser.data_type,
spread=ns_parser.spread,
start_date=ns_parser.start_date,
end_date=ns_parser.end_date,
raw=ns_parser.raw,
export=ns_parser.export,
sheet_name=" ".join(ns_parser.sheet_name)
if ns_parser.sheet_name
else None,
)
@log_start_end(log=logger)
@@ -1206,8 +1274,10 @@ class FixedIncomeController(BaseController):
add_help=False,
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
prog="cp",
description="Plot various rates from the United States. This includes tbill (Treasury Bills), "
"Constant Maturity treasuries (cmn) and Inflation Protected Treasuries (TIPS)",
description="Commercial paper (CP) consists of short-term, promissory notes "
"issued primarily by corporations. Maturities range up to 270 days but average "
"about 30 days. Many companies use CP to raise cash needed for current "
"transactions, and many find it to be a lower-cost alternative to bank loans."
)
parser.add_argument(
@@ -1306,8 +1376,10 @@ class FixedIncomeController(BaseController):
add_help=False,
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
prog="spot",
description="Plot various rates from the United States. This includes tbill (Treasury Bills), "
"Constant Maturity treasuries (cmn) and Inflation Protected Treasuries (TIPS)",
description="The spot rate for any maturity is the yield on a bond that provides "
"a single payment at that maturity. This is a zero coupon bond. Because each "
"spot rate pertains to a single cashflow, it is the relevant interest rate "
"concept for discounting a pension liability at the same maturity."
)
parser.add_argument(
@@ -1372,6 +1444,51 @@ class FixedIncomeController(BaseController):
if ns_parser.sheet_name
else None,
)
@log_start_end(log=logger)
def call_hqm(self, other_args: List[str]):
"""Process hqdm command"""
parser = argparse.ArgumentParser(
add_help=False,
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
prog="hqm",
description="The HQM yield curve represents the high quality corporate bond market, i.e., "
"corporate bonds rated AAA, AA, or A. The HQM curve contains two regression terms. These "
"terms are adjustment factors that blend AAA, AA, and A bonds into a single HQM yield curve "
"that is the market-weighted average (MWA) quality of high quality bonds.",
)
parser.add_argument(
"-d",
"--date",
dest="date",
type=valid_date,
help="Define the date of the yield curve.",
default=None
)
parser.add_argument(
"-p",
"--par",
dest="par",
action='store_true',
help="Whether to include the Par Yield.",
default=False
)
ns_parser = self.parse_known_args_and_warn(
parser, other_args, EXPORT_BOTH_RAW_DATA_AND_FIGURES, raw=True
)
if ns_parser:
fred_view.plot_cycrv(
date=ns_parser.date.strftime("%Y-%m-%d") if ns_parser.date else "",
par=ns_parser.par,
raw=ns_parser.raw,
export=ns_parser.export,
sheet_name=" ".join(ns_parser.sheet_name)
if ns_parser.sheet_name
else None,
)
@log_start_end(log=logger)
def call_icespread(self, other_args: List[str]):

View File

@@ -40,9 +40,31 @@ YIELD_CURVE_SERIES_REAL = {
"30Year": "DFII30",
}
YIELD_CURVE_NOMINAL_RATES = [1 / 12, 0.25, 0.5, 1, 2, 3, 5, 7, 10, 20, 30]
YIELD_CURVE_REAL_RATES = [5, 7, 10, 20, 30]
YIELD_CURVE_SERIES_CORPORATE_SPOT = {
"6Month": "HQMCB6MT",
"1Year": "HQMCB1YR",
"2Year": "HQMCB2YR",
"3Year": "HQMCB3YR",
"5Year": "HQMCB5YR",
"7Year": "HQMCB7YR",
"10Year": "HQMCB10YR",
"20Year": "HQMCB20YR",
"30Year": "HQMCB30YR",
"50Year": "HQMCB50YR",
"75Year": "HQMCB75YR",
"100Year": "HQMCB100YR"
}
YIELD_CURVE_SERIES_CORPORATE_PAR = {
"2Year": "HQMCB2YRP",
"5Year": "HQMCB5YRP",
"10Year": "HQMCB10YRP",
"30Year": "HQMCB30YRP",
}
YIELD_CURVE_NOMINAL_RATES = [1 / 12, 0.25, 0.5, 1, 2, 3, 5, 7, 10, 20, 30]
YIELD_CURVE_SPOT_RATES = [0.5, 1, 2, 3, 5, 7, 10, 20, 30, 50, 75, 100]
YIELD_CURVE_REAL_RATES = [5, 7, 10, 20, 30]
YIELD_CURVE_PAR_RATES = [2, 5, 10, 30]
@log_start_end(log=logger)
@check_api_key(["API_FRED_KEY"])
@@ -83,7 +105,7 @@ def get_series_data(
@log_start_end(log=logger)
@check_api_key(["API_FRED_KEY"])
def get_yield_curve(
date: str = "", return_date: bool = False, inflation_adjusted: bool = False
date: str = "", return_date: bool = False, inflation_adjusted: bool = False, spot_or_par: str = None
) -> Tuple[pd.DataFrame, str]:
"""Gets yield curve data from FRED.
@@ -134,6 +156,7 @@ def get_yield_curve(
fredapi_client = Fred(cfg.API_FRED_KEY)
df = pd.DataFrame()
# Check that the date is in the past
today = datetime.now().strftime("%Y-%m-%d")
if date and date >= today:
@@ -142,16 +165,27 @@ def get_yield_curve(
return pd.DataFrame(), date
return pd.DataFrame()
# Add in logic that will get the most recent date.
get_last = False
if not date:
date = (datetime.now() - timedelta(days=7)).strftime("%Y-%m-%d")
# Add in logic that will get the most recent date
if date:
get_last = False
start_date = (datetime.strptime(date, "%Y-%m-%d") - timedelta(days=50)).strftime("%Y-%m-%d")
else:
date = datetime.now().strftime("%Y-%m-%d")
start_date = (datetime.now() - timedelta(days=50)).strftime("%Y-%m-%d")
get_last = True
if inflation_adjusted:
fred_series = YIELD_CURVE_SERIES_REAL
years = YIELD_CURVE_REAL_RATES
elif spot_or_par:
if spot_or_par == "spot":
years = YIELD_CURVE_SPOT_RATES
fred_series = YIELD_CURVE_SERIES_CORPORATE_SPOT
elif spot_or_par == "par":
years = YIELD_CURVE_PAR_RATES
fred_series = YIELD_CURVE_SERIES_CORPORATE_PAR
else:
console.print("Please select either 'spot' or 'par' rates.")
else:
fred_series = YIELD_CURVE_SERIES_NOMINAL
years = YIELD_CURVE_NOMINAL_RATES
@@ -160,7 +194,7 @@ def get_yield_curve(
df = pd.concat(
[
df,
pd.DataFrame(fredapi_client.get_series(s_id, date), columns=[key]),
pd.DataFrame(fredapi_client.get_series(s_id, start_date), columns=[key]),
],
axis=1,
)
@@ -176,6 +210,10 @@ def get_yield_curve(
idx = -1 if get_last else 0
date_of_yield = df.index[idx].strftime("%Y-%m-%d")
rates = pd.DataFrame(df.iloc[idx, :].values, columns=["Rate"])
if spot_or_par:
console.print(f"Because {spot_or_par.title()} rates are published monthly, "
f"the nearest date to {date} is used which is {date_of_yield}.")
else:
date_of_yield = date
series = df[df.index == date]

View File

@@ -176,6 +176,27 @@ ICE_BOFA_TO_OPTIONS = {
'public_sector']
}
MOODY_TO_OPTIONS = {
"Type": {"aaa": {
'index': {
"id": "DAAA", "name": "Moody's Seasoned Aaa Corporate Bond Yield"},
'treasury': {
"id": "AAA10Y", "name": "Moody's Seasoned Aaa Corporate Bond Yield Relative to Yield on 10-Year Treasury Constant Maturity"},
"fed_funds":
{"id": "AAAFF", "name": "Moody's Seasoned Aaa Corporate Bond Minus Federal Funds Rate"},
},
"baa": {
'index': {
"id": "DBAA", "name": "Moody's Seasoned Baa Corporate Bond Yield"},
'treasury': {
"id": "BAA10Y", "name": "Moody's Seasoned Baa Corporate Bond Yield Relative to Yield on 10-Year Treasury Constant Maturity"},
"fed_funds":
{"id": "BAAFF", "name": "Moody's Seasoned Baa Corporate Bond Minus Federal Funds Rate"},
},
},
"Spread": ['treasury', 'fed_funds']
}
CP_TO_OPTIONS = {
'Maturity': ['15d', '30d', '60d', '7d', '90d', 'overnight'],
'Category': ['asset_backed', 'financial', 'non_financial', 'spread'],
@@ -699,8 +720,9 @@ def plot_fftr(
df.index,
df.values,
)
ax.set_title("Federal Funds Target Range [Percent]")
ax.set_title("Federal Funds Target Range")
ax.legend(["Upper limit", "Lower limit"])
ax.set_ylabel("Yield (%)")
theme.style_primary_axis(ax)
if external_axes is None:
@@ -916,7 +938,8 @@ def plot_iorb(
df.values,
color=next(colors, "#FCED00"),
)
ax.set_title("Interest Rate on Reserve Balances [Percent]")
ax.set_title("Interest Rate on Reserve Balances")
ax.set_ylabel("Yield (%)")
theme.style_primary_axis(ax)
if external_axes is None:
@@ -1058,8 +1081,8 @@ def plot_dwpcr(
)
ax.set_title(
"Discount Window Primary Credit Rate "
+ ID_TO_NAME_DWPCR[series_id]
+ " [Percent]"
+ ID_TO_NAME_DWPCR[series_id],
fontsize=10
)
theme.style_primary_axis(ax)
@@ -1222,7 +1245,8 @@ def plot_ecbmlfr(
df.values,
color=next(colors, "#FCED00"),
)
ax.set_title("ECB Marginal Lending Facility Rate for Euro Area [Percent]")
ax.set_title("ECB Marginal Lending Facility Rate for Euro Area")
ax.set_ylabel("Yield (%)")
theme.style_primary_axis(ax)
if external_axes is None:
@@ -1282,8 +1306,9 @@ def plot_ecbmrofr(
color=next(colors, "#FCED00"),
)
ax.set_title(
"ECB Main Refinancing Operations Rate: Fixed Rate Tenders for Euro Area [Percent]"
"ECB Main Refinancing Operations Rate: Fixed Rate Tenders for Euro Area"
)
ax.set_ylabel("Yield (%)")
theme.style_primary_axis(ax)
if external_axes is None:
@@ -1348,8 +1373,11 @@ def plot_tmc(
ax.set_title(
"10-Year Treasury Constant Maturity Minus "
+ ID_TO_NAME_TMC[series_id]
+ " Treasury Constant Maturity [Percent]"
+ " Treasury Constant Maturity",
fontsize=10
)
ax.set_ylabel("Yield (%)")
theme.style_primary_axis(ax)
if external_axes is None:
@@ -1413,7 +1441,8 @@ def plot_ffrmc(
)
ax.set_title(
ID_TO_NAME_FFRMC[series_id]
+ " Treasury Constant Maturity Minus Federal Funds Rate [Percent]"
+ " Treasury Constant Maturity Minus Federal Funds Rate",
fontsize=10
)
theme.style_primary_axis(ax)
@@ -1481,7 +1510,7 @@ def display_yield_curve(
ax.plot(rates["Maturity"], rates["Rate"], "-o")
ax.set_xlabel("Maturity")
ax.set_ylabel("Rate (%)")
ax.set_ylabel("Yield (%)")
theme.style_primary_axis(ax)
if external_axes is None:
ax.set_title(
@@ -1582,7 +1611,7 @@ def plot_usrates(
title = f"{maturity.replace('_', ' ').title()} Yields on Treasury inflation protected securities (TIPS) adjusted to constant maturities"
ax.set_title(title, fontsize=15)
ax.set_ylabel("Yield (%})")
ax.set_ylabel("Yield (%)")
theme.style_primary_axis(ax)
if external_axes is None:
@@ -1650,10 +1679,11 @@ def plot_tbffr(
)
ax.set_title(
ID_TO_NAME_TBFFR[series_id]
+ " Treasury Bill Minus Federal Funds Rate [Percent]"
+ " Treasury Bill Minus Federal Funds Rate"
)
theme.style_primary_axis(ax)
ax.set_ylabel("Yield (%)")
if external_axes is None:
theme.visualize_output()
@@ -1830,6 +1860,94 @@ def plot_icebofa(
df / 100,
sheet_name,
)
@log_start_end(log=logger)
@check_api_key(["API_FRED_KEY"])
def plot_moody(
data_type: str = "aaa",
spread: str = None,
start_date: Optional[str] = None,
end_date: Optional[str] = None,
raw: bool = False,
export: str = "",
sheet_name: str = "",
external_axes: Optional[List[plt.Axes]] = None,
):
"""Plot ICE BofA US Corporate Bond Index data.
Parameters
----------
data_type: str
The type of data you want to see, either "yield", "yield_to_worst", "total_return", or "spread"
category: str
The type of category you want to see, either "all", "duration", "eur" or "usd".
area: str
The type of area you want to see, either "asia", "emea", "eu", "ex_g10", "latin_america" or "us"
grade: str
The type of grade you want to see, either "a", "aa", "aaa", "b", "bb", "bbb", "ccc", "crossover",
"high_grade", "high_yield", "non_financial", "non_sovereign", "private_sector", "public_sector"
start_date: Optional[str]
Start date, formatted YYYY-MM-DD
end_date: Optional[str]
End date, formatted YYYY-MM-DD
raw: bool
Show raw data
export: str
Export data to csv or excel file
sheet_name: str
Name of the sheet to export to
external_axes: Optional[List[plt.Axes]]
External axes (1 axis is expected in the list)
"""
series_id = MOODY_TO_OPTIONS['Type'][data_type][spread if spread else 'index']['id']
name = MOODY_TO_OPTIONS['Type'][data_type][spread if spread else 'index']['name']
series = fred_model.get_series_data(
series_id=series_id, start_date=start_date, end_date=end_date
)
df = pd.DataFrame(series, columns=[f"{data_type}_{spread if spread else 'index'}"])
df.index = pd.to_datetime(df.index).date
# This plot has 1 axis
if not external_axes:
_, ax = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI)
elif is_valid_axes_count(external_axes, 1):
(ax,) = external_axes
else:
return
colors = cycle(theme.get_colors())
ax.plot(
df.index,
df.values,
color=next(colors, "#FCED00"),
)
ax.set_title(name, fontsize=10)
ax.set_ylabel("Yield (%)")
theme.style_primary_axis(ax)
if external_axes is None:
theme.visualize_output()
if raw:
print_rich_table(
df.iloc[-10:],
title=name,
show_index=True,
floatfmt=".3f",
)
export_data(
export,
os.path.dirname(os.path.abspath(__file__)),
"MOODY",
df / 100,
sheet_name,
)
@log_start_end(log=logger)
@check_api_key(["API_FRED_KEY"])
@@ -1962,7 +2080,11 @@ def plot_spot(
sheet_name: str = "",
external_axes: Optional[List[plt.Axes]] = None,
):
"""Plot ICE BofA US Corporate Bond Index data.
"""
The spot rate for any maturity is the yield on a bond that provides
a single payment at that maturity. This is a zero coupon bond. Because each
spot rate pertains to a single cashflow, it is the relevant interest rate
concept for discounting a pension liability at the same maturity.
Parameters
----------
@@ -2058,4 +2180,90 @@ def plot_spot(
"SPOT",
df / 100,
sheet_name,
)
@log_start_end(log=logger)
@check_api_key(["API_FRED_KEY"])
def plot_hqm(
date: Optional[str] = None,
par: bool = False,
raw: bool = False,
export: str = "",
sheet_name: str = "",
external_axes: Optional[List[plt.Axes]] = None,
):
"""
The HQM yield curve represents the high quality corporate bond market, i.e.,
corporate bonds rated AAA, AA, or A. The HQM curve contains two regression terms. These
terms are adjustment factors that blend AAA, AA, and A bonds into a single HQM yield curve
that is the market-weighted average (MWA) quality of high quality bonds.
Parameters
----------
date: str
The date of the yield curve you wish to plot
par: bool
Whether you wish to plot the par yield curve as well
raw: bool
Show raw data
export: str
Export data to csv or excel file
sheet_name: str
Name of the sheet to export to
external_axes: Optional[List[plt.Axes]]
External axes (1 axis is expected in the list)
"""
df = pd.DataFrame()
data_types = ["spot", "par"] if par else ['spot']
for types in data_types:
subset, date_of_yield = fred_model.get_yield_curve(date, True, spot_or_par=types)
subset.set_index('Maturity', inplace=True)
subset.columns = [types]
df = pd.concat([df, subset], axis=1)
if par:
# Drop NaNs because of length mismatch
df = df.dropna()
if df.empty:
console.print(f"[red]Yield data not found at {date_of_yield}.[/red]\n")
# This plot has 1 axis
if not external_axes:
_, ax = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI)
elif is_valid_axes_count(external_axes, 1):
(ax,) = external_axes
else:
return
for types in data_types:
ax.plot(df.index, df[types], label=f"{types.title()} Yield")
ax.set_title(f"Spot{'and Par' if par else ''} Yield Curve for {date_of_yield}")
ax.set_xlabel("Maturity")
ax.set_ylabel("Yield (%)")
ax.legend() if par else None
theme.style_primary_axis(ax)
if external_axes is None:
theme.visualize_output()
if raw:
print_rich_table(
df,
headers=list(df.columns),
show_index=True,
index_name="Maturity",
title=f"Spot {'and Par' if par else ''} Yield Curve for {date_of_yield}",
floatfmt=".3f",
)
export_data(
export,
os.path.dirname(os.path.abspath(__file__)),
"cycrv",
df / 100,
sheet_name,
)

View File

@@ -505,6 +505,12 @@
"usrates": ["FRED"],
"ycrv": ["FRED"],
"ecbycrv": ["ECB"],
"icebofa": ["FRED"],
"moody": ["FRED"],
"spot": ["FRED"],
"cp": ["FRED"],
"hqm": ["FRED"],
"icespread": ["FRED"],
"tmc": ["FRED"],
"ffrmc": ["FRED"],
"tbffr": ["FRED"]

View File

@@ -792,11 +792,15 @@ en:
fixedincome/ecb: key ECB interest rates
fixedincome/_government_bonds_: Government Bonds
fixedincome/treasury: plot countries (including forecast) treasury rates
fixedincome/usrates: plot secondary market, constant maturity or inflation protected rates
fixedincome/ycrv: plot US yield curve
fixedincome/ecbycrv: plot euro area yield curve
fixedincome/usrates: plot U.S. secondary market, constant maturity or inflation protected treasuries
fixedincome/ycrv: plot the yield curve based on constant maturity U.S. treasuries
fixedincome/ecbycrv: plot the yield curve based on Euro Area treasuries
fixedincome/_corporate_bonds_: Corporate Bonds
fixedincome/icebofa: display ICE BofA Corporate Indices
fixedincome/moody: display Moody's AAA and BAA Corporate indices
fixedincome/cp: display short-term, promissory notes issued by corporations
fixedincome/spot: display spot rates ranging from 1 year to a 100 years
fixedincome/hqm: display the High Quality Market (HQM) corporate yield curve
fixedincome/_spreads_: Spreads
fixedincome/icespread: display spread between ICE BofA Corporate Indices and spot treasury curve
fixedincome/tmc: 10-year treasury constant maturity minus selected treasury constant maturity