diff --git a/openbb_terminal/fixedincome/ecb_model.py b/openbb_terminal/fixedincome/ecb_model.py index 14ab0c76e3d..5a15ea299c4 100644 --- a/openbb_terminal/fixedincome/ecb_model.py +++ b/openbb_terminal/fixedincome/ecb_model.py @@ -8,7 +8,7 @@ from typing import Tuple import pandas as pd from openbb_terminal.decorators import log_start_end -from openbb_terminal.rich_config import console +from openbb_terminal.rich_config import console, optional_rich_track logger = logging.getLogger(__name__) @@ -49,7 +49,7 @@ def get_ecb_yield_curve( yield_type: str = "spot_rate", return_date: bool = False, detailed: bool = False, - aaa_only: bool = True, + any_rating: bool = True, ) -> Tuple[pd.DataFrame, str]: """Gets euro area yield curve data from ECB. @@ -97,11 +97,11 @@ def get_ecb_yield_curve( >>> ycrv_df, ycrv_date = openbb.fixedincome.ycrv(return_date=True) """ if yield_type == "spot_rate": - yield_type = f"YC.B.U2.EUR.4F.G_N_{'A' if aaa_only else 'C'}.SV_C_YM.SR_" + yield_type = f"YC.B.U2.EUR.4F.G_N_{'A' if any_rating else 'C'}.SV_C_YM.SR_" elif yield_type == "instantaneous_forward": - yield_type = f"YC.B.U2.EUR.4F.G_N_{'A' if aaa_only else 'C'}.SV_C_YM.IF_" + yield_type = f"YC.B.U2.EUR.4F.G_N_{'A' if any_rating else 'C'}.SV_C_YM.IF_" elif yield_type == "par_yield": - yield_type = f"YC.B.U2.EUR.4F.G_N_{'A' if aaa_only else 'C'}.SV_C_YM.PY" + yield_type = f"YC.B.U2.EUR.4F.G_N_{'A' if any_rating else 'C'}.SV_C_YM.PY" else: console.print("[red]Incorrect input for parameter yield_type[/red]") if return_date: @@ -109,6 +109,7 @@ def get_ecb_yield_curve( return pd.DataFrame() if detailed: + console.print("Note that due to the large amount of data, this may take a while. Use CTRL + C to cancel.") series_id = [ f"{yield_type}{y}Y{m}M" if y != 0 else f"{yield_type}{m}M" for y in range(0, 30) @@ -149,10 +150,14 @@ def get_ecb_yield_curve( if not date: date = (datetime.now() - timedelta(days=1)).strftime("%Y-%m-%d") - for i in range(len(series_id)): - temp = get_series_data(series_id[i], date, date) - temp.columns = [labels[i]] - df = pd.concat([df, temp], axis=1) + try: + for i in optional_rich_track( range(len(series_id)), desc="Obtaining yield curve data"): + temp = get_series_data(series_id[i], date, date) + temp.columns = [labels[i]] + df = pd.concat([df, temp], axis=1) + except KeyboardInterrupt: + console.print("Data collection was canceled.") + return pd.DataFrame(), date if df.empty: if return_date: @@ -162,8 +167,13 @@ def get_ecb_yield_curve( # Drop rows with NaN -- corresponding to weekends typically df = df.dropna() if datetime.strptime(date, "%Y-%m-%d") not in df.index: - date_of_yield = df.index[-1].strftime("%Y-%m-%d") - rates = pd.DataFrame(df.iloc[-1, :].values, columns=["Rate"]) + nearest_value = df.index.get_indexer([datetime.strptime(date, "%Y-%m-%d")], method='nearest') + date_of_yield = df.iloc[nearest_value].index[0].date() + series = df[df.index == df.iloc[nearest_value].index[0]] + if series.empty: + return pd.DataFrame(), date_of_yield + rates = pd.DataFrame(series.values.T, columns=["Rate"]) + console.print(f"{date} not available, therefore selecting the nearest date, {date_of_yield}.") else: date_of_yield = date series = df[df.index == datetime.strptime(date, "%Y-%m-%d")] diff --git a/openbb_terminal/fixedincome/ecb_view.py b/openbb_terminal/fixedincome/ecb_view.py index 4e794773cb8..3b3e733f66f 100644 --- a/openbb_terminal/fixedincome/ecb_view.py +++ b/openbb_terminal/fixedincome/ecb_view.py @@ -107,7 +107,7 @@ def display_ecb_yield_curve( date: str = "", yield_type: str = "spot_rate", detailed: bool = False, - aaa_only: bool = True, + any_rating: bool = True, external_axes: Optional[List[plt.Axes]] = None, raw: bool = False, export: str = "", @@ -148,8 +148,9 @@ 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, aaa_only + date, yield_type, True, detailed, any_rating ) if rates.empty: console.print(f"[red]Yield data not found for {date_of_yield}.[/red]\n") @@ -167,8 +168,9 @@ def display_ecb_yield_curve( theme.style_primary_axis(ax) if external_axes is None: ax.set_title( - f"Euro Area{' AAA Bonds' if aaa_only else ' All Bonds'} {yield_type.replace('_', ' ').title()} " - f"Yield Curve for {date_of_yield}" + f"Euro Area{' AAA Bonds' if not any_rating else ' All Bonds'} {yield_type.replace('_', ' ').title()} " + f"Yield Curve for {date_of_yield}", + fontsize=15 ) theme.visualize_output() @@ -177,7 +179,7 @@ def display_ecb_yield_curve( rates, headers=list(rates.columns), show_index=False, - title=f"Euro Area{' AAA Bonds' if aaa_only else ' All Bonds'} {yield_type.replace('_', ' ').title()} " + title=f"Euro Area{' AAA Bonds' if not any_rating else ' All Bonds'} {yield_type.replace('_', ' ').title()} " f"Yield Curve for {date_of_yield}", floatfmt=".3f", ) @@ -186,6 +188,6 @@ def display_ecb_yield_curve( export, os.path.dirname(os.path.abspath(__file__)), "ecbycrv", - pd.DataFrame(rates, columns=[date_of_yield]) / 100, + rates / 100, sheet_name ) diff --git a/openbb_terminal/fixedincome/fixedincome_controller.py b/openbb_terminal/fixedincome/fixedincome_controller.py index b70361ed022..ec441063cbf 100644 --- a/openbb_terminal/fixedincome/fixedincome_controller.py +++ b/openbb_terminal/fixedincome/fixedincome_controller.py @@ -7,6 +7,7 @@ import argparse import logging from datetime import datetime, timedelta from typing import List +import pandas as pd from openbb_terminal.custom_prompt_toolkit import NestedCompleter @@ -18,6 +19,7 @@ from openbb_terminal.fixedincome import fred_view, oecd_model from openbb_terminal.helper_funcs import ( EXPORT_BOTH_RAW_DATA_AND_FIGURES, list_from_str, + print_rich_table, valid_date, EXPORT_ONLY_RAW_DATA_ALLOWED, ) @@ -45,13 +47,9 @@ class FixedIncomeController(BaseController): "tmc", "ffrmc", "ycrv", - "iiycrv", "ecbycrv", - "tbill", - "tips", - "cmn", + "usrates", "tbffr", - "ty" ] PATH = "/fixedincome/" @@ -138,32 +136,7 @@ class FixedIncomeController(BaseController): "6_month": "T6MFF", "3_month": "T3MFF", } - tbill_parameter_to_fred_id = { - "4_week": "DTB4WK", - "3_month": "TB3MS", - "6_month": "DTB6", - "1_year": "DTB1YR", - } - tips_parameter_to_fred_id = { - "5_year": "DFII5", - "7_year": "DFII7", - "10_year": "DFII10", - "20_year": "DFII20", - "30_year": "DFII30", - } - cmn_parameter_to_fred_id = { - "1_month": "DGS1MO", - "3_month": "DGS3MO", - "6_month": "DGS6MO", - "1_year": "DGS1", - "2_year": "DGS2", - "3_year": "DGS3", - "5_year": "DGS5", - "7_year": "DGS7", - "10_year": "DGS10", - "20_year": "DGS20", - "30_year": "DGS30", - } + tbffr_parameter_to_fred_id = { "3_month": "TB3SMFFM", "6_month": "TB6SMFFM", @@ -197,15 +170,14 @@ class FixedIncomeController(BaseController): mt.add_raw("\n") mt.add_info("_government_bonds_") mt.add_cmd("treasury") + mt.add_cmd("usrates") mt.add_cmd("ycrv") - mt.add_cmd("iiycrv") mt.add_cmd("ecbycrv") - mt.add_cmd("tbill") - mt.add_cmd("cmn") - mt.add_cmd("tips") - mt.add_cmd("ty") + mt.add_raw("\n") + mt.add_info("_corporate_bonds_") mt.add_raw("\n") mt.add_info("_spreads_") + mt.add_raw("\n") mt.add_cmd("tmc") mt.add_cmd("ffrmc") mt.add_cmd("tbffr") @@ -763,76 +735,6 @@ class FixedIncomeController(BaseController): else None, ) - @log_start_end(log=logger) - def call_ltir(self, other_args: List[str]): - """Process ltir command""" - parser = argparse.ArgumentParser( - add_help=False, - formatter_class=argparse.ArgumentDefaultsHelpFormatter, - prog="str", - description="Plot long term interest rates from selected countries. \nLong-term interest rates refer to " - "government bonds maturing in ten years. Rates are mainly determined by the price charged by " - "the lender, the risk from the borrower and the fall in the capital value. Long-term interest " - "rates are generally averages of daily rates, measured as a percentage. These interest rates " - "are implied by the prices at which the government bonds are traded on financial markets, " - "not the interest rates at which the loans were issued. In all cases, they refer to bonds " - "whose capital repayment is guaranteed by governments. Long-term interest rates are one of " - "the determinants of business investment. Low long-term interest rates encourage investment " - "in new equipment and high interest rates discourage it. Investment is, in turn, " - "a major source of economic growth.", - ) - parser.add_argument( - "-c", - "--country", - type=str, - action="store", - nargs="+", - dest="countries", - help="Countries to get data for, use three letter country codes.", - default=["USA"], - ) - parser.add_argument( - "-s", - "--start", - type=valid_date, - help="Start date of data, in YYYY-MM-DD format", - dest="start_date", - default=None, - ) - parser.add_argument( - "-e", - "--end", - type=valid_date, - help="End date of data, in YYYY-MM-DD format", - dest="end_date", - default=None, - ) - parser.add_argument( - "--forecast", - action="store_true", - dest="forecast", - default=False, - help="If True, plot forecasts for long term interest rates", - ) - - ns_parser = self.parse_known_args_and_warn( - parser, - other_args, - export_allowed=EXPORT_ONLY_RAW_DATA_ALLOWED, - raw=True, - ) - if ns_parser: - oecd_view.plot_long_term_interest_rate( - countries=ns_parser.countries, - forecast=ns_parser.forecast, - start_date=ns_parser.start_date, - end_date=ns_parser.end_date, - 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_tmc(self, other_args: List[str]): """Process tmc command""" @@ -971,6 +873,14 @@ class FixedIncomeController(BaseController): dest="date", default=None, ) + parser.add_argument( + "-i", + "--inflation-adjusted", + action="store_true", + help="Whether to plot the inflation adjusted yield curve.", + dest="inflation_adjusted", + default=False, + ) ns_parser = self.parse_known_args_and_warn( parser, other_args, @@ -978,59 +888,9 @@ class FixedIncomeController(BaseController): raw=True, ) if ns_parser: - fred_view.display_yield_curve( date=ns_parser.date.strftime("%Y-%m-%d") if ns_parser.date else "", - 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_iiycrv(self, other_args: List[str]): - """Process iiycrv command""" - parser = argparse.ArgumentParser( - add_help=False, - formatter_class=argparse.ArgumentDefaultsHelpFormatter, - prog="iiycrv", - description="Generate US inflation-indexed yield curve. \nThe yield curve shows the bond rates" - "at different maturities.\nThe graphic depiction of the relationship between the yield on bonds of the " - "same credit quality but different maturities is known as the yield curve. In the past, " - "most market participants have constructed yield curves from the observations of prices and " - "yields in the Treasury market. Two reasons account for this tendency. First, " - "Treasury securities are viewed as free of default risk, and differences in creditworthiness " - "do not affect yield estimates. Second, as the most active bond market, the Treasury market " - "offers the fewest problems of illiquidity or infrequent trading. The key function of the " - "Treasury yield curve is to serve as a benchmark for pricing bonds and setting yields in " - "other sectors of the debt market.\nIt is clear that the market’s expectations of future rate " - "changes are one important determinant of the yield-curve shape. For example, " - "a steeply upward-sloping curve may indicate market expectations of near-term Fed tightening " - "or of rising inflation. However, it may be too restrictive to assume that the yield " - "differences across bonds with different maturities only reflect the market’s rate " - "expectations. The well-known pure expectations hypothesis has such an extreme implication. " - "The pure expectations hypothesis asserts that all government bonds have the same near-term " - "expected return (as the nominally riskless short-term bond) because the return-seeking " - "activity of risk-neutral traders removes all expected return differentials across bonds.", - ) - parser.add_argument( - "-d", - "--date", - type=valid_date, - help="Date to get data from FRED. If not supplied, the most recent entry will be used.", - dest="date", - default=None, - ) - ns_parser = self.parse_known_args_and_warn( - parser, - other_args, - export_allowed=EXPORT_ONLY_RAW_DATA_ALLOWED, - raw=True, - ) - if ns_parser: - fred_view.display_inflation_indexed_yield_curve( - date=ns_parser.date.strftime("%Y-%m-%d") if ns_parser.date else "", + inflation_adjusted=ns_parser.inflation_adjusted, raw=ns_parser.raw, export=ns_parser.export, sheet_name=" ".join(ns_parser.sheet_name) @@ -1089,11 +949,11 @@ class FixedIncomeController(BaseController): help="If True, returns detailed data. Note that this is very slow.", ) parser.add_argument( - "--aaa_only", + "--any-rating", action="store_true", - dest="aaa_only", - default=True, - help="If True, it only returns rates for AAA rated bonds. If False, it returns rates for all bonds.", + dest="any_rating", + default=False, + help="If False, it only returns rates for AAA rated bonds. If True, it returns rates for all bonds.", ) ns_parser = self.parse_known_args_and_warn( parser, @@ -1106,7 +966,7 @@ class FixedIncomeController(BaseController): date=ns_parser.date.strftime("%Y-%m-%d") if ns_parser.date else "", yield_type=ns_parser.parameter, detailed=ns_parser.detailed, - aaa_only=ns_parser.aaa_only, + any_rating=ns_parser.any_rating, raw=ns_parser.raw, export=ns_parser.export, sheet_name=" ".join(ns_parser.sheet_name) @@ -1115,98 +975,43 @@ class FixedIncomeController(BaseController): ) @log_start_end(log=logger) - def call_tbill(self, other_args: List[str]): - """Process tbill command""" + def call_usrates(self, other_args: List[str]): + """Process usrates command""" parser = argparse.ArgumentParser( add_help=False, formatter_class=argparse.ArgumentDefaultsHelpFormatter, - prog="tbill", - description="Plot the Treasury Bill Secondary Market Rate.\nA Treasury Bill (T-Bill) is a short-term U.S. " - "government debt obligation backed by the Treasury Department with a maturity of one year or " - "less. Treasury bills are usually sold in denominations of $1,000. However, some can reach a " - "maximum denomination of $5 million in non-competitive bids. These securities are widely " - "regarded as low-risk and secure investments.", + prog="usrates", + description="Plot various rates from the United States. This includes tbill (Treasury Bills), " + "Constant Maturity treasuries (cmn) and Inflation Protected Treasuries (TIPS)" ) parser.add_argument( - "-p", - "--parameter", - dest="parameter", + "-m", + "--maturity", + dest="maturity", type=str, help="Specific Treasury Bill Secondary Market Rate data to plot", default="3_month", - choices=list(self.tbill_parameter_to_fred_id.keys()), - ) - 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 - ) - if ns_parser: - if ns_parser.source == "FRED": - fred_view.plot_tbill( - self.tbill_parameter_to_fred_id[ns_parser.parameter], - ns_parser.start_date, - ns_parser.end_date, - ns_parser.export, - " ".join(ns_parser.sheet_name) - if ns_parser.sheet_name - else None, - ) - elif ns_parser.source == "EconDB": - econdb_view.plot_tbill( - ns_parser.parameter, - ns_parser.start_date, - ns_parser.end_date, - ns_parser.export, - " ".join(ns_parser.sheet_name) - if ns_parser.sheet_name - else None, - ) - - @log_start_end(log=logger) - def call_cmn(self, other_args: List[str]): - """Process cmn command""" - parser = argparse.ArgumentParser( - add_help=False, - formatter_class=argparse.ArgumentDefaultsHelpFormatter, - prog="cmn", - description="Plot the Treasury Constant Maturity Nominal Market Yield. \nYields on Treasury nominal " - "securities at “constant maturity” are interpolated by the U.S. Treasury from the daily yield " - "curve for non-inflation-indexed Treasury securities. This curve, which relates the yield on " - "a security to its time to maturity, is based on the closing market bid yields on actively " - "traded Treasury securities in the over-the-counter market. These market yields are " - "calculated from composites of quotations obtained by the Federal Reserve Bank of New York. " - "The constant maturity yield values are read from the yield curve at fixed maturities, " - "currently 1, 3, and 6 months and 1, 2, 3, 5, 7, 10, 20, and 30 years. This method provides a " - "yield for a 10-year maturity, for example, even if no outstanding security has exactly 10 " - "years remaining to maturity. Similarly, yields on inflation-indexed securities at “constant " - "maturity” are interpolated from the daily yield curve for Treasury inflation protected " - "securities in the over-the-counter market. The inflation-indexed constant maturity yields " - "are read from this yield curve at fixed maturities, currently 5, 7, 10, 20, and 30 years.", + choices=list(fred_view.USARATES_TO_FRED_ID.keys()), ) parser.add_argument( "-p", "--parameter", dest="parameter", type=str, - help="Specific Treasury Constant Maturity Nominal Market Yield data to plot", - default="3_month", - choices=list(self.cmn_parameter_to_fred_id.keys()), + help="Choose either tbill (Treasury Bills), Constant Maturity treasuries (cmn) " + "or Inflation Protected Treasuries (TIPS)", + default="tbill", + choices=['tbill', 'cmn', 'tips'] ) + parser.add_argument( + "-o", + "--options", + dest="options", + action="store_true", + help="See the available options", + default=False + ) + parser.add_argument( "-s", "--start", @@ -1224,96 +1029,25 @@ class FixedIncomeController(BaseController): default=None, ) ns_parser = self.parse_known_args_and_warn( - parser, other_args, EXPORT_BOTH_RAW_DATA_AND_FIGURES + parser, other_args, EXPORT_BOTH_RAW_DATA_AND_FIGURES, raw=True ) if ns_parser: - if ns_parser.source == "FRED": - fred_view.plot_cmn( - self.cmn_parameter_to_fred_id[ns_parser.parameter], - ns_parser.start_date, - ns_parser.end_date, - ns_parser.export, - " ".join(ns_parser.sheet_name) - if ns_parser.sheet_name - else None, + if ns_parser.options: + print_rich_table( + pd.DataFrame.from_dict(fred_view.USARATES_TO_FRED_ID).T.fillna("-"), + show_index=True, + title="Available options including FRED Series name" ) - elif ns_parser.source == "EconDB": - econdb_view.plot_cmn( - ns_parser.parameter, - ns_parser.start_date, - ns_parser.end_date, - ns_parser.export, - " ".join(ns_parser.sheet_name) - if ns_parser.sheet_name - else None, - ) - - @log_start_end(log=logger) - def call_tips(self, other_args: List[str]): - """Process tips command""" - parser = argparse.ArgumentParser( - add_help=False, - formatter_class=argparse.ArgumentDefaultsHelpFormatter, - prog="tips", - description="Plot Yields on Treasury inflation protected securities (TIPS) adjusted to constant " - "maturities. \nYields on Treasury nominal securities at “constant maturity” are interpolated " - "by the U.S. Treasury from the daily yield curve for non-inflation-indexed Treasury " - "securities. This curve, which relates the yield on a security to its time to maturity, " - "is based on the closing market bid yields on actively traded Treasury securities in the " - "over-the-counter market. These market yields are calculated from composites of quotations " - "obtained by the Federal Reserve Bank of New York. The constant maturity yield values are " - "read from the yield curve at fixed maturities, currently 1, 3, and 6 months and 1, 2, 3, 5, " - "7, 10, 20, and 30 years. This method provides a yield for a 10-year maturity, for example, " - "even if no outstanding security has exactly 10 years remaining to maturity. Similarly, " - "yields on inflation-indexed securities at “constant maturity” are interpolated from the " - "daily yield curve for Treasury inflation protected securities in the over-the-counter " - "market. The inflation-indexed constant maturity yields are read from this yield curve at " - "fixed maturities, currently 5, 7, 10, 20, and 30 years.", - ) - parser.add_argument( - "-p", - "--parameter", - dest="parameter", - type=str, - help="Specific Yields on TIPS adjusted to constant maturities data to plot", - default="10_year", - choices=list(self.tips_parameter_to_fred_id.keys()), - ) - 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 - ) - if ns_parser: - if ns_parser.source == "FRED": - fred_view.plot_tips( - self.tips_parameter_to_fred_id[ns_parser.parameter], - ns_parser.start_date, - ns_parser.end_date, - ns_parser.export, - " ".join(ns_parser.sheet_name) - if ns_parser.sheet_name - else None, - ) - elif ns_parser.source == "EconDB": - econdb_view.plot_tips( + elif ns_parser.parameter not in fred_view.USARATES_TO_FRED_ID[ns_parser.maturity]: + console.print(f"[red]Maturity {ns_parser.maturity.replace('_', ' ')} is not " + f"available for {ns_parser.parameter}. Please use 'usrates --options'.[/red]") + else: + fred_view.plot_usrates( ns_parser.parameter, + ns_parser.maturity, ns_parser.start_date, ns_parser.end_date, + ns_parser.raw, ns_parser.export, " ".join(ns_parser.sheet_name) if ns_parser.sheet_name @@ -1366,52 +1100,4 @@ class FixedIncomeController(BaseController): " ".join(ns_parser.sheet_name) if ns_parser.sheet_name else None, - ) - - @log_start_end(log=logger) - def call_ty(self, other_args: List[str]): - """Process ty command""" - parser = argparse.ArgumentParser( - add_help=False, - formatter_class=argparse.ArgumentDefaultsHelpFormatter, - prog="ty", - description="Plot Selected Treasury Yield.", - ) - parser.add_argument( - "-p", - "--parameter", - dest="parameter", - type=str, - help="Selected Treasury Yield", - default="10_year", - choices=["5_year", "10_year", "30_year"], - ) - parser.add_argument( - "-s", - "--start", - dest="start_date", - type=valid_date, - help="Starting date (YYYY-MM-DD) of data", - default=None, - ) - 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 - ) - if ns_parser: - yfinance_view.plot_ty( - ns_parser.parameter, - ns_parser.start_date, - ns_parser.end_date, - ns_parser.export, - " ".join(ns_parser.sheet_name) - if ns_parser.sheet_name - else None, - ) + ) \ No newline at end of file diff --git a/openbb_terminal/fixedincome/fred_model.py b/openbb_terminal/fixedincome/fred_model.py index b9eb135447d..c4756a5d389 100644 --- a/openbb_terminal/fixedincome/fred_model.py +++ b/openbb_terminal/fixedincome/fred_model.py @@ -19,6 +19,30 @@ from openbb_terminal.decorators import log_start_end, check_api_key logger = logging.getLogger(__name__) +YIELD_CURVE_SERIES_NOMINAL = { + "1Month": "DGS1MO", + "3Month": "DGS3MO", + "6Month": "DGS6MO", + "1Year": "DGS1", + "2Year": "DGS2", + "3Year": "DGS3", + "5Year": "DGS5", + "7Year": "DGS7", + "10Year": "DGS10", + "20Year": "DGS20", + "30Year": "DGS30", +} +YIELD_CURVE_SERIES_REAL = { + "5Year": "DFII5", + "7Year": "DFII7", + "10Year": "DFII10", + "20Year": "DFII20", + "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] + @log_start_end(log=logger) @check_api_key(["API_FRED_KEY"]) @@ -59,7 +83,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 + date: str = "", return_date: bool = False, inflation_adjusted: bool = False ) -> Tuple[pd.DataFrame, str]: """Gets yield curve data from FRED. @@ -108,19 +132,7 @@ def get_yield_curve( # os.environ["SSL_CERT_FILE"] = certifi.where() fredapi_client = Fred(cfg.API_FRED_KEY) - fred_series = { - "1Month": "DGS1MO", - "3Month": "DGS3MO", - "6Month": "DGS6MO", - "1Year": "DGS1", - "2Year": "DGS2", - "3Year": "DGS3", - "5Year": "DGS5", - "7Year": "DGS7", - "10Year": "DGS10", - "20Year": "DGS20", - "30Year": "DGS30", - } + df = pd.DataFrame() # Check that the date is in the past today = datetime.now().strftime("%Y-%m-%d") @@ -136,6 +148,13 @@ def get_yield_curve( if not date: date = (datetime.now() - timedelta(days=7)).strftime("%Y-%m-%d") get_last = True + + if inflation_adjusted: + fred_series = YIELD_CURVE_SERIES_REAL + years = YIELD_CURVE_REAL_RATES + else: + fred_series = YIELD_CURVE_SERIES_NOMINAL + years = YIELD_CURVE_NOMINAL_RATES for key, s_id in fred_series.items(): df = pd.concat( @@ -167,119 +186,7 @@ def get_yield_curve( rates.insert( 0, "Maturity", - [1 / 12, 0.25, 0.5, 1, 2, 3, 5, 7, 10, 20, 30], - ) - if return_date: - return rates, date_of_yield - return rates - - -@log_start_end(log=logger) -@check_api_key(["API_FRED_KEY"]) -def get_inflation_indexed_yield_curve( - date: str = "", return_date: bool = False -) -> Tuple[pd.DataFrame, str]: - """Gets inflation-indexed yield curve data from FRED. - - The graphic depiction of the relationship between the yield on bonds of the same credit quality but different - maturities is known as the yield curve. In the past, most market participants have constructed yield curves from - the observations of prices and yields in the Treasury market. Two reasons account for this tendency. First, - Treasury securities are viewed as free of default risk, and differences in creditworthiness do not affect yield - estimates. Second, as the most active bond market, the Treasury market offers the fewest problems of illiquidity - or infrequent trading. The key function of the Treasury yield curve is to serve as a benchmark for pricing bonds - and setting yields in other sectors of the debt market. - - It is clear that the market’s expectations of future rate changes are one important determinant of the - yield-curve shape. For example, a steeply upward-sloping curve may indicate market expectations of near-term Fed - tightening or of rising inflation. However, it may be too restrictive to assume that the yield differences across - bonds with different maturities only reflect the market’s rate expectations. The well-known pure expectations - hypothesis has such an extreme implication. The pure expectations hypothesis asserts that all government bonds - have the same near-term expected return (as the nominally riskless short-term bond) because the return-seeking - activity of risk-neutral traders removes all expected return differentials across bonds. - - Parameters - ---------- - date: str - Date to get curve for. If empty, gets most recent date (format yyyy-mm-dd) - return_date: bool - If True, returns date of yield curve - - Returns - ------- - Tuple[pd.DataFrame, str] - Dataframe of yields and maturities, - Date for which the yield curve is obtained - - Examples - -------- - >>> from openbb_terminal.sdk import openbb - >>> ycrv_df = openbb.fixedincome.iiycrv() - - Since there is a delay with the data, the most recent date is returned and can be accessed with return_date=True - >>> ycrv_df, ycrv_date = openbb.fixedincome.iiycrv(return_date=True) - """ - - # Necessary for installer so that it can locate the correct certificates for - # API calls and https - # https://stackoverflow.com/questions/27835619/urllib-and-ssl-certificate-verify-failed-error/73270162#73270162 - # os.environ["REQUESTS_CA_BUNDLE"] = certifi.where() - # os.environ["SSL_CERT_FILE"] = certifi.where() - - fredapi_client = Fred(cfg.API_FRED_KEY) - fred_series = { - "5Year": "DFII5", - "7Year": "DFII7", - "10Year": "DFII10", - "20Year": "DFII20", - "30Year": "DFII30", - } - df = pd.DataFrame() - # Check that the date is in the past - today = datetime.now().strftime("%Y-%m-%d") - if date and date >= today: - console.print("[red]Date cannot be today or in the future[/red]") - if return_date: - 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") - get_last = True - - for key, s_id in fred_series.items(): - df = pd.concat( - [ - df, - pd.DataFrame(fredapi_client.get_series(s_id, date), columns=[key]), - ], - axis=1, - ) - if df.empty: - if return_date: - return pd.DataFrame(), date - return pd.DataFrame() - # Drop rows with NaN -- corresponding to weekends typically - df = df.dropna() - - if date not in df.index or get_last: - # If the get_last flag is true, we want the first date, otherwise we want the last date. - 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"]) - else: - date_of_yield = date - series = df[df.index == date] - if series.empty: - return pd.DataFrame(), date_of_yield - rates = pd.DataFrame(series.values.T, columns=["Rate"]) - - rates.insert( - 0, - "Maturity", - [5, 7, 10, 20, 30], + years ) if return_date: return rates, date_of_yield diff --git a/openbb_terminal/fixedincome/fred_view.py b/openbb_terminal/fixedincome/fred_view.py index ffcaf0d8fdf..a312daa6f0e 100644 --- a/openbb_terminal/fixedincome/fred_view.py +++ b/openbb_terminal/fixedincome/fred_view.py @@ -139,6 +139,21 @@ NAME_TO_ID_ECB = { "refinancing": "ECBMRRFR" } +USARATES_TO_FRED_ID = { + "4_week": {"tbill": "DTB4WK"}, + "1_month": { "cmn": "DGS1MO"}, + "3_month": {"tbill": "TB3MS", "cmn": "DGS3MO"}, + "6_month": {"tbill": "DTB6", "cmn": "DGS6MO"}, + "1_year": {"tbill": "DTB1YR", "cmn": "DGS1"}, + "2_year": {"cmn": "DGS2"}, + "3_year": {"cmn": "DGS3"}, + "5_year": {"tips": "DFII5", "cmn": "DGS5"}, + "7_year": {"tips": "DFII7", "cmn": "DGS7"}, + "10_year": {"tips": "DFII10", "cmn": "DGS10"}, + "20_year": {"tips": "DFII20", "cmn": "DGS20"}, + "30_year": {"tips": "DFII30", "cmn": "DGS30"}, +} + @log_start_end(log=logger) @check_api_key(["API_FRED_KEY"]) @@ -1201,10 +1216,11 @@ def plot_ffrmc( @check_api_key(["API_FRED_KEY"]) def display_yield_curve( date: str = "", - external_axes: Optional[List[plt.Axes]] = None, + inflation_adjusted: bool = False, raw: bool = False, export: str = "", sheet_name: str = "", + external_axes: Optional[List[plt.Axes]] = None, ): """Display yield curve based on US Treasury rates for a specified date. @@ -1235,7 +1251,7 @@ def display_yield_curve( export : str Export data to csv,json,xlsx or png,jpg,pdf,svg file """ - rates, date_of_yield = fred_model.get_yield_curve(date, True) + rates, date_of_yield = fred_model.get_yield_curve(date, True, inflation_adjusted) if rates.empty: console.print(f"[red]Yield data not found for {date_of_yield}.[/red]\n") return @@ -1251,7 +1267,7 @@ def display_yield_curve( ax.set_ylabel("Rate (%)") theme.style_primary_axis(ax) if external_axes is None: - ax.set_title(f"US Yield Curve for {date_of_yield} ") + ax.set_title(f"US {'Real' if inflation_adjusted else 'Nominal'} Yield Curve for {date_of_yield} ") theme.visualize_output() if raw: @@ -1259,7 +1275,7 @@ def display_yield_curve( rates, headers=list(rates.columns), show_index=False, - title=f"United States Yield Curve for {date_of_yield}", + title=f"United States {'Real' if inflation_adjusted else 'Nominal'} Yield Curve for {date_of_yield}", floatfmt=".3f", ) @@ -1267,105 +1283,46 @@ def display_yield_curve( export, os.path.dirname(os.path.abspath(__file__)), "ycrv", - pd.DataFrame(rates, columns=["YCRV"]) / 100, + rates.set_index('Maturity') / 100, sheet_name ) - @log_start_end(log=logger) @check_api_key(["API_FRED_KEY"]) -def display_inflation_indexed_yield_curve( - date: str = "", - external_axes: Optional[List[plt.Axes]] = None, +def plot_usrates( + parameter: str = "tbills", + maturity: str = "3_months", + start_date: Optional[str] = None, + end_date: Optional[str] = None, raw: bool = False, export: str = "", sheet_name: str = "", -): - """Display inflation-indexed yield curve based on US Treasury rates for a specified date. - - The graphic depiction of the relationship between the yield on bonds of the same credit quality but different - maturities is known as the yield curve. In the past, most market participants have constructed yield curves from - the observations of prices and yields in the Treasury market. Two reasons account for this tendency. First, - Treasury securities are viewed as free of default risk, and differences in creditworthiness do not affect yield - estimates. Second, as the most active bond market, the Treasury market offers the fewest problems of illiquidity - or infrequent trading. The key function of the Treasury yield curve is to serve as a benchmark for pricing bonds - and setting yields in other sectors of the debt market. - - It is clear that the market’s expectations of future rate changes are one important determinant of the - yield-curve shape. For example, a steeply upward-sloping curve may indicate market expectations of near-term Fed - tightening or of rising inflation. However, it may be too restrictive to assume that the yield differences across - bonds with different maturities only reflect the market’s rate expectations. The well-known pure expectations - hypothesis has such an extreme implication. The pure expectations hypothesis asserts that all government bonds - have the same near-term expected return (as the nominally riskless short-term bond) because the return-seeking - activity of risk-neutral traders removes all expected return differentials across bonds. - - Parameters - ---------- - date: str - Date to get curve for. If None, gets most recent date (format yyyy-mm-dd) - external_axes : Optional[List[plt.Axes]], optional - External axes (1 axis is expected in the list), by default None - raw : bool - Output only raw data - export : str - Export data to csv,json,xlsx or png,jpg,pdf,svg file - """ - rates, date_of_yield = fred_model.get_inflation_indexed_yield_curve(date, True) - if rates.empty: - console.print(f"[red]Yield data not found for {date_of_yield}.[/red]\n") - return - if external_axes is None: - _, ax = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI) - elif is_valid_axes_count(external_axes, 1): - (ax,) = external_axes - else: - return - - ax.plot(rates["Maturity"], rates["Rate"], "-o") - ax.set_xlabel("Maturity") - ax.set_ylabel("Rate (%)") - theme.style_primary_axis(ax) - if external_axes is None: - ax.set_title(f"US Yield Curve for {date_of_yield} ") - theme.visualize_output() - - if raw: - print_rich_table( - rates, - headers=list(rates.columns), - show_index=False, - title=f"United States Yield Curve for {date_of_yield}", - floatfmt=".3f", - ) - - export_data( - export, - os.path.dirname(os.path.abspath(__file__)), - "iiycrv", - pd.DataFrame(rates, columns=["IIYCRV"]) / 100, - sheet_name - ) - - -@log_start_end(log=logger) -@check_api_key(["API_FRED_KEY"]) -def plot_tbill( - series_id: str = "TB3MS", - start_date: Optional[str] = None, - end_date: Optional[str] = None, - export: str = "", - sheet_name: str = "", external_axes: Optional[List[plt.Axes]] = None, ): - """Plot Treasury Bill Secondary Market Rate. + """Plot various treasury rates from the United States A Treasury Bill (T-Bill) is a short-term U.S. government debt obligation backed by the Treasury Department with a maturity of one year or less. Treasury bills are usually sold in denominations of $1,000. However, some can reach a maximum denomination of $5 million in non-competitive bids. These securities are widely regarded as low-risk and secure investments. + + Yields on Treasury nominal securities at “constant maturity” are interpolated by the U.S. Treasury from the daily + yield curve for non-inflation-indexed Treasury securities. This curve, which relates the yield on a security to + its time to maturity, is based on the closing market bid yields on actively traded Treasury securities in the + over-the-counter market. These market yields are calculated from composites of quotations obtained by the Federal + Reserve Bank of New York. The constant maturity yield values are read from the yield curve at fixed maturities, + currently 1, 3, and 6 months and 1, 2, 3, 5, 7, 10, 20, and 30 years. This method provides a yield for a 10-year + maturity, for example, even if no outstanding security has exactly 10 years remaining to maturity. Similarly, + yields on inflation-indexed securities at “constant maturity” are interpolated from the daily yield curve for + Treasury inflation protected securities in the over-the-counter market. The inflation-indexed constant maturity + yields are read from this yield curve at fixed maturities, currently 5, 7, 10, 20, and 30 years. Parameters ---------- + parameter: str + Either "tbills", "cmn", or "tips". + maturity: str + Depending on the chosen parameter, a set of maturities is available. series_id: str FRED ID of Treasury Bill Secondary Market Rate data to plot, options: ['TB3MS', 'DTB4WK', 'DTB1YR', 'DTB6'] start_date: Optional[str] @@ -1377,6 +1334,7 @@ def plot_tbill( external_axes: Optional[List[plt.Axes]] External axes (1 axis is expected in the list) """ + series_id = USARATES_TO_FRED_ID[maturity][parameter] df = fred_model.get_series_data( series_id=series_id, start_date=start_date, end_date=end_date ) @@ -1393,170 +1351,37 @@ def plot_tbill( ax.plot( df.index, df.values, - marker="o", - linestyle="dashed", - linewidth=2, - markersize=4, color=next(colors, "#FCED00"), ) - ax.set_title(f"{ID_TO_NAME_SECONDARY[series_id]} Treasury Bill Secondary Market Rate, Discount Basis [Percent]") + + if parameter == "tbill": + title = f"{maturity.replace('_', ' ').title()} Treasury Bill Secondary Market Rate, Discount Basis" + elif parameter == "cmn": + title = f"{maturity.replace('_', ' ').title()} Treasury Constant Maturity Nominal Market Yield" + elif parameter == "tips": + 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 (%})") theme.style_primary_axis(ax) if external_axes is None: theme.visualize_output() + + if raw: + print_rich_table( + pd.DataFrame(df, columns=[parameter]).iloc[-10:], + title=title, + show_index=True, + floatfmt=".3f", + ) + export_data( export, os.path.dirname(os.path.abspath(__file__)), series_id, - pd.DataFrame(df, columns=["TBILL"]) / 100, - sheet_name - ) - - -@log_start_end(log=logger) -@check_api_key(["API_FRED_KEY"]) -def plot_cmn( - series_id: str = "DGS10", - start_date: Optional[str] = None, - end_date: Optional[str] = None, - export: str = "", - sheet_name: str = "", - external_axes: Optional[List[plt.Axes]] = None, -): - """Plot Treasury Constant Maturity Nominal Market Yield. - - Yields on Treasury nominal securities at “constant maturity” are interpolated by the U.S. Treasury from the daily - yield curve for non-inflation-indexed Treasury securities. This curve, which relates the yield on a security to - its time to maturity, is based on the closing market bid yields on actively traded Treasury securities in the - over-the-counter market. These market yields are calculated from composites of quotations obtained by the Federal - Reserve Bank of New York. The constant maturity yield values are read from the yield curve at fixed maturities, - currently 1, 3, and 6 months and 1, 2, 3, 5, 7, 10, 20, and 30 years. This method provides a yield for a 10-year - maturity, for example, even if no outstanding security has exactly 10 years remaining to maturity. Similarly, - yields on inflation-indexed securities at “constant maturity” are interpolated from the daily yield curve for - Treasury inflation protected securities in the over-the-counter market. The inflation-indexed constant maturity - yields are read from this yield curve at fixed maturities, currently 5, 7, 10, 20, and 30 years. - - Parameters - ---------- - series_id: str - FRED ID of Treasury Constant Maturity Nominal Market Yield data to plot, options: ['DGS1MO', 'DGS3MO', 'DGS6MO', 'DGS1', 'DGS2', 'DGS3', 'DGS5', 'DGS7', 'DGS10', 'DGS20', DGS30'] - start_date: Optional[str] - Start date, formatted YYYY-MM-DD - end_date: Optional[str] - End date, formatted YYYY-MM-DD - export: str - Export data to csv or excel file - external_axes: Optional[List[plt.Axes]] - External axes (1 axis is expected in the list) - """ - df = fred_model.get_series_data( - series_id=series_id, start_date=start_date, end_date=end_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, - marker="o", - linestyle="dashed", - linewidth=2, - markersize=4, - color=next(colors, "#FCED00"), - ) - ax.set_title(f"{ID_TO_NAME_CMN[series_id]} Treasury Constant Maturity Nominal Market Yield [Percent]") - theme.style_primary_axis(ax) - - if external_axes is None: - theme.visualize_output() - - export_data( - export, - os.path.dirname(os.path.abspath(__file__)), - series_id, - pd.DataFrame(df, columns=["CMN"]) / 100, - sheet_name - ) - - -@log_start_end(log=logger) -@check_api_key(["API_FRED_KEY"]) -def plot_tips( - series_id: str = "DFII10", - start_date: Optional[str] = None, - end_date: Optional[str] = None, - export: str = "", - sheet_name: str = "", - external_axes: Optional[List[plt.Axes]] = None, -): - """Plot Plot Yields on Treasury inflation protected securities (TIPS) adjusted to constant maturities. - - Yields on Treasury nominal securities at “constant maturity” are interpolated by the U.S. Treasury from the daily - yield curve for non-inflation-indexed Treasury securities. This curve, which relates the yield on a security to - its time to maturity, is based on the closing market bid yields on actively traded Treasury securities in the - over-the-counter market. These market yields are calculated from composites of quotations obtained by the Federal - Reserve Bank of New York. The constant maturity yield values are read from the yield curve at fixed maturities, - currently 1, 3, and 6 months and 1, 2, 3, 5, 7, 10, 20, and 30 years. This method provides a yield for a 10-year - maturity, for example, even if no outstanding security has exactly 10 years remaining to maturity. Similarly, - yields on inflation-indexed securities at “constant maturity” are interpolated from the daily yield curve for - Treasury inflation protected securities in the over-the-counter market. The inflation-indexed constant maturity - yields are read from this yield curve at fixed maturities, currently 5, 7, 10, 20, and 30 years. - - Parameters - ---------- - series_id: str - FRED ID of TIPS adjusted to constant maturities data to plot, options: ['DFII5', 'DFII7', 'DFII10', 'DFII20', 'DFII30'] - start_date: Optional[str] - Start date, formatted YYYY-MM-DD - end_date: Optional[str] - End date, formatted YYYY-MM-DD - export: str - Export data to csv or excel file - external_axes: Optional[List[plt.Axes]] - External axes (1 axis is expected in the list) - """ - df = fred_model.get_series_data( - series_id=series_id, start_date=start_date, end_date=end_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, - marker="o", - linestyle="dashed", - linewidth=2, - markersize=4, - color=next(colors, "#FCED00"), - ) - ax.set_title(f"{ID_TO_NAME_TIPS[series_id]} Yields on Treasury inflation protected securities (TIPS) adjusted to " - f"constant maturities [Percent]") - theme.style_primary_axis(ax) - - if external_axes is None: - theme.visualize_output() - - export_data( - export, - os.path.dirname(os.path.abspath(__file__)), - series_id, - pd.DataFrame(df, columns=["TIPS"]) / 100, + pd.DataFrame(df, columns=[parameter]) / 100, sheet_name ) diff --git a/openbb_terminal/miscellaneous/data_sources_default.json b/openbb_terminal/miscellaneous/data_sources_default.json index cc42173b17c..abd083e00c0 100644 --- a/openbb_terminal/miscellaneous/data_sources_default.json +++ b/openbb_terminal/miscellaneous/data_sources_default.json @@ -499,20 +499,15 @@ "fed": ["FRED"], "iorb": ["FRED"], "projection": ["FRED"], - "oldprojetion": ["FRED"], "dwpcr": ["FRED"], "ecb": ["FRED"], "treasury": ["OECD"], + "usrates": ["FRED"], + "ycrv": ["FRED"], + "ecbycrv": ["ECB"], "tmc": ["FRED"], "ffrmc": ["FRED"], - "ycrv": ["FRED"], - "iiycrv": ["FRED"], - "ecbycrv": ["ECB"], - "tbill": ["FRED", "EconDB"], - "cmn": ["FRED", "EconDB"], - "tips": ["FRED", "EconDB"], - "tbffr": ["FRED"], - "ty": ["YahooFinance"] + "tbffr": ["FRED"] }, "portfolio": { "po": { diff --git a/openbb_terminal/miscellaneous/i18n/en.yml b/openbb_terminal/miscellaneous/i18n/en.yml index d2113bdfd26..a9c07b2e43b 100644 --- a/openbb_terminal/miscellaneous/i18n/en.yml +++ b/openbb_terminal/miscellaneous/i18n/en.yml @@ -790,16 +790,12 @@ en: fixedincome/projection: the Federal Reserve's projection of the federal funds rate. fixedincome/dwpcr: discount window primary credit rate fixedincome/ecb: key ECB interest rates - fixedincome/treasury: plot countries (incl. forecasted) short term interest rate - fixedincome/_yield_curves_: Yield curves - fixedincome/ycrv: plot US yield curve - fixedincome/iiycrv: plot US inflation-indexed yield curve - fixedincome/ecbycrv: plot euro area yield curve fixedincome/_government_bonds_: Government Bonds - fixedincome/tbill: plot secondary market rate of treasury bills - fixedincome/cmn: plot nominal constant maturity treasuries - fixedincome/tips: plot treasury inflation protected securities (tips) - fixedincome/ty: plot treasury yields + 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/_corporate_bonds_: Corporate Bonds fixedincome/_spreads_: Spreads fixedincome/tmc: 10-year treasury constant maturity minus selected treasury constant maturity fixedincome/ffrmc: selected treasury constant maturity minus federal funds rate