diff --git a/gamestonk_terminal/fundamental_analysis/alpha_vantage_api.py b/gamestonk_terminal/fundamental_analysis/alpha_vantage_api.py index 74e46ba63ad..b25a4f046f6 100644 --- a/gamestonk_terminal/fundamental_analysis/alpha_vantage_api.py +++ b/gamestonk_terminal/fundamental_analysis/alpha_vantage_api.py @@ -4,10 +4,14 @@ from alpha_vantage.fundamentaldata import FundamentalData import pandas as pd from pandas.io.json import json_normalize from gamestonk_terminal import config_terminal as cfg -from gamestonk_terminal.helper_funcs import check_positive, long_number_format +from gamestonk_terminal.dataframe_helpers import clean_df_index +from gamestonk_terminal.helper_funcs import ( + check_positive, + long_number_format, + parse_known_args_and_warn, +) -# ---------------------------------------------------- OVERVIEW ---------------------------------------------------- def overview(l_args, s_ticker): parser = argparse.ArgumentParser( prog="overview", @@ -17,23 +21,19 @@ def overview(l_args, s_ticker): Address, Full time employees, Fiscal year end, Latest quarter, Market capitalization, EBITDA, PE ratio, PEG ratio, Book value, Dividend per share, Dividend yield, EPS, Revenue per share TTM, Profit margin, Operating margin TTM, Return on assets TTM, - Return on equity TTM, Revenue TTM, Gross profit TTM, Diluted EPS TTM, Quarterly earnings growth YOY, - Quarterly revenue growth YOY, Analyst target price, Trailing PE, Forward PE, - Price to sales ratio TTM, Price to book ratio, EV to revenue, EV to EBITDA, Beta, 52 week high, - 52 week low, 50 day moving average, 200 day moving average, Shares outstanding, Shares float, - Shares short, Shares short prior month, Short ratio, Short percent outstanding, Short percent float, - Percent insiders, Percent institutions, Forward annual dividend rate, Forward annual dividend yield, - Payout ratio, Dividend date, Ex dividend date, Last split factor, and Last split date. - [Source: Alpha Vantage] + Return on equity TTM, Revenue TTM, Gross profit TTM, Diluted EPS TTM, Quarterly + earnings growth YOY, Quarterly revenue growth YOY, Analyst target price, Trailing PE, + Forward PE, Price to sales ratio TTM, Price to book ratio, EV to revenue, EV to EBITDA, + Beta, 52 week high, 52 week low, 50 day moving average, 200 day moving average, Shares + outstanding, Shares float, Shares short, Shares short prior month, Short ratio, Short + percent outstanding, Short percent float, Percent insiders, Percent institutions, + Forward annual dividend rate, Forward annual dividend yield, Payout ratio, Dividend + date, Ex dividend date, Last split factor, and Last split date. [Source: Alpha Vantage] """, ) try: - (_, l_unknown_args) = parser.parse_known_args(l_args) - - if l_unknown_args: - print(f"The following args couldn't be interpreted: {l_unknown_args}\n") - return + parse_known_args_and_warn(parser, l_args) # Request OVERVIEW data from Alpha Vantage API s_req = f"https://www.alphavantage.co/query?function=OVERVIEW&symbol={s_ticker}&apikey={cfg.API_KEY_ALPHAVANTAGE}" @@ -46,13 +46,7 @@ def overview(l_args, s_ticker): # Keep json data sorting in dataframe df_fa = df_fa[list(result.json().keys())].T df_fa = df_fa.applymap(lambda x: long_number_format(x)) - df_fa.index = [ - "".join( - " " + char if char.isupper() else char.strip() for char in idx - ).strip() - for idx in df_fa.index.tolist() - ] - df_fa.index = [s_val.capitalize() for s_val in df_fa.index] + clean_df_index(df_fa) df_fa = df_fa.rename( index={ "E b i t d a": "EBITDA", @@ -91,24 +85,20 @@ def overview(l_args, s_ticker): return -# ------------------------------------------------------ KEY ------------------------------------------------------ def key(l_args, s_ticker): parser = argparse.ArgumentParser( prog="key", description=""" - Gives main key metrics about the company (it's a subset of the Overview data from Alpha Vantage API). - The following fields are expected: Market capitalization, EBITDA, EPS, PE ratio, PEG ratio, Price to book ratio, - Return on equity TTM, Payout ratio, Price to sales ratio TTM, Dividend yield, 50 day moving average, Analyst - target price, Beta [Source: Alpha Vantage API] + Gives main key metrics about the company (it's a subset of the Overview data from Alpha + Vantage API). The following fields are expected: Market capitalization, EBITDA, EPS, PE + ratio, PEG ratio, Price to book ratio, Return on equity TTM, Payout ratio, Price to + sales ratio TTM, Dividend yield, 50 day moving average, Analyst target price, Beta + [Source: Alpha Vantage API] """, ) try: - (_, l_unknown_args) = parser.parse_known_args(l_args) - - if l_unknown_args: - print(f"The following args couldn't be interpreted: {l_unknown_args}\n") - return + parse_known_args_and_warn(parser, l_args) # Request OVERVIEW data s_req = f"https://www.alphavantage.co/query?function=OVERVIEW&symbol={s_ticker}&apikey={cfg.API_KEY_ALPHAVANTAGE}" @@ -118,15 +108,8 @@ def key(l_args, s_ticker): if result.status_code == 200: df_fa = json_normalize(result.json()) df_fa = df_fa[list(result.json().keys())].T - df_fa = df_fa.applymap(lambda x: long_number_format(x)) - df_fa.index = [ - "".join( - " " + char if char.isupper() else char.strip() for char in idx - ).strip() - for idx in df_fa.index.tolist() - ] - df_fa.index = [s_val.capitalize() for s_val in df_fa.index] + clean_df_index(df_fa) df_fa = df_fa.rename( index={ "E b i t d a": "EBITDA", @@ -165,19 +148,19 @@ def key(l_args, s_ticker): return -# ---------------------------------------------------- INCOME_STATEMENT ---------------------------------------------------- def income_statement(l_args, s_ticker): parser = argparse.ArgumentParser( prog="incom", description=""" Prints a complete income statement over time. This can be either quarterly or annually. - The following fields are expected: Accepted date, Cost and expenses, Cost of revenue, Depreciation - and amortization, Ebitda, Ebitdaratio, Eps, Epsdiluted, Filling date, Final link, General and - administrative expenses, Gross profit, Gross profit ratio, Income before tax, Income before tax ratio, - Income tax expense, Interest expense, Link, Net income, Net income ratio, Operating expenses, - Operating income, Operating income ratio, Other expenses, Period, Research and development expenses, - Revenue, Selling and marketing expenses, Total other income expenses net, Weighted average shs out, - Weighted average shs out dil [Source: Alpha Vantage]""", + The following fields are expected: Accepted date, Cost and expenses, Cost of revenue, + Depreciation and amortization, Ebitda, Ebitdaratio, Eps, Epsdiluted, Filling date, + Final link, General and administrative expenses, Gross profit, Gross profit ratio, + Income before tax, Income before tax ratio, Income tax expense, Interest expense, Link, + Net income, Net income ratio, Operating expenses, Operating income, Operating income + ratio, Other expenses, Period, Research and development expenses, Revenue, Selling and + marketing expenses, Total other income expenses net, Weighted average shs out, Weighted + average shs out dil [Source: Alpha Vantage]""", ) parser.add_argument( @@ -199,11 +182,7 @@ def income_statement(l_args, s_ticker): ) try: - (ns_parser, l_unknown_args) = parser.parse_known_args(l_args) - - if l_unknown_args: - print(f"The following args couldn't be interpreted: {l_unknown_args}\n") - return + ns_parser = parse_known_args_and_warn(parser, l_args) if ns_parser.n_num == 1: pd.set_option("display.max_colwidth", -1) @@ -218,24 +197,8 @@ def income_statement(l_args, s_ticker): # pylint: disable=unbalanced-tuple-unpacking df_fa, _ = fd.get_income_statement_annual(symbol=s_ticker) - # pylint: disable=no-member - df_fa = df_fa.set_index("fiscalDateEnding") - df_fa = df_fa.head(n=ns_parser.n_num).T - df_fa = df_fa.mask(df_fa.astype(object).eq(ns_parser.n_num * ["None"])).dropna() - df_fa = df_fa.mask(df_fa.astype(object).eq(ns_parser.n_num * ["0"])).dropna() - df_fa = df_fa.applymap(lambda x: long_number_format(x)) - # begin problematic for pylint - df_fa.index = [ - "".join( - " " + char if char.isupper() else char.strip() for char in idx - ).strip() - for idx in df_fa.index.tolist() - ] - df_fa.index = [s_val.capitalize() for s_val in df_fa.index] - df_fa.columns.name = "Fiscal Date Ending" - # end problematic for pylint + df_fa = clean_fundamentals_df(df_fa, num=ns_parser.n_num) print(df_fa) - print("") except Exception as e: @@ -244,98 +207,23 @@ def income_statement(l_args, s_ticker): return -# ---------------------------------------------------- BALANCE_SHEET ---------------------------------------------------- def balance_sheet(l_args, s_ticker): parser = argparse.ArgumentParser( prog="balance", description=""" - Prints a complete balance sheet statement over time. This can be either quarterly or annually. - The following fields are expected: Accepted date, Account payables, Accumulated other comprehensive - income loss, Cash and cash equivalents, Cash and short term investments, Common stock, Deferred revenue, - Deferred revenue non current, Deferred tax liabilities non current, Filling date, Final link, Goodwill, - Goodwill and intangible assets, Intangible assets, Inventory, Link, Long term debt, Long term investments, - Net debt, Net receivables, Other assets, Other current assets, Other current liabilities, Other liabilities, - Other non current assets, Other non current liabilities, Othertotal stockholders equity, Period, Property - plant equipment net, Retained earnings, Short term debt, Short term investments, Tax assets, Tax payables, - Total assets, Total current assets, Total current liabilities, Total debt, Total investments, Total - liabilities, Total liabilities and stockholders equity, Total non current assets, Total non current - liabilities, and Total stockholders equity. [Source: Alpha Vantage] - """, - ) - - parser.add_argument( - "-n", - "--num", - action="store", - dest="n_num", - type=check_positive, - default=1, - help="Number of latest years/quarters.", - ) - parser.add_argument( - "-q", - "--quarter", - action="store_true", - default=False, - dest="b_quarter", - help="Quarter fundamental data flag.", - ) - - try: - (ns_parser, l_unknown_args) = parser.parse_known_args(l_args) - - if l_unknown_args: - print(f"The following args couldn't be interpreted: {l_unknown_args}\n") - return - - if ns_parser.n_num == 1: - pd.set_option("display.max_colwidth", -1) - else: - pd.options.display.max_colwidth = 40 - - fd = FundamentalData(key=cfg.API_KEY_ALPHAVANTAGE, output_format="pandas") - if ns_parser.b_quarter: - df_fa, _ = fd.get_balance_sheet_quarterly(symbol=s_ticker) - else: - df_fa, _ = fd.get_balance_sheet_annual(symbol=s_ticker) - - df_fa = df_fa.set_index("fiscalDateEnding") - df_fa = df_fa.head(n=ns_parser.n_num).T - df_fa = df_fa.mask(df_fa.astype(object).eq(ns_parser.n_num * ["None"])).dropna() - df_fa = df_fa.mask(df_fa.astype(object).eq(ns_parser.n_num * ["0"])).dropna() - df_fa = df_fa.applymap(lambda x: long_number_format(x)) - df_fa.index = [ - "".join( - " " + char if char.isupper() else char.strip() for char in idx - ).strip() - for idx in df_fa.index.tolist() - ] - df_fa.index = [s_val.capitalize() for s_val in df_fa.index] - df_fa.columns.name = "Fiscal Date Ending" - print(df_fa) - - print("") - - except Exception as e: - print(e) - print("") - return - - -# ---------------------------------------------------- CASH_FLOW ---------------------------------------------------- -def cash_flow(l_args, s_ticker): - parser = argparse.ArgumentParser( - prog="cash", - description=""" - Prints a complete cash flow statement over time. This can be either quarterly or annually. The following - fields are expected: Accepted date, Accounts payables, Accounts receivables, Acquisitions net, Capital - expenditure, Cash at beginning of period, Cash at end of period, Change in working capital, Common stock - issued, Common stock repurchased, Debt repayment, Deferred income tax, Depreciation and amortization, - Dividends paid, Effect of forex changes on cash, Filling date, Final link, Free cash flow, Inventory, - Investments in property plant and equipment, Link, Net cash provided by operating activities, Net cash - used for investing activities, Net cash used provided by financing activities, Net change in cash, Net income, - Operating cash flow, Other financing activities, Other investing activities, Other non cash items, Other working - capital, Period, Purchases of investments, Sales maturities of investments, Stock based compensation. + Prints a complete balance sheet statement over time. This can be either quarterly or + annually. The following fields are expected: Accepted date, Account payables, + Accumulated other comprehensive income loss, Cash and cash equivalents, Cash and short + term investments, Common stock, Deferred revenue, Deferred revenue non current, + Deferred tax liabilities non current, Filling date, Final link, Goodwill, + Goodwill and intangible assets, Intangible assets, Inventory, Link, Long term debt, + Long term investments, Net debt, Net receivables, Other assets, Other current assets, + Other current liabilities, Other liabilities, Other non current assets, Other non + current liabilities, Othertotal stockholders equity, Period, Property plant equipment + net, Retained earnings, Short term debt, Short term investments, Tax assets, Tax + payables, Total assets, Total current assets, Total current liabilities, Total debt, + Total investments, Total liabilities, Total liabilities and stockholders equity, Total + non current assets, Total non current liabilities, and Total stockholders equity. [Source: Alpha Vantage] """, ) @@ -372,25 +260,77 @@ def cash_flow(l_args, s_ticker): fd = FundamentalData(key=cfg.API_KEY_ALPHAVANTAGE, output_format="pandas") if ns_parser.b_quarter: - df_fa, _ = fd.get_cash_flow_quarterly(symbol=s_ticker) + # pylint: disable=unbalanced-tuple-unpacking + df_fa, _ = fd.get_balance_sheet_quarterly(symbol=s_ticker) else: - df_fa, _ = fd.get_cash_flow_annual(symbol=s_ticker) + # pylint: disable=unbalanced-tuple-unpacking + df_fa, _ = fd.get_balance_sheet_annual(symbol=s_ticker) - df_fa = df_fa.set_index("fiscalDateEnding") - df_fa = df_fa.head(n=ns_parser.n_num).T - df_fa = df_fa.mask(df_fa.astype(object).eq(ns_parser.n_num * ["None"])).dropna() - df_fa = df_fa.mask(df_fa.astype(object).eq(ns_parser.n_num * ["0"])).dropna() - df_fa = df_fa.applymap(lambda x: long_number_format(x)) - df_fa.index = [ - "".join( - " " + char if char.isupper() else char.strip() for char in idx - ).strip() - for idx in df_fa.index.tolist() - ] - df_fa.index = [s_val.capitalize() for s_val in df_fa.index] - df_fa.columns.name = "Fiscal Date Ending" + df_fa = clean_fundamentals_df(df_fa, num=ns_parser.n_num) + print(df_fa) + print("") + + except Exception as e: + print(e) + print("") + return + + +def cash_flow(l_args, s_ticker): + parser = argparse.ArgumentParser( + prog="cash", + description=""" + Prints a complete cash flow statement over time. This can be either quarterly or + annually. The following fields are expected: Accepted date, Accounts payables, Accounts + receivables, Acquisitions net, Capital expenditure, Cash at beginning of period, Cash + at end of period, Change in working capital, Common stock issued, Common stock + repurchased, Debt repayment, Deferred income tax, Depreciation and amortization, + Dividends paid, Effect of forex changes on cash, Filling date, Final link, Free cash + flow, Inventory, Investments in property plant and equipment, Link, Net cash provided + by operating activities, Net cash used for investing activities, Net cash used provided + by financing activities, Net change in cash, Net income, Operating cash flow, Other + financing activities, Other investing activities, Other non cash items, Other working + capital, Period, Purchases of investments, Sales maturities of investments, Stock based + compensation. [Source: Alpha Vantage] + """, + ) + + parser.add_argument( + "-n", + "--num", + action="store", + dest="n_num", + type=check_positive, + default=1, + help="Number of latest years/quarters.", + ) + parser.add_argument( + "-q", + "--quarter", + action="store_true", + default=False, + dest="b_quarter", + help="Quarter fundamental data flag.", + ) + + try: + ns_parser = parse_known_args_and_warn(parser, l_args) + + if ns_parser.n_num == 1: + pd.set_option("display.max_colwidth", -1) + else: + pd.options.display.max_colwidth = 40 + + fd = FundamentalData(key=cfg.API_KEY_ALPHAVANTAGE, output_format="pandas") + if ns_parser.b_quarter: + # pylint: disable=unbalanced-tuple-unpacking + df_fa, _ = fd.get_cash_flow_quarterly(symbol=s_ticker) + else: + # pylint: disable=unbalanced-tuple-unpacking + df_fa, _ = fd.get_cash_flow_annual(symbol=s_ticker) + + df_fa = clean_fundamentals_df(df_fa, num=ns_parser.n_num) print(df_fa) - print("") except Exception as e: @@ -399,13 +339,12 @@ def cash_flow(l_args, s_ticker): return -# ---------------------------------------------------- EARNINGS ---------------------------------------------------- def earnings(l_args, s_ticker): parser = argparse.ArgumentParser( prog="earnings", description=""" - Print earnings dates and reported EPS of the company. The following fields are expected: Fiscal Date - Ending and Reported EPS. [Source: Alpha Vantage] + Print earnings dates and reported EPS of the company. The following fields are + expected: Fiscal Date Ending and Reported EPS. [Source: Alpha Vantage] """, ) @@ -428,11 +367,7 @@ def earnings(l_args, s_ticker): ) try: - (ns_parser, l_unknown_args) = parser.parse_known_args(l_args) - - if l_unknown_args: - print(f"The following args couldn't be interpreted: {l_unknown_args}\n") - return + ns_parser = parse_known_args_and_warn(parser, l_args) if ns_parser.n_num == 1: pd.set_option("display.max_colwidth", -1) @@ -488,3 +423,15 @@ def earnings(l_args, s_ticker): print(e) print("") return + + +def clean_fundamentals_df(df_fa: pd.DataFrame, num: int) -> pd.DataFrame: + # pylint: disable=no-member + df_fa = df_fa.set_index("fiscalDateEnding") + df_fa = df_fa.head(n=num).T + df_fa = df_fa.mask(df_fa.astype(object).eq(num * ["None"])).dropna() + df_fa = df_fa.mask(df_fa.astype(object).eq(num * ["0"])).dropna() + df_fa = df_fa.applymap(lambda x: long_number_format(x)) + clean_df_index(df_fa) + df_fa.columns.name = "Fiscal Date Ending" + return df_fa diff --git a/gamestonk_terminal/fundamental_analysis/business_insider_api.py b/gamestonk_terminal/fundamental_analysis/business_insider_api.py index eaad59dd5b7..69d0d11e27b 100644 --- a/gamestonk_terminal/fundamental_analysis/business_insider_api.py +++ b/gamestonk_terminal/fundamental_analysis/business_insider_api.py @@ -3,10 +3,9 @@ import requests from bs4 import BeautifulSoup import pandas as pd from rapidfuzz import fuzz -from gamestonk_terminal.helper_funcs import get_user_agent +from gamestonk_terminal.helper_funcs import get_user_agent, parse_known_args_and_warn -# ---------------------------------------------------- MANAGEMENT ---------------------------------------------------- def management(l_args, s_ticker): parser = argparse.ArgumentParser( prog="mgmt", @@ -17,11 +16,7 @@ def management(l_args, s_ticker): ) try: - (_, l_unknown_args) = parser.parse_known_args(l_args) - - if l_unknown_args: - print(f"The following args couldn't be interpreted: {l_unknown_args}\n") - return + parse_known_args_and_warn(parser, l_args) url_market_business_insider = ( f"https://markets.businessinsider.com/stocks/{s_ticker.lower()}-stock" diff --git a/gamestonk_terminal/fundamental_analysis/fa_menu.py b/gamestonk_terminal/fundamental_analysis/fa_menu.py index e505598eb0e..a6bc613e1d3 100644 --- a/gamestonk_terminal/fundamental_analysis/fa_menu.py +++ b/gamestonk_terminal/fundamental_analysis/fa_menu.py @@ -10,7 +10,6 @@ from gamestonk_terminal.fundamental_analysis import business_insider_api as bi_a from gamestonk_terminal.fundamental_analysis import yahoo_finance_api as yf_api -# ----------------------------------------------------------------------------------------------------------------------- def print_fundamental_analysis(s_ticker, s_start, s_interval): """ Print help """ @@ -65,9 +64,7 @@ def print_fundamental_analysis(s_ticker, s_start, s_interval): return -# ---------------------------------------------------- INFO ---------------------------------------------------- -# pylint: disable=unused-argument -def info(l_args, s_ticker): +def key_metrics_explained(l_args): parser = argparse.ArgumentParser( prog="info", description=""" @@ -96,7 +93,6 @@ def info(l_args, s_ticker): return -# ---------------------------------------------------- MENU ---------------------------------------------------- # pylint: disable=too-many-branches def fa_menu(s_ticker, s_start, s_interval): @@ -107,29 +103,29 @@ def fa_menu(s_ticker, s_start, s_interval): choices=[ "help", "q", - "quit", # - "screener", # Finviz - "mgmt", # Business Insider + "quit", + "screener", + "mgmt", "info", "shrs", "sust", - "cal", # Yahoo Finance + "cal", "income", "assets", "liabilities", "operating", "investing", - "financing", # MW + "financing", "overview", "key", "incom", "balance", "cash", - "earnings", # AV + "earnings", "profile", "quote", "enterprise", - "dcf", # FMP + "dcf", "inc", "bal", "cashf", @@ -137,7 +133,7 @@ def fa_menu(s_ticker, s_start, s_interval): "ratios", "growth", ], - ) # FMP + ) print_fundamental_analysis(s_ticker, s_start, s_interval) @@ -154,9 +150,6 @@ def fa_menu(s_ticker, s_start, s_interval): print("The command selected doesn't exist\n") continue - # if ns_known_args.cmd == 'info': - # info(l_args, s_ticker) - if ns_known_args.cmd == "help": print_fundamental_analysis(s_ticker, s_start, s_interval) diff --git a/gamestonk_terminal/fundamental_analysis/financial_modeling_prep_api.py b/gamestonk_terminal/fundamental_analysis/financial_modeling_prep_api.py index 5758ad55f8d..e8594975f63 100644 --- a/gamestonk_terminal/fundamental_analysis/financial_modeling_prep_api.py +++ b/gamestonk_terminal/fundamental_analysis/financial_modeling_prep_api.py @@ -3,42 +3,36 @@ from datetime import datetime import pandas as pd import FundamentalAnalysis as fa # Financial Modeling Prep from gamestonk_terminal import config_terminal as cfg -from gamestonk_terminal.helper_funcs import long_number_format, check_positive +from gamestonk_terminal.dataframe_helpers import clean_df_index +from gamestonk_terminal.helper_funcs import ( + long_number_format, + check_positive, + parse_known_args_and_warn, +) -# ---------------------------------------------------- PROFILE ---------------------------------------------------- def profile(l_args, s_ticker): parser = argparse.ArgumentParser( prog="profile", description=""" - Prints information about, among other things, the industry, sector - exchange and company description. The following fields are expected: Address, Beta, - Ceo, Changes, Cik, City, Company name, Country, Currency, Cusip, Dcf, Dcf diff, - Default image, Description, Exchange, Exchange short name, Full time employees, Image, - Industry, Ipo date, Isin, Last div, Mkt cap, Phone, Price, Range, Sector, State, Symbol, - Vol avg, Website, Zip. [Source: Financial Modeling Prep] + Prints information about, among other things, the industry, sector exchange and company + description. The following fields are expected: Address, Beta, Ceo, Changes, Cik, City + Company name, Country, Currency, Cusip, Dcf, Dcf diff, Default image, Description, + Exchange, Exchange short name, Full time employees, Image, Industry, Ipo date, Isin, + Last div, Mkt cap, Phone, Price, Range, Sector, State, Symbol, Vol avg, Website, Zip. + [Source: Financial Modeling Prep] """, ) try: - (_, l_unknown_args) = parser.parse_known_args(l_args) - - if l_unknown_args: - print(f"The following args couldn't be interpreted: {l_unknown_args}\n") - return + parse_known_args_and_warn(parser, l_args) df_fa = fa.profile(s_ticker, cfg.API_KEY_FINANCIALMODELINGPREP) - df_fa.index = [ - "".join( - " " + char if char.isupper() else char.strip() for char in idx - ).strip() - for idx in df_fa.index.tolist() - ] - df_fa.index = [s_val.capitalize() for s_val in df_fa.index] + clean_df_index(df_fa) + print(df_fa.drop(index=["Description", "Image"]).to_string(header=False)) print(f"\nImage: {df_fa.loc['Image'][0]}") print(f"\nDescription: {df_fa.loc['Description'][0]}") - print("") except Exception as e: @@ -47,48 +41,40 @@ def profile(l_args, s_ticker): return -# ---------------------------------------------------- QUOTE ---------------------------------------------------- def quote(l_args, s_ticker): parser = argparse.ArgumentParser( prog="quote", description=""" - Prints actual information about the company which is, among - other things, the day high, market cap, open and close price and price-to-equity - ratio. The following fields are expected: Avg volume, Change, Changes percentage, - Day high, Day low, Earnings announcement, Eps, Exchange, Market cap, Name, Open, - Pe, Previous close, Price, Price avg200, Price avg50, Shares outstanding, Symbol, - Timestamp, Volume, Year high, and Year low. [Source: Financial Modeling Prep] + Prints actual information about the company which is, among other things, the day high, + market cap, open and close price and price-to-equity ratio. The following fields are + expected: Avg volume, Change, Changes percentage, Day high, Day low, Earnings + announcement, Eps, Exchange, Market cap, Name, Open, Pe, Previous close, Price, Price + avg200, Price avg50, Shares outstanding, Symbol, Timestamp, Volume, Year high, and Year + low. [Source: Financial Modeling Prep] """, ) try: - (_, l_unknown_args) = parser.parse_known_args(l_args) - - if l_unknown_args: - print(f"The following args couldn't be interpreted: {l_unknown_args}\n") - return + parse_known_args_and_warn(parser, l_args) df_fa = fa.quote(s_ticker, cfg.API_KEY_FINANCIALMODELINGPREP) - df_fa.index = [ - "".join( - " " + char if char.isupper() else char.strip() for char in idx - ).strip() - for idx in df_fa.index.tolist() - ] - df_fa.index = [s_val.capitalize() for s_val in df_fa.index] + + clean_df_index(df_fa) + df_fa.loc["Market cap"][0] = long_number_format(df_fa.loc["Market cap"][0]) df_fa.loc["Shares outstanding"][0] = long_number_format( df_fa.loc["Shares outstanding"][0] ) df_fa.loc["Volume"][0] = long_number_format(df_fa.loc["Volume"][0]) - earning_announcment = datetime.strptime( - df_fa.loc["Earnings announcement"][0][0:19], "%Y-%m-%dT%H:%M:%S" - ) - df_fa.loc["Earnings announcement"][ - 0 - ] = f"{earning_announcment.date()} {earning_announcment.time()}" + # Check if there is a valid earnings announcement + if df_fa.loc["Earnings announcement"][0]: + earning_announcement = datetime.strptime( + df_fa.loc["Earnings announcement"][0][0:19], "%Y-%m-%dT%H:%M:%S" + ) + df_fa.loc["Earnings announcement"][ + 0 + ] = f"{earning_announcement.date()} {earning_announcement.time()}" print(df_fa.to_string(header=False)) - print("") except Exception as e: @@ -97,7 +83,6 @@ def quote(l_args, s_ticker): return -# ---------------------------------------------------- ENTERPRISE ---------------------------------------------------- def enterprise(l_args, s_ticker): parser = argparse.ArgumentParser( prog="enterprise", @@ -128,11 +113,7 @@ def enterprise(l_args, s_ticker): ) try: - (ns_parser, l_unknown_args) = parser.parse_known_args(l_args) - - if l_unknown_args: - print(f"The following args couldn't be interpreted: {l_unknown_args}\n") - return + ns_parser = parse_known_args_and_warn(parser, l_args) if ns_parser.n_num == 1: pd.set_option("display.max_colwidth", -1) @@ -146,17 +127,9 @@ def enterprise(l_args, s_ticker): else: df_fa = fa.enterprise(s_ticker, cfg.API_KEY_FINANCIALMODELINGPREP) - df_fa = df_fa.iloc[:, 0 : ns_parser.n_num] - df_fa = df_fa.applymap(lambda x: long_number_format(x)) - df_fa.index = [ - "".join( - " " + char if char.isupper() else char.strip() for char in idx - ).strip() - for idx in df_fa.index.tolist() - ] - df_fa.index = [s_val.capitalize() for s_val in df_fa.index] - print(df_fa) + df_fa = clean_metrics_df(df_fa, num=ns_parser.n_num, mask=False) + print(df_fa) print("") except Exception as e: @@ -165,14 +138,13 @@ def enterprise(l_args, s_ticker): return -# ------------------------------------------ DISCOUNTED CASH FLOW ------------------------------------------------------ def discounted_cash_flow(l_args, s_ticker): parser = argparse.ArgumentParser( prog="dcf", description=""" - Prints the discounted cash flow of a company over time including - the DCF of today. The following fields are expected: DCF, Stock price, and Date. - [Source: Financial Modeling Prep] + Prints the discounted cash flow of a company over time including the DCF of today. The + following fields are expected: DCF, Stock price, and Date. [Source: Financial Modeling + Prep] """, ) parser.add_argument( @@ -194,11 +166,7 @@ def discounted_cash_flow(l_args, s_ticker): ) try: - (ns_parser, l_unknown_args) = parser.parse_known_args(l_args) - - if l_unknown_args: - print(f"The following args couldn't be interpreted: {l_unknown_args}\n") - return + ns_parser = parse_known_args_and_warn(parser, l_args) if ns_parser.n_num == 1: pd.set_option("display.max_colwidth", -1) @@ -212,18 +180,9 @@ def discounted_cash_flow(l_args, s_ticker): else: df_fa = fa.discounted_cash_flow(s_ticker, cfg.API_KEY_FINANCIALMODELINGPREP) - df_fa = df_fa.iloc[:, 0 : ns_parser.n_num] - df_fa = df_fa.applymap(lambda x: long_number_format(x)) - df_fa.index = [ - "".join( - " " + char if char.isupper() else char.strip() for char in idx - ).strip() - for idx in df_fa.index.tolist() - ] - df_fa.index = [s_val.capitalize() for s_val in df_fa.index] - df_fa = df_fa.rename(index={"D c f": "DCF"}) - print(df_fa) + df_fa = clean_metrics_df(df_fa, num=ns_parser.n_num, mask=False) + print(df_fa) print("") except Exception as e: @@ -232,19 +191,19 @@ def discounted_cash_flow(l_args, s_ticker): return -# ---------------------------------------------------- INCOME_STATEMENT ---------------------------------------------------- def income_statement(l_args, s_ticker): parser = argparse.ArgumentParser( prog="inc", description=""" - Prints a complete income statement over time. This can be either quarterly - or annually. The following fields are expected: Accepted date, Cost and expenses, Cost of - revenue, Depreciation and amortization, Ebitda, Ebitdaratio, Eps, Epsdiluted, Filling date, - Final link, General and administrative expenses, Gross profit, Gross profit ratio, Income - before tax, Income before tax ratio, Income tax expense, Interest expense, Link, Net income, - Net income ratio, Operating expenses, Operating income, Operating income ratio, Other expenses, - Period, Research and development expenses, Revenue, Selling and marketing expenses, Total other - income expenses net, Weighted average shs out, Weighted average shs out dil [Source: Financial Modeling Prep] + Prints a complete income statement over time. This can be either quarterly or annually. + The following fields are expected: Accepted date, Cost and expenses, Cost of + revenue, Depreciation and amortization, Ebitda, Ebitdaratio, Eps, Epsdiluted, Filling + date, Final link, General and administrative expenses, Gross profit, Gross profit + ratio, Income before tax, Income before tax ratio, Income tax expense, Interest + expense, Link, Net income, Net income ratio, Operating expenses, Operating income, + Operating income ratio, Other expenses, Period, Research and development expenses, + Revenue, Selling and marketing expenses, Total other income expenses net, Weighted + average shs out, Weighted average shs out dil [Source: Financial Modeling Prep] """, ) @@ -267,11 +226,7 @@ def income_statement(l_args, s_ticker): ) try: - (ns_parser, l_unknown_args) = parser.parse_known_args(l_args) - - if l_unknown_args: - print(f"The following args couldn't be interpreted: {l_unknown_args}\n") - return + ns_parser = parse_known_args_and_warn(parser, l_args) if ns_parser.n_num == 1: pd.set_option("display.max_colwidth", -1) @@ -285,18 +240,8 @@ def income_statement(l_args, s_ticker): else: df_fa = fa.income_statement(s_ticker, cfg.API_KEY_FINANCIALMODELINGPREP) - df_fa = df_fa.iloc[:, 0 : ns_parser.n_num] - df_fa = df_fa.mask(df_fa.astype(object).eq(ns_parser.n_num * ["None"])).dropna() - df_fa = df_fa.mask(df_fa.astype(object).eq(ns_parser.n_num * ["0"])).dropna() - df_fa = df_fa.applymap(lambda x: long_number_format(x)) - df_fa.index = [ - "".join( - " " + char if char.isupper() else char.strip() for char in idx - ).strip() - for idx in df_fa.index.tolist() - ] - df_fa.index = [s_val.capitalize() for s_val in df_fa.index] - df_fa.columns.name = "Fiscal Date Ending" + df_fa = clean_metrics_df(df_fa, num=ns_parser.n_num) + print(df_fa.drop(index=["Final link", "Link"]).to_string()) pd.set_option("display.max_colwidth", -1) @@ -304,7 +249,6 @@ def income_statement(l_args, s_ticker): print(df_fa.loc["Final link"].to_frame().to_string()) print("") print(df_fa.loc["Link"].to_frame().to_string()) - print("") except Exception as e: @@ -313,7 +257,6 @@ def income_statement(l_args, s_ticker): return -# ---------------------------------------------------- BALANCE_SHEET ---------------------------------------------------- def balance_sheet(l_args, s_ticker): parser = argparse.ArgumentParser( prog="bal", @@ -327,11 +270,11 @@ def balance_sheet(l_args, s_ticker): Link, Long term debt, Long term investments, Net debt, Net receivables, Other assets, Other current assets, Other current liabilities, Other liabilities, Other non current assets, Other non current liabilities, Othertotal stockholders equity, Period, Property - plant equipment net, Retained earnings, Short term debt, Short term investments, Tax assets, - Tax payables, Total assets, Total current assets, Total current liabilities, Total debt, - Total investments, Total liabilities, Total liabilities and stockholders equity, Total - non current assets, Total non current liabilities, and Total stockholders equity. - [Source: Financial Modeling Prep] + plant equipment net, Retained earnings, Short term debt, Short term investments, Tax + assets, Tax payables, Total assets, Total current assets, Total current liabilities, + Total debt, Total investments, Total liabilities, Total liabilities and stockholders + equity, Total non current assets, Total non current liabilities, and Total stockholders + equity. [Source: Financial Modeling Prep] """, ) @@ -354,11 +297,7 @@ def balance_sheet(l_args, s_ticker): ) try: - (ns_parser, l_unknown_args) = parser.parse_known_args(l_args) - - if l_unknown_args: - print(f"The following args couldn't be interpreted: {l_unknown_args}\n") - return + ns_parser = parse_known_args_and_warn(parser, l_args) if ns_parser.n_num == 1: pd.set_option("display.max_colwidth", -1) @@ -374,18 +313,8 @@ def balance_sheet(l_args, s_ticker): s_ticker, cfg.API_KEY_FINANCIALMODELINGPREP ) - df_fa = df_fa.iloc[:, 0 : ns_parser.n_num] - df_fa = df_fa.mask(df_fa.astype(object).eq(ns_parser.n_num * ["None"])).dropna() - df_fa = df_fa.mask(df_fa.astype(object).eq(ns_parser.n_num * ["0"])).dropna() - df_fa = df_fa.applymap(lambda x: long_number_format(x)) - df_fa.index = [ - "".join( - " " + char if char.isupper() else char.strip() for char in idx - ).strip() - for idx in df_fa.index.tolist() - ] - df_fa.index = [s_val.capitalize() for s_val in df_fa.index] - df_fa.columns.name = "Fiscal Date Ending" + df_fa = clean_metrics_df(df_fa, num=ns_parser.n_num) + print(df_fa.drop(index=["Final link", "Link"]).to_string()) pd.set_option("display.max_colwidth", -1) @@ -393,7 +322,6 @@ def balance_sheet(l_args, s_ticker): print(df_fa.loc["Final link"].to_frame().to_string()) print("") print(df_fa.loc["Link"].to_frame().to_string()) - print("") except Exception as e: @@ -402,22 +330,22 @@ def balance_sheet(l_args, s_ticker): return -# ---------------------------------------------------- CASH_FLOW ---------------------------------------------------- def cash_flow(l_args, s_ticker): parser = argparse.ArgumentParser( prog="cash", description=""" Prints a complete cash flow statement over time. This can be either - quarterly or annually. The following fields are expected: Accepted date, Accounts payables, - Accounts receivables, Acquisitions net, Capital expenditure, Cash at beginning of period, - Cash at end of period, Change in working capital, Common stock issued, Common stock repurchased, - Debt repayment, Deferred income tax, Depreciation and amortization, Dividends paid, - Effect of forex changes on cash, Filling date, Final link, Free cash flow, Inventory, - Investments in property plant and equipment, Link, Net cash provided by operating activities, - Net cash used for investing activities, Net cash used provided by financing activities, Net - change in cash, Net income, Operating cash flow, Other financing activities, Other investing - activities, Other non cash items, Other working capital, Period, Purchases of investments, - Sales maturities of investments, Stock based compensation. [Source: Financial Modeling Prep] + quarterly or annually. The following fields are expected: Accepted date, Accounts + payables, Accounts receivables, Acquisitions net, Capital expenditure, Cash at + beginning of period, Cash at end of period, Change in working capital, Common stock + issued, Common stock repurchased, Debt repayment, Deferred income tax, Depreciation and + amortization, Dividends paid, Effect of forex changes on cash, Filling date, Final + link, Free cash flow, Inventory, Investments in property plant and equipment, Link, Net + cash provided by operating activities, Net cash used for investing activities, Net cash + used provided by financing activities, Net change in cash, Net income, Operating cash + flow, Other financing activities, Other investing activities, Other non cash items, + Other working capital, Period, Purchases of investments, Sales maturities of + investments, Stock based compensation. [Source: Financial Modeling Prep] """, ) @@ -440,11 +368,7 @@ def cash_flow(l_args, s_ticker): ) try: - (ns_parser, l_unknown_args) = parser.parse_known_args(l_args) - - if l_unknown_args: - print(f"The following args couldn't be interpreted: {l_unknown_args}\n") - return + ns_parser = parse_known_args_and_warn(parser, l_args) if ns_parser.n_num == 1: pd.set_option("display.max_colwidth", -1) @@ -458,18 +382,8 @@ def cash_flow(l_args, s_ticker): else: df_fa = fa.cash_flow_statement(s_ticker, cfg.API_KEY_FINANCIALMODELINGPREP) - df_fa = df_fa.iloc[:, 0 : ns_parser.n_num] - df_fa = df_fa.mask(df_fa.astype(object).eq(ns_parser.n_num * ["None"])).dropna() - df_fa = df_fa.mask(df_fa.astype(object).eq(ns_parser.n_num * ["0"])).dropna() - df_fa = df_fa.applymap(lambda x: long_number_format(x)) - df_fa.index = [ - "".join( - " " + char if char.isupper() else char.strip() for char in idx - ).strip() - for idx in df_fa.index.tolist() - ] - df_fa.index = [s_val.capitalize() for s_val in df_fa.index] - df_fa.columns.name = "Fiscal Date Ending" + df_fa = clean_metrics_df(df_fa, num=ns_parser.n_num) + print(df_fa.drop(index=["Final link", "Link"]).to_string()) pd.set_option("display.max_colwidth", -1) @@ -477,7 +391,6 @@ def cash_flow(l_args, s_ticker): print(df_fa.loc["Final link"].to_frame().to_string()) print("") print(df_fa.loc["Link"].to_frame().to_string()) - print("") except Exception as e: @@ -486,7 +399,6 @@ def cash_flow(l_args, s_ticker): return -# ---------------------------------------------------- KEY_METRICS ---------------------------------------------------- def key_metrics(l_args, s_ticker): parser = argparse.ArgumentParser( prog="metrics", @@ -496,17 +408,18 @@ def key_metrics(l_args, s_ticker): Working Capital, Current Ratio and Debt to Assets. The following fields are expected: Average inventory, Average payables, Average receivables, Book value per share, Capex per share, Capex to depreciation, Capex to operating cash flow, Capex to revenue, Cash - per share, Current ratio, Days of inventory on hand, Days payables outstanding, Days sales - outstanding, Debt to assets, Debt to equity, Dividend yield, Earnings yield, Enterprise value, - Enterprise value over EBITDA, Ev to free cash flow, Ev to operating cash flow, Ev to sales, - Free cash flow per share, Free cash flow yield, Graham net net, Graham number, Income quality, - Intangibles to total assets, Interest debt per share, Inventory turnover, Market cap, Net - current asset value, Net debt to EBITDA, Net income per share, Operating cash flow per share, - Payables turnover, Payout ratio, Pb ratio, Pe ratio, Pfcf ratio, Pocfratio, Price to sales ratio, - Ptb ratio, Receivables turnover, Research and ddevelopement to revenue, Return on tangible assets, - Revenue per share, Roe, Roic, Sales general and administrative to revenue, Shareholders equity per - share, Stock based compensation to revenue, Tangible book value per share, and Working capital. - [Source: Financial Modeling Prep] + per share, Current ratio, Days of inventory on hand, Days payables outstanding, Days + sales outstanding, Debt to assets, Debt to equity, Dividend yield, Earnings yield, + Enterprise value, Enterprise value over EBITDA, Ev to free cash flow, Ev to operating + cash flow, Ev to sales, Free cash flow per share, Free cash flow yield, Graham net net, + Graham number, Income quality, Intangibles to total assets, Interest debt per share, + Inventory turnover, Market cap, Net current asset value, Net debt to EBITDA, Net income + per share, Operating cash flow per share, Payables turnover, Payout ratio, Pb ratio, Pe + ratio, Pfcf ratio, Pocfratio, Price to sales ratio, Ptb ratio, Receivables turnover, + Research and ddevelopement to revenue, Return on tangible assets, Revenue per share, + Roe, Roic, Sales general and administrative to revenue, Shareholders equity per + share, Stock based compensation to revenue, Tangible book value per share, and Working + capital. [Source: Financial Modeling Prep] """, ) @@ -529,11 +442,7 @@ def key_metrics(l_args, s_ticker): ) try: - (ns_parser, l_unknown_args) = parser.parse_known_args(l_args) - - if l_unknown_args: - print(f"The following args couldn't be interpreted: {l_unknown_args}\n") - return + ns_parser = parse_known_args_and_warn(parser, l_args) if ns_parser.n_num == 1: pd.set_option("display.max_colwidth", -1) @@ -547,24 +456,9 @@ def key_metrics(l_args, s_ticker): else: df_fa = fa.key_metrics(s_ticker, cfg.API_KEY_FINANCIALMODELINGPREP) - df_fa = df_fa.iloc[:, 0 : ns_parser.n_num] - df_fa = df_fa.mask(df_fa.astype(object).eq(ns_parser.n_num * ["None"])).dropna() - df_fa = df_fa.mask(df_fa.astype(object).eq(ns_parser.n_num * ["0"])).dropna() - df_fa = df_fa.applymap(lambda x: long_number_format(x)) - df_fa.index = [ - "".join( - " " + char if char.isupper() else char.strip() for char in idx - ).strip() - for idx in df_fa.index.tolist() - ] - df_fa.index = [s_val.capitalize() for s_val in df_fa.index] - df_fa.columns.name = "Fiscal Date Ending" - df_fa = df_fa.rename( - index={"Enterprise value over e b i t d a": "Enterprise value over EBITDA"} - ) - df_fa = df_fa.rename(index={"Net debt to e b i t d a": "Net debt to EBITDA"}) - print(df_fa) + df_fa = clean_metrics_df(df_fa, num=ns_parser.n_num) + print(df_fa) print("") except Exception as e: @@ -573,28 +467,28 @@ def key_metrics(l_args, s_ticker): return -# ---------------------------------------------------- FINANCIAL_RATIOS ---------------------------------------------------- def financial_ratios(l_args, s_ticker): parser = argparse.ArgumentParser( prog="ratios", description=""" - Prints in-depth ratios of a company over time. This can be either - quarterly or annually. This contains, among other things, Price-to-Book Ratio, Payout - Ratio and Operating Cycle. The following fields are expected: Asset turnover, Capital - expenditure coverage ratio, Cash conversion cycle, Cash flow coverage ratios, Cash flow - to debt ratio, Cash per share, Cash ratio, Company equity multiplier, Current ratio, - Days of inventory outstanding, Days of payables outstanding, Days of sales outstanding, - Debt equity ratio, Debt ratio, Dividend paid and capex coverage ratio, Dividend payout ratio, - Dividend yield, Ebit per revenue, Ebt per ebit, Effective tax rate, Enterprise value multiple, - Fixed asset turnover, Free cash flow operating cash flow ratio, Free cash flow per share, Gross - profit margin, Inventory turnover, Long term debt to capitalization, Net income per EBT, Net - profit margin, Operating cash flow per share, Operating cash flow sales ratio, Operating cycle, - Operating profit margin, Payables turnover, Payout ratio, Pretax profit margin, Price book value - ratio, Price cash flow ratio, Price earnings ratio, Price earnings to growth ratio, Price fair value, - Price sales ratio, Price to book ratio, Price to free cash flows ratio, Price to operating cash flows - ratio, Price to sales ratio, Quick ratio, Receivables turnover, Return on assets, Return on capital - employed, Return on equity, Short term coverage ratios, and Total debt to capitalization. - [Source: Financial Modeling Prep] + Prints in-depth ratios of a company over time. This can be either quarterly or + annually. This contains, among other things, Price-to-Book Ratio, Payout Ratio and + Operating Cycle. The following fields are expected: Asset turnover, Capital expenditure + coverage ratio, Cash conversion cycle, Cash flow coverage ratios, Cash flow to debt + ratio, Cash per share, Cash ratio, Company equity multiplier, Current ratio, Days of + inventory outstanding, Days of payables outstanding, Days of sales outstanding, Debt + equity ratio, Debt ratio, Dividend paid and capex coverage ratio, Dividend payout ratio, + Dividend yield, Ebit per revenue, Ebt per ebit, Effective tax rate, Enterprise value + multiple, Fixed asset turnover, Free cash flow operating cash flow ratio, Free cash + flow per share, Gross profit margin, Inventory turnover, Long term debt to + capitalization, Net income per EBT, Net profit margin, Operating cash flow per share, + Operating cash flow sales ratio, Operating cycle, Operating profit margin, Payables + turnover, Payout ratio, Pretax profit margin, Price book value ratio, Price cash flow + ratio, Price earnings ratio, Price earnings to growth ratio, Price fair value, + Price sales ratio, Price to book ratio, Price to free cash flows ratio, Price to + operating cash flows ratio, Price to sales ratio, Quick ratio, Receivables turnover, + Return on assets, Return on capital employed, Return on equity, Short term coverage + ratios, and Total debt to capitalization. [Source: Financial Modeling Prep] """, ) @@ -617,11 +511,7 @@ def financial_ratios(l_args, s_ticker): ) try: - (ns_parser, l_unknown_args) = parser.parse_known_args(l_args) - - if l_unknown_args: - print(f"The following args couldn't be interpreted: {l_unknown_args}\n") - return + ns_parser = parse_known_args_and_warn(parser, l_args) if ns_parser.n_num == 1: pd.set_option("display.max_colwidth", -1) @@ -635,21 +525,9 @@ def financial_ratios(l_args, s_ticker): else: df_fa = fa.financial_ratios(s_ticker, cfg.API_KEY_FINANCIALMODELINGPREP) - df_fa = df_fa.iloc[:, 0 : ns_parser.n_num] - df_fa = df_fa.mask(df_fa.astype(object).eq(ns_parser.n_num * ["None"])).dropna() - df_fa = df_fa.mask(df_fa.astype(object).eq(ns_parser.n_num * ["0"])).dropna() - df_fa = df_fa.applymap(lambda x: long_number_format(x)) - df_fa.index = [ - "".join( - " " + char if char.isupper() else char.strip() for char in idx - ).strip() - for idx in df_fa.index.tolist() - ] - df_fa.index = [s_val.capitalize() for s_val in df_fa.index] - df_fa.columns.name = "Fiscal Date Ending" - df_fa = df_fa.rename(index={"Net income per e b t": "Net income per EBT"}) - print(df_fa) + df_fa = clean_metrics_df(df_fa, num=ns_parser.n_num) + print(df_fa) print("") except Exception as e: @@ -658,25 +536,24 @@ def financial_ratios(l_args, s_ticker): return -# ---------------------------------------------------- FINANCIAL_STATEMENT_GROWTH ---------------------------------------------------- def financial_statement_growth(l_args, s_ticker): parser = argparse.ArgumentParser( prog="growth", - description=""" - Prints the growth of several financial statement items and ratios over time. This can be - either annually and quarterly. These are, among other things, Revenue Growth (3, 5 and 10 years), - inventory growth and operating cash flow growth (3, 5 and 10 years). The following fields - are expected: Asset growth, Book valueper share growth, Debt growth, Dividendsper share growth, - Ebitgrowth, Epsdiluted growth, Epsgrowth, Five y dividendper share growth per share, Five y net - income growth per share, Five y operating c f growth per share, Five y revenue growth per share, - Five y shareholders equity growth per share, Free cash flow growth, Gross profit growth, Inventory - growth, Net income growth, Operating cash flow growth, Operating income growth, Rdexpense growth, - Receivables growth, Revenue growth, Sgaexpenses growth, Ten y dividendper share growth per share, - Ten y net income growth per share, Ten y operating c f growth per share, Ten y revenue growth per - share, Ten y shareholders equity growth per share, Three y dividendper share growth per share, - Three y net income growth per share, Three y operating c f growth per share, Three y revenue growth - per share, Three y shareholders equity growth per share, Weighted average shares diluted growth, - and Weighted average shares growth [Source: Financial Modeling Prep] + description=""" Prints the growth of several financial statement items and ratios over + time. This can be either annually and quarterly. These are, among other things, Revenue + Growth (3, 5 and 10 years), inventory growth and operating cash flow growth (3, 5 and 10 + years). The following fields are expected: Asset growth, Book valueper share growth, Debt + growth, Dividendsper share growth, Ebitgrowth, Epsdiluted growth, Epsgrowth, Five y + dividendper share growth per share, Five y net income growth per share, Five y operating c + f growth per share, Five y revenue growth per share, Five y shareholders equity growth per + share, Free cash flow growth, Gross profit growth, Inventory growth, Net income growth, + Operating cash flow growth, Operating income growth, Rdexpense growth, Receivables growth, + Revenue growth, Sgaexpenses growth, Ten y dividendper share growth per share, Ten y net + income growth per share, Ten y operating c f growth per share, Ten y revenue growth per + share, Ten y shareholders equity growth per share, Three y dividendper share growth per + share, Three y net income growth per share, Three y operating c f growth per share, Three y + revenue growth per share, Three y shareholders equity growth per share, Weighted average + shares diluted growth, and Weighted average shares growth [Source: Financial Modeling Prep] """, ) @@ -699,11 +576,7 @@ def financial_statement_growth(l_args, s_ticker): ) try: - (ns_parser, l_unknown_args) = parser.parse_known_args(l_args) - - if l_unknown_args: - print(f"The following args couldn't be interpreted: {l_unknown_args}\n") - return + ns_parser = parse_known_args_and_warn(parser, l_args) if ns_parser.n_num == 1: pd.set_option("display.max_colwidth", -1) @@ -719,23 +592,31 @@ def financial_statement_growth(l_args, s_ticker): s_ticker, cfg.API_KEY_FINANCIALMODELINGPREP ) - df_fa = df_fa.iloc[:, 0 : ns_parser.n_num] - df_fa = df_fa.mask(df_fa.astype(object).eq(ns_parser.n_num * ["None"])).dropna() - df_fa = df_fa.mask(df_fa.astype(object).eq(ns_parser.n_num * ["0"])).dropna() - df_fa = df_fa.applymap(lambda x: long_number_format(x)) - df_fa.index = [ - "".join( - " " + char if char.isupper() else char.strip() for char in idx - ).strip() - for idx in df_fa.index.tolist() - ] - df_fa.index = [s_val.capitalize() for s_val in df_fa.index] - df_fa.columns.name = "Fiscal Date Ending" - print(df_fa) + df_fa = clean_metrics_df(df_fa, num=ns_parser.n_num) + print(df_fa) print("") except Exception as e: print(e) print("") return + + +def clean_metrics_df(df_fa: pd.DataFrame, num: int, mask: bool = True) -> pd.DataFrame: + df_fa = df_fa.iloc[:, 0:num] + if mask: + df_fa = df_fa.mask(df_fa.astype(object).eq(num * ["None"])).dropna() + df_fa = df_fa.mask(df_fa.astype(object).eq(num * ["0"])).dropna() + df_fa = df_fa.applymap(lambda x: long_number_format(x)) + clean_df_index(df_fa) + df_fa.columns.name = "Fiscal Date Ending" + df_fa = df_fa.rename( + index={ + "Enterprise value over e b i t d a": "Enterprise value over EBITDA", + "Net debt to e b i t d a": "Net debt to EBITDA", + "D c f": "DCF", + "Net income per e b t": "Net income per EBT", + } + ) + return df_fa diff --git a/gamestonk_terminal/fundamental_analysis/finviz_api.py b/gamestonk_terminal/fundamental_analysis/finviz_api.py index a6b18559672..6ca1dce2b97 100644 --- a/gamestonk_terminal/fundamental_analysis/finviz_api.py +++ b/gamestonk_terminal/fundamental_analysis/finviz_api.py @@ -1,9 +1,9 @@ import argparse import finviz import pandas as pd +from gamestonk_terminal.helper_funcs import parse_known_args_and_warn -# ---------------------------------------------------- SCREENER ---------------------------------------------------- def screener(l_args, s_ticker): parser = argparse.ArgumentParser( prog="screener", @@ -23,11 +23,7 @@ def screener(l_args, s_ticker): ) try: - (_, l_unknown_args) = parser.parse_known_args(l_args) - - if l_unknown_args: - print(f"The following args couldn't be interpreted: {l_unknown_args}\n") - return + parse_known_args_and_warn(parser, l_args) d_finviz_stock = finviz.get_stock(s_ticker) df_fa = pd.DataFrame.from_dict( diff --git a/gamestonk_terminal/fundamental_analysis/market_watch_api.py b/gamestonk_terminal/fundamental_analysis/market_watch_api.py index 4c7f0759f63..248547e396f 100644 --- a/gamestonk_terminal/fundamental_analysis/market_watch_api.py +++ b/gamestonk_terminal/fundamental_analysis/market_watch_api.py @@ -1,30 +1,33 @@ import argparse +import re import requests import pandas as pd from bs4 import BeautifulSoup -from gamestonk_terminal.helper_funcs import get_user_agent +from gamestonk_terminal.helper_funcs import get_user_agent, parse_known_args_and_warn + -# ---------------------------------------------------- INCOME ---------------------------------------------------- def income(l_args, s_ticker): parser = argparse.ArgumentParser( prog="income", description=""" - Prints either yearly or quarterly income statement the company. - The following fields are expected: Sales Growth, Cost of Goods Sold (COGS) incl. D&A, - COGS Growth, COGS excluding D&A, Depreciation & Amortization Expense, Depreciation, - Amortization of Intangibles, Gross Income, Gross Income Growth, Gross Profit Margin, - SG&A Expense, SGA Growth, Research & Development, Other SG&A, Other Operating Expense, - Unusual Expense, EBIT after Unusual Expense, Non Operating Income/Expense, Non-Operating - Interest Income, Equity in Affiliates (Pretax), Interest Expense, Interest Expense Growth, - Gross Interest Expense, Interest Capitalized, Pretax Income, Pretax Income Growth, Pretax Margin, - Income Tax, Income Tax - Current Domestic, Income Tax - Current Foreign, Income Tax - Deferred - Domestic, Income Tax - Deferred Foreign, Income Tax Credits, Equity in Affiliates, Other After - Tax Income (Expense), Consolidated Net Income, Minority Interest Expense, Net Income Growth, - Net Margin Growth, Extraordinaries & Discontinued Operations, Extra Items & Gain/Loss Sale Of Assets, - Cumulative Effect - Accounting Chg, Discontinued Operations, Net Income After Extraordinaries, + Prints either yearly or quarterly income statement the company. The following fields + are expected: Sales Growth, Cost of Goods Sold (COGS) incl. D&A, COGS Growth, COGS + excluding D&A, Depreciation & Amortization Expense, Depreciation, Amortization of + Intangibles, Gross Income, Gross Income Growth, Gross Profit Margin, SG&A Expense, SGA + Growth, Research & Development, Other SG&A, Other Operating Expense, Unusual Expense, + EBIT after Unusual Expense, Non Operating Income/Expense, Non-Operating Interest + Income, Equity in Affiliates (Pretax), Interest Expense, Interest Expense Growth, + Gross Interest Expense, Interest Capitalized, Pretax Income, Pretax Income Growth, + Pretax Margin, Income Tax, Income Tax - Current Domestic, Income Tax - Current Foreign, + Income Tax - Deferred Domestic, Income Tax - Deferred Foreign, Income Tax Credits, + Equity in Affiliates, Other After Tax Income (Expense), Consolidated Net Income, + Minority Interest Expense, Net Income Growth, Net Margin Growth, Extraordinaries & + Discontinued Operations, Extra Items & Gain/Loss Sale Of Assets, Cumulative Effect - + Accounting Chg, Discontinued Operations, Net Income After Extraordinaries, Preferred Dividends, Net Income Available to Common, EPS (Basic), EPS (Basic) Growth, - Basic Shares Outstanding, EPS (Diluted), EPS (Diluted) Growth, Diluted Shares Outstanding, EBITDA, - EBITDA Growth, EBITDA Margin, Sales/Revenue, and Net Income. [Source: Market Watch] + Basic Shares Outstanding, EPS (Diluted), EPS (Diluted) Growth, Diluted Shares + Outstanding, EBITDA, EBITDA Growth, EBITDA Margin, Sales/Revenue, and Net Income. + [Source: Market Watch] """, ) @@ -38,43 +41,16 @@ def income(l_args, s_ticker): ) try: - (ns_parser, l_unknown_args) = parser.parse_known_args(l_args) - - if l_unknown_args: - print(f"The following args couldn't be interpreted: {l_unknown_args}\n") - return + ns_parser = parse_known_args_and_warn(parser, l_args) if ns_parser.b_quarter: url_financials = f"https://www.marketwatch.com/investing/stock/{s_ticker}/financials/income/quarter" else: url_financials = f"https://www.marketwatch.com/investing/stock/{s_ticker}/financials/income" - text_soup_financials = BeautifulSoup( - requests.get(url_financials, headers={"User-Agent": get_user_agent()}).text, - "lxml", - ) + df_financials = prepare_df_financials(url_financials, ns_parser.b_quarter) - # Define financials columns - a_financials_header = list() - for financials_header in text_soup_financials.findAll( - "th", {"class": "overflow__heading"} - ): - a_financials_header.append( - financials_header.text.strip("\n").split("\n")[0] - ) - df_financials = pd.DataFrame(columns=a_financials_header[0:-1]) - - # Add financials values - soup_financials = text_soup_financials.findAll("tr", {"class": "table__row "}) - soup_financials += text_soup_financials.findAll( - "tr", {"class": "table__row is-highlighted"} - ) - for financials_info in soup_financials: - a_financials_info = financials_info.text.split("\n") - l_financials = [a_financials_info[2]] - l_financials.extend(a_financials_info[5:-2]) - # Append data values to financials - df_financials.loc[len(df_financials.index)] = l_financials + df_financials = df_financials.drop(index="Item") print(df_financials.to_string(index=False)) print("") @@ -85,22 +61,22 @@ def income(l_args, s_ticker): return -# ---------------------------------------------------- ASSETS ---------------------------------------------------- def assets(l_args, s_ticker): parser = argparse.ArgumentParser( prog="assets", description=""" Prints either yearly or quarterly assets from balance sheet of the company. - The following fields are expected: Cash & Short Term Investments, Cash & Short Term Investments - Growth, Cash Only, Short-Term Investments, Cash & ST Investments / Total Assets, Total Accounts - Receivable, Total Accounts Receivable Growth, Accounts Receivables, Net, Accounts Receivables, - Gross, Bad Debt/Doubtful Accounts, Other Receivable, Accounts Receivable Turnover, Inventories, - Finished Goods, Work in Progress, Raw Materials, Progress Payments & Other, Other Current Assets, - Miscellaneous Current Assets, Net Property, Plant & Equipment, Property, Plant & Equipment - Gross, - Buildings, Land & Improvements, Computer Software and Equipment, Other Property, Plant & Equipment, - Accumulated Depreciation, Total Investments and Advances, Other Long-Term Investments, - Long-Term Note Receivables, Intangible Assets, Net Goodwill, Net Other Intangibles, Other Assets - [Source: Market Watch] + The following fields are expected: Cash & Short Term Investments, Cash & Short Term + Investments Growth, Cash Only, Short-Term Investments, Cash & ST Investments / Total + Assets, Total Accounts Receivable, Total Accounts Receivable Growth, Accounts + Receivables, Net, Accounts Receivables, Gross, Bad Debt/Doubtful Accounts, Other + Receivable, Accounts Receivable Turnover, Inventories, Finished Goods, Work in + Progress, Raw Materials, Progress Payments & Other, Other Current Assets, + Miscellaneous Current Assets, Net Property, Plant & Equipment, Property, Plant & + Equipment - Gross, Buildings, Land & Improvements, Computer Software and Equipment, + Other Property, Plant & Equipment, Accumulated Depreciation, Total Investments and + Advances, Other Long-Term Investments, Long-Term Note Receivables, Intangible Assets, + Net Goodwill, Net Other Intangibles, Other Assets [Source: Market Watch] """, ) @@ -114,50 +90,16 @@ def assets(l_args, s_ticker): ) try: - (ns_parser, l_unknown_args) = parser.parse_known_args(l_args) - - if l_unknown_args: - print(f"The following args couldn't be interpreted: {l_unknown_args}") + ns_parser = parse_known_args_and_warn(parser, l_args) if ns_parser.b_quarter: url_financials = f"https://www.marketwatch.com/investing/stock/{s_ticker}/financials/balance-sheet/quarter" else: url_financials = f"https://www.marketwatch.com/investing/stock/{s_ticker}/financials/balance-sheet" - text_soup_financials = BeautifulSoup( - requests.get(url_financials, headers={"User-Agent": get_user_agent()}).text, - "lxml", - ) + df_financials = prepare_df_financials(url_financials, ns_parser.b_quarter) - # Define financials columns - a_financials_header = list() - for financials_header in text_soup_financials.findAll( - "th", {"class": "overflow__heading"} - ): - a_financials_header.append( - financials_header.text.strip("\n").split("\n")[0] - ) - s_header_end_trend = ("5-year trend", "5- qtr trend")[ns_parser.b_quarter] - df_financials = pd.DataFrame( - columns=a_financials_header[ - 0 : a_financials_header.index(s_header_end_trend) - ] - ) - - # Add financials values - soup_financials = text_soup_financials.findAll("tr", {"class": "table__row "}) - soup_financials += text_soup_financials.findAll( - "tr", {"class": "table__row is-highlighted"} - ) - for financials_info in soup_financials: - a_financials_info = financials_info.text.split("\n") - l_financials = [a_financials_info[2]] - l_financials.extend(a_financials_info[5:-2]) - # Append data values to financials - df_financials.loc[len(df_financials.index)] = l_financials - - # Set item name as index - df_financials = df_financials.set_index("Item") + df_financials.drop(index="Item") print(df_financials.iloc[:33].to_string()) print("") @@ -168,25 +110,27 @@ def assets(l_args, s_ticker): return -# ---------------------------------------------------- LIABILITIES ---------------------------------------------------- def liabilities(l_args, s_ticker): parser = argparse.ArgumentParser( prog="liabilities", description=""" - Prints either yearly or quarterly liablities and shareholders' equity from balance sheet of the company. - The following fields are expected: ST Debt & Current Portion LT Debt, Short Term Debt, - Current Portion of Long Term Debt, Accounts Payable, Accounts Payable Growth, Income Tax Payable, - Other Current Liabilities, Dividends Payable, Accrued Payroll, Miscellaneous Current Liabilities, - Long-Term Debt, Long-Term Debt excl. Capitalized Leases, Non-Convertible Debt, Convertible Debt, - Capitalized Lease Obligations, Provision for Risks & Charges, Deferred Taxes, Deferred Taxes - Credits, - Deferred Taxes - Debit, Other Liabilities, Other Liabilities (excl. Deferred Income), Deferred Income, - Non-Equity Reserves, Total Liabilities / Total Assets, Preferred Stock (Carrying Value), - Redeemable Preferred Stock, Non-Redeemable Preferred Stock, Common Equity (Total), Common Equity/Total Assets, - Common Stock Par/Carry Value, Retained Earnings, ESOP Debt Guarantee, Cumulative Translation - Adjustment/Unrealized For. Exch. Gain, Unrealized Gain/Loss Marketable Securities, Revaluation Reserves, - Treasury Stock, Total Shareholders' Equity, Total Shareholders' Equity / Total Assets, - Accumulated Minority Interest, Total Equity, Total Current Assets, Total Assets, Total Current Liabilities, - Total Liabilities, and Liabilities & Shareholders' Equity. [Source: Market Watch] + Prints either yearly or quarterly liablities and shareholders' equity from balance + sheet of the company. The following fields are expected: ST Debt & Current Portion LT + Debt, Short Term Debt, Current Portion of Long Term Debt, Accounts Payable, Accounts + Payable Growth, Income Tax Payable, Other Current Liabilities, Dividends Payable, + Accrued Payroll, Miscellaneous Current Liabilities, Long-Term Debt, Long-Term Debt + excl. Capitalized Leases, Non-Convertible Debt, Convertible Debt, Capitalized Lease + Obligations, Provision for Risks & Charges, Deferred Taxes, Deferred Taxes - Credits, + Deferred Taxes - Debit, Other Liabilities, Other Liabilities (excl. Deferred Income), + Deferred Income, Non-Equity Reserves, Total Liabilities / Total Assets, Preferred Stock + (Carrying Value), Redeemable Preferred Stock, Non-Redeemable Preferred Stock, Common + Equity (Total), Common Equity/Total Assets, Common Stock Par/Carry Value, Retained + Earnings, ESOP Debt Guarantee, Cumulative Translation Adjustment/Unrealized For. Exch. + Gain, Unrealized Gain/Loss Marketable Securities, Revaluation Reserves, Treasury Stock, + Total Shareholders' Equity, Total Shareholders' Equity / Total Assets, Accumulated + Minority Interest, Total Equity, Total Current Assets, Total Assets, Total Current + Liabilities, Total Liabilities, and Liabilities & Shareholders' Equity. [Source: Market + Watch] """, ) @@ -200,51 +144,14 @@ def liabilities(l_args, s_ticker): ) try: - (ns_parser, l_unknown_args) = parser.parse_known_args(l_args) - - if l_unknown_args: - print(f"The following args couldn't be interpreted: {l_unknown_args}\n") - return + ns_parser = parse_known_args_and_warn(parser, l_args) if ns_parser.b_quarter: url_financials = f"https://www.marketwatch.com/investing/stock/{s_ticker}/financials/balance-sheet/quarter" else: url_financials = f"https://www.marketwatch.com/investing/stock/{s_ticker}/financials/balance-sheet" - text_soup_financials = BeautifulSoup( - requests.get(url_financials, headers={"User-Agent": get_user_agent()}).text, - "lxml", - ) - - # Define financials columns - a_financials_header = list() - for financials_header in text_soup_financials.findAll( - "th", {"class": "overflow__heading"} - ): - a_financials_header.append( - financials_header.text.strip("\n").split("\n")[0] - ) - s_header_end_trend = ("5-year trend", "5- qtr trend")[ns_parser.b_quarter] - df_financials = pd.DataFrame( - columns=a_financials_header[ - 0 : a_financials_header.index(s_header_end_trend) - ] - ) - - # Add financials values - soup_financials = text_soup_financials.findAll("tr", {"class": "table__row "}) - soup_financials += text_soup_financials.findAll( - "tr", {"class": "table__row is-highlighted"} - ) - for financials_info in soup_financials: - a_financials_info = financials_info.text.split("\n") - l_financials = [a_financials_info[2]] - l_financials.extend(a_financials_info[5:-2]) - # Append data values to financials - df_financials.loc[len(df_financials.index)] = l_financials - - # Set item name as index - df_financials = df_financials.set_index("Item") + df_financials = prepare_df_financials(url_financials, ns_parser.b_quarter) print(df_financials.iloc[34:].to_string()) print("") @@ -255,17 +162,17 @@ def liabilities(l_args, s_ticker): return -# ---------------------------------------------------- OPERATING ---------------------------------------------------- def operating(l_args, s_ticker): parser = argparse.ArgumentParser( prog="operating", description=""" Prints either yearly or quarterly cash flow operating activities of the company. - The following fields are expected: Net Income before Extraordinaries, Net Income Growth, Depreciation, - Depletion & Amortization, Depreciation and Depletion, Amortization of Intangible Assets, - Deferred Taxes & Investment Tax Credit, Deferred Taxes, Investment Tax Credit, Other Funds, - Funds from Operations, Extraordinaries, Changes in Working Capital, Receivables, Accounts Payable, - Other Assets/Liabilities, and Net Operating Cash Flow Growth. [Source: Market Watch] + The following fields are expected: Net Income before Extraordinaries, Net Income + Growth, Depreciation, Depletion & Amortization, Depreciation and Depletion, + Amortization of Intangible Assets, Deferred Taxes & Investment Tax Credit, Deferred + Taxes, Investment Tax Credit, Other Funds, Funds from Operations, Extraordinaries, + Changes in Working Capital, Receivables, Accounts Payable, Other Assets/Liabilities, + and Net Operating Cash Flow Growth. [Source: Market Watch] """, ) @@ -279,55 +186,16 @@ def operating(l_args, s_ticker): ) try: - (ns_parser, l_unknown_args) = parser.parse_known_args(l_args) - - if l_unknown_args: - print(f"The following args couldn't be interpreted: {l_unknown_args}\n") - return + ns_parser = parse_known_args_and_warn(parser, l_args) if ns_parser.b_quarter: url_financials = f"https://www.marketwatch.com/investing/stock/{s_ticker}/financials/cash-flow/quarter" else: url_financials = f"https://www.marketwatch.com/investing/stock/{s_ticker}/financials/cash-flow" - text_soup_financials = BeautifulSoup( - requests.get(url_financials, headers={"User-Agent": get_user_agent()}).text, - "lxml", - ) + df_financials = prepare_df_financials(url_financials, ns_parser.b_quarter) - # Define financials columns - a_financials_header = list() - for financials_header in text_soup_financials.findAll( - "th", {"class": "overflow__heading"} - ): - a_financials_header.append( - financials_header.text.strip("\n").split("\n")[0] - ) - - s_header_end_trend = ("5-year trend", "5- qtr trend")[ns_parser.b_quarter] - df_financials = pd.DataFrame( - columns=a_financials_header[ - 0 : a_financials_header.index(s_header_end_trend) - ] - ) - - # Add financials values - soup_financials = text_soup_financials.findAll("tr", {"class": "table__row "}) - soup_financials += text_soup_financials.findAll( - "tr", {"class": "table__row is-highlighted"} - ) - for financials_info in soup_financials: - a_financials_info = financials_info.text.split("\n") - l_financials = [a_financials_info[2]] - l_financials.extend(a_financials_info[5:-2]) - n_vals_to_add = len(df_financials.columns) - len(l_financials) - if n_vals_to_add > 0: - l_financials.append(n_vals_to_add * " ") - # Append data values to financials - df_financials.loc[len(df_financials.index)] = l_financials - - # Set item name as index - df_financials = df_financials.set_index("Item") + df_financials.drop(index="Item") print(df_financials.iloc[:16].to_string()) print("") @@ -338,17 +206,16 @@ def operating(l_args, s_ticker): return -# ---------------------------------------------------- INVESTING ---------------------------------------------------- def investing(l_args, s_ticker): parser = argparse.ArgumentParser( prog="investing", description=""" Prints either yearly or quarterly cash flow investing activities of the company. - The following fields are expected: Capital Expenditures, Capital Expenditures Growth, Capital - Expenditures/Sales, Capital Expenditures (Fixed Assets), Capital Expenditures (Other Assets), - Net Assets from Acquisitions, Sale of Fixed Assets & Businesses, Purchase/Sale of Investments, - Purchase of Investments, Sale/Maturity of Investments, Other Uses, Other Sources, Net Investing - Cash Flow Growth. [Source: Market Watch] + The following fields are expected: Capital Expenditures, Capital Expenditures Growth, + Capital Expenditures/Sales, Capital Expenditures (Fixed Assets), Capital Expenditures + (Other Assets), Net Assets from Acquisitions, Sale of Fixed Assets & Businesses, + Purchase/Sale of Investments, Purchase of Investments, Sale/Maturity of Investments, + Other Uses, Other Sources, Net Investing Cash Flow Growth. [Source: Market Watch] """, ) @@ -362,55 +229,14 @@ def investing(l_args, s_ticker): ) try: - (ns_parser, l_unknown_args) = parser.parse_known_args(l_args) - - if l_unknown_args: - print(f"The following args couldn't be interpreted: {l_unknown_args}\n") - return + ns_parser = parse_known_args_and_warn(parser, l_args) if ns_parser.b_quarter: url_financials = f"https://www.marketwatch.com/investing/stock/{s_ticker}/financials/cash-flow/quarter" else: url_financials = f"https://www.marketwatch.com/investing/stock/{s_ticker}/financials/cash-flow" - text_soup_financials = BeautifulSoup( - requests.get(url_financials, headers={"User-Agent": get_user_agent()}).text, - "lxml", - ) - - # Define financials columns - a_financials_header = list() - for financials_header in text_soup_financials.findAll( - "th", {"class": "overflow__heading"} - ): - a_financials_header.append( - financials_header.text.strip("\n").split("\n")[0] - ) - - s_header_end_trend = ("5-year trend", "5- qtr trend")[ns_parser.b_quarter] - df_financials = pd.DataFrame( - columns=a_financials_header[ - 0 : a_financials_header.index(s_header_end_trend) - ] - ) - - # Add financials values - soup_financials = text_soup_financials.findAll("tr", {"class": "table__row "}) - soup_financials += text_soup_financials.findAll( - "tr", {"class": "table__row is-highlighted"} - ) - for financials_info in soup_financials: - a_financials_info = financials_info.text.split("\n") - l_financials = [a_financials_info[2]] - l_financials.extend(a_financials_info[5:-2]) - n_vals_to_add = len(df_financials.columns) - len(l_financials) - if n_vals_to_add > 0: - l_financials.append(n_vals_to_add * " ") - # Append data values to financials - df_financials.loc[len(df_financials.index)] = l_financials - - # Set item name as index - df_financials = df_financials.set_index("Item") + df_financials = prepare_df_financials(url_financials, ns_parser.b_quarter) print(df_financials.iloc[17:30].to_string()) print("") @@ -421,20 +247,20 @@ def investing(l_args, s_ticker): return -# ---------------------------------------------------- FINANCING ---------------------------------------------------- def financing(l_args, s_ticker): parser = argparse.ArgumentParser( prog="financing", description=""" Prints either yearly or quarterly cash flow financing activities of the company. - The following fields are expected: Cash Dividends Paid - Total, Common Dividends, Preferred Dividends, - Change in Capital Stock, Repurchase of Common & Preferred Stk., Sale of Common & Preferred Stock, - Proceeds from Stock Options, Other Proceeds from Sale of Stock, Issuance/Reduction of Debt, Net, - Change in Current Debt, Change in Long-Term Debt, Issuance of Long-Term Debt, Reduction in Long-Term Debt, - Other Funds, Other Uses, Other Sources, Net Financing Cash Flow Growth, Net Financing Cash Flow/Sales, - Exchange Rate Effect, Miscellaneous Funds, Net Change in Cash, Free Cash Flow, Free Cash Flow Growth, - Free Cash Flow Yield, Net Operating Cash Flow, Net Investing Cash Flow, Net Financing Cash Flow - [Source: Market Watch] + The following fields are expected: Cash Dividends Paid - Total, Common Dividends, + Preferred Dividends, Change in Capital Stock, Repurchase of Common & Preferred Stk., + Sale of Common & Preferred Stock, Proceeds from Stock Options, Other Proceeds from Sale + of Stock, Issuance/Reduction of Debt, Net, Change in Current Debt, Change in Long-Term + Debt, Issuance of Long-Term Debt, Reduction in Long-Term Debt, Other Funds, Other Uses, + Other Sources, Net Financing Cash Flow Growth, Net Financing Cash Flow/Sales, Exchange + Rate Effect, Miscellaneous Funds, Net Change in Cash, Free Cash Flow, Free Cash Flow + Growth, Free Cash Flow Yield, Net Operating Cash Flow, Net Investing Cash Flow, Net + Financing Cash Flow [Source: Market Watch] """, ) @@ -448,55 +274,14 @@ def financing(l_args, s_ticker): ) try: - (ns_parser, l_unknown_args) = parser.parse_known_args(l_args) - - if l_unknown_args: - print(f"The following args couldn't be interpreted: {l_unknown_args}\n") - return + ns_parser = parse_known_args_and_warn(parser, l_args) if ns_parser.b_quarter: url_financials = f"https://www.marketwatch.com/investing/stock/{s_ticker}/financials/cash-flow/quarter" else: url_financials = f"https://www.marketwatch.com/investing/stock/{s_ticker}/financials/cash-flow" - text_soup_financials = BeautifulSoup( - requests.get(url_financials, headers={"User-Agent": get_user_agent()}).text, - "lxml", - ) - - # Define financials columns - a_financials_header = list() - for financials_header in text_soup_financials.findAll( - "th", {"class": "overflow__heading"} - ): - a_financials_header.append( - financials_header.text.strip("\n").split("\n")[0] - ) - - s_header_end_trend = ("5-year trend", "5- qtr trend")[ns_parser.b_quarter] - df_financials = pd.DataFrame( - columns=a_financials_header[ - 0 : a_financials_header.index(s_header_end_trend) - ] - ) - - # Add financials values - soup_financials = text_soup_financials.findAll("tr", {"class": "table__row "}) - soup_financials += text_soup_financials.findAll( - "tr", {"class": "table__row is-highlighted"} - ) - for financials_info in soup_financials: - a_financials_info = financials_info.text.split("\n") - l_financials = [a_financials_info[2]] - l_financials.extend(a_financials_info[5:-2]) - n_vals_to_add = len(df_financials.columns) - len(l_financials) - if n_vals_to_add > 0: - l_financials.append(n_vals_to_add * " ") - # Append data values to financials - df_financials.loc[len(df_financials.index)] = l_financials - - # Set item name as index - df_financials = df_financials.set_index("Item") + df_financials = prepare_df_financials(url_financials, ns_parser.b_quarter) print(df_financials.iloc[31:].to_string()) print("") @@ -505,3 +290,46 @@ def financing(l_args, s_ticker): print(e) print("") return + + +def prepare_df_financials(url_financials: str, quarter: bool) -> pd.DataFrame: + text_soup_financials = BeautifulSoup( + requests.get(url_financials, headers={"User-Agent": get_user_agent()}).text, + "lxml", + ) + + # Define financials columns + a_financials_header = list() + for financials_header in text_soup_financials.findAll( + "th", {"class": "overflow__heading"} + ): + a_financials_header.append(financials_header.text.strip("\n").split("\n")[0]) + + s_header_end_trend = ("5-year trend", "5- qtr trend")[quarter] + df_financials = pd.DataFrame( + columns=a_financials_header[0 : a_financials_header.index(s_header_end_trend)] + ) + + # Add financials values + soup_financials = text_soup_financials.findAll( + lambda tag: tag.name == "tr" and tag.get("class") == ["table__row"] + ) + soup_financials += text_soup_financials.findAll( + "tr", {"class": "table__row is-highlighted"} + ) + for financials_info in soup_financials: + financials_row = financials_info.text.split("\n") + if len(financials_row) > 5: + for item in financials_row: + if bool(re.search(r"\d", item)): + a_financials_info = financials_info.text.split("\n") + l_financials = [a_financials_info[2]] + l_financials.extend(a_financials_info[5:-2]) + # Append data values to financials + df_financials.loc[len(df_financials.index)] = l_financials + break + + # Set item name as index + df_financials = df_financials.set_index("Item") + + return df_financials diff --git a/terminal.py b/terminal.py index 5f749b309ce..bf6e8c3cf1b 100644 --- a/terminal.py +++ b/terminal.py @@ -455,6 +455,7 @@ def main(): ts = TimeSeries( key=cfg.API_KEY_ALPHAVANTAGE, output_format="pandas" ) + # pylint: disable=unbalanced-tuple-unpacking df_stock_pred, _ = ts.get_daily_adjusted( symbol=s_ticker, outputsize="full" ) @@ -465,8 +466,9 @@ def main(): df_stock_pred, s_ticker, s_start, s_interval="1440min" ) except Exception as e: - print("Either the ticker or the API_KEY are invalids. Try again!") print(e) + print("Either the ticker or the API_KEY are invalids. Try again!") + b_quit = False return