diff --git a/openbb_terminal/miscellaneous/i18n/en.yml b/openbb_terminal/miscellaneous/i18n/en.yml index e83dfd47139..c2c3c9086fb 100644 --- a/openbb_terminal/miscellaneous/i18n/en.yml +++ b/openbb_terminal/miscellaneous/i18n/en.yml @@ -166,6 +166,7 @@ en: stocks/th/all: show all markets stocks/th/exchange: show one exchange stocks/th/holidays: show all dates on which there is a market holiday + stocks/disc/filings: the most-recent form submissions to the SEC stocks/disc/pipo: past IPOs dates stocks/disc/fipo: future IPOs dates stocks/disc/gainers: show latest top gainers diff --git a/openbb_terminal/stocks/discovery/disc_controller.py b/openbb_terminal/stocks/discovery/disc_controller.py index a7a1a48137a..85020d53f7d 100644 --- a/openbb_terminal/stocks/discovery/disc_controller.py +++ b/openbb_terminal/stocks/discovery/disc_controller.py @@ -25,6 +25,7 @@ from openbb_terminal.stocks.discovery import ( ark_view, finnhub_view, finviz_view, + fmp_view, nasdaq_view, seeking_alpha_view, shortinterest_view, @@ -59,6 +60,7 @@ class DiscoveryController(BaseController): "rtat", "divcal", "heatmap", + "filings", ] arkord_sortby_choices = [ @@ -125,6 +127,7 @@ class DiscoveryController(BaseController): def print_help(self): """Print help""" mt = MenuText("stocks/disc/") + mt.add_cmd("filings", "FinancialModelingPrep") mt.add_cmd("pipo", "Finnhub") mt.add_cmd("fipo", "Finnhub") mt.add_cmd("gainers", "Yahoo Finance") @@ -911,3 +914,42 @@ class DiscoveryController(BaseController): if ns_parser.sheet_name else None, ) + + @log_start_end(log=logger) + def call_filings(self, other_args: List[str]) -> None: + """Process Filings command""" + parser = argparse.ArgumentParser( + add_help=False, + formatter_class=argparse.ArgumentDefaultsHelpFormatter, + prog="filings", + description="The most-recent filings submitted to the SEC", + ) + parser.add_argument( + "-p", + "--pages", + dest="pages", + metavar="pages", + type=int, + default=1, + help="The number of pages to get data from (1000 entries/page; maximum 30 pages)", + ) + parser.add_argument( + "-t", + "--today", + dest="today", + action="store_true", + default=False, + help="Show all filings from today", + ) + if other_args and "-" not in other_args[0][0]: + other_args.insert(0, "-l") + ns_parser = self.parse_known_args_and_warn( + parser, + other_args, + EXPORT_ONLY_RAW_DATA_ALLOWED, + limit=5, + ) + if ns_parser: + fmp_view.display_filings( + ns_parser.pages, ns_parser.limit, ns_parser.today, ns_parser.export + ) diff --git a/openbb_terminal/stocks/discovery/fmp_model.py b/openbb_terminal/stocks/discovery/fmp_model.py new file mode 100644 index 00000000000..b8b4878e6c5 --- /dev/null +++ b/openbb_terminal/stocks/discovery/fmp_model.py @@ -0,0 +1,74 @@ +""" Financial Modeling Prep Model""" +__docformat__ = "numpy" +import logging + +import pandas as pd +from requests.exceptions import HTTPError + +from openbb_terminal import config_terminal as cfg +from openbb_terminal.decorators import check_api_key, log_start_end +from openbb_terminal.rich_config import console + +logger = logging.getLogger(__name__) + + +@log_start_end(log=logger) +@check_api_key(["API_KEY_FINANCIALMODELINGPREP"]) +def get_filings( + pages: int = 1, +) -> pd.DataFrame: + """Get SEC Filings RSS feed, disseminated by FMP + Parameters + ---------- + pages: range = 1 + The range of most-rececnt pages to get entries from (1000 per page; maximum of 30 pages) + Returns + ------- + df: pd.DataFrame + Dataframe of results + Examples + -------- + df = openbb.stocks.filings() + df = openbb.stocks.filings(pages=30) + """ + + temp = [] + try: + for i in range(pages): + temp.append( + pd.read_json( + "https://financialmodelingprep.com/api/v3/rss_feed?&page=" + f"{i}" + "&apikey=" + f"{cfg.API_KEY_FINANCIALMODELINGPREP}" + ) + ) + df = pd.concat(temp) + df = df.rename( + columns={ + "title": "Title", + "date": "Date", + "link": "URL", + "cik": "CIK", + "form_type": "Form Type", + "ticker": "Ticker", + }, + ) + df_columns = ["Date", "Ticker", "CIK", "Form Type", "Title", "URL"] + df = ( + pd.DataFrame(df, columns=df_columns) + .set_index(keys=["Date"]) + .copy() + .sort_index(ascending=False) + ) + + # Invalid API Keys + except ValueError as e: + console.print(e) + df = pd.DataFrame() + # Premium feature, API plan is not authorized + except HTTPError as e: + console.print(e) + df = pd.DataFrame() + + return df diff --git a/openbb_terminal/stocks/discovery/fmp_view.py b/openbb_terminal/stocks/discovery/fmp_view.py new file mode 100644 index 00000000000..879640dabda --- /dev/null +++ b/openbb_terminal/stocks/discovery/fmp_view.py @@ -0,0 +1,83 @@ +""" Financial Modeling Prep View """ +__docformat__ = "numpy" + +import datetime +import logging +import os + +from openbb_terminal.decorators import check_api_key, log_start_end +from openbb_terminal.helper_funcs import export_data +from openbb_terminal.rich_config import console +from openbb_terminal.stocks.fundamental_analysis import fmp_model + +logger = logging.getLogger(__name__) + + +@log_start_end(log=logger) +@check_api_key(["API_KEY_FINANCIALMODELINGPREP"]) +def display_filings( + pages: int = 1, + limit: int = 5, + today: bool = False, + export: str = "", + sheet_name: str = None, +) -> None: + """Display recent forms submitted to the SEC + Parameters + ---------- + pages: int = 1 + The range of most-rececnt pages to get entries from (1000 per page, max 30 pages) + limit: int = 5 + Limit the number of entries to display (default: 5) + today: bool = False + Show all from today + export: str = "" + Export data as csv, json, or xlsx + Examples + -------- + openbb.stocks.display_filings() + openbb.stocks.display_filings(today = True, export = "csv") + """ + filings = fmp_model.get_filings(pages) + if today is True: + now: str = datetime.datetime.now().strftime("%Y-%m-%d") + iso_today: int = datetime.datetime.today().isoweekday() + if iso_today < 6 and not filings.empty: + filings = filings.filter(like=now, axis=0) + limit = 1000 + else: + console.print( + "[red]No filings today, displaying the most recent submissions instead[/red]" + ) + + if not filings.empty: + filings.reset_index(["Date"], inplace=True) + for _, row in filings.head(limit).iterrows(): + console.print( + "Timestamp: ", + f"{row['Date']}", + " US/Eastern", + "\n", + "Ticker: ", + f"{row['Ticker']}", + "\n", + "CIK: " f"{row['CIK']}", + "\n", + "Form Type: ", + f"{row['Form Type']}", + "\n", + f"{row['Title']}", + "\n", + f"{row['URL']}\n", + sep="", + ) + export_data( + export, + os.path.dirname(os.path.abspath(__file__)), + "filings", + filings, + sheet_name, + ) + else: + logger.error("Could not get data") + console.print("[red]Could not get data[/red]\n")