diff --git a/openbb_terminal/config_terminal.py b/openbb_terminal/config_terminal.py index 6d0894b3d2e1..ff6f6a7e8170 100644 --- a/openbb_terminal/config_terminal.py +++ b/openbb_terminal/config_terminal.py @@ -42,7 +42,9 @@ LOGGING_FREQUENCY = os.getenv("OPENBB_LOGGING_FREQUENCY") or "H" # stdout,stderr,noop,file LOGGING_HANDLERS = os.getenv("OPENBB_LOGGING_HANDLERS") or "file" -LOGGING_ROLLING_CLOCK = bool(strtobool(os.getenv("OPENBB_LOGGING_ROLLING_CLOCK", "False"))) +LOGGING_ROLLING_CLOCK = bool( + strtobool(os.getenv("OPENBB_LOGGING_ROLLING_CLOCK", "False")) +) # CRITICAL = 50 # FATAL = CRITICAL # ERROR = 40 diff --git a/openbb_terminal/economy/economy_controller.py b/openbb_terminal/economy/economy_controller.py index b679226de3d2..87f88f4de7d9 100644 --- a/openbb_terminal/economy/economy_controller.py +++ b/openbb_terminal/economy/economy_controller.py @@ -26,6 +26,8 @@ fred_model, yfinance_model, yfinance_view, + investingcom_model, + investingcom_view, plot_view, ) from openbb_terminal.helper_funcs import ( @@ -63,6 +65,7 @@ class EconomyController(BaseController): "rtps", "industry", "bigmac", + "ycrv", ] CHOICES_MENUS = ["pred", "qa"] @@ -142,6 +145,7 @@ class EconomyController(BaseController): "country": "Country (U.S. listed stocks only)", "capitalization": "Capitalization", } + ycrv_sources = ["FRED", "investpy"] PATH = "/economy/" FILE_PATH = os.path.join(os.path.dirname(__file__), "README.md") @@ -172,6 +176,11 @@ def __init__(self, queue: List[str] = None): c: None for c in econdb_model.COUNTRY_CODES } + self.choices["ycrv"]["-c"] = {c: None for c in investingcom_model.COUNTRIES} + self.choices["ycrv"]["--countries"] = { + c: None for c in investingcom_model.COUNTRIES + } + self.choices["valuation"]["-s"] = { c: None for c in self.valuation_sort_cols } @@ -226,6 +235,7 @@ def print_help(self): index find and plot any (major) index on the market [src][Source: Yahoo Finance][/src] treasury obtain U.S. treasury rates [src][Source: EconDB][/src] yield show the U.S. Treasury yield curve [src][Source: FRED][/src] + ycrv show sovereign yield curves [src][Source: Investing.com/FRED][/src] plot plot data from the above commands together options show the available options for 'plot' or show/export the data @@ -968,6 +978,64 @@ def call_yield(self, other_args: List[str]): if ns_parser: fred_view.display_yield_curve(ns_parser.date) + @log_start_end(log=logger) + def call_ycrv(self, other_args: List[str]): + """Process ycrv command""" + parser = argparse.ArgumentParser( + add_help=False, + formatter_class=argparse.ArgumentDefaultsHelpFormatter, + prog="ycrv", + description="Generate country yield curve. The yield curve shows the bond rates" + " at different maturities.", + ) + parser.add_argument( + "-s", + "--source", + action="store", + dest="source", + choices=self.ycrv_sources, + type=str, + default="investpy", + help="Source for the data. If not supplied, the most recent entry from investpy will be used.", + ) + parser.add_argument( + "-c", + "--country", + action="store", + dest="country", + nargs="+", + default="united states", + help="Display yield curve for specific country.", + ) + 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 = parse_known_args_and_warn( + parser, + other_args, + export_allowed=EXPORT_ONLY_RAW_DATA_ALLOWED, + raw=True, + ) + if ns_parser: + if isinstance(ns_parser.country, list): + ns_parser.country = " ".join(ns_parser.country) + + investingcom_model.check_correct_country(ns_parser.country) + + if ns_parser.source == "FRED": + fred_view.display_yield_curve(ns_parser.date) + elif ns_parser.source == "investpy": + investingcom_view.display_yieldcurve( + country=ns_parser.country, + raw=ns_parser.raw, + export=ns_parser.export, + ) + @log_start_end(log=logger) def call_plot(self, other_args: List[str]): """Process plot command""" diff --git a/openbb_terminal/economy/investingcom_model.py b/openbb_terminal/economy/investingcom_model.py new file mode 100644 index 000000000000..8ab383418372 --- /dev/null +++ b/openbb_terminal/economy/investingcom_model.py @@ -0,0 +1,53 @@ +""" Investing.com Model """ +__docformat__ = "numpy" + +import logging +import argparse + +import pandas as pd +import investpy + +from openbb_terminal.decorators import log_start_end +from openbb_terminal.helper_funcs import log_and_raise + +logger = logging.getLogger(__name__) + +COUNTRIES = investpy.bonds.get_bond_countries() + + +def check_correct_country(country): + """Argparse type to check that correct country is inserted""" + if country not in investpy.bonds.get_bond_countries(): + log_and_raise( + argparse.ArgumentTypeError( + f"{country} is an invalid country. Choose from {', '.join(investpy.bonds.get_bond_countries())}" + ) + ) + return country + + +@log_start_end(log=logger) +def get_yieldcurve(country) -> pd.DataFrame: + """Get country yield curve [Source: Investing.com] + + Returns + ------- + pd.DataFrame + Country yield curve + """ + + data = investpy.bonds.get_bonds_overview(country) + data.drop(columns=data.columns[0], axis=1, inplace=True) + data.rename( + columns={ + "name": "Tenor", + "last": "Current", + "last_close": "Previous", + "high": "High", + "low": "Low", + "change": "Change", + "change_percentage": "% Change", + }, + inplace=True, + ) + return data diff --git a/openbb_terminal/economy/investingcom_view.py b/openbb_terminal/economy/investingcom_view.py new file mode 100644 index 000000000000..ea484615b22d --- /dev/null +++ b/openbb_terminal/economy/investingcom_view.py @@ -0,0 +1,114 @@ +""" Investing.com View """ +__docformat__ = "numpy" + +import logging +import os +from typing import Optional, List + +import matplotlib.pyplot as plt +from pandas.plotting import register_matplotlib_converters + +from openbb_terminal.config_plot import PLOT_DPI +from openbb_terminal.config_terminal import theme +from openbb_terminal.decorators import log_start_end +from openbb_terminal.economy import investingcom_model +from openbb_terminal.helper_funcs import ( + export_data, + plot_autoscale, + print_rich_table, +) +from openbb_terminal.rich_config import console + +logger = logging.getLogger(__name__) + +register_matplotlib_converters() + +tenors_dict = { + "1M": 1 / 12, + "3M": 0.25, + "6M": 0.5, + "9M": 0.75, + "1Y": 1, + "2Y": 2, + "3Y": 3, + "4Y": 4, + "5Y": 5, + "6Y": 6, + "7Y": 7, + "8Y": 8, + "9Y": 9, + "10Y": 10, + "15Y": 15, + "20Y": 20, + "25Y": 25, + "30Y": 30, + "50Y": 50, +} + + +@log_start_end(log=logger) +def display_yieldcurve( + country: str, + external_axes: Optional[List[plt.Axes]] = None, + raw: bool = False, + export: str = "", +): + """Display yield curve. [Source: Investing.com] + + Parameters + ---------- + country: str + Country to display + export : str + Export dataframe data to csv,json,xlsx file + """ + + df = investingcom_model.get_yieldcurve(country) + df = df.replace(float("NaN"), "") + + if df.empty: + console.print(f"[red]Yield data not found for {country.title()}[/red].\n") + return + if external_axes is None: + _, ax = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI) + + else: + if len(external_axes) != 1: + logger.error("Expected list of 3 axis items") + console.print("[red]Expected list of 3 axis items.\n[/red]") + return + (ax,) = external_axes + + tenors = [] + for i, row in df.iterrows(): + t = row["Tenor"][-3:].strip() + df.at[i, "Tenor"] = t + if t[-1] == "M": + tenors.append(int(t[:-1]) / 12) + elif t[-1] == "Y": + tenors.append(int(t[:-1])) + + ax.plot(tenors, df["Current"], "-o") + ax.set_xlabel("Maturity") + ax.set_ylabel("Rate (%)") + theme.style_primary_axis(ax) + if external_axes is None: + ax.set_title(f"Yield Curve for {country.title()} ") + theme.visualize_output() + + if raw: + print_rich_table( + df, + headers=list(df.columns), + show_index=False, + title=f"{country.title()} Yield Curve", + floatfmt=".3f", + ) + console.print("") + + export_data( + export, + os.path.dirname(os.path.abspath(__file__)), + "ycrv", + df, + ) diff --git a/tests/openbb_terminal/economy/test_economy_controller.py b/tests/openbb_terminal/economy/test_economy_controller.py index 6486da2293f7..98adf47dc566 100644 --- a/tests/openbb_terminal/economy/test_economy_controller.py +++ b/tests/openbb_terminal/economy/test_economy_controller.py @@ -430,6 +430,16 @@ def test_call_func_expect_queue(expected_queue, func, queue): map_type="world", ), ), + ( + "call_ycrv", + [ + "--country=portugal", + "--export=csv", + ], + "investingcom_view.display_yieldcurve", + [], + dict(country="portugal", export="csv", raw=False), + ), ], ) def test_call_func( diff --git a/tests/openbb_terminal/economy/test_investingcom_model.py b/tests/openbb_terminal/economy/test_investingcom_model.py new file mode 100644 index 000000000000..780587e65388 --- /dev/null +++ b/tests/openbb_terminal/economy/test_investingcom_model.py @@ -0,0 +1,24 @@ +# IMPORTATION STANDARD + +# IMPORTATION THIRDPARTY +import pandas as pd +import pytest + +# IMPORTATION INTERNAL +from openbb_terminal.economy import investingcom_model + + +# @pytest.mark.vcr +@pytest.mark.parametrize( + "country", + [ + "united states", + "portugal", + "spain", + "germany", + ], +) +def test_get_yieldcurve(country): + result_df = investingcom_model.get_yieldcurve(country) + + assert isinstance(result_df, pd.DataFrame) diff --git a/tests/openbb_terminal/economy/test_investingcom_view.py b/tests/openbb_terminal/economy/test_investingcom_view.py new file mode 100644 index 000000000000..5d8950546e59 --- /dev/null +++ b/tests/openbb_terminal/economy/test_investingcom_view.py @@ -0,0 +1,16 @@ +# IMPORTATION STANDARD +# import gzip + +# IMPORTATION THIRDPARTY +# import pandas as pd + +# import pytest + +# IMPORTATION INTERNAL +from openbb_terminal.economy import investingcom_view + + +# @pytest.mark.vcr +# @pytest.mark.record_stdout +def test_display_yieldcurve(): + investingcom_view.display_yieldcurve(country="portugal", export="") diff --git a/tests/openbb_terminal/economy/txt/test_econdb_view/test_show_treasuries[instruments0-maturities0-monthly-2020-01-01-2020-02-03].txt b/tests/openbb_terminal/economy/txt/test_econdb_view/test_show_treasuries[instruments0-maturities0-monthly-2020-01-01-2020-02-03].txt index 172193941724..b01b614bd708 100644 --- a/tests/openbb_terminal/economy/txt/test_econdb_view/test_show_treasuries[instruments0-maturities0-monthly-2020-01-01-2020-02-03].txt +++ b/tests/openbb_terminal/economy/txt/test_econdb_view/test_show_treasuries[instruments0-maturities0-monthly-2020-01-01-2020-02-03].txt @@ -1,2 +1 @@ The maturity 3y is not an option for inflation. Please choose between 5y, 7y, 10y, 20y, 30y - diff --git a/tests/openbb_terminal/economy/txt/test_econdb_view/test_show_treasuries[instruments1-maturities1-annually-2015-01-04-2015-01-28].txt b/tests/openbb_terminal/economy/txt/test_econdb_view/test_show_treasuries[instruments1-maturities1-annually-2015-01-04-2015-01-28].txt index 1e19320c855c..431ccb5ce0b1 100644 --- a/tests/openbb_terminal/economy/txt/test_econdb_view/test_show_treasuries[instruments1-maturities1-annually-2015-01-04-2015-01-28].txt +++ b/tests/openbb_terminal/economy/txt/test_econdb_view/test_show_treasuries[instruments1-maturities1-annually-2015-01-04-2015-01-28].txt @@ -1,3 +1,2 @@ No data found for the combination nominal and 1m. No data found for the combination nominal and 30y. - diff --git a/tests/openbb_terminal/economy/txt/test_econdb_view/test_show_treasuries[instruments2-maturities2-weekly-2018-06-05-2018-07-06].txt b/tests/openbb_terminal/economy/txt/test_econdb_view/test_show_treasuries[instruments2-maturities2-weekly-2018-06-05-2018-07-06].txt index 172193941724..b01b614bd708 100644 --- a/tests/openbb_terminal/economy/txt/test_econdb_view/test_show_treasuries[instruments2-maturities2-weekly-2018-06-05-2018-07-06].txt +++ b/tests/openbb_terminal/economy/txt/test_econdb_view/test_show_treasuries[instruments2-maturities2-weekly-2018-06-05-2018-07-06].txt @@ -1,2 +1 @@ The maturity 3y is not an option for inflation. Please choose between 5y, 7y, 10y, 20y, 30y - diff --git a/tests/openbb_terminal/economy/txt/test_economy_controller/test_print_help.txt b/tests/openbb_terminal/economy/txt/test_economy_controller/test_print_help.txt index 8d8603145177..02a951dfc1d2 100644 --- a/tests/openbb_terminal/economy/txt/test_economy_controller/test_print_help.txt +++ b/tests/openbb_terminal/economy/txt/test_economy_controller/test_print_help.txt @@ -11,6 +11,7 @@ Macro Data index find and plot any (major) index on the market [Source: Yahoo Finance] treasury obtain U.S. treasury rates [Source: EconDB] yield show the U.S. Treasury yield curve [Source: FRED] + ycrv show sovereign yield curves [Source: Investing.com/FRED] plot plot data from the above commands together options show the available options for 'plot' or show/export the data diff --git a/website/data/menu/main.yml b/website/data/menu/main.yml index ae2526fd3d59..31fb09d3630f 100755 --- a/website/data/menu/main.yml +++ b/website/data/menu/main.yml @@ -1010,6 +1010,8 @@ main: ref: "/terminal/economy/treasury" - name: yield ref: "/terminal/economy/yield" + - name: ycrv + ref: "/terminal/economy/ycrv" - name: plot ref: "/terminal/economy/plot" - name: rtps