diff --git a/gamestonk_terminal/etf/etf_controller.py b/gamestonk_terminal/etf/etf_controller.py index f8305ffb288..ff17e6cd665 100644 --- a/gamestonk_terminal/etf/etf_controller.py +++ b/gamestonk_terminal/etf/etf_controller.py @@ -11,7 +11,12 @@ from prompt_toolkit.completion import NestedCompleter from thepassiveinvestor import create_ETF_report from gamestonk_terminal import feature_flags as gtff -from gamestonk_terminal.etf import screener_view, stockanalysis_view, wsj_view +from gamestonk_terminal.etf import ( + screener_view, + stockanalysis_view, + wsj_view, + financedatabase_view, +) from gamestonk_terminal.helper_funcs import ( get_flair, parse_known_args_and_warn, @@ -45,6 +50,7 @@ class ETFController: "decliners", "active", "pir", + "fds", ] CHOICES += CHOICES_COMMANDS @@ -80,6 +86,9 @@ Wall St. Journal: The Passive Investor: pir create ETF report of multiple tickers + +Finance Database: + fds advanced ETF search based on category, name and/or description """ print(help_str) @@ -400,6 +409,79 @@ The Passive Investor: f"Created ETF report as {ns_parser.filename} in folder {ns_parser.folder} \n" ) + @try_except + def call_fds(self, other_args): + """Process fds command""" + parser = argparse.ArgumentParser( + description="Display a selection of ETFs based on category, name and/or description filtered by total " + "assets. Returns the top ETFs when no argument is given. [Source: Finance Database]", + add_help=False, + ) + + parser.add_argument( + "-c", + "--category", + default=None, + nargs="+", + dest="category", + help="Specify the ETF selection based on a category", + ) + + parser.add_argument( + "-n", + "--name", + default=None, + nargs="+", + dest="name", + help="Specify the ETF selection based on the name", + ) + + parser.add_argument( + "-d", + "--description", + default=None, + nargs="+", + dest="description", + help="Specify the ETF selection based on the description (not shown in table)", + ) + + parser.add_argument( + "-ie", + "--include_exchanges", + action="store_false", + help="When used, data from different exchanges is also included. This leads to a much larger " + "pool of data due to the same ETF being listed on multiple exchanges", + ) + + parser.add_argument( + "-a", + "--amount", + default=10, + type=int, + dest="amount", + help="Enter the number of ETFs you wish to see in the Tabulate window", + ) + + parser.add_argument( + "-o", + "--options", + action="store_true", + help="Obtain the available categories", + ) + + ns_parser = parse_known_args_and_warn(parser, other_args) + if not ns_parser: + return + + financedatabase_view.show_etfs( + category=ns_parser.category, + name=ns_parser.name, + description=ns_parser.description, + include_exchanges=ns_parser.include_exchanges, + amount=ns_parser.amount, + options=ns_parser.options, + ) + def menu(): etf_controller = ETFController() diff --git a/gamestonk_terminal/etf/financedatabase_view.py b/gamestonk_terminal/etf/financedatabase_view.py new file mode 100644 index 00000000000..08f3c63e3cd --- /dev/null +++ b/gamestonk_terminal/etf/financedatabase_view.py @@ -0,0 +1,75 @@ +"""Finance Database view""" +__docformat__ = "numpy" + +import financedatabase as fd +import pandas as pd +from tabulate import tabulate +from gamestonk_terminal import feature_flags as gtff + + +def show_etfs( + category: str, + name: str, + description: str, + include_exchanges: bool, + amount: int, + options: str, +): + """ + Display a selection of ETFs based on category, name and/or description filtered by total assets. + Returns the top ETFs when no argument is given. [Source: Finance Database] + + Parameters + ---------- + category: str + Search by category to find ETFs matching the criteria. + name: str + Search by name to find ETFs matching the criteria. + description: str + Search by description to find ETFs matching the criteria. + include_exchanges: bool + When you wish to include different exchanges use this boolean. + amount : int + Number of ETFs to display, default is 10. + options : str + Show the category options. + """ + if options: + for option in fd.show_options("etfs"): + print(option) + return + + if category is not None: + data = fd.select_etfs( + category=" ".join(category).title(), exclude_exchanges=include_exchanges + ) + else: + data = fd.select_etfs(category=category, exclude_exchanges=include_exchanges) + + if name is not None: + print(name) + data = fd.search_products(data, query=" ".join(name), search="long_name") + if description is not None: + data = fd.search_products(data, query=" ".join(description), search="summary") + + tabulate_data = pd.DataFrame(data).T[ + ["long_name", "family", "category", "total_assets"] + ] + tabulate_data_sorted = tabulate_data.sort_values(by="total_assets", ascending=False) + tabulate_data_sorted["total_assets"] = ( + tabulate_data_sorted["total_assets [M]"] / 1e6 + ) + + if gtff.USE_TABULATE_DF: + print( + tabulate( + tabulate_data_sorted.iloc[:amount], + showindex=True, + headers=["Name", "Family", "Category", "Total Assets [M]"], + floatfmt=".2f", + tablefmt="fancy_grid", + ), + "\n", + ) + else: + print(tabulate_data_sorted.iloc[:amount].to_string(), "\n") diff --git a/gamestonk_terminal/stocks/discovery/disc_controller.py b/gamestonk_terminal/stocks/discovery/disc_controller.py index bf06ad5787d..a1af4de863c 100644 --- a/gamestonk_terminal/stocks/discovery/disc_controller.py +++ b/gamestonk_terminal/stocks/discovery/disc_controller.py @@ -1,17 +1,17 @@ """ Disc Controller """ __docformat__ = "numpy" +# pylint:disable=too-many-lines import argparse import os -from typing import List from datetime import datetime +from typing import List 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.helper_funcs import ( parse_known_args_and_warn, check_non_negative, @@ -20,6 +20,7 @@ from gamestonk_terminal.helper_funcs import ( check_int_range, try_except, ) +from gamestonk_terminal.menu import session from gamestonk_terminal.stocks.discovery import ( ark_view, fidelity_view, @@ -28,6 +29,7 @@ from gamestonk_terminal.stocks.discovery import ( yahoofinance_view, finnhub_view, geekofwallstreet_view, + financedatabase_view, ) @@ -61,6 +63,7 @@ class DiscoveryController: "lowfloat", "hotpenny", "rtearn", + "fds", ] CHOICES += CHOICES_COMMANDS @@ -107,6 +110,8 @@ shortinterest.com lowfloat low float stocks under 10M shares float pennystockflow.com hotpenny today's hot penny stocks +Finance Database: + fds advanced Equities search based on country, sector, industry, name and/or description """ print(help_text) @@ -881,6 +886,103 @@ pennystockflow.com export=ns_parser.export, ) + @try_except + def call_fds(self, other_args: List[str]): + """Process fds command""" + parser = argparse.ArgumentParser( + description="Display a selection of Equities based on country, sector, industry, name and/or description " + "filtered by market cap. If no arguments are given, return the equities with the highest " + "market cap. [Source: Finance Database]", + add_help=False, + ) + + parser.add_argument( + "-c", + "--country", + default=None, + nargs="+", + dest="country", + help="Specify the Equities selection based on a country", + ) + + parser.add_argument( + "-s", + "--sector", + default=None, + nargs="+", + dest="sector", + help="Specify the Equities selection based on a sector", + ) + + parser.add_argument( + "-i", + "--industry", + default=None, + nargs="+", + dest="industry", + help="Specify the Equities selection based on an industry", + ) + + parser.add_argument( + "-n", + "--name", + default=None, + nargs="+", + dest="name", + help="Specify the Equities selection based on the name", + ) + + parser.add_argument( + "-d", + "--description", + default=None, + nargs="+", + dest="description", + help="Specify the Equities selection based on the description (not shown in table)", + ) + + parser.add_argument( + "-ie", + "--include_exchanges", + action="store_false", + help="When used, data from different exchanges is also included. This leads to a much larger " + "pool of data due to the same company being listed on multiple exchanges", + ) + + parser.add_argument( + "-a", + "--amount", + default=10, + type=int, + dest="amount", + help="Enter the number of Equities you wish to see in the Tabulate window", + ) + + parser.add_argument( + "-o", + "--options ", + choices=["countries", "sectors", "industries"], + default=None, + dest="options", + help="Obtain the available options for country, sector and industry", + ) + + ns_parser = parse_known_args_and_warn(parser, other_args) + + if not ns_parser: + return + + financedatabase_view.show_equities( + country=ns_parser.country, + sector=ns_parser.sector, + industry=ns_parser.industry, + name=ns_parser.name, + description=ns_parser.description, + include_exchanges=ns_parser.include_exchanges, + amount=ns_parser.amount, + options=ns_parser.options, + ) + def menu(): """Discovery Menu""" diff --git a/gamestonk_terminal/stocks/discovery/financedatabase_view.py b/gamestonk_terminal/stocks/discovery/financedatabase_view.py new file mode 100644 index 00000000000..aef82ce5ce1 --- /dev/null +++ b/gamestonk_terminal/stocks/discovery/financedatabase_view.py @@ -0,0 +1,103 @@ +"""Finance Database view""" +__docformat__ = "numpy" + +import financedatabase as fd +import pandas as pd +from tabulate import tabulate +from gamestonk_terminal import feature_flags as gtff + + +def show_equities( + country: str, + sector: str, + industry: str, + name: str, + description: str, + amount: int, + include_exchanges: bool, + options: str, +): + """ + Display a selection of Equities based on country, sector, industry, name and/or description filtered + by market cap. If no arguments are given, return the equities with the highest market cap. + [Source: Finance Database] + + Parameters + ---------- + country: str + Search by country to find stocks matching the criteria. + sector : str + Search by sector to find stocks matching the criteria. + industry : str + Search by industry to find stocks matching the criteria. + name : str + Search by name to find stocks matching the criteria. + description : str + Search by description to find stocks matching the criteria. + amount : int + Number of stocks to display, default is 10. + include_exchanges: bool + When you wish to include different exchanges use this boolean. + options : str + Show the country, sector or industry options. + """ + if options is not None: + for option in fd.show_options("equities", options): + print(option) + return + + if country is not None: + country = " ".join(country).title() + if sector is not None: + sector = " ".join(sector).title() + if industry is not None: + industry = " ".join(industry).title() + + data = fd.select_equities( + country=country, + sector=sector, + industry=industry, + exclude_exchanges=include_exchanges, + ) + + if name is not None: + data = fd.search_products(data, query=" ".join(name), search="long_name") + if description is not None: + data = fd.search_products(data, query=" ".join(description), search="summary") + + tabulate_data = pd.DataFrame(data).T[ + [ + "long_name", + "sector", + "industry", + "country", + "city", + "website", + "market_cap", + ] + ] + + tabulate_data_sorted = tabulate_data.sort_values(by="market_cap", ascending=False) + tabulate_data_sorted["market_cap"] = tabulate_data_sorted["market_cap"] / 1e6 + + if gtff.USE_TABULATE_DF: + print( + tabulate( + tabulate_data_sorted.iloc[:amount], + showindex=True, + headers=[ + "Name", + "Sector", + "Industry", + "Country", + "City", + "Website", + "Market Cap [M]", + ], + floatfmt=".2f", + tablefmt="fancy_grid", + ), + "\n", + ) + else: + print(tabulate_data_sorted.iloc[:amount].to_string(), "\n") diff --git a/requirements-full.txt b/requirements-full.txt index d6eb3002ffd..90bdeb6ef9f 100644 --- a/requirements-full.txt +++ b/requirements-full.txt @@ -223,6 +223,7 @@ termcolor==1.1.0 terminado==0.12.1; python_version >= "3.6" testpath==0.5.0; python_version >= "3.7" textwrap3==0.9.2; python_version >= "3.6" +thepassiveinvestor==1.0.9 threadpoolctl==3.0.0; python_version >= "3.7" timeseries-cv==0.1.4; python_version >= "3.6" and python_version < "4.0" tokenize-rt==4.2.1; python_full_version >= "3.6.1" diff --git a/requirements.txt b/requirements.txt index dba5148e375..ddf38c6f9f8 100644 --- a/requirements.txt +++ b/requirements.txt @@ -200,6 +200,7 @@ termcolor==1.1.0 terminado==0.12.1; python_version >= "3.6" testpath==0.5.0; python_version >= "3.7" textwrap3==0.9.2; python_version >= "3.6" +thepassiveinvestor==1.0.9 threadpoolctl==3.0.0; python_version >= "3.7" timeseries-cv==0.1.4; python_version >= "3.6" and python_version < "4.0" tokenize-rt==4.2.1; python_full_version >= "3.6.1" diff --git a/website/content/etf/fds/_index.md b/website/content/etf/fds/_index.md new file mode 100644 index 00000000000..24959ff19ba --- /dev/null +++ b/website/content/etf/fds/_index.md @@ -0,0 +1,14 @@ +``` +usage: fds [-c --category CATEGORY [CATEGORY ...]] [-n --name NAME [NAME ...]] + [-d --description DESCRIPTION [DESCRIPTION ...]] [-ie --include_exchanges] + [-a --amount AMOUNT] [-o --options] [-h] +``` +Display a selection of ETFs based on category, name and/or description filtered by total assets. Returns the top ETFs +when no argument is given. + +* -c --category: Specify the ETF selection based on a category +* -n --name: Specify the ETF selection based on the name +* -d --description: Specify the ETF selection based on the description (not shown in table) +* -ie --include_exchanges: If used, you also obtain ETFs from different exchanges (a lot of data) +* -a --amount: Enter the number of ETFs you wish to see in the Tabulate window +* -o --options: Obtain the available categories diff --git a/website/content/stocks/discovery/fds/_index.md b/website/content/stocks/discovery/fds/_index.md new file mode 100644 index 00000000000..af474dc77fd --- /dev/null +++ b/website/content/stocks/discovery/fds/_index.md @@ -0,0 +1,17 @@ +``` +usage: fds [-c --country COUNTRY [COUNTRY ...]] [-s --sector SECTOR [SECTOR ...]] + [-i --industry INDUSTRY [INDUSTRY ...]] [-n --name NAME [NAME ...]] + [-d --description DESCRIPTION [DESCRIPTION ...]] [-ie --include_exchanges] [-a --amount AMOUNT] + [-o --options {countries,sectors,industries}] [-h] +``` +Display a selection of Equities based on country, sector, industry, name and/or description filtered by market cap. +If no arguments are given, return the equities with the highest market cap. + +* -c --country: Specify the Equities selection based on a country +* -s --sector: Specify the Equities selection based on a sector +* -i --industry: Specify the Equities selection based on an industry +* -n --name: Specify the Equities selection based on the name +* -d --description: Specify the Equities selection based on the description (not shown in table) +* -ie --include_exchanges: If used, you also obtain Equities from different exchanges (a lot of data) +* -a --amount: Enter the number of Equities you wish to see in the Tabulate window +* -o --options: Obtain the available options for country, sector and industry diff --git a/website/data/menu/main.yml b/website/data/menu/main.yml index 75fb2a1576a..c92640e3ecf 100755 --- a/website/data/menu/main.yml +++ b/website/data/menu/main.yml @@ -48,6 +48,8 @@ main: ref: "/stocks/discovery/lowfloat" - name: hotpenny ref: "/stocks/discovery/hotpenny" + - name: fds + ref: "/stocks/discovery/fds" - name: dark pool shorts ref: "/stocks/dark_pool_shorts" sub: @@ -804,6 +806,8 @@ main: ref: "/etf/active" - name: pir ref: "/etf/pir" + - name: fds + ref: "/etf/fds" - name: portfolio ref: "/portfolio" sub: