Merge pull request #345 from DidierRLopes/refactor-fa

Refactor Fundamental Analysis menu
This commit is contained in:
Artem Veremey
2021-04-19 13:45:37 -07:00
committed by GitHub
17 changed files with 1125 additions and 615 deletions

View File

@@ -0,0 +1,168 @@
""" Alpha Vantage Controller """
__docformat__ = "numpy"
import argparse
from typing import List
from prompt_toolkit.completion import NestedCompleter
from gamestonk_terminal.fundamental_analysis import alpha_vantage_view as avv
from gamestonk_terminal import feature_flags as gtff
from gamestonk_terminal.helper_funcs import get_flair
from gamestonk_terminal.menu import session
class AlphaVantageController:
""" Alpha Vantage Controller """
# Command choices
CHOICES = [
"help",
"q",
"quit",
"overview",
"key",
"income",
"balance",
"cash",
"earnings",
]
def __init__(self, ticker: str, start: str, interval: str):
"""Constructor
Parameters
----------
ticker : str
Fundamental analysis ticker symbol
start : str
Stat date of the stock data
interval : str
Stock data interval
"""
self.ticker = ticker
self.start = start
self.interval = interval
self.av_parser = argparse.ArgumentParser(add_help=False, prog="av")
self.av_parser.add_argument(
"cmd",
choices=self.CHOICES,
)
def print_help(self):
""" Print help """
intraday = (f"Intraday {self.interval}", "Daily")[self.interval == "1440min"]
if self.start:
print(
f"\n{intraday} Stock: {self.ticker} (from {self.start.strftime('%Y-%m-%d')})"
)
else:
print(f"\n{intraday} Stock: {self.ticker}")
print("\nAlpha Vantage:")
print(" help show this alpha vantage menu again")
print(" q quit this menu, and shows back to main menu")
print(" quit quit to abandon program")
print("")
print(" overview overview of the company")
print(" key company key metrics")
print(" income income statements of the company")
print(" balance balance sheet of the company")
print(" cash cash flow of the company")
print(" earnings earnings dates and reported EPS")
print("")
def switch(self, an_input: str):
"""Process and dispatch input
Returns
-------
True, False or None
False - quit the menu
True - quit the program
None - continue in the menu
"""
(known_args, other_args) = self.av_parser.parse_known_args(an_input.split())
return getattr(
self, "call_" + known_args.cmd, lambda: "Command not recognized!"
)(other_args)
def call_help(self, _):
"""Process Help command"""
self.print_help()
def call_q(self, _):
"""Process Q command - quit the menu"""
return False
def call_quit(self, _):
"""Process Quit command - quit the program"""
return True
def call_overview(self, other_args: List[str]):
""" Process overview command """
avv.overview(other_args, self.ticker)
def call_key(self, other_args: List[str]):
""" Process overview command """
avv.key(other_args, self.ticker)
def call_income(self, other_args: List[str]):
""" Process income command """
avv.income_statement(other_args, self.ticker)
def call_balance(self, other_args: List[str]):
""" Process balance command """
avv.balance_sheet(other_args, self.ticker)
def call_cash(self, other_args: List[str]):
""" Process cash command """
avv.cash_flow(other_args, self.ticker)
def call_earnings(self, other_args: List[str]):
""" Process earnings command """
avv.earnings(other_args, self.ticker)
def menu(ticker: str, start: str, interval: str):
"""Alpha Vantage menu
Parameters
----------
ticker : str
Fundamental analysis ticker symbol
start : str
Start date of the stock data
interval : str
Stock data interval
"""
av_controller = AlphaVantageController(ticker, start, interval)
av_controller.call_help(None)
while True:
# Get input command from user
if session and gtff.USE_PROMPT_TOOLKIT:
completer = NestedCompleter.from_nested_dict(
{c: None for c in av_controller.CHOICES}
)
an_input = session.prompt(
f"{get_flair()} (fa)>(av)> ",
completer=completer,
)
else:
an_input = input(f"{get_flair()} (fa)>(av)> ")
try:
process_input = av_controller.switch(an_input)
if process_input is not None:
return process_input
except SystemExit:
print("The command selected doesn't exist\n")
continue

View File

@@ -1,112 +1,33 @@
""" Alpha Vantage View """
__docformat__ = "numpy"
import argparse
from typing import List
import requests
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.dataframe_helpers import clean_df_index
from gamestonk_terminal.helper_funcs import (
check_positive,
long_number_format,
parse_known_args_and_warn,
get_flair,
)
from gamestonk_terminal.menu import session
from prompt_toolkit.completion import NestedCompleter
def print_menu(s_ticker, s_start, s_interval):
""" Print help """
def overview(other_args: List[str], ticker: str):
"""Alpha Vantage stock ticker overview
s_intraday = (f"Intraday {s_interval}", "Daily")[s_interval == "1440min"]
Parameters
----------
other_args : List[str]
argparse other args
ticker : str
Fundamental analysis ticker symbol
"""
if s_start:
print(f"\n{s_intraday} Stock: {s_ticker} (from {s_start.strftime('%Y-%m-%d')})")
else:
print(f"\n{s_intraday} Stock: {s_ticker}")
print("\nAlpha Vantage:")
print(" help show this alpha vantage menu again")
print(" q quit this menu, and shows back to main menu")
print(" quit quit to abandon program")
print("")
print(" overview overview of the company")
print(" income income statements of the company")
print(" balance balance sheet of the company")
print(" cash cash flow of the company")
print(" earnings earnings dates and reported EPS")
print("")
def menu(s_ticker, s_start, s_interval):
# Add list of arguments that the fundamental analysis parser accepts
av_parser = argparse.ArgumentParser(prog="av", add_help=False)
choices = [
"help",
"q",
"quit",
"overview",
"income",
"balance",
"cash",
"earnings",
]
av_parser.add_argument("cmd", choices=choices)
completer = NestedCompleter.from_nested_dict({c: None for c in choices})
print_menu(s_ticker, s_start, s_interval)
# Loop forever and ever
while True:
# Get input command from user
if session:
as_input = session.prompt(
f"{get_flair()} (fa)>(av)> ",
completer=completer,
)
else:
as_input = input(f"{get_flair()} (fa)>(av)> ")
# Parse alpha vantage command of the list of possible commands
try:
(ns_known_args, l_args) = av_parser.parse_known_args(as_input.split())
except SystemExit:
print("The command selected doesn't exist\n")
continue
if ns_known_args.cmd == "help":
print_menu(s_ticker, s_start, s_interval)
elif ns_known_args.cmd == "q":
# Just leave the menu
return False
elif ns_known_args.cmd == "quit":
# Abandon the program
return True
elif ns_known_args.cmd == "overview":
overview(l_args, s_ticker)
elif ns_known_args.cmd == "income":
income_statement(l_args, s_ticker)
elif ns_known_args.cmd == "balance":
balance_sheet(l_args, s_ticker)
elif ns_known_args.cmd == "cash":
cash_flow(l_args, s_ticker)
elif ns_known_args.cmd == "earnings":
earnings(l_args, s_ticker)
else:
print("Command not recognized!")
def overview(l_args, s_ticker):
parser = argparse.ArgumentParser(
add_help=False,
prog="overview",
@@ -128,18 +49,18 @@ def overview(l_args, s_ticker):
)
try:
ns_parser = parse_known_args_and_warn(parser, l_args)
ns_parser = parse_known_args_and_warn(parser, other_args)
if not ns_parser:
return
# 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}"
s_req = f"https://www.alphavantage.co/query?function=OVERVIEW&symbol={ticker}&apikey={cfg.API_KEY_ALPHAVANTAGE}"
result = requests.get(s_req, stream=True)
# If the returned data was successful
if result.status_code == 200:
# Parse json data to dataframe
df_fa = json_normalize(result.json())
df_fa = pd.json_normalize(result.json())
# 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))
@@ -182,7 +103,17 @@ def overview(l_args, s_ticker):
return
def key(l_args, s_ticker):
def key(other_args: List[str], ticker: str):
"""Alpha Vantage key metrics
Parameters
----------
other_args : List[str]
argparse other args
ticker : str
Fundamental analysis ticker symbol
"""
parser = argparse.ArgumentParser(
add_help=False,
prog="key",
@@ -196,17 +127,17 @@ def key(l_args, s_ticker):
)
try:
ns_parser = parse_known_args_and_warn(parser, l_args)
ns_parser = parse_known_args_and_warn(parser, other_args)
if not ns_parser:
return
# Request OVERVIEW data
s_req = f"https://www.alphavantage.co/query?function=OVERVIEW&symbol={s_ticker}&apikey={cfg.API_KEY_ALPHAVANTAGE}"
s_req = f"https://www.alphavantage.co/query?function=OVERVIEW&symbol={ticker}&apikey={cfg.API_KEY_ALPHAVANTAGE}"
result = requests.get(s_req, stream=True)
# If the returned data was successful
if result.status_code == 200:
df_fa = json_normalize(result.json())
df_fa = pd.json_normalize(result.json())
df_fa = df_fa[list(result.json().keys())].T
df_fa = df_fa.applymap(lambda x: long_number_format(x))
clean_df_index(df_fa)
@@ -248,10 +179,20 @@ def key(l_args, s_ticker):
return
def income_statement(l_args, s_ticker):
def income_statement(other_args: List[str], ticker: str):
"""Alpha Vantage income statement
Parameters
----------
other_args : List[str]
argparse other args
ticker : str
Fundamental analysis ticker symbol
"""
parser = argparse.ArgumentParser(
add_help=False,
prog="incom",
prog="income",
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,
@@ -283,7 +224,7 @@ def income_statement(l_args, s_ticker):
)
try:
ns_parser = parse_known_args_and_warn(parser, l_args)
ns_parser = parse_known_args_and_warn(parser, other_args)
if not ns_parser:
return
@@ -295,10 +236,10 @@ def income_statement(l_args, s_ticker):
fd = FundamentalData(key=cfg.API_KEY_ALPHAVANTAGE, output_format="pandas")
if ns_parser.b_quarter:
# pylint: disable=unbalanced-tuple-unpacking
df_fa, _ = fd.get_income_statement_quarterly(symbol=s_ticker)
df_fa, _ = fd.get_income_statement_quarterly(symbol=ticker)
else:
# pylint: disable=unbalanced-tuple-unpacking
df_fa, _ = fd.get_income_statement_annual(symbol=s_ticker)
df_fa, _ = fd.get_income_statement_annual(symbol=ticker)
df_fa = clean_fundamentals_df(df_fa, num=ns_parser.n_num)
print(df_fa)
@@ -310,7 +251,17 @@ def income_statement(l_args, s_ticker):
return
def balance_sheet(l_args, s_ticker):
def balance_sheet(other_args: List[str], ticker: str):
"""Alpha Vantage balance sheet
Parameters
----------
other_args : List[str]
argparse other args
ticker : str
Fundamental analysis ticker symbol
"""
parser = argparse.ArgumentParser(
add_help=False,
prog="balance",
@@ -351,7 +302,7 @@ def balance_sheet(l_args, s_ticker):
)
try:
(ns_parser, l_unknown_args) = parser.parse_known_args(l_args)
(ns_parser, l_unknown_args) = parser.parse_known_args(other_args)
if l_unknown_args:
print(f"The following args couldn't be interpreted: {l_unknown_args}\n")
@@ -365,10 +316,10 @@ def balance_sheet(l_args, s_ticker):
fd = FundamentalData(key=cfg.API_KEY_ALPHAVANTAGE, output_format="pandas")
if ns_parser.b_quarter:
# pylint: disable=unbalanced-tuple-unpacking
df_fa, _ = fd.get_balance_sheet_quarterly(symbol=s_ticker)
df_fa, _ = fd.get_balance_sheet_quarterly(symbol=ticker)
else:
# pylint: disable=unbalanced-tuple-unpacking
df_fa, _ = fd.get_balance_sheet_annual(symbol=s_ticker)
df_fa, _ = fd.get_balance_sheet_annual(symbol=ticker)
df_fa = clean_fundamentals_df(df_fa, num=ns_parser.n_num)
print(df_fa)
@@ -380,7 +331,17 @@ def balance_sheet(l_args, s_ticker):
return
def cash_flow(l_args, s_ticker):
def cash_flow(other_args: List[str], ticker: str):
"""Alpha Vantage cash flow
Parameters
----------
other_args : List[str]
argparse other args
ticker : str
Fundamental analysis ticker symbol
"""
parser = argparse.ArgumentParser(
add_help=False,
prog="cash",
@@ -419,7 +380,7 @@ def cash_flow(l_args, s_ticker):
)
try:
ns_parser = parse_known_args_and_warn(parser, l_args)
ns_parser = parse_known_args_and_warn(parser, other_args)
if not ns_parser:
return
@@ -431,10 +392,10 @@ def cash_flow(l_args, s_ticker):
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)
df_fa, _ = fd.get_cash_flow_quarterly(symbol=ticker)
else:
# pylint: disable=unbalanced-tuple-unpacking
df_fa, _ = fd.get_cash_flow_annual(symbol=s_ticker)
df_fa, _ = fd.get_cash_flow_annual(symbol=ticker)
df_fa = clean_fundamentals_df(df_fa, num=ns_parser.n_num)
print(df_fa)
@@ -446,7 +407,17 @@ def cash_flow(l_args, s_ticker):
return
def earnings(l_args, s_ticker):
def earnings(other_args: List[str], ticker: str):
"""Alpha Vantage earnings
Parameters
----------
other_args : List[str]
argparse other args
ticker : str
Fundamental analysis ticker symbol
"""
parser = argparse.ArgumentParser(
add_help=False,
prog="earnings",
@@ -475,7 +446,7 @@ def earnings(l_args, s_ticker):
)
try:
ns_parser = parse_known_args_and_warn(parser, l_args)
ns_parser = parse_known_args_and_warn(parser, other_args)
if not ns_parser:
return
@@ -487,13 +458,13 @@ def earnings(l_args, s_ticker):
# Request EARNINGS data from Alpha Vantage API
s_req = (
"https://www.alphavantage.co/query?function=EARNINGS&"
f"symbol={s_ticker}&apikey={cfg.API_KEY_ALPHAVANTAGE}"
f"symbol={ticker}&apikey={cfg.API_KEY_ALPHAVANTAGE}"
)
result = requests.get(s_req, stream=True)
# If the returned data was successful
if result.status_code == 200:
df_fa = json_normalize(result.json())
df_fa = pd.json_normalize(result.json())
if ns_parser.b_quarter:
df_fa = pd.DataFrame(df_fa["quarterlyEarnings"][0])
df_fa = df_fa[

View File

@@ -1,4 +1,8 @@
""" Business Insider View """
__docformat__ = "numpy"
import argparse
from typing import List
import requests
from bs4 import BeautifulSoup
import pandas as pd
@@ -6,7 +10,17 @@ from rapidfuzz import fuzz
from gamestonk_terminal.helper_funcs import get_user_agent, parse_known_args_and_warn
def management(l_args, s_ticker):
def management(other_args: List[str], ticker: str):
"""Display company's managers
Parameters
----------
other_args : List[str]
argparse other args
ticker : str
Stock ticker
"""
parser = argparse.ArgumentParser(
add_help=False,
prog="mgmt",
@@ -17,12 +31,12 @@ def management(l_args, s_ticker):
)
try:
ns_parser = parse_known_args_and_warn(parser, l_args)
ns_parser = parse_known_args_and_warn(parser, other_args)
if not ns_parser:
return
url_market_business_insider = (
f"https://markets.businessinsider.com/stocks/{s_ticker.lower()}-stock"
f"https://markets.businessinsider.com/stocks/{ticker.lower()}-stock"
)
text_soup_market_business_insider = BeautifulSoup(
requests.get(
@@ -42,7 +56,7 @@ def management(l_args, s_ticker):
found_h2s[next_h2.text] = next_table
if found_h2s.get("Management") is None:
print(f"No management information in Business Insider for {s_ticker}")
print(f"No management information in Business Insider for {ticker}")
print("")
return
@@ -73,7 +87,7 @@ def management(l_args, s_ticker):
for s_name in df_management.index:
df_management.loc[s_name][
"Info"
] = f"http://www.google.com/search?q={s_name} {s_ticker.upper()}".replace(
] = f"http://www.google.com/search?q={s_name} {ticker.upper()}".replace(
" ", "%20"
)

View File

@@ -0,0 +1,253 @@
""" Fundamental Analysis Controller """
__docformat__ = "numpy"
import argparse
from typing import List
from prompt_toolkit.completion import NestedCompleter
from gamestonk_terminal.fundamental_analysis import alpha_vantage_controller as avc
from gamestonk_terminal.fundamental_analysis import business_insider_view as biw
from gamestonk_terminal.fundamental_analysis import (
financial_modeling_prep_controller as fmpc,
)
from gamestonk_terminal.fundamental_analysis import finviz_view
from gamestonk_terminal.fundamental_analysis import market_watch_view
from gamestonk_terminal.fundamental_analysis import yahoo_finance_view
from gamestonk_terminal import feature_flags as gtff
from gamestonk_terminal.helper_funcs import get_flair
from gamestonk_terminal.menu import session
class FundamentalAnalysisController:
""" Fundamental Analysis Controller """
# Command choices
CHOICES = [
"help",
"q",
"quit",
"screener",
"income",
"balance",
"cash",
"mgmt",
"info",
"shrs",
"sust",
"cal",
"av",
"fmp",
]
def __init__(self, ticker: str, start: str, interval: str):
"""Constructor
Parameters
----------
ticker : str
Fundamental analysis ticker symbol
start : str
Stat date of the stock data
interval : str
Stock data interval
"""
self.ticker = ticker
self.start = start
self.interval = interval
self.fa_parser = argparse.ArgumentParser(add_help=False, prog="fa")
self.fa_parser.add_argument(
"cmd",
choices=self.CHOICES,
)
def print_help(self):
""" Print help """
intraday = (f"Intraday {self.interval}", "Daily")[self.interval == "1440min"]
if self.start:
print(
f"\n{intraday} Stock: {self.ticker} (from {self.start.strftime('%Y-%m-%d')})"
)
else:
print(f"\n{intraday} Stock: {self.ticker}")
print(
"\nFundamental Analysis:"
) # https://github.com/JerBouma/FundamentalAnalysis
print(" help show this fundamental analysis menu again")
print(" q quit this menu, and shows back to main menu")
print(" quit quit to abandon program")
print("")
print(" screener screen info about the company [Finviz]")
print(" mgmt management team of the company [Business Insider]")
print("")
print("Market Watch API")
print(" income income statement of the company")
print(" balance balance sheet of the company")
print(" cash cash flow statement of the company")
print("")
print("Yahoo Finance API")
print(" info information scope of the company")
print(" shrs shareholders of the company")
print(" sust sustainability values of the company")
print(" cal calendar earnings and estimates of the company")
print("")
print("Other Sources:")
print("> av Alpha Vantage MENU")
print("> fmp Financial Modeling Prep MENU")
print("")
def switch(self, an_input: str):
"""Process and dispatch input
Returns
-------
True, False or None
False - quit the menu
True - quit the program
None - continue in the menu
"""
(known_args, other_args) = self.fa_parser.parse_known_args(an_input.split())
return getattr(
self, "call_" + known_args.cmd, lambda: "Command not recognized!"
)(other_args)
def call_help(self, _):
"""Process Help command"""
self.print_help()
def call_q(self, _):
"""Process Q command - quit the menu"""
return False
def call_quit(self, _):
"""Process Quit command - quit the program"""
return True
def call_mgmt(self, other_args: List[str]):
""" Process mgmt command """
biw.management(other_args, self.ticker)
def call_screener(self, other_args: List[str]):
""" Process screener command """
finviz_view.screener(other_args, self.ticker)
def call_income(self, other_args: List[str]):
""" Process income command """
market_watch_view.income(other_args, self.ticker)
def call_balance(self, other_args: List[str]):
""" Process balance command """
market_watch_view.balance(other_args, self.ticker)
def call_cash(self, other_args: List[str]):
""" Process cash command """
market_watch_view.cash(other_args, self.ticker)
def call_info(self, other_args: List[str]):
""" Process info command """
yahoo_finance_view.info(other_args, self.ticker)
def call_shrs(self, other_args: List[str]):
""" Process shrs command """
yahoo_finance_view.shareholders(other_args, self.ticker)
def call_sust(self, other_args: List[str]):
""" Process sust command """
yahoo_finance_view.sustainability(other_args, self.ticker)
def call_cal(self, other_args: List[str]):
""" Process cal command """
yahoo_finance_view.calendar_earnings(other_args, self.ticker)
# pylint: disable=unused-argument
def call_av(self, other_args: List[str]):
""" Process av command """
ret = avc.menu(self.ticker, self.start, self.interval)
if ret is not True:
self.print_help()
# pylint: disable=unused-argument
def call_fmp(self, other_args: List[str]):
""" Process fmp command """
ret = fmpc.menu(self.ticker, self.start, self.interval)
if ret is not True:
self.print_help()
def key_metrics_explained(other_args: List[str]):
parser = argparse.ArgumentParser(
add_help=False,
prog="info",
description="""
Provides information about main key metrics. Namely: EBITDA,
EPS, P/E, PEG, FCF, P/B, ROE, DPR, P/S, Dividend Yield Ratio, D/E, and Beta.
""",
)
try:
(_, l_unknown_args) = parser.parse_known_args(other_args)
if l_unknown_args:
print(f"The following args couldn't be interpreted: {l_unknown_args}")
filepath = "fundamental_analysis/key_metrics_explained.txt"
with open(filepath) as fp:
line = fp.readline()
while line:
print(f"{line.strip()}")
line = fp.readline()
print("")
except Exception as e:
print(e)
print("ERROR!\n")
return
def menu(ticker: str, start: str, interval: str):
"""Fundamental Analysis menu
Parameters
----------
ticker : str
Fundamental analysis ticker symbol
start : str
Start date of the stock data
interval : str
Stock data interval
"""
fa_controller = FundamentalAnalysisController(ticker, start, interval)
fa_controller.call_help(None)
while True:
# Get input command from user
if session and gtff.USE_PROMPT_TOOLKIT:
completer = NestedCompleter.from_nested_dict(
{c: None for c in fa_controller.CHOICES}
)
an_input = session.prompt(
f"{get_flair()} (fa)> ",
completer=completer,
)
else:
an_input = input(f"{get_flair()} (fa)> ")
try:
process_input = fa_controller.switch(an_input)
if process_input is not None:
return process_input
except SystemExit:
print("The command selected doesn't exist\n")
continue

View File

@@ -1,193 +0,0 @@
import argparse
from gamestonk_terminal.fundamental_analysis import alpha_vantage_api as av_api
from gamestonk_terminal.fundamental_analysis import business_insider_api as bi_api
from gamestonk_terminal.fundamental_analysis import (
financial_modeling_prep_api as fmp_api,
)
from gamestonk_terminal.fundamental_analysis import finviz_api as fvz_api
from gamestonk_terminal.fundamental_analysis import market_watch_api as mw_api
from gamestonk_terminal.fundamental_analysis import yahoo_finance_api as yf_api
from gamestonk_terminal import feature_flags as gtff
from gamestonk_terminal.helper_funcs import get_flair
from gamestonk_terminal.menu import session
from prompt_toolkit.completion import NestedCompleter
def print_fundamental_analysis(s_ticker, s_start, s_interval):
""" Print help """
s_intraday = (f"Intraday {s_interval}", "Daily")[s_interval == "1440min"]
if s_start:
print(f"\n{s_intraday} Stock: {s_ticker} (from {s_start.strftime('%Y-%m-%d')})")
else:
print(f"\n{s_intraday} Stock: {s_ticker}")
print("\nFundamental Analysis:") # https://github.com/JerBouma/FundamentalAnalysis
print(" help show this fundamental analysis menu again")
print(" q quit this menu, and shows back to main menu")
print(" quit quit to abandon program")
print("")
print(" screener screen info about the company [Finviz]")
print(" mgmt management team of the company [Business Insider]")
print("")
print("Market Watch API")
print(" income income statement of the company")
print(" balance balance sheet of the company")
print(" cash cash flow statement of the company")
print("")
print("Yahoo Finance API")
print(" info information scope of the company")
print(" shrs shareholders of the company")
print(" sust sustainability values of the company")
print(" cal calendar earnings and estimates of the company")
print("")
print("Other Sources:")
print("> av Alpha Vantage MENU")
print("> fmp Financial Modeling Prep MENU")
print("")
return
def key_metrics_explained(l_args):
parser = argparse.ArgumentParser(
add_help=False,
prog="info",
description="""
Provides information about main key metrics. Namely: EBITDA,
EPS, P/E, PEG, FCF, P/B, ROE, DPR, P/S, Dividend Yield Ratio, D/E, and Beta.
""",
)
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}")
filepath = "fundamental_analysis/key_metrics_explained.txt"
with open(filepath) as fp:
line = fp.readline()
while line:
print(f"{line.strip()}")
line = fp.readline()
print("")
except Exception as e:
print(e)
print("ERROR!\n")
return
# pylint: disable=too-many-branches
def fa_menu(s_ticker, s_start, s_interval):
# Add list of arguments that the fundamental analysis parser accepts
fa_parser = argparse.ArgumentParser(prog="fa", add_help=False)
choices = [
"help",
"q",
"quit",
"screener",
"income",
"balance",
"cash",
"mgmt",
"info",
"shrs",
"sust",
"cal",
"av",
"fmp",
]
fa_parser.add_argument("cmd", choices=choices)
completer = NestedCompleter.from_nested_dict({c: None for c in choices})
should_print_help = True
# Loop forever and ever
while True:
if should_print_help:
print_fundamental_analysis(s_ticker, s_start, s_interval)
should_print_help = False
# Get input command from user
if session and gtff.USE_PROMPT_TOOLKIT:
as_input = session.prompt(
f"{get_flair()} (fa)> ",
completer=completer,
)
else:
as_input = input(f"{get_flair()} (fa)> ")
# Parse fundamental analysis command of the list of possible commands
try:
(ns_known_args, l_args) = fa_parser.parse_known_args(as_input.split())
except SystemExit:
print("The command selected doesn't exist\n")
continue
if ns_known_args.cmd == "help":
should_print_help = True
elif ns_known_args.cmd == "q":
# Just leave the FA menu
return False
elif ns_known_args.cmd == "quit":
# Abandon the program
return True
# BUSINESS INSIDER API
elif ns_known_args.cmd == "mgmt":
bi_api.management(l_args, s_ticker)
# FINVIZ API
elif ns_known_args.cmd == "screener":
fvz_api.screener(l_args, s_ticker)
# MARKET WATCH API
elif ns_known_args.cmd == "income":
mw_api.income(l_args, s_ticker)
elif ns_known_args.cmd == "balance":
mw_api.balance(l_args, s_ticker)
elif ns_known_args.cmd == "cash":
mw_api.cash(l_args, s_ticker)
# YAHOO FINANCE API
elif ns_known_args.cmd == "info":
yf_api.info(l_args, s_ticker)
elif ns_known_args.cmd == "shrs":
yf_api.shareholders(l_args, s_ticker)
elif ns_known_args.cmd == "sust":
yf_api.sustainability(l_args, s_ticker)
elif ns_known_args.cmd == "cal":
yf_api.calendar_earnings(l_args, s_ticker)
# ALPHA VANTAGE API
elif ns_known_args.cmd == "av":
b_quit = av_api.menu(s_ticker, s_start, s_interval)
if b_quit:
return True
else:
should_print_help = True
# FINANCIAL MODELING PREP API
elif ns_known_args.cmd == "fmp":
b_quit = fmp_api.menu(s_ticker, s_start, s_interval)
if b_quit:
return True
else:
should_print_help = True
else:
print("Command not recognized!")

View File

@@ -0,0 +1,194 @@
""" Financial Modeling Prep Controller """
__docformat__ = "numpy"
import argparse
from typing import List
from prompt_toolkit.completion import NestedCompleter
from gamestonk_terminal.fundamental_analysis import financial_modeling_prep_view as fmpv
from gamestonk_terminal import feature_flags as gtff
from gamestonk_terminal.helper_funcs import (
get_flair,
)
from gamestonk_terminal.menu import session
class FinancialModelingPrepController:
""" Financial Modeling Prep Controller """
# Command choices
CHOICES = [
"help",
"q",
"quit",
"profile",
"quote",
"enterprise",
"dcf",
"income",
"balance",
"cash",
"metrics",
"ratios",
"growth",
]
def __init__(self, ticker: str, start: str, interval: str):
"""Constructor
Parameters
----------
ticker : str
Fundamental analysis ticker symbol
start : str
Stat date of the stock data
interval : str
Stock data interval
"""
self.ticker = ticker
self.start = start
self.interval = interval
self.fmp_parser = argparse.ArgumentParser(add_help=False, prog="fmp")
self.fmp_parser.add_argument(
"cmd",
choices=self.CHOICES,
)
def print_help(self):
""" Print help """
intraday = (f"Intraday {self.interval}", "Daily")[self.interval == "1440min"]
if self.start:
print(
f"\n{intraday} Stock: {self.ticker} (from {self.start.strftime('%Y-%m-%d')})"
)
else:
print(f"\n{intraday} Stock: {self.ticker}")
print("\nFinancial Modeling Prep API")
print(" help show this financial modeling prep menu again")
print(" q quit this menu, and shows back to main menu")
print(" quit quit to abandon program")
print("")
print(" profile profile of the company")
print(" quote quote of the company")
print(" enterprise enterprise value of the company over time")
print(" dcf discounted cash flow of the company over time")
print(" income income statements of the company")
print(" balance balance sheet of the company")
print(" cash cash flow statement of the company")
print(" metrics key metrics of the company")
print(" ratios financial ratios of the company")
print(" growth financial statement growth of the company")
print("")
def switch(self, an_input: str):
"""Process and dispatch input
Returns
-------
True, False or None
False - quit the menu
True - quit the program
None - continue in the menu
"""
(known_args, other_args) = self.fmp_parser.parse_known_args(an_input.split())
return getattr(
self, "call_" + known_args.cmd, lambda: "Command not recognized!"
)(other_args)
def call_help(self, _):
"""Process Help command"""
self.print_help()
def call_q(self, _):
"""Process Q command - quit the menu"""
return False
def call_quit(self, _):
"""Process Quit command - quit the program"""
return True
def call_profile(self, other_args: List[str]):
""" Process profile command """
fmpv.profile(other_args, self.ticker)
def call_quote(self, other_args: List[str]):
""" Process quote command """
fmpv.quote(other_args, self.ticker)
def call_enterprise(self, other_args: List[str]):
""" Process income command """
fmpv.enterprise(other_args, self.ticker)
def call_dcf(self, other_args: List[str]):
""" Process dcf command """
fmpv.discounted_cash_flow(other_args, self.ticker)
def call_income(self, other_args: List[str]):
""" Process income command """
fmpv.income_statement(other_args, self.ticker)
def call_balance(self, other_args: List[str]):
""" Process balance command """
fmpv.balance_sheet(other_args, self.ticker)
def call_cash(self, other_args: List[str]):
""" Process cash command """
fmpv.cash_flow(other_args, self.ticker)
def call_metrics(self, other_args: List[str]):
""" Process metrics command """
fmpv.key_metrics(other_args, self.ticker)
def call_ratios(self, other_args: List[str]):
""" Process cash command """
fmpv.financial_ratios(other_args, self.ticker)
def call_growth(self, other_args: List[str]):
""" Process cash command """
fmpv.financial_statement_growth(other_args, self.ticker)
def menu(ticker: str, start: str, interval: str):
"""Financial Modeling Prep menu
Parameters
----------
ticker : str
Fundamental analysis ticker symbol
start : str
Start date of the stock data
interval : str
Stock data interval
"""
fmp_controller = FinancialModelingPrepController(ticker, start, interval)
fmp_controller.call_help(None)
while True:
# Get input command from user
if session and gtff.USE_PROMPT_TOOLKIT:
completer = NestedCompleter.from_nested_dict(
{c: None for c in fmp_controller.CHOICES}
)
an_input = session.prompt(
f"{get_flair()} (fa)>(fmp)> ",
completer=completer,
)
else:
an_input = input(f"{get_flair()} (fa)>(fmp)> ")
try:
process_input = fmp_controller.switch(an_input)
if process_input is not None:
return process_input
except SystemExit:
print("The command selected doesn't exist\n")
continue

View File

@@ -1,139 +1,31 @@
""" Financial Modeling Prep View """
__docformat__ = "numpy"
import argparse
from typing import List
from datetime import datetime
import pandas as pd
import FundamentalAnalysis as fa # Financial Modeling Prep
from prompt_toolkit.completion import NestedCompleter
from gamestonk_terminal import config_terminal as cfg
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,
get_flair,
)
from gamestonk_terminal.menu import session
def print_menu(s_ticker, s_start, s_interval):
""" Print help """
def profile(other_args: List[str], ticker: str):
"""Financial Modeling Prep ticker profile
s_intraday = (f"Intraday {s_interval}", "Daily")[s_interval == "1440min"]
Parameters
----------
other_args : List[str]
argparse other args
ticker : str
Fundamental analysis ticker symbol
"""
if s_start:
print(f"\n{s_intraday} Stock: {s_ticker} (from {s_start.strftime('%Y-%m-%d')})")
else:
print(f"\n{s_intraday} Stock: {s_ticker}")
print("\nFinancial Modeling Prep API")
print(" help show this financial modeling prep menu again")
print(" q quit this menu, and shows back to main menu")
print(" quit quit to abandon program")
print("")
print(" profile profile of the company")
print(" quote quote of the company")
print(" enterprise enterprise value of the company over time")
print(" dcf discounted cash flow of the company over time")
print(" income income statements of the company")
print(" balance balance sheet of the company")
print(" cash cash flow statement of the company")
print(" metrics key metrics of the company")
print(" ratios financial ratios of the company")
print(" growth financial statement growth of the company")
print("")
def menu(s_ticker, s_start, s_interval):
# Add list of arguments that the fundamental analysis parser accepts
fmp_parser = argparse.ArgumentParser(prog="fmp", add_help=False)
choices = [
"help",
"q",
"quit",
"profile",
"quote",
"enterprise",
"dcf",
"fmp_income",
"fmp_balance",
"fmp_cash",
"metrics",
"ratios",
"growth",
]
fmp_parser.add_argument("cmd", choices=choices)
completer = NestedCompleter.from_nested_dict({c: None for c in choices})
print_menu(s_ticker, s_start, s_interval)
# Loop forever and ever
while True:
# Get input command from user
if session:
as_input = session.prompt(
f"{get_flair()} (fa)>(fmp)> ",
completer=completer,
)
else:
as_input = input(f"{get_flair()} (fa)>(av)> ")
# Parse alpha vantage command of the list of possible commands
try:
(ns_known_args, l_args) = fmp_parser.parse_known_args(as_input.split())
except SystemExit:
print("The command selected doesn't exist\n")
continue
if ns_known_args.cmd == "help":
print_menu(s_ticker, s_start, s_interval)
elif ns_known_args.cmd == "q":
# Just leave the menu
return False
elif ns_known_args.cmd == "quit":
# Abandon the program
return True
# Details:
elif ns_known_args.cmd == "profile":
profile(l_args, s_ticker)
elif ns_known_args.cmd == "quote":
quote(l_args, s_ticker)
elif ns_known_args.cmd == "enterprise":
enterprise(l_args, s_ticker)
elif ns_known_args.cmd == "dcf":
discounted_cash_flow(l_args, s_ticker)
# Financial statement:
elif ns_known_args.cmd == "income":
income_statement(l_args, s_ticker)
elif ns_known_args.cmd == "balance":
balance_sheet(l_args, s_ticker)
elif ns_known_args.cmd == "cash":
cash_flow(l_args, s_ticker)
# Ratios:
elif ns_known_args.cmd == "metrics":
key_metrics(l_args, s_ticker)
elif ns_known_args.cmd == "ratios":
financial_ratios(l_args, s_ticker)
elif ns_known_args.cmd == "growth":
financial_statement_growth(l_args, s_ticker)
else:
print("Command not recognized!")
def profile(l_args, s_ticker):
parser = argparse.ArgumentParser(
add_help=False,
prog="profile",
@@ -148,11 +40,11 @@ def profile(l_args, s_ticker):
)
try:
ns_parser = parse_known_args_and_warn(parser, l_args)
ns_parser = parse_known_args_and_warn(parser, other_args)
if not ns_parser:
return
df_fa = fa.profile(s_ticker, cfg.API_KEY_FINANCIALMODELINGPREP)
df_fa = fa.profile(ticker, cfg.API_KEY_FINANCIALMODELINGPREP)
clean_df_index(df_fa)
print(df_fa.drop(index=["Description", "Image"]).to_string(header=False))
@@ -166,7 +58,17 @@ def profile(l_args, s_ticker):
return
def quote(l_args, s_ticker):
def quote(other_args: List[str], ticker: str):
"""Financial Modeling Prep ticker quote
Parameters
----------
other_args : List[str]
argparse other args
ticker : str
Fundamental analysis ticker symbol
"""
parser = argparse.ArgumentParser(
add_help=False,
prog="quote",
@@ -181,11 +83,11 @@ def quote(l_args, s_ticker):
)
try:
ns_parser = parse_known_args_and_warn(parser, l_args)
ns_parser = parse_known_args_and_warn(parser, other_args)
if not ns_parser:
return
df_fa = fa.quote(s_ticker, cfg.API_KEY_FINANCIALMODELINGPREP)
df_fa = fa.quote(ticker, cfg.API_KEY_FINANCIALMODELINGPREP)
clean_df_index(df_fa)
@@ -211,7 +113,17 @@ def quote(l_args, s_ticker):
return
def enterprise(l_args, s_ticker):
def enterprise(other_args: List[str], ticker: str):
"""Financial Modeling Prep ticker enterprise
Parameters
----------
other_args : List[str]
argparse other args
ticker : str
Fundamental analysis ticker symbol
"""
parser = argparse.ArgumentParser(
add_help=False,
prog="enterprise",
@@ -242,7 +154,7 @@ def enterprise(l_args, s_ticker):
)
try:
ns_parser = parse_known_args_and_warn(parser, l_args)
ns_parser = parse_known_args_and_warn(parser, other_args)
if not ns_parser:
return
@@ -253,10 +165,10 @@ def enterprise(l_args, s_ticker):
if ns_parser.b_quarter:
df_fa = fa.enterprise(
s_ticker, cfg.API_KEY_FINANCIALMODELINGPREP, period="quarter"
ticker, cfg.API_KEY_FINANCIALMODELINGPREP, period="quarter"
)
else:
df_fa = fa.enterprise(s_ticker, cfg.API_KEY_FINANCIALMODELINGPREP)
df_fa = fa.enterprise(ticker, cfg.API_KEY_FINANCIALMODELINGPREP)
df_fa = clean_metrics_df(df_fa, num=ns_parser.n_num, mask=False)
@@ -269,7 +181,17 @@ def enterprise(l_args, s_ticker):
return
def discounted_cash_flow(l_args, s_ticker):
def discounted_cash_flow(other_args: List[str], ticker: str):
"""Financial Modeling Prep ticker discounted cash flow
Parameters
----------
other_args : List[str]
argparse other args
ticker : str
Fundamental analysis ticker symbol
"""
parser = argparse.ArgumentParser(
add_help=False,
prog="dcf",
@@ -298,7 +220,7 @@ def discounted_cash_flow(l_args, s_ticker):
)
try:
ns_parser = parse_known_args_and_warn(parser, l_args)
ns_parser = parse_known_args_and_warn(parser, other_args)
if not ns_parser:
return
@@ -309,10 +231,10 @@ def discounted_cash_flow(l_args, s_ticker):
if ns_parser.b_quarter:
df_fa = fa.discounted_cash_flow(
s_ticker, cfg.API_KEY_FINANCIALMODELINGPREP, period="quarter"
ticker, cfg.API_KEY_FINANCIALMODELINGPREP, period="quarter"
)
else:
df_fa = fa.discounted_cash_flow(s_ticker, cfg.API_KEY_FINANCIALMODELINGPREP)
df_fa = fa.discounted_cash_flow(ticker, cfg.API_KEY_FINANCIALMODELINGPREP)
df_fa = clean_metrics_df(df_fa, num=ns_parser.n_num, mask=False)
@@ -325,7 +247,17 @@ def discounted_cash_flow(l_args, s_ticker):
return
def income_statement(l_args, s_ticker):
def income_statement(other_args: List[str], ticker: str):
"""Financial Modeling Prep ticker income statement
Parameters
----------
other_args : List[str]
argparse other args
ticker : str
Fundamental analysis ticker symbol
"""
parser = argparse.ArgumentParser(
add_help=False,
prog="inc",
@@ -361,7 +293,7 @@ def income_statement(l_args, s_ticker):
)
try:
ns_parser = parse_known_args_and_warn(parser, l_args)
ns_parser = parse_known_args_and_warn(parser, other_args)
if not ns_parser:
return
@@ -372,10 +304,10 @@ def income_statement(l_args, s_ticker):
if ns_parser.b_quarter:
df_fa = fa.income_statement(
s_ticker, cfg.API_KEY_FINANCIALMODELINGPREP, period="quarter"
ticker, cfg.API_KEY_FINANCIALMODELINGPREP, period="quarter"
)
else:
df_fa = fa.income_statement(s_ticker, cfg.API_KEY_FINANCIALMODELINGPREP)
df_fa = fa.income_statement(ticker, cfg.API_KEY_FINANCIALMODELINGPREP)
df_fa = clean_metrics_df(df_fa, num=ns_parser.n_num)
@@ -394,7 +326,17 @@ def income_statement(l_args, s_ticker):
return
def balance_sheet(l_args, s_ticker):
def balance_sheet(other_args: List[str], ticker: str):
"""Financial Modeling Prep ticker balance sheet
Parameters
----------
other_args : List[str]
argparse other args
ticker : str
Fundamental analysis ticker symbol
"""
parser = argparse.ArgumentParser(
add_help=False,
prog="bal",
@@ -435,7 +377,7 @@ def balance_sheet(l_args, s_ticker):
)
try:
ns_parser = parse_known_args_and_warn(parser, l_args)
ns_parser = parse_known_args_and_warn(parser, other_args)
if not ns_parser:
return
@@ -446,11 +388,11 @@ def balance_sheet(l_args, s_ticker):
if ns_parser.b_quarter:
df_fa = fa.balance_sheet_statement(
s_ticker, cfg.API_KEY_FINANCIALMODELINGPREP, period="quarter"
ticker, cfg.API_KEY_FINANCIALMODELINGPREP, period="quarter"
)
else:
df_fa = fa.balance_sheet_statement(
s_ticker, cfg.API_KEY_FINANCIALMODELINGPREP
ticker, cfg.API_KEY_FINANCIALMODELINGPREP
)
df_fa = clean_metrics_df(df_fa, num=ns_parser.n_num)
@@ -470,7 +412,17 @@ def balance_sheet(l_args, s_ticker):
return
def cash_flow(l_args, s_ticker):
def cash_flow(other_args: List[str], ticker: str):
"""Financial Modeling Prep ticker cash flow
Parameters
----------
other_args : List[str]
argparse other args
ticker : str
Fundamental analysis ticker symbol
"""
parser = argparse.ArgumentParser(
add_help=False,
prog="cash",
@@ -509,7 +461,7 @@ def cash_flow(l_args, s_ticker):
)
try:
ns_parser = parse_known_args_and_warn(parser, l_args)
ns_parser = parse_known_args_and_warn(parser, other_args)
if not ns_parser:
return
@@ -520,10 +472,10 @@ def cash_flow(l_args, s_ticker):
if ns_parser.b_quarter:
df_fa = fa.cash_flow_statement(
s_ticker, cfg.API_KEY_FINANCIALMODELINGPREP, period="quarter"
ticker, cfg.API_KEY_FINANCIALMODELINGPREP, period="quarter"
)
else:
df_fa = fa.cash_flow_statement(s_ticker, cfg.API_KEY_FINANCIALMODELINGPREP)
df_fa = fa.cash_flow_statement(ticker, cfg.API_KEY_FINANCIALMODELINGPREP)
df_fa = clean_metrics_df(df_fa, num=ns_parser.n_num)
@@ -542,7 +494,17 @@ def cash_flow(l_args, s_ticker):
return
def key_metrics(l_args, s_ticker):
def key_metrics(other_args: List[str], ticker: str):
"""Financial Modeling Prep ticker key metrics
Parameters
----------
other_args : List[str]
argparse other args
ticker : str
Fundamental analysis ticker symbol
"""
parser = argparse.ArgumentParser(
add_help=False,
prog="metrics",
@@ -560,7 +522,7 @@ def key_metrics(l_args, s_ticker):
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,
Research and development 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]
@@ -586,7 +548,7 @@ def key_metrics(l_args, s_ticker):
)
try:
ns_parser = parse_known_args_and_warn(parser, l_args)
ns_parser = parse_known_args_and_warn(parser, other_args)
if not ns_parser:
return
@@ -597,10 +559,10 @@ def key_metrics(l_args, s_ticker):
if ns_parser.b_quarter:
df_fa = fa.key_metrics(
s_ticker, cfg.API_KEY_FINANCIALMODELINGPREP, period="quarter"
ticker, cfg.API_KEY_FINANCIALMODELINGPREP, period="quarter"
)
else:
df_fa = fa.key_metrics(s_ticker, cfg.API_KEY_FINANCIALMODELINGPREP)
df_fa = fa.key_metrics(ticker, cfg.API_KEY_FINANCIALMODELINGPREP)
df_fa = clean_metrics_df(df_fa, num=ns_parser.n_num)
@@ -613,7 +575,17 @@ def key_metrics(l_args, s_ticker):
return
def financial_ratios(l_args, s_ticker):
def financial_ratios(other_args: List[str], ticker: str):
"""Financial Modeling Prep ticker ratios
Parameters
----------
other_args : List[str]
argparse other args
ticker : str
Fundamental analysis ticker symbol
"""
parser = argparse.ArgumentParser(
add_help=False,
prog="ratios",
@@ -658,7 +630,7 @@ def financial_ratios(l_args, s_ticker):
)
try:
ns_parser = parse_known_args_and_warn(parser, l_args)
ns_parser = parse_known_args_and_warn(parser, other_args)
if not ns_parser:
return
@@ -669,10 +641,10 @@ def financial_ratios(l_args, s_ticker):
if ns_parser.b_quarter:
df_fa = fa.financial_ratios(
s_ticker, cfg.API_KEY_FINANCIALMODELINGPREP, period="quarter"
ticker, cfg.API_KEY_FINANCIALMODELINGPREP, period="quarter"
)
else:
df_fa = fa.financial_ratios(s_ticker, cfg.API_KEY_FINANCIALMODELINGPREP)
df_fa = fa.financial_ratios(ticker, cfg.API_KEY_FINANCIALMODELINGPREP)
df_fa = clean_metrics_df(df_fa, num=ns_parser.n_num)
@@ -685,7 +657,17 @@ def financial_ratios(l_args, s_ticker):
return
def financial_statement_growth(l_args, s_ticker):
def financial_statement_growth(other_args: List[str], ticker: str):
"""Financial Modeling Prep ticker growth
Parameters
----------
other_args : List[str]
argparse other args
ticker : str
Fundamental analysis ticker symbol
"""
parser = argparse.ArgumentParser(
add_help=False,
prog="growth",
@@ -726,7 +708,7 @@ def financial_statement_growth(l_args, s_ticker):
)
try:
ns_parser = parse_known_args_and_warn(parser, l_args)
ns_parser = parse_known_args_and_warn(parser, other_args)
if not ns_parser:
return
@@ -737,11 +719,11 @@ def financial_statement_growth(l_args, s_ticker):
if ns_parser.b_quarter:
df_fa = fa.financial_statement_growth(
s_ticker, cfg.API_KEY_FINANCIALMODELINGPREP, period="quarter"
ticker, cfg.API_KEY_FINANCIALMODELINGPREP, period="quarter"
)
else:
df_fa = fa.financial_statement_growth(
s_ticker, cfg.API_KEY_FINANCIALMODELINGPREP
ticker, cfg.API_KEY_FINANCIALMODELINGPREP
)
df_fa = clean_metrics_df(df_fa, num=ns_parser.n_num)
@@ -756,6 +738,23 @@ def financial_statement_growth(l_args, s_ticker):
def clean_metrics_df(df_fa: pd.DataFrame, num: int, mask: bool = True) -> pd.DataFrame:
"""Clean metrics data frame
Parameters
----------
df_fa : pd.DataFrame
Metrics data frame
num : int
Number of columns to clean
mask : bool, optional
Apply mask, by default True
Returns
-------
pd.DataFrame
Cleaned metrics data frame
"""
df_fa = df_fa.iloc[:, 0:num]
if mask:
df_fa = df_fa.mask(df_fa.astype(object).eq(num * ["None"])).dropna()

View File

@@ -1,10 +1,25 @@
""" FinViz View """
__docformat__ = "numpy"
import argparse
from typing import List
import finviz
import pandas as pd
from gamestonk_terminal.helper_funcs import parse_known_args_and_warn
def screener(l_args, s_ticker):
def screener(other_args: List[str], ticker: str):
"""FinViz ticker screener
Parameters
----------
other_args : List[str]
argparse other args
ticker : str
Fundamental analysis ticker symbol
"""
parser = argparse.ArgumentParser(
add_help=False,
prog="screener",
@@ -24,11 +39,11 @@ def screener(l_args, s_ticker):
)
try:
ns_parser = parse_known_args_and_warn(parser, l_args)
ns_parser = parse_known_args_and_warn(parser, other_args)
if not ns_parser:
return
d_finviz_stock = finviz.get_stock(s_ticker)
d_finviz_stock = finviz.get_stock(ticker)
df_fa = pd.DataFrame.from_dict(
d_finviz_stock, orient="index", columns=["Values"]
)

View File

@@ -0,0 +1,111 @@
""" Fundamental Analysis Market Watch Model """
__docformat__ = "numpy"
import requests
import pandas as pd
from bs4 import BeautifulSoup
from gamestonk_terminal.helper_funcs import (
get_user_agent,
)
def prepare_df_financials(
ticker: str, statement: str, quarter: bool = False
) -> pd.DataFrame:
"""Builds a DataFrame with financial statements for a given company
Parameters
----------
ticker : str
Company's stock ticker
statement : str
Either income, balance or cashflow
quarter : bool, optional
Return quarterly financial statements instead of annual, by default False
Returns
-------
pd.DataFrame
A DataFrame with financial info
Raises
------
ValueError
If statement is not income, balance or cashflow
"""
financial_urls = {
"income": {
"quarter": "https://www.marketwatch.com/investing/stock/{}/financials/income/quarter",
"annual": "https://www.marketwatch.com/investing/stock/{}/financials/income",
},
"balance": {
"quarter": "https://www.marketwatch.com/investing/stock/{}/financials/balance-sheet/quarter",
"annual": "https://www.marketwatch.com/investing/stock/{}/financials/balance-sheet",
},
"cashflow": {
"quarter": "https://www.marketwatch.com/investing/stock/{}/financials/cash-flow/quarter",
"annual": "https://www.marketwatch.com/investing/stock/{}/financials/cash-flow",
},
}
if statement not in financial_urls.keys():
raise ValueError(f"type {statement} is not in {financial_urls.keys()}")
if quarter:
period = "quarter"
else:
period = "annual"
text_soup_financials = BeautifulSoup(
requests.get(
financial_urls[statement][period].format(ticker),
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)]
)
find_table = text_soup_financials.findAll(
"div", {"class": "element element--table table--fixed financials"}
)
if not find_table:
return df_financials
financials_rows = find_table[0].findAll(
"tr", {"class": ["table__row is-highlighted", "table__row"]}
)
for a_row in financials_rows:
constructed_row = list()
financial_columns = a_row.findAll(
"td", {"class": ["overflow__cell", "overflow__cell fixed--column"]}
)
if not financial_columns:
continue
for a_column in financial_columns:
column_to_text = a_column.text.strip()
if "\n" in column_to_text:
column_to_text = column_to_text.split("\n")[0]
if column_to_text == "":
continue
constructed_row.append(column_to_text)
df_financials.loc[len(df_financials)] = constructed_row
return df_financials

View File

@@ -1,12 +1,12 @@
""" Fundamental Analysis Market Watch API """
""" Fundamental Analysis Market Watch View """
__docformat__ = "numpy"
import argparse
import requests
from typing import List
import pandas as pd
from bs4 import BeautifulSoup
from gamestonk_terminal.fundamental_analysis import market_watch_model as mwm
from gamestonk_terminal.helper_funcs import (
get_user_agent,
parse_known_args_and_warn,
patch_pandas_text_adjustment,
financials_colored_values,
@@ -14,7 +14,17 @@ from gamestonk_terminal.helper_funcs import (
from gamestonk_terminal import feature_flags as gtff
def income(l_args, s_ticker):
def income(other_args: List[str], ticker: str):
"""Market Watch ticker income statement
Parameters
----------
other_args : List[str]
argparse other args
ticker : str
Fundamental analysis ticker symbol
"""
parser = argparse.ArgumentParser(
add_help=False,
prog="income",
@@ -50,11 +60,11 @@ def income(l_args, s_ticker):
)
try:
ns_parser = parse_known_args_and_warn(parser, l_args)
ns_parser = parse_known_args_and_warn(parser, other_args)
if not ns_parser:
return
df_financials = prepare_df_financials(s_ticker, "income", ns_parser.b_quarter)
df_financials = mwm.prepare_df_financials(ticker, "income", ns_parser.b_quarter)
if gtff.USE_COLOR:
df_financials = df_financials.applymap(financials_colored_values)
@@ -72,7 +82,17 @@ def income(l_args, s_ticker):
return
def balance(l_args, s_ticker):
def balance(other_args: List[str], ticker: str):
"""Market Watch ticker balance statement
Parameters
----------
other_args : List[str]
argparse other args
ticker : str
Fundamental analysis ticker symbol
"""
parser = argparse.ArgumentParser(
add_help=False,
prog="balance",
@@ -120,11 +140,13 @@ def balance(l_args, s_ticker):
)
try:
ns_parser = parse_known_args_and_warn(parser, l_args)
ns_parser = parse_known_args_and_warn(parser, other_args)
if not ns_parser:
return
df_financials = prepare_df_financials(s_ticker, "balance", ns_parser.b_quarter)
df_financials = mwm.prepare_df_financials(
ticker, "balance", ns_parser.b_quarter
)
if gtff.USE_COLOR:
df_financials = df_financials.applymap(financials_colored_values)
@@ -142,7 +164,17 @@ def balance(l_args, s_ticker):
return
def cash(l_args, s_ticker):
def cash(other_args: List[str], ticker: str):
"""Market Watch ticker cash flow statement
Parameters
----------
other_args : List[str]
argparse other args
ticker : str
Fundamental analysis ticker symbol
"""
parser = argparse.ArgumentParser(
add_help=False,
prog="cash_flow",
@@ -186,11 +218,13 @@ def cash(l_args, s_ticker):
)
try:
ns_parser = parse_known_args_and_warn(parser, l_args)
ns_parser = parse_known_args_and_warn(parser, other_args)
if not ns_parser:
return
df_financials = prepare_df_financials(s_ticker, "cashflow", ns_parser.b_quarter)
df_financials = mwm.prepare_df_financials(
ticker, "cashflow", ns_parser.b_quarter
)
if gtff.USE_COLOR:
df_financials = df_financials.applymap(financials_colored_values)
@@ -206,104 +240,3 @@ def cash(l_args, s_ticker):
print(e)
print("")
return
def prepare_df_financials(
ticker: str, statement: str, quarter: bool = False
) -> pd.DataFrame:
"""Builds a DataFrame with financial statements for a given company
Parameters
----------
ticker : str
Company's stock ticker
statement : str
Either income, balance or cashflow
quarter : bool, optional
Return quarterly financial statements instead of annual, by default False
Returns
-------
pd.DataFrame
A DataFrame with financial info
Raises
------
ValueError
If statement is not income, balance or cashflow
"""
financial_urls = {
"income": {
"quarter": "https://www.marketwatch.com/investing/stock/{}/financials/income/quarter",
"annual": "https://www.marketwatch.com/investing/stock/{}/financials/income",
},
"balance": {
"quarter": "https://www.marketwatch.com/investing/stock/{}/financials/balance-sheet/quarter",
"annual": "https://www.marketwatch.com/investing/stock/{}/financials/balance-sheet",
},
"cashflow": {
"quarter": "https://www.marketwatch.com/investing/stock/{}/financials/cash-flow/quarter",
"annual": "https://www.marketwatch.com/investing/stock/{}/financials/cash-flow",
},
}
if statement not in financial_urls.keys():
raise ValueError(f"type {statement} is not in {financial_urls.keys()}")
if quarter:
period = "quarter"
else:
period = "annual"
text_soup_financials = BeautifulSoup(
requests.get(
financial_urls[statement][period].format(ticker),
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)]
)
find_table = text_soup_financials.findAll(
"div", {"class": "element element--table table--fixed financials"}
)
if not find_table:
return df_financials
financials_rows = find_table[0].findAll(
"tr", {"class": ["table__row is-highlighted", "table__row"]}
)
for a_row in financials_rows:
constructed_row = list()
financial_columns = a_row.findAll(
"td", {"class": ["overflow__cell", "overflow__cell fixed--column"]}
)
if not financial_columns:
continue
for a_column in financial_columns:
column_to_text = a_column.text.strip()
if "\n" in column_to_text:
column_to_text = column_to_text.split("\n")[0]
if column_to_text == "":
continue
constructed_row.append(column_to_text)
df_financials.loc[len(df_financials)] = constructed_row
return df_financials

View File

@@ -1,7 +1,12 @@
""" Yahoo Finance View """
__docformat__ = "numpy"
import argparse
from typing import List
from datetime import datetime
import yfinance as yf
import pandas as pd
from gamestonk_terminal.dataframe_helpers import clean_df_index
from gamestonk_terminal.helper_funcs import (
long_number_format,
@@ -9,7 +14,17 @@ from gamestonk_terminal.helper_funcs import (
)
def info(l_args, s_ticker):
def info(other_args: List[str], ticker: str):
"""Yahoo Finance ticker info
Parameters
----------
other_args : List[str]
argparse other args
ticker : str
Fundamental analysis ticker symbol
"""
parser = argparse.ArgumentParser(
add_help=False,
prog="info",
@@ -36,11 +51,11 @@ def info(l_args, s_ticker):
)
try:
ns_parser = parse_known_args_and_warn(parser, l_args)
ns_parser = parse_known_args_and_warn(parser, other_args)
if not ns_parser:
return
stock = yf.Ticker(s_ticker)
stock = yf.Ticker(ticker)
df_info = pd.DataFrame(stock.info.items(), columns=["Metric", "Value"])
df_info = df_info.set_index("Metric")
@@ -86,7 +101,17 @@ def info(l_args, s_ticker):
return
def shareholders(l_args, s_ticker):
def shareholders(other_args: List[str], ticker: str):
"""Yahoo Finance ticker shareholders
Parameters
----------
other_args : List[str]
argparse other args
ticker : str
Fundamental analysis ticker symbol
"""
parser = argparse.ArgumentParser(
add_help=False,
prog="shrs",
@@ -95,11 +120,11 @@ def shareholders(l_args, s_ticker):
)
try:
ns_parser = parse_known_args_and_warn(parser, l_args)
ns_parser = parse_known_args_and_warn(parser, other_args)
if not ns_parser:
return
stock = yf.Ticker(s_ticker)
stock = yf.Ticker(ticker)
pd.set_option("display.max_colwidth", None)
# Major holders
@@ -154,7 +179,17 @@ def shareholders(l_args, s_ticker):
return
def sustainability(l_args, s_ticker):
def sustainability(other_args: List[str], ticker: str):
"""Yahoo Finance ticker sustainability
Parameters
----------
other_args : List[str]
argparse other args
ticker : str
Fundamental analysis ticker symbol
"""
parser = argparse.ArgumentParser(
add_help=False,
prog="sust",
@@ -169,17 +204,17 @@ def sustainability(l_args, s_ticker):
)
try:
ns_parser = parse_known_args_and_warn(parser, l_args)
ns_parser = parse_known_args_and_warn(parser, other_args)
if not ns_parser:
return
stock = yf.Ticker(s_ticker)
stock = yf.Ticker(ticker)
pd.set_option("display.max_colwidth", None)
df_sustainability = stock.sustainability
if not df_sustainability:
print(f"No sustainability information in Yahoo for {s_ticker}")
print(f"No sustainability information in Yahoo for {ticker}")
print("")
return
@@ -209,7 +244,17 @@ def sustainability(l_args, s_ticker):
return
def calendar_earnings(l_args, s_ticker):
def calendar_earnings(other_args: List[str], ticker: str):
"""Yahoo Finance ticker calendar earnings
Parameters
----------
other_args : List[str]
argparse other args
ticker : str
Fundamental analysis ticker symbol
"""
parser = argparse.ArgumentParser(
add_help=False,
prog="cal",
@@ -220,15 +265,15 @@ def calendar_earnings(l_args, s_ticker):
)
try:
ns_parser = parse_known_args_and_warn(parser, l_args)
ns_parser = parse_known_args_and_warn(parser, other_args)
if not ns_parser:
return
stock = yf.Ticker(s_ticker)
stock = yf.Ticker(ticker)
df_calendar = stock.calendar
if df_calendar.empty:
print(f"No earnings calendar information in Yahoo for {s_ticker}")
print(f"No earnings calendar information in Yahoo for {ticker}")
print("")
return

View File

@@ -16,7 +16,7 @@ from gamestonk_terminal import thought_of_the_day as thought
from gamestonk_terminal import res_menu as rm
from gamestonk_terminal.discovery import disc_controller
from gamestonk_terminal.due_diligence import dd_controller
from gamestonk_terminal.fundamental_analysis import fa_menu as fam
from gamestonk_terminal.fundamental_analysis import fa_controller
from gamestonk_terminal.helper_funcs import b_is_stock_market_open, get_flair
from gamestonk_terminal.main_helper import clear, export, load, print_help, view, candle
from gamestonk_terminal.menu import session
@@ -211,7 +211,7 @@ def main():
b_quit = ca_controller.menu(df_stock, s_ticker, s_start, s_interval)
elif ns_known_args.opt == "fa":
b_quit = fam.fa_menu(
b_quit = fa_controller.menu(
s_ticker.split(".")[0] if "." in s_ticker else s_ticker,
s_start,
s_interval,
@@ -329,7 +329,7 @@ def main():
df_stock_pred,
s_ticker.split(".")[0] if "." in s_ticker else s_ticker,
s_start,
s_interval="1440min",
interval="1440min",
)
except Exception as e:
print(e)

View File

@@ -1,7 +1,7 @@
""" fundamental_analysis/business_insider_api.py tests """
import unittest
from gamestonk_terminal.fundamental_analysis.business_insider_api import management
from gamestonk_terminal.fundamental_analysis.business_insider_view import management
class TestFaBusinessInsiderApi(unittest.TestCase):

View File

@@ -8,7 +8,7 @@ from gamestonk_terminal.test_helper import ( # noqa: F401
pytest_generate_tests,
)
from gamestonk_terminal.fundamental_analysis.market_watch_api import (
from gamestonk_terminal.fundamental_analysis.market_watch_model import (
prepare_df_financials,
)
@@ -16,10 +16,10 @@ assertions = unittest.TestCase("__init__")
class TestFaMarketWatchApiUnit:
@mock.patch("gamestonk_terminal.fundamental_analysis.market_watch_api.requests")
@mock.patch("gamestonk_terminal.fundamental_analysis.market_watch_model.requests")
@parameterize_from_file(
"test_prepare_df_financials",
"../tests/data/fa_market_watch_api.yaml",
"../tests/data/fa_market_watch_model.yaml",
)
# pylint: disable=too-many-arguments
def test_prepare_df_financials(

View File

@@ -1,7 +1,7 @@
""" fundamental_analysis/market_watch_api.py tests """
import unittest
from gamestonk_terminal.fundamental_analysis.market_watch_api import income
from gamestonk_terminal.fundamental_analysis.market_watch_view import income
class TestFaMarketWatchApi(unittest.TestCase):

View File

@@ -2,7 +2,7 @@
import unittest
# pylint: disable=unused-import
from gamestonk_terminal.fundamental_analysis.yahoo_finance_api import ( # noqa: F401
from gamestonk_terminal.fundamental_analysis.yahoo_finance_view import ( # noqa: F401
info,
sustainability,
calendar_earnings,