mirror of
https://github.com/OpenBB-finance/OpenBB.git
synced 2026-10-27 12:40:35 +00:00
Fred menu (#1038)
This commit is contained in:
@@ -16,7 +16,6 @@ from gamestonk_terminal.economy import (
|
||||
cnn_view,
|
||||
finnhub_view,
|
||||
finviz_view,
|
||||
fred_view,
|
||||
nasdaq_model,
|
||||
wsj_view,
|
||||
nasdaq_view,
|
||||
@@ -35,7 +34,7 @@ from gamestonk_terminal.helper_funcs import (
|
||||
)
|
||||
from gamestonk_terminal.menu import session
|
||||
|
||||
# pylint: disable=R1710,R0904
|
||||
# pylint: disable=R1710,R0904,C0415
|
||||
|
||||
|
||||
class EconomyController:
|
||||
@@ -67,6 +66,7 @@ class EconomyController:
|
||||
"quit",
|
||||
"reset",
|
||||
]
|
||||
CHOICES_MENUS = ["fred"]
|
||||
|
||||
CHOICES_COMMANDS = [
|
||||
"feargreed",
|
||||
@@ -82,8 +82,6 @@ class EconomyController:
|
||||
"meats",
|
||||
"grains",
|
||||
"softs",
|
||||
"search",
|
||||
"series",
|
||||
"valuation",
|
||||
"performance",
|
||||
"spectrum",
|
||||
@@ -99,7 +97,7 @@ class EconomyController:
|
||||
"bigmac",
|
||||
]
|
||||
|
||||
CHOICES += CHOICES_COMMANDS
|
||||
CHOICES += CHOICES_COMMANDS + CHOICES_MENUS
|
||||
|
||||
def __init__(self):
|
||||
"""Constructor"""
|
||||
@@ -147,11 +145,10 @@ Alpha Vantage:
|
||||
cpi consumer price index for United States
|
||||
tyld treasury yields for United States
|
||||
unemp United States unemployment rates
|
||||
FRED:
|
||||
search search FRED series notes
|
||||
series plot series from https://fred.stlouisfed.org
|
||||
NASDAQ DataLink (formerly Quandl):
|
||||
bigmac the economists Big Mac index
|
||||
|
||||
> fred Federal Reserve Economic Data submenu
|
||||
"""
|
||||
print(help_text)
|
||||
|
||||
@@ -1236,102 +1233,6 @@ NASDAQ DataLink (formerly Quandl):
|
||||
export=ns_parser.export,
|
||||
)
|
||||
|
||||
@try_except
|
||||
def call_series(self, other_args: List[str]):
|
||||
"""Process series command"""
|
||||
parser = argparse.ArgumentParser(
|
||||
add_help=False,
|
||||
prog="series",
|
||||
description="""
|
||||
Display (multiple) series from https://fred.stlouisfed.org. [Source: FRED]
|
||||
""",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-i",
|
||||
"--id",
|
||||
dest="series_id",
|
||||
required="-h" not in other_args,
|
||||
type=str,
|
||||
help="FRED Series from https://fred.stlouisfed.org. For multiple series use: series1,series2,series3",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-s",
|
||||
dest="start_date",
|
||||
type=valid_date,
|
||||
default="2019-01-01",
|
||||
help="Starting date (YYYY-MM-DD) of data",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--raw",
|
||||
action="store_true",
|
||||
dest="raw",
|
||||
help="Only output raw data",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--export",
|
||||
choices=["csv", "json", "xlsx"]
|
||||
if "--raw" in other_args
|
||||
else ["png", "jpg", "pdf", "svg"],
|
||||
default="",
|
||||
type=str,
|
||||
dest="export",
|
||||
help="Export data to csv,json,xlsx or png,jpg,pdf,svg file",
|
||||
)
|
||||
if other_args:
|
||||
if "-" not in other_args[0]:
|
||||
other_args.insert(0, "-i")
|
||||
|
||||
ns_parser = parse_known_args_and_warn(parser, other_args)
|
||||
if not ns_parser:
|
||||
return
|
||||
|
||||
fred_view.display_series(
|
||||
series=ns_parser.series_id,
|
||||
start_date=ns_parser.start_date,
|
||||
raw=ns_parser.raw,
|
||||
export=ns_parser.export,
|
||||
)
|
||||
|
||||
@try_except
|
||||
def call_search(self, other_args: List[str]):
|
||||
"""Process search command"""
|
||||
parser = argparse.ArgumentParser(
|
||||
add_help=False,
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||
prog="search",
|
||||
description="Print series notes when searching for series. [Source: FRED]",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-s",
|
||||
"--series",
|
||||
action="store",
|
||||
dest="series_term",
|
||||
type=str,
|
||||
required="-h" not in other_args,
|
||||
help="Search for this series term.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-n",
|
||||
"--num",
|
||||
action="store",
|
||||
dest="num",
|
||||
type=check_positive,
|
||||
default=5,
|
||||
help="Maximum number of series notes to display.",
|
||||
)
|
||||
if other_args:
|
||||
if "-" not in other_args[0]:
|
||||
other_args.insert(0, "-s")
|
||||
|
||||
ns_parser = parse_known_args_and_warn(parser, other_args)
|
||||
if not ns_parser:
|
||||
return
|
||||
|
||||
fred_view.notes(
|
||||
series_term=ns_parser.series_term,
|
||||
num=ns_parser.num,
|
||||
)
|
||||
|
||||
@try_except
|
||||
def call_bigmac(self, other_args: List[str]):
|
||||
"""Process bigmac command"""
|
||||
@@ -1382,6 +1283,17 @@ NASDAQ DataLink (formerly Quandl):
|
||||
export=ns_parser.export,
|
||||
)
|
||||
|
||||
def call_fred(self, _):
|
||||
"""Process fred command"""
|
||||
from gamestonk_terminal.economy.fred import fred_controller
|
||||
|
||||
ret = fred_controller.menu()
|
||||
|
||||
if ret is False:
|
||||
self.print_help()
|
||||
else:
|
||||
return True
|
||||
|
||||
|
||||
def menu():
|
||||
"""Econ Menu"""
|
||||
|
||||
0
gamestonk_terminal/economy/fred/__init__.py
Normal file
0
gamestonk_terminal/economy/fred/__init__.py
Normal file
301
gamestonk_terminal/economy/fred/fred_controller.py
Normal file
301
gamestonk_terminal/economy/fred/fred_controller.py
Normal file
@@ -0,0 +1,301 @@
|
||||
"""FRED Controller"""
|
||||
__docformat__ = "numpy"
|
||||
|
||||
import argparse
|
||||
import difflib
|
||||
from typing import List
|
||||
|
||||
from colorama import Style
|
||||
from prompt_toolkit.completion import NestedCompleter
|
||||
|
||||
from gamestonk_terminal import feature_flags as gtff
|
||||
from gamestonk_terminal.economy.fred import fred_view, fred_model
|
||||
from gamestonk_terminal.helper_funcs import (
|
||||
EXPORT_BOTH_RAW_DATA_AND_FIGURES,
|
||||
check_positive,
|
||||
get_flair,
|
||||
parse_known_args_and_warn,
|
||||
valid_date,
|
||||
try_except,
|
||||
system_clear,
|
||||
)
|
||||
from gamestonk_terminal.menu import session
|
||||
|
||||
|
||||
class FredController:
|
||||
CHOICES = ["cls", "?", "help", "q", "quit"]
|
||||
|
||||
CHOICES_COMMANDS = ["search", "add", "rmv", "plot"]
|
||||
|
||||
CHOICES += CHOICES_COMMANDS
|
||||
|
||||
def __init__(self):
|
||||
"""Constructor"""
|
||||
self.fred_parser = argparse.ArgumentParser(add_help=False, prog="fred")
|
||||
self.fred_parser.add_argument(
|
||||
"cmd",
|
||||
choices=self.CHOICES,
|
||||
)
|
||||
self.current_series = dict()
|
||||
self.current_long_id = 0
|
||||
|
||||
def print_help(self):
|
||||
"""Print help"""
|
||||
id_string = ""
|
||||
for s_id, sub_dict in self.current_series.items():
|
||||
id_string += f" {s_id.upper()}{(self.current_long_id-len(s_id)) * ' '} : {sub_dict['title']}\n"
|
||||
help_text = f"""
|
||||
What do you want to do?
|
||||
cls clear screen
|
||||
?/help show this menu again
|
||||
q quit this menu, and shows back to main menu
|
||||
quit quit to abandon program
|
||||
|
||||
search search FRED series notes
|
||||
add add series ID to list
|
||||
rmv remove series ID from list
|
||||
|
||||
Current Series IDs:
|
||||
{id_string}{Style.DIM if not self.current_series else ""}
|
||||
plot plot selected series {Style.RESET_ALL}
|
||||
"""
|
||||
print(help_text)
|
||||
|
||||
def switch(self, an_input: str):
|
||||
"""Process and dispatch input
|
||||
|
||||
Returns
|
||||
-------
|
||||
MENU_GO_BACK, MENU_QUIT, MENU_RESET
|
||||
MENU_GO_BACK - Show main context menu again
|
||||
MENU_QUIT - Quit terminal
|
||||
MENU_RESET - Reset terminal and go back to same previous menu
|
||||
"""
|
||||
|
||||
# Empty command
|
||||
if not an_input:
|
||||
print("")
|
||||
return None
|
||||
|
||||
(known_args, other_args) = self.fred_parser.parse_known_args(an_input.split())
|
||||
|
||||
# Help menu again
|
||||
if known_args.cmd == "?":
|
||||
self.print_help()
|
||||
return None
|
||||
|
||||
# Clear screen
|
||||
if known_args.cmd == "cls":
|
||||
system_clear()
|
||||
return None
|
||||
|
||||
return getattr(
|
||||
self, "call_" + known_args.cmd, lambda: "Command not recognized!"
|
||||
)(other_args)
|
||||
|
||||
def call_help(self, _):
|
||||
"""Process Help command"""
|
||||
self.print_help()
|
||||
|
||||
def call_q(self, _):
|
||||
"""Process Q command - quit the menu"""
|
||||
return False
|
||||
|
||||
def call_quit(self, _):
|
||||
"""Process Quit command - exit the program"""
|
||||
return True
|
||||
|
||||
@try_except
|
||||
def call_search(self, other_args: List[str]):
|
||||
"""Process search command"""
|
||||
parser = argparse.ArgumentParser(
|
||||
add_help=False,
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||
prog="search",
|
||||
description="Print series notes when searching for series. [Source: FRED]",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-s",
|
||||
"--series",
|
||||
action="store",
|
||||
dest="series_term",
|
||||
type=str,
|
||||
required="-h" not in other_args,
|
||||
help="Search for this series term.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-n",
|
||||
"--num",
|
||||
action="store",
|
||||
dest="num",
|
||||
type=check_positive,
|
||||
default=5,
|
||||
help="Maximum number of series notes to display.",
|
||||
)
|
||||
if other_args and "-" not in other_args[0]:
|
||||
other_args.insert(0, "-s")
|
||||
|
||||
ns_parser = parse_known_args_and_warn(parser, other_args)
|
||||
if not ns_parser:
|
||||
return
|
||||
|
||||
fred_view.notes(
|
||||
series_term=ns_parser.series_term,
|
||||
num=ns_parser.num,
|
||||
)
|
||||
|
||||
@try_except
|
||||
def call_add(self, other_args: List[str]):
|
||||
"""Process add command"""
|
||||
parser = argparse.ArgumentParser(
|
||||
add_help=False,
|
||||
prog="add",
|
||||
description="Add a FRED series to current selection",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-i",
|
||||
"--id",
|
||||
dest="series_id",
|
||||
required="-h" not in other_args,
|
||||
type=str,
|
||||
help="FRED Series from https://fred.stlouisfed.org. For multiple series use: series1,series2,series3",
|
||||
)
|
||||
if other_args and "-" not in other_args[0]:
|
||||
other_args.insert(0, "-i")
|
||||
ns_parser = parse_known_args_and_warn(parser, other_args)
|
||||
if not ns_parser:
|
||||
return
|
||||
|
||||
# Loop through entries. If it exists, save title in dictionary
|
||||
for s_id in ns_parser.series_id.split(","):
|
||||
exists, information = fred_model.check_series_id(s_id)
|
||||
if exists:
|
||||
self.current_series[s_id] = {
|
||||
"title": information["seriess"][0]["title"],
|
||||
"units": information["seriess"][0]["units_short"],
|
||||
}
|
||||
self.current_long_id = max(self.current_long_id, len(s_id))
|
||||
|
||||
print(
|
||||
f"Current Series: {', '.join(self.current_series.keys()) .upper() or None}\n"
|
||||
)
|
||||
|
||||
@try_except
|
||||
def call_rmv(self, other_args: List[str]):
|
||||
"""Process rmv command"""
|
||||
parser = argparse.ArgumentParser(
|
||||
add_help=False,
|
||||
prog="rmv",
|
||||
description="Remove a FRED series from current selection",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-a",
|
||||
"--all",
|
||||
help="Flag to remove all selections",
|
||||
dest="all",
|
||||
action="store_true",
|
||||
default=False,
|
||||
)
|
||||
parser.add_argument(
|
||||
"-i",
|
||||
"--id",
|
||||
type=str,
|
||||
choices=self.current_series.keys(),
|
||||
required="-h" not in other_args
|
||||
and "-a" not in other_args
|
||||
and "--all" not in other_args,
|
||||
dest="series_id",
|
||||
help="Specific id's to remove",
|
||||
)
|
||||
|
||||
if other_args:
|
||||
if (
|
||||
"-h" not in other_args
|
||||
and "-i" not in other_args
|
||||
and "--id" not in other_args
|
||||
and "-a" not in other_args
|
||||
and "--all" not in other_args
|
||||
):
|
||||
other_args.insert(0, "-i")
|
||||
ns_parser = parse_known_args_and_warn(parser, other_args)
|
||||
if not ns_parser:
|
||||
return
|
||||
|
||||
if ns_parser.all:
|
||||
self.current_series = {}
|
||||
self.current_long_id = 0
|
||||
print("")
|
||||
return
|
||||
|
||||
self.current_series.pop(ns_parser.series_id)
|
||||
print(f"Current Series Ids: {', '.join(self.current_series.keys()) or None}\n")
|
||||
|
||||
@try_except
|
||||
def call_plot(self, other_args):
|
||||
"""Process plot command"""
|
||||
parser = argparse.ArgumentParser(
|
||||
add_help=False,
|
||||
prog="plot",
|
||||
description="Plot selected FRED Series",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-s",
|
||||
dest="start_date",
|
||||
type=valid_date,
|
||||
default="2020-01-01",
|
||||
help="Starting date (YYYY-MM-DD) of data",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--raw",
|
||||
help="Flag to show raw data",
|
||||
dest="raw",
|
||||
action="store_true",
|
||||
default=False,
|
||||
)
|
||||
|
||||
ns_parser = parse_known_args_and_warn(
|
||||
parser, other_args, export_allowed=EXPORT_BOTH_RAW_DATA_AND_FIGURES
|
||||
)
|
||||
if not ns_parser:
|
||||
return
|
||||
|
||||
fred_view.display_fred_series(
|
||||
self.current_series, ns_parser.start_date, ns_parser.raw, ns_parser.export
|
||||
)
|
||||
|
||||
|
||||
def menu():
|
||||
"""Fred Menu"""
|
||||
|
||||
fred_controller = FredController()
|
||||
fred_controller.print_help()
|
||||
|
||||
# Loop forever and ever
|
||||
while True:
|
||||
# Get input command from user
|
||||
if session and gtff.USE_PROMPT_TOOLKIT:
|
||||
completer = NestedCompleter.from_nested_dict(
|
||||
{c: None for c in fred_controller.CHOICES}
|
||||
)
|
||||
|
||||
an_input = session.prompt(
|
||||
f"{get_flair()} (economy)(fred)> ",
|
||||
completer=completer,
|
||||
)
|
||||
else:
|
||||
an_input = input(f"{get_flair()} (economy)(fred)> ")
|
||||
try:
|
||||
process_input = fred_controller.switch(an_input)
|
||||
|
||||
if process_input is not None:
|
||||
return process_input
|
||||
|
||||
except SystemExit:
|
||||
print("The command selected doesn't exist\n")
|
||||
similar_cmd = difflib.get_close_matches(
|
||||
an_input, fred_controller.CHOICES, n=1, cutoff=0.7
|
||||
)
|
||||
|
||||
if similar_cmd:
|
||||
print(f"Did you mean '{similar_cmd[0]}'?\n")
|
||||
continue
|
||||
@@ -1,23 +1,46 @@
|
||||
""" Fred Model """
|
||||
__docformat__ = "numpy"
|
||||
|
||||
from typing import List, Tuple
|
||||
|
||||
from typing import List, Tuple, Dict
|
||||
import requests
|
||||
import fred
|
||||
import pandas as pd
|
||||
from fredapi import Fred
|
||||
|
||||
from gamestonk_terminal import config_terminal as cfg
|
||||
from gamestonk_terminal.helper_funcs import get_user_agent
|
||||
|
||||
|
||||
def check_series_id(series_id: str) -> Tuple[bool, Dict]:
|
||||
"""Checks if series ID exists in fred
|
||||
|
||||
Parameters
|
||||
----------
|
||||
series_id: str
|
||||
Series ID to check
|
||||
|
||||
Returns
|
||||
-------
|
||||
bool:
|
||||
Boolean if series ID exists
|
||||
dict:
|
||||
Dictionary of series information
|
||||
"""
|
||||
url = f"https://api.stlouisfed.org/fred/series?series_id={series_id}&api_key={cfg.API_FRED_KEY}&file_type=json"
|
||||
r = requests.get(url, headers={"User-Agent": get_user_agent()})
|
||||
# The above returns 200 if series is found
|
||||
# There seems to be an occasional bug giving a 503 response where the json decoding fails
|
||||
if r.status_code >= 500:
|
||||
return False, {}
|
||||
return r.status_code == 200, r.json()
|
||||
|
||||
|
||||
def get_series_notes(series_term: str) -> pd.DataFrame:
|
||||
"""Get Series notes. [Source: FRED]
|
||||
|
||||
Parameters
|
||||
----------
|
||||
series_term : str
|
||||
Search for this series term
|
||||
|
||||
Returns
|
||||
----------
|
||||
pd.DataFrame
|
||||
@@ -38,14 +61,12 @@ def get_series_notes(series_term: str) -> pd.DataFrame:
|
||||
|
||||
def get_series_ids(series_term: str, num: int) -> Tuple[List[str], List[str]]:
|
||||
"""Get Series IDs. [Source: FRED]
|
||||
|
||||
Parameters
|
||||
----------
|
||||
series_term : str
|
||||
Search for this series term
|
||||
num : int
|
||||
Maximum number of series IDs to output
|
||||
|
||||
Returns
|
||||
----------
|
||||
List[str]
|
||||
@@ -67,16 +88,14 @@ def get_series_ids(series_term: str, num: int) -> Tuple[List[str], List[str]]:
|
||||
return df_series["id"].values, df_series["title"].values
|
||||
|
||||
|
||||
def get_series_data(series_id: str, start: str):
|
||||
def get_series_data(series_id: str, start: str) -> pd.DataFrame:
|
||||
"""Get Series data. [Source: FRED]
|
||||
|
||||
Parameters
|
||||
----------
|
||||
series_id : str
|
||||
Series ID to get data from
|
||||
start : str
|
||||
Start date to get data from, format yyyy-mm-dd
|
||||
|
||||
Returns
|
||||
----------
|
||||
pd.DataFrame
|
||||
145
gamestonk_terminal/economy/fred/fred_view.py
Normal file
145
gamestonk_terminal/economy/fred/fred_view.py
Normal file
@@ -0,0 +1,145 @@
|
||||
""" Fred View """
|
||||
__docformat__ = "numpy"
|
||||
|
||||
import os
|
||||
import textwrap
|
||||
from typing import Dict
|
||||
import matplotlib.pyplot as plt
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
from pandas.plotting import register_matplotlib_converters
|
||||
from tabulate import tabulate
|
||||
|
||||
from gamestonk_terminal import feature_flags as gtff
|
||||
from gamestonk_terminal.config_plot import PLOT_DPI
|
||||
from gamestonk_terminal.economy.fred import fred_model
|
||||
from gamestonk_terminal.helper_funcs import export_data, plot_autoscale
|
||||
|
||||
register_matplotlib_converters()
|
||||
|
||||
|
||||
def format_units(num: int) -> str:
|
||||
"""Helper to format number into string with K,M,B,T. Number will be in form of 10^n"""
|
||||
number_zeros = int(np.log10(num))
|
||||
if number_zeros < 3:
|
||||
return str(num)
|
||||
if number_zeros < 6:
|
||||
return f"{int(num/1000)}K"
|
||||
if number_zeros < 9:
|
||||
return f"{int(num/1_000_000)}M"
|
||||
if number_zeros < 12:
|
||||
return f"{int(num/1_000_000_000)}B"
|
||||
if number_zeros < 15:
|
||||
return f"{int(num/1_000_000_000_000)}T"
|
||||
return f"10^{number_zeros}"
|
||||
|
||||
|
||||
def notes(series_term: str, num: int):
|
||||
"""Print Series notes. [Source: FRED]
|
||||
Parameters
|
||||
----------
|
||||
series_term : str
|
||||
Search for these series_term
|
||||
num : int
|
||||
Maximum number of series notes to display
|
||||
"""
|
||||
df_search = fred_model.get_series_notes(series_term)
|
||||
if df_search.empty:
|
||||
print("No matches found. \n")
|
||||
return
|
||||
df_search["notes"] = df_search["notes"].apply(
|
||||
lambda x: "\n".join(textwrap.wrap(x, width=100)) if isinstance(x, str) else x
|
||||
)
|
||||
df_search["title"] = df_search["title"].apply(
|
||||
lambda x: "\n".join(textwrap.wrap(x, width=50)) if isinstance(x, str) else x
|
||||
)
|
||||
if gtff.USE_TABULATE_DF:
|
||||
print(
|
||||
tabulate(
|
||||
df_search[["id", "title", "notes"]].head(num),
|
||||
tablefmt="fancy_grid",
|
||||
headers=["Series ID", "Title", "Description"],
|
||||
showindex=False,
|
||||
)
|
||||
)
|
||||
else:
|
||||
print(df_search[["id", "title", "notes"]].head(num).to_string(index=False))
|
||||
print("")
|
||||
|
||||
|
||||
def display_fred_series(
|
||||
d_series: Dict[str, Dict[str, str]],
|
||||
start_date: str,
|
||||
raw: bool = False,
|
||||
export: str = "",
|
||||
):
|
||||
"""Display (multiple) series from https://fred.stlouisfed.org. [Source: FRED]
|
||||
|
||||
Parameters
|
||||
----------
|
||||
series : str
|
||||
FRED Series ID from https://fred.stlouisfed.org. For multiple series use: series1,series2,series3
|
||||
start_date : str
|
||||
Starting date (YYYY-MM-DD) of data
|
||||
raw : bool
|
||||
Output only raw data
|
||||
export : str
|
||||
Export data to csv,json,xlsx or png,jpg,pdf,svg file
|
||||
"""
|
||||
series_ids = list(d_series.keys())
|
||||
data = pd.DataFrame()
|
||||
|
||||
for s_id in series_ids:
|
||||
data = pd.concat(
|
||||
[
|
||||
data,
|
||||
pd.DataFrame(
|
||||
fred_model.get_series_data(s_id, start_date), columns=[s_id]
|
||||
),
|
||||
],
|
||||
axis=1,
|
||||
)
|
||||
|
||||
# Try to get everything onto the same 0-10 scale.
|
||||
# To do so, think in scientific notation. Divide the data by whatever the E would be
|
||||
fig, ax = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI)
|
||||
if len(series_ids) == 1:
|
||||
s_id = series_ids[0]
|
||||
sub_dict: Dict = d_series[s_id]
|
||||
title = f"{sub_dict['title']} ({sub_dict['units']})"
|
||||
ax.plot(data.index, data, label="\n".join(textwrap.wrap(title, 80)))
|
||||
else:
|
||||
for s_id, sub_dict in d_series.items():
|
||||
data_to_plot = data[s_id].dropna()
|
||||
exponent = int(np.log10(data_to_plot.max()))
|
||||
data_to_plot /= 10 ** exponent
|
||||
multiplier = f"x {format_units(10**exponent)}" if exponent > 0 else ""
|
||||
title = f"{sub_dict['title']} ({sub_dict['units']}) {'['+multiplier+']' if multiplier else ''}"
|
||||
ax.plot(
|
||||
data_to_plot.index,
|
||||
data_to_plot,
|
||||
label="\n".join(textwrap.wrap(title, 80)),
|
||||
)
|
||||
|
||||
ax.legend(prop={"size": 10}, bbox_to_anchor=(0, 1), loc="lower left")
|
||||
ax.grid()
|
||||
ax.set_xlim(data.index[0], data.index[-1])
|
||||
ax.spines["top"].set_visible(False)
|
||||
ax.spines["right"].set_visible(False)
|
||||
if gtff.USE_ION:
|
||||
plt.ion()
|
||||
plt.gcf().autofmt_xdate()
|
||||
fig.tight_layout()
|
||||
plt.show()
|
||||
if raw:
|
||||
if gtff.USE_TABULATE_DF:
|
||||
print(tabulate(data.tail(20), headers=data.columns, tablefmt="fancy_grid"))
|
||||
else:
|
||||
print(data.tail(20).to_string())
|
||||
export_data(
|
||||
export,
|
||||
os.path.dirname(os.path.abspath(__file__)),
|
||||
"plot",
|
||||
data,
|
||||
)
|
||||
print("")
|
||||
@@ -1,177 +0,0 @@
|
||||
""" Fred View """
|
||||
__docformat__ = "numpy"
|
||||
|
||||
import os
|
||||
import textwrap
|
||||
|
||||
import matplotlib.pyplot as plt
|
||||
import pandas as pd
|
||||
from pandas.plotting import register_matplotlib_converters
|
||||
from tabulate import tabulate
|
||||
|
||||
from gamestonk_terminal import feature_flags as gtff
|
||||
from gamestonk_terminal.config_plot import PLOT_DPI
|
||||
from gamestonk_terminal.economy import fred_model
|
||||
from gamestonk_terminal.helper_funcs import export_data, plot_autoscale
|
||||
|
||||
register_matplotlib_converters()
|
||||
|
||||
|
||||
def notes(series_term: str, num: int):
|
||||
"""Print Series notes. [Source: FRED]
|
||||
|
||||
Parameters
|
||||
----------
|
||||
series_term : str
|
||||
Search for these series_term
|
||||
num : int
|
||||
Maximum number of series notes to display
|
||||
"""
|
||||
df_search = fred_model.get_series_notes(series_term)
|
||||
if df_search.empty:
|
||||
print("No matches found. \n")
|
||||
return
|
||||
df_search["notes"] = df_search["notes"].apply(
|
||||
lambda x: "\n".join(textwrap.wrap(x, width=100)) if isinstance(x, str) else x
|
||||
)
|
||||
df_search["title"] = df_search["title"].apply(
|
||||
lambda x: "\n".join(textwrap.wrap(x, width=50)) if isinstance(x, str) else x
|
||||
)
|
||||
if gtff.USE_TABULATE_DF:
|
||||
print(
|
||||
tabulate(
|
||||
df_search[["id", "title", "notes"]].head(num),
|
||||
tablefmt="fancy_grid",
|
||||
headers=["Series ID", "Title", "Description"],
|
||||
showindex=False,
|
||||
)
|
||||
)
|
||||
else:
|
||||
print(df_search[["id", "title", "notes"]].head(num).to_string(index=False))
|
||||
print("")
|
||||
|
||||
|
||||
def display_series(series: str, start_date: str, raw: bool, export: str):
|
||||
"""Display (multiple) series from https://fred.stlouisfed.org. [Source: FRED]
|
||||
|
||||
Parameters
|
||||
----------
|
||||
series : str
|
||||
FRED Series ID from https://fred.stlouisfed.org. For multiple series use: series1,series2,series3
|
||||
start_date : str
|
||||
Starting date (YYYY-MM-DD) of data
|
||||
raw : bool
|
||||
Output only raw data
|
||||
export : str
|
||||
Export data to csv,json,xlsx or png,jpg,pdf,svg file
|
||||
"""
|
||||
if export:
|
||||
l_series_fred = []
|
||||
|
||||
if not raw:
|
||||
_, ax = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI)
|
||||
ax.axes.get_yaxis().set_visible(False)
|
||||
plt.subplots_adjust(right=0.9 - series.count(",") * 0.1)
|
||||
l_colors = [
|
||||
"tab:blue",
|
||||
"tab:orange",
|
||||
"tab:green",
|
||||
"tab:red",
|
||||
"tab:purple",
|
||||
"tab:brown",
|
||||
"tab:pink",
|
||||
"tab:gray",
|
||||
"tab:olive",
|
||||
"tab:cyan",
|
||||
]
|
||||
|
||||
l_ts_start = []
|
||||
l_ts_end = []
|
||||
p = {}
|
||||
success = -1
|
||||
success_series = []
|
||||
success_titles = []
|
||||
|
||||
for series_term in series.split(","):
|
||||
if series_term:
|
||||
l_series, l_title = fred_model.get_series_ids(series_term, 5)
|
||||
|
||||
if len(l_series) == 0:
|
||||
print(f"No series found for term '{series_term}'\n")
|
||||
continue
|
||||
|
||||
print(f"For '{series_term}', series IDs found: {', '.join(l_series)}.\n")
|
||||
|
||||
ser = l_series[0]
|
||||
ser_title = l_title[0]
|
||||
df_fred = fred_model.get_series_data(ser, start_date)
|
||||
|
||||
if export:
|
||||
l_series_fred.append(df_fred)
|
||||
|
||||
df_fred.index.name = "Date"
|
||||
|
||||
if raw:
|
||||
df_fred.index = df_fred.index.strftime("%d/%m/%Y")
|
||||
if gtff.USE_TABULATE_DF:
|
||||
print(
|
||||
tabulate(
|
||||
df_fred.dropna().to_frame(),
|
||||
showindex=True,
|
||||
headers=[f"{ser}: {ser_title}"],
|
||||
tablefmt="fancy_grid",
|
||||
floatfmt=".2f",
|
||||
),
|
||||
"\n",
|
||||
)
|
||||
else:
|
||||
print(df_fred.dropna().to_frame().to_string(), "\n")
|
||||
|
||||
else:
|
||||
success += 1
|
||||
success_series.append(ser.upper())
|
||||
success_titles.append(ser_title)
|
||||
|
||||
axes = ax.twinx()
|
||||
axes.spines["right"].set_position(("axes", 1 + success * 0.15))
|
||||
axes.spines["right"].set_color(l_colors[success])
|
||||
(p[success],) = axes.plot(
|
||||
df_fred.index,
|
||||
df_fred.values,
|
||||
c=l_colors[success],
|
||||
label=ser.upper(),
|
||||
)
|
||||
|
||||
axes.yaxis.label.set_color(l_colors[success])
|
||||
|
||||
l_ts_start.append(df_fred.index[0])
|
||||
l_ts_end.append(df_fred.index[-1])
|
||||
|
||||
if not raw and success > -1:
|
||||
plt.title("FRED: " + ", ".join(success_series))
|
||||
plt.xlim(min(l_ts_start), max(l_ts_end))
|
||||
plt.gcf().autofmt_xdate()
|
||||
plt.xlabel("Time")
|
||||
plt.legend(
|
||||
[val for _, val in p.items()], success_titles, loc="best", prop={"size": 6}
|
||||
)
|
||||
plt.gca().spines["left"].set_visible(False)
|
||||
export_data(
|
||||
export,
|
||||
os.path.dirname(os.path.abspath(__file__)),
|
||||
"series",
|
||||
)
|
||||
if gtff.USE_ION:
|
||||
plt.ion()
|
||||
plt.show()
|
||||
|
||||
if export and raw:
|
||||
df_data = pd.concat(l_series_fred, axis=1)
|
||||
df_data.columns = success_series
|
||||
|
||||
export_data(
|
||||
export,
|
||||
os.path.dirname(os.path.abspath(__file__)),
|
||||
"series",
|
||||
df_data,
|
||||
)
|
||||
@@ -2,10 +2,10 @@
|
||||
import unittest
|
||||
from unittest import mock
|
||||
import io
|
||||
|
||||
import pytest
|
||||
import pandas as pd
|
||||
|
||||
from gamestonk_terminal.economy.fred_view import display_series
|
||||
from gamestonk_terminal.economy.fred.fred_view import display_fred_series
|
||||
from tests.helpers import check_print
|
||||
|
||||
fred_data_mock = """
|
||||
@@ -27,15 +27,16 @@ Date
|
||||
"""
|
||||
|
||||
|
||||
@pytest.mark.skip
|
||||
class TestFredFredView(unittest.TestCase):
|
||||
@check_print(assert_in="No series found for term")
|
||||
@mock.patch("gamestonk_terminal.economy.fred_model.get_series_data")
|
||||
@check_print(assert_in="gdp")
|
||||
@mock.patch("gamestonk_terminal.economy.fred.fred_model.get_series_data")
|
||||
def test_display_fred(self, mock_get_series):
|
||||
fred_data = pd.read_csv(io.StringIO(fred_data_mock), header=0, index_col=0)
|
||||
|
||||
mock_get_series.return_value = fred_data
|
||||
display_series(
|
||||
series="gdp",
|
||||
display_fred_series(
|
||||
d_series={"gdp": {"title": "GDP", "units": "Bil Dollars"}},
|
||||
start_date="2019-01-01",
|
||||
raw=True,
|
||||
export="",
|
||||
|
||||
11
website/content/economy/fred/add/_index.md
vendored
Normal file
11
website/content/economy/fred/add/_index.md
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
```
|
||||
usage: add [-i SERIES_ID] [-h]
|
||||
```
|
||||
|
||||
Add a FRED series to current selection
|
||||
```
|
||||
optional arguments:
|
||||
-i SERIES_ID, --id SERIES_ID
|
||||
FRED Series from https://fred.stlouisfed.org. For multiple series use: series1,series2,series3
|
||||
-h, --help show this help message
|
||||
```
|
||||
13
website/content/economy/fred/plot/_index.md
vendored
Normal file
13
website/content/economy/fred/plot/_index.md
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
```
|
||||
usage: plot [-s START_DATE] [--raw] [-h] [--export {csv,json,xlsx,png,jpg,pdf,svg}]
|
||||
```
|
||||
|
||||
Plot selected FRED Series
|
||||
``````
|
||||
optional arguments:
|
||||
-s START_DATE Starting date (YYYY-MM-DD) of data
|
||||
--raw Flag to show raw data
|
||||
-h, --help show this help message
|
||||
--export {csv,json,xlsx,png,jpg,pdf,svg}
|
||||
Export raw data into csv, json, xlsx and figure into png, jpg, pdf, svg
|
||||
```
|
||||
12
website/content/economy/fred/rmv/_index.md
vendored
Normal file
12
website/content/economy/fred/rmv/_index.md
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
```
|
||||
usage: rmv [-a] [-i {}] [-h]
|
||||
```
|
||||
|
||||
Remove a FRED series from current selection
|
||||
|
||||
```
|
||||
optional arguments:
|
||||
-a, --all Flag to remove all selections
|
||||
-i {}, --id {} Specific id's to remove
|
||||
-h, --help show this help message
|
||||
```
|
||||
42
website/content/economy/fred/search/_index.md
vendored
Normal file
42
website/content/economy/fred/search/_index.md
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
```
|
||||
usage: search [-s SERIES_TERM] [-n NUM] [-h]
|
||||
```
|
||||
|
||||
Print series notes when searching for series. [Source: FRED]
|
||||
|
||||
```
|
||||
optional arguments:
|
||||
-s SERIES_TERM, --series SERIES_TERM
|
||||
Search for this series term. (default: None)
|
||||
-n NUM, --num NUM Maximum number of series notes to display. (default: 5)
|
||||
-h, --help show this help message (default: False)
|
||||
```
|
||||
|
||||
Sample usage:
|
||||
```python
|
||||
(✨) (economy)(fred)> search gdp -n 3
|
||||
╒═════════════════╤═════════════════════════════╤══════════════════════════════════════════════════════════════════════════════════════════════════════╕
|
||||
│ Series ID │ Title │ Description │
|
||||
╞═════════════════╪═════════════════════════════╪══════════════════════════════════════════════════════════════════════════════════════════════════════╡
|
||||
│ GDPC1 │ Real Gross Domestic Product │ BEA Account Code: A191RX Real gross domestic product is the inflation adjusted value of the goods │
|
||||
│ │ │ and services produced by labor and property located in the United States.For more information see │
|
||||
│ │ │ the Guide to the National Income and Product Accounts of the United States (NIPA). For more │
|
||||
│ │ │ information, please visit the Bureau of Economic Analysis │
|
||||
│ │ │ (http://www.bea.gov/national/pdf/nipaguid.pdf). │
|
||||
├─────────────────┼─────────────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────┤
|
||||
│ A191RL1Q225SBEA │ Real Gross Domestic Product │ BEA Account Code: A191RL Gross domestic product (GDP) is the value of the goods and services │
|
||||
│ │ │ produced by the nation's economy less the value of the goods and services used up in production. GDP │
|
||||
│ │ │ is also equal to the sum of personal consumption expenditures, gross private domestic investment, │
|
||||
│ │ │ net exports of goods and services, and government consumption expenditures and gross investment. │
|
||||
│ │ │ Real values are inflation-adjusted estimates—that is, estimates that exclude the effects of price │
|
||||
│ │ │ changes. For more information about this series, please visit the Bureau of Economic Analysis │
|
||||
│ │ │ (http://www.bea.gov/national/). │
|
||||
├─────────────────┼─────────────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────┤
|
||||
│ GDP │ Gross Domestic Product │ BEA Account Code: A191RC Gross domestic product (GDP), the featured measure of U.S. output, is the │
|
||||
│ │ │ market value of the goods and services produced by labor and property located in the United │
|
||||
│ │ │ States.For more information, see the Guide to the National Income and Product Accounts of the United │
|
||||
│ │ │ States (NIPA) and the Bureau of Economic Analysis (http://www.bea.gov/national/pdf/nipaguid.pdf). │
|
||||
╘═════════════════╧═════════════════════════════╧══════════════════════════════════════════════════════════════════════════════════════════════════════╛
|
||||
|
||||
|
||||
```
|
||||
58
website/content/economy/search/_index.md
vendored
58
website/content/economy/search/_index.md
vendored
@@ -1,58 +0,0 @@
|
||||
```
|
||||
usage: search [-s SERIES_TERM] [-n NUM] [-h]
|
||||
```
|
||||
|
||||
Print series notes when searching for series. https://fred.stlouisfed.org
|
||||
|
||||
```
|
||||
optional arguments:
|
||||
-s SERIES_TERM, --series SERIES_TERM
|
||||
Search for this series term. (default: None)
|
||||
-n NUM, --num NUM Maximum number of series notes to display. (default: 5)
|
||||
-h, --help show this help message (default: False)
|
||||
```
|
||||
search household
|
||||
```
|
||||
(✨) (economy)> search household
|
||||
UNRATE
|
||||
------
|
||||
The unemployment rate represents the number of unemployed as a percentage of the labor force. Labor force data are restricted to people 16 years of age and older, who currently reside in 1 of the 50 states or the District of Columbia, who do not reside in institutions (e.g., penal and mental facilities, homes for the aged), and who are not on active duty in the Armed Forces.
|
||||
|
||||
This rate is also defined as the U-3 measure of labor underutilization.
|
||||
|
||||
The series comes from the 'Current Population Survey (Household Survey)'
|
||||
|
||||
The source code is: LNS14000000
|
||||
|
||||
CIVPART
|
||||
-------
|
||||
The series comes from the 'Current Population Survey (Household Survey)'
|
||||
|
||||
The source code is: LNS11300000
|
||||
|
||||
MEHOINUSA672N
|
||||
-------------
|
||||
Household data are collected as of March.
|
||||
|
||||
As stated in the Census's Source and Accuracy of Estimates for Income, Poverty, and Health Insurance Coverage in the United States: 2011 (http://www.census.gov/hhes/www/p60_243sa.pdf).
|
||||
|
||||
Estimation of Median Incomes. The Census Bureau has changed the methodology for computing median income over time. The Census Bureau has computed medians using either Pareto interpolation or linear interpolation. Currently, we are using linear interpolation to estimate all medians. Pareto interpolation assumes a decreasing density of population within an income interval, whereas linear interpolation assumes a constant density of population within an income interval. The Census Bureau calculated estimates of median income and associated standard errors for 1979 through 1987 using Pareto interpolation if the estimate was larger than $20,000 for people or $40,000 for families and households. This is because the width of the income interval containing the estimate is greater than $2,500.
|
||||
|
||||
We calculated estimates of median income and associated standard errors for 1976, 1977, and 1978 using Pareto interpolation if the estimate was larger than $12,000 for people or $18,000 for families and households. This is because the width of the income interval containing the estimate is greater than $1,000. All other estimates of median income and associated standard errors for 1976 through 2011 (2012 ASEC) and almost all of the estimates of median income and associated standard errors for 1975 and earlier were calculated using linear interpolation.
|
||||
|
||||
Thus, use caution when comparing median incomes above $12,000 for people or $18,000 for families and households for different years. Median incomes below those levels are more comparable from year to year since they have always been calculated using linear interpolation. For an indication of the comparability of medians calculated using Pareto interpolation with medians calculated using linear interpolation, see Series P-60, Number 114, (https://www2.census.gov/prod2/popscan/p60-114.pdf) Money Income in 1976 of Families and Persons in the United States.
|
||||
|
||||
TDSP
|
||||
----
|
||||
The Household Debt Service Ratio (DSR) (https://fred.stlouisfed.org/series/TDSP) is the ratio of total required household debt payments to total disposable income.
|
||||
|
||||
The DSR is divided into two parts. The Mortgage DSR (MDSP) (https://fred.stlouisfed.org/series/MDSP) is total quarterly required mortgage payments divided by total quarterly disposable personal income. The Consumer DSR (CDSP) (https://fred.stlouisfed.org/series/CDSP) is total quarterly scheduled consumer debt payments divided by total quarterly disposable personal income. The Mortgage DSR and the Consumer DSR sum to the DSR.
|
||||
|
||||
For more information, please visit the Board of Governors (https://www.federalreserve.gov/releases/housedebt/about.htm).
|
||||
|
||||
LNS14000006
|
||||
-----------
|
||||
The series comes from the 'Current Population Survey (Household Survey)'
|
||||
|
||||
The source code is: LNS14000006
|
||||
```
|
||||
18
website/content/economy/series/_index.md
vendored
18
website/content/economy/series/_index.md
vendored
@@ -1,18 +0,0 @@
|
||||
```
|
||||
usage: series [-i SERIES_ID] [-s START_DATE] [--raw] [--export {png,jpg,pdf,svg}] [-h]
|
||||
```
|
||||
|
||||
Search for series numbers by term and display one or more series in a chart. https://fred.stlouisfed.org
|
||||
|
||||
```
|
||||
optional arguments:
|
||||
-i SERIES_ID, --id SERIES_ID
|
||||
FRED Series from https://fred.stlouisfed.org. For multiple series use: series1,series2,series3
|
||||
-s START_DATE Starting date (YYYY-MM-DD) of data
|
||||
--raw Only output raw data
|
||||
--export {png,jpg,pdf,svg}
|
||||
Export data to csv,json,xlsx or png,jpg,pdf,svg file
|
||||
-h, --help show this help message
|
||||
```
|
||||
<img size="1400" alt="Feature Screenshot - series" src="https://user-images.githubusercontent.com/85772166/141927396-50828ef4-fb19-443c-93a1-ba7276979ade.png">
|
||||
<img size="1400" alt="Feature Screenshot - series ID" src="https://user-images.githubusercontent.com/85772166/141927959-7199673f-d88a-48e2-9fea-f43733a8ac04.png">
|
||||
15
website/data/menu/main.yml
vendored
15
website/data/menu/main.yml
vendored
@@ -873,12 +873,19 @@ main:
|
||||
ref: "/economy/tyld"
|
||||
- name: unemp
|
||||
ref: "/economy/unemp"
|
||||
- name: search
|
||||
ref: "/economy/search"
|
||||
- name: series
|
||||
ref: "/economy/series"
|
||||
- name: bigmac
|
||||
ref: "/economy/bigmac"
|
||||
- name: fred
|
||||
ref: "/economy/fred"
|
||||
sub:
|
||||
- name: search
|
||||
ref : "/economy/fred/search"
|
||||
- name: add
|
||||
ref: "/economy/fred/add"
|
||||
- name: rmv
|
||||
ref: "/economy/fred/rmv"
|
||||
- name: plot
|
||||
ref: "/economy/fred/plot"
|
||||
- name: etf
|
||||
ref: "/etf"
|
||||
sub:
|
||||
|
||||
Reference in New Issue
Block a user