diff --git a/gamestonk_terminal/config_terminal.py b/gamestonk_terminal/config_terminal.py index f1b8757890d..6939d823cee 100644 --- a/gamestonk_terminal/config_terminal.py +++ b/gamestonk_terminal/config_terminal.py @@ -25,3 +25,6 @@ API_POLYGON_KEY = os.getenv("GT_API_POLYGON_KEY") or "REPLACE_ME" API_TWITTER_KEY = os.getenv("GT_API_TWITTER_KEY") or "REPLACE_ME" API_TWITTER_SECRET_KEY = os.getenv("GT_API_TWITTER_SECRET_KEY") or "REPLACE_ME" API_TWITTER_BEARER_TOKEN = os.getenv("GT_API_TWITTER_BEARER_TOKEN") or "REPLACE_ME" + +# https://fred.stlouisfed.org/docs/api/api_key.html +API_FRED_KEY = os.getenv("GT_FRED_API_KEY") or "REPLACE_ME" diff --git a/gamestonk_terminal/fred/README.md b/gamestonk_terminal/fred/README.md new file mode 100644 index 00000000000..f781a1ac1e4 --- /dev/null +++ b/gamestonk_terminal/fred/README.md @@ -0,0 +1,124 @@ +# FRED + +https://fred.stlouisfed.org + +The purpose of fred is to have the ability to look at economic data. This page offers 2 options: + +* [predefined](#gdp) + * Get predefined data +* [cust](#cust) + * Get custom fred data + +The current predefined options are +* GDP +* 1,5,10,30 Year Treasury Rates +* 30 Year Mortgage Rates +* Unemployment Rate +* Effective Federal Funds rate +* Moody's AAA Corporate Bond +* CAD to USD Conversion. + +## predefined +```text +usage: selected [-n N_TO_GET] [-s START_DATE] [--noplot] [--hidedata] +``` +Gets predefined data. Arguments +* selected : Key from the predefined list. +* -s : Start Date. Format YYYY-mm-dd. First point to get. Defaults to Jan 1 2019 +* --noplot : Flag to hide plot +* --hidedata : Flag to suppress printing output. Useful for data released daily/weekly. + +To plot the 30-Year Mortgage rates since 2018-01-01 suppressing the output. +```` +mort30 -s 2018-01-01 --hidedata +```` + +![mort30](https://user-images.githubusercontent.com/18151143/111521185-3d80dc80-872f-11eb-989d-c2bb256aa213.png) + +To show all GDP data since 1/1/2016, with no plot. +```` +gdp -s 2016-01-01 --noplot +```` +Output: +```` + GDP +Date +2016-01-01 18470.156 +2016-04-01 18656.207 +2016-07-01 18821.359 +2016-10-01 19032.580 +2017-01-01 19237.435 +2017-04-01 19379.232 +2017-07-01 19617.288 +2017-10-01 19937.963 +2018-01-01 20242.215 +2018-04-01 20552.653 +2018-07-01 20742.723 +2018-10-01 20909.853 +2019-01-01 21115.309 +2019-04-01 21329.877 +2019-07-01 21540.325 +2019-10-01 21747.394 +2020-01-01 21561.139 +2020-04-01 19520.114 +2020-07-01 21170.252 +2020-10-01 21487.896 +```` + + +## cust + +The fred database has many different datasets freely available. They each have their own custom SERIES_ID which can be obtained through the website. + +```` +usage: cust [-i --id] [-s START_DATE] [--noplot] [--hidedata] +```` +* -i/--id : Series ID for FRED data. Required argument +* -s : Start Date. Format YYYY-mm-dd. First point to get. Defaults to Jan 1 2015. +* --noplot : Flag to suppress output plot. +* --hidedata : Flag to suppress data output + +An example of custom data could be the USD/EURO exchange rate. +According to https://fred.stlouisfed.org/series/DEXUSEU , the series ID is DEXUSEU. So to plot this from the start of February 2021 to now (3/17) + +```` +cust --id DEXUSEU -s 2021-02-01 +```` +This will plot and display: +![cust](https://user-images.githubusercontent.com/18151143/111521481-92bcee00-872f-11eb-8a02-e7346e56e462.png) + +```` + DEXUSEU +Date +2021-02-01 1.2070 +2021-02-02 1.2020 +2021-02-03 1.2025 +2021-02-04 1.1974 +2021-02-05 1.2035 +2021-02-08 1.2045 +2021-02-09 1.2106 +2021-02-10 1.2132 +2021-02-11 1.2127 +2021-02-12 1.2126 +2021-02-15 NaN +2021-02-16 1.2107 +2021-02-17 1.2042 +2021-02-18 1.2078 +2021-02-19 1.2136 +2021-02-22 1.2155 +2021-02-23 1.2142 +2021-02-24 1.2143 +2021-02-25 1.2229 +2021-02-26 1.2093 +2021-03-01 1.2054 +2021-03-02 1.2079 +2021-03-03 1.2073 +2021-03-04 1.2045 +2021-03-05 1.1914 +2021-03-08 1.1849 +2021-03-09 1.1885 +2021-03-10 1.1900 +2021-03-11 1.1978 +```` + +Note the NaN on 2-15, which corresponds to President's Day. \ No newline at end of file diff --git a/gamestonk_terminal/fred/__init__.py b/gamestonk_terminal/fred/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/gamestonk_terminal/fred/fred_api.py b/gamestonk_terminal/fred/fred_api.py new file mode 100644 index 00000000000..1b90ca10e87 --- /dev/null +++ b/gamestonk_terminal/fred/fred_api.py @@ -0,0 +1,191 @@ +import argparse +import pandas as pd +from pandas.plotting import register_matplotlib_converters +import matplotlib.pyplot as plt +from fredapi import Fred +from gamestonk_terminal.helper_funcs import ( + parse_known_args_and_warn, + valid_date, + plot_autoscale, +) +from gamestonk_terminal.config_plot import PLOT_DPI +from gamestonk_terminal.config_terminal import API_FRED_KEY +from gamestonk_terminal import feature_flags as gtff + +register_matplotlib_converters() + +api_map = { + "gdp": "GDP", + "t10": "DGS10", + "t1": "DGS1", + "t5": "DGS5", + "t30": "DGS30", + "mort30": "MORTGAGE30US", + "fedrate": "FEDFUNDS", + "moodAAA": "AAA", + "usdcad": "DEXCAUS", + "unemp": "UNRATE", +} +title_map = { + "gdp": "Gross Domestic Product", + "t10": "10-Year Treasury Constant Maturity Rate", + "t1": "1-Year Treasury Constant Maturity Rate", + "t5": "5-Year Treasury Constant Maturity Rate", + "t30": "30-Year Treasury Constant Maturity Rate", + "mort30": "30-Year Mortgage Rate", + "fedrate": "Effective Federal Funds Rate", + "moodAAA": "Moody's Seasoned AAA Corporate Bond Yield", + "usdcad": "Canada / U.S. Foreign Exchange Rate", + "unemp": "Unemployment Rate", +} + + +def get_fred_data(l_args, choice): + fred = Fred(api_key=API_FRED_KEY) + + parser = argparse.ArgumentParser( + add_help=False, + prog="Custom", + description=""" + Custom Data + """, + ) + + parser.add_argument( + "-s", + dest="start_date", + type=valid_date, + default="2019-01-01", + required=False, + help="Starting date (YYYY-MM-DD) of data", + ) + + parser.add_argument( + "--noplot", + action="store_false", + default=True, + dest="noplot", + help="Suppress output plot", + ) + + parser.add_argument( + "--hidedata", + action="store_false", + default=True, + dest="hidedata", + help="Suppress data display plot", + ) + + try: + ns_parser = parse_known_args_and_warn(parser, l_args) + + if not ns_parser: + return + + string_to_get = api_map[choice] + title = title_map[choice] + data = fred.get_series(string_to_get, ns_parser.start_date) + + data = pd.DataFrame(data, columns=[f"{string_to_get}"]) + data.index.name = "Date" + if ns_parser.hidedata: + print(data) + print("") + if ns_parser.noplot: + plt.figure(figsize=plot_autoscale(), dpi=PLOT_DPI) + plt.plot(data.index, data.iloc[:, 0], "-ok") + plt.xlabel("Time") + plt.xlim(data.index[0], data.index[-1]) + plt.ylabel(f"{string_to_get}") + plt.grid(b=True, which="major", color="#666666", linestyle="-") + plt.minorticks_on() + plt.grid(b=True, which="minor", color="#999999", linestyle="-", alpha=0.2) + plt.title(title) + plt.show() + print("") + + if gtff.USE_ION: + plt.ion() + + except SystemExit: + print("") + except Exception as e: + print(e) + print("") + return + + +def custom_data(l_args): + fred = Fred(api_key=API_FRED_KEY) + + parser = argparse.ArgumentParser( + add_help=False, + prog="Custom", + description=""" + Custom Data + """, + ) + parser.add_argument( + "-i", "--id", dest="series_id", required=True, type=str, help="FRED Series ID" + ) + + parser.add_argument( + "-s", + dest="start_date", + type=valid_date, + default="2019-01-01", + required=False, + help="Starting date (YYYY-MM-DD) of data", + ) + + parser.add_argument( + "--noplot", + action="store_false", + default=True, + dest="noplot", + help="Suppress output plot", + ) + + parser.add_argument( + "--hidedata", + action="store_false", + default=True, + dest="hidedata", + help="Suppress data display plot", + ) + + try: + ns_parser = parse_known_args_and_warn(parser, l_args) + + if not ns_parser: + return + + data = fred.get_series(ns_parser.series_id, ns_parser.start_date) + + data = pd.DataFrame(data, columns=[f"{ns_parser.series_id}"]) + data.index.name = "Date" + if ns_parser.hidedata: + print(data) + print("") + if ns_parser.noplot: + plt.figure(figsize=plot_autoscale(), dpi=PLOT_DPI) + plt.plot(data.index, data.iloc[:, 0], "-ok") + plt.xlabel("Time") + plt.xlim(data.index[0], data.index[-1]) + plt.ylabel(f"{ns_parser.series_id}") + plt.grid(b=True, which="major", color="#666666", linestyle="-") + plt.minorticks_on() + plt.grid(b=True, which="minor", color="#999999", linestyle="-", alpha=0.2) + plt.title(f"FRED {ns_parser.series_id} Series") + plt.show() + print("") + + if gtff.USE_ION: + plt.ion() + + except SystemExit: + print("") + except Exception as e: + print(e) + print("") + return diff --git a/gamestonk_terminal/fred/fred_menu.py b/gamestonk_terminal/fred/fred_menu.py new file mode 100644 index 00000000000..5a7734835be --- /dev/null +++ b/gamestonk_terminal/fred/fred_menu.py @@ -0,0 +1,90 @@ +import argparse +from matplotlib import pyplot as plt +from prompt_toolkit.completion import NestedCompleter +from gamestonk_terminal import feature_flags as gtff +from gamestonk_terminal.helper_funcs import get_flair +from gamestonk_terminal.menu import session +from gamestonk_terminal.fred import fred_api + + +def print_fred(): + """ Print help """ + + print("\nFred Economic Data:") + print(" help show this menu again") + print(" q quit this menu, and shows back to main menu") + print(" quit quit to abandon program") + print(" ") + print(" gdp GDP") + print(" unemp Unemployment Rate") + print(" t1 1-Year Treasury Constant Maturity Rate") + print(" t5 5-Year Treasury Constant Maturity Rate") + print(" t10 10-Year Treasury Constant Maturity Rate") + print(" t30 30-Year Treasury Constant Maturity Rate") + print(" mort30 30-Year Fixed Rate Mortgage Average") + print(" fedrate Effective Federal Funds Rate") + print(" moodAAA Moody's Seasoned AAA Corporate Bond Yield") + print(" usdcad Canada / U.S. Foreign Exchange Rate (CAD per 1 USD)") + print("") + print(" cust User Specified FRED Data - Please Specify --id") + print("") + return + + +def fred_menu(): + plt.close("all") + fred_parser = argparse.ArgumentParser(prog="fred", add_help=False) + defined_choices = [ + "gdp", + "unemp", + "t1", + "t5", + "t10", + "t30", + "mort30", + "fedrate", + "moodAAA", + "usdcad", + ] + choices = ["help", "q", "quit", "cust"] + defined_choices + + fred_parser.add_argument("cmd", choices=choices) + completer = NestedCompleter.from_nested_dict({c: None for c in choices}) + + should_print_help = True + while True: + if should_print_help: + print_fred() + should_print_help = False + + # Get input command from user + if session and gtff.USE_PROMPT_TOOLKIT: + as_input = session.prompt( + f"{get_flair()} (fred)> ", + completer=completer, + ) + else: + as_input = input(f"{get_flair()} (fred)> ") + try: + (ns_known_args, l_args) = fred_parser.parse_known_args(as_input.split()) + + except SystemExit: + print("The command selected doesn't exist\n") + continue + + if ns_known_args.cmd == "help": + should_print_help = True + + elif ns_known_args.cmd == "q": + # Leave the fred menu + return False + + elif ns_known_args.cmd == "quit": + # Abandon the program + return True + + elif ns_known_args.cmd in defined_choices: + fred_api.get_fred_data(l_args, ns_known_args.cmd) + + elif ns_known_args.cmd == "cust": + fred_api.custom_data(l_args) diff --git a/gamestonk_terminal/helper_funcs.py b/gamestonk_terminal/helper_funcs.py index 17e255bba25..1f0ab039d11 100644 --- a/gamestonk_terminal/helper_funcs.py +++ b/gamestonk_terminal/helper_funcs.py @@ -357,6 +357,16 @@ def get_flair() -> str: return "" +def str_to_bool(value): + if isinstance(value, bool): + return value + if value.lower() in {"false", "f", "0", "no", "n"}: + return False + if value.lower() in {"true", "t", "1", "yes", "y"}: + return True + raise ValueError(f"{value} is not a valid boolean value") + + def get_screeninfo(): screens = get_monitors() # Get all available monitors if len(screens) - 1 < cfgPlot.MONITOR: # Check to see if chosen monitor is detected diff --git a/gamestonk_terminal/main_helper.py b/gamestonk_terminal/main_helper.py index 30e9905287c..78272a3b092 100644 --- a/gamestonk_terminal/main_helper.py +++ b/gamestonk_terminal/main_helper.py @@ -53,6 +53,10 @@ def print_help(s_ticker, s_start, s_interval, b_is_market_open): print( " sen sentiment of the market, \t from: reddit, stocktwits, twitter" ) + print( + " fred economic data, \t\t\t from: Federal Reserve Bank of St. Louis " + ) + if s_ticker: print( " res research web page, \t e.g.: macroaxis, yahoo finance, fool" diff --git a/poetry.lock b/poetry.lock index 5b554d913be..45b449e6623 100644 --- a/poetry.lock +++ b/poetry.lock @@ -476,6 +476,17 @@ category = "main" optional = true python-versions = "*" +[[package]] +name = "fredapi" +version = "0.4.3" +description = "Python API for Federal Reserve Economic Data (FRED) from St. Louis Fed" +category = "main" +optional = false +python-versions = "*" + +[package.dependencies] +pandas = "*" + [[package]] name = "ftfy" version = "5.9" @@ -2506,7 +2517,8 @@ prediction = ["fbprophet", "tensorflow", "pmdarima", "transformers", "flair", "t [metadata] lock-version = "1.1" python-versions = "^3.6.8" -content-hash = "c4a363cd8824c8ccab409ccfc74956db82f9cf9800cd46539b14c7ea927f36de" +content-hash = "184502c6b8d4b7db5baa4323e7f70b2585c6140c304583f0678e24681b8f9c9b" + [metadata.files] absl-py = [ @@ -2810,6 +2822,10 @@ flatbuffers = [ {file = "flatbuffers-1.12-py2.py3-none-any.whl", hash = "sha256:9e9ef47fa92625c4721036e7c4124182668dc6021d9e7c73704edd395648deb9"}, {file = "flatbuffers-1.12.tar.gz", hash = "sha256:63bb9a722d5e373701913e226135b28a6f6ac200d5cc7b4d919fa38d73b44610"}, ] +fredapi = [ + {file = "fredapi-0.4.3-py3-none-any.whl", hash = "sha256:e06075592eabddadfe0635f3c59e9072c9f48647430328b4582171ea10f7df2f"}, + {file = "fredapi-0.4.3.tar.gz", hash = "sha256:d9b3194fb60541991bd33f019c710d4a9580ecfb5e47efbf2d2571888a2aac02"}, +] ftfy = [ {file = "ftfy-5.9.tar.gz", hash = "sha256:8c4fb2863c0b82eae2ab3cf353d9ade268dfbde863d322f78d6a9fd5cefb31e9"}, ] diff --git a/pyproject.toml b/pyproject.toml index e775e13f428..84c831a6e37 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -38,6 +38,7 @@ jupyter = "^1.0.0" mplfinance = "^0.12.7-alpha.7" seaborn = "^0.11.0" scipy = "1.5.4" +fredapi = "^0.4.3" screeninfo = "^0.6.7" [tool.poetry.dev-dependencies] diff --git a/requirements.txt b/requirements.txt index 8c767a55b06..06971cc844c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -25,6 +25,7 @@ decorator==4.4.2; python_full_version >= "3.6.1" and python_version >= "3.6" and defusedxml==0.7.1; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.6" entrypoints==0.3; python_version >= "3.6" finviz==1.3.4 +fredapi==0.4.3 fundamentalanalysis==0.2.6 hijri-converter==2.1.1; python_version >= "3.6" holidays==0.10.5.2 diff --git a/terminal.py b/terminal.py index 48c7e7cab05..7fdcdf2f797 100644 --- a/terminal.py +++ b/terminal.py @@ -22,6 +22,7 @@ from gamestonk_terminal.papermill import papermill_controller as mill from gamestonk_terminal.sentiment import sen_menu as sm from gamestonk_terminal.technical_analysis import ta_menu as tam from gamestonk_terminal.comparison_analysis import ca_menu as cam +from gamestonk_terminal.fred import fred_menu as fm # import warnings # warnings.simplefilter("always") @@ -71,6 +72,7 @@ def main(): "dd", "pred", "ca", + "fred", ] menu_parser.add_argument("opt", choices=choices) completer = NestedCompleter.from_nested_dict({c: None for c in choices}) @@ -178,6 +180,9 @@ def main(): elif ns_known_args.opt == "dd": b_quit = ddm.dd_menu(df_stock, s_ticker, s_start, s_interval) + elif ns_known_args.opt == "fred": + b_quit = fm.fred_menu() + elif ns_known_args.opt == "pred": if not gtff.ENABLE_PREDICT: