Refactoring Financial Modeling Prep

This commit is contained in:
Artem Veremey
2021-04-19 11:54:42 -07:00
parent 508d9c1363
commit a36bbc4d3d
4 changed files with 355 additions and 162 deletions

View File

@@ -8,7 +8,7 @@ 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_api as fmp_api,
financial_modeling_prep_controller as fmpc,
)
from gamestonk_terminal.fundamental_analysis import finviz_api as fvz_api
from gamestonk_terminal.fundamental_analysis import market_watch_api as mw_api
@@ -176,7 +176,7 @@ class FundamentalAnalysisController:
# pylint: disable=unused-argument
def call_fmp(self, other_args: List[str]):
""" Process fmp command """
ret = fmp_api.menu(self.ticker, self.start, self.interval)
ret = fmpc.menu(self.ticker, self.start, self.interval)
if ret is not True:
self.print_help()

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

@@ -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)