mirror of
https://github.com/OpenBB-finance/OpenBB.git
synced 2026-10-30 22:11:55 +00:00
Refactor FA menu (#845)
* Business insider * cleanup BI + test * Finviz fns * Market watch fa * yahoo fa stuff * yahoo fa tests * AV FA menu * FMP Menu * Fix fmp test * Update dd notebook template * Actually fix fmp test * Add missing docstring Co-authored-by: James Maslek <james@macbook-pro.myfiosgateway.com> Co-authored-by: James Maslek <james@Jamess-MacBook-Pro.local>
This commit is contained in:
376
gamestonk_terminal/stocks/fundamental_analysis/av_model.py
Normal file
376
gamestonk_terminal/stocks/fundamental_analysis/av_model.py
Normal file
@@ -0,0 +1,376 @@
|
||||
"""Alpha Vantage Model"""
|
||||
__docformat__ = "numpy"
|
||||
|
||||
from typing import Dict, Tuple
|
||||
|
||||
import requests
|
||||
|
||||
from alpha_vantage.fundamentaldata import FundamentalData
|
||||
import pandas as pd
|
||||
from gamestonk_terminal.stocks.fundamental_analysis.fa_helper import clean_df_index
|
||||
from gamestonk_terminal.helper_funcs import long_number_format
|
||||
from gamestonk_terminal import config_terminal as cfg
|
||||
|
||||
|
||||
def get_overview(ticker: str) -> pd.DataFrame:
|
||||
"""Get alpha vantage company overview
|
||||
|
||||
Parameters
|
||||
----------
|
||||
ticker : str
|
||||
Stock ticker
|
||||
|
||||
Returns
|
||||
-------
|
||||
pd.DataFrame
|
||||
Dataframe of fundamentals
|
||||
"""
|
||||
# Request OVERVIEW data from Alpha Vantage API
|
||||
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 = pd.json_normalize(result.json())
|
||||
# Keep json data sorting in dataframe
|
||||
df_fa = df_fa[list(result.json().keys())].T
|
||||
df_fa.iloc[5:] = df_fa.iloc[5:].applymap(lambda x: long_number_format(x))
|
||||
clean_df_index(df_fa)
|
||||
df_fa = df_fa.rename(
|
||||
index={
|
||||
"E b i t d a": "EBITDA",
|
||||
"P e ratio": "PE ratio",
|
||||
"P e g ratio": "PEG ratio",
|
||||
"E p s": "EPS",
|
||||
"Revenue per share t t m": "Revenue per share TTM",
|
||||
"Operating margin t t m": "Operating margin TTM",
|
||||
"Return on assets t t m": "Return on assets TTM",
|
||||
"Return on equity t t m": "Return on equity TTM",
|
||||
"Revenue t t m": "Revenue TTM",
|
||||
"Gross profit t t m": "Gross profit TTM",
|
||||
"Diluted e p s t t m": "Diluted EPS TTM",
|
||||
"Quarterly earnings growth y o y": "Quarterly earnings growth YOY",
|
||||
"Quarterly revenue growth y o y": "Quarterly revenue growth YOY",
|
||||
"Trailing p e": "Trailing PE",
|
||||
"Forward p e": "Forward PE",
|
||||
"Price to sales ratio t t m": "Price to sales ratio TTM",
|
||||
"E v to revenue": "EV to revenue",
|
||||
"E v to e b i t d a": "EV to EBITDA",
|
||||
}
|
||||
)
|
||||
return df_fa
|
||||
return pd.DataFrame()
|
||||
|
||||
|
||||
def get_key_metrics(ticker: str) -> pd.DataFrame:
|
||||
"""Get key metrics from overview
|
||||
|
||||
Parameters
|
||||
----------
|
||||
ticker : str
|
||||
Stock ticker
|
||||
|
||||
Returns
|
||||
-------
|
||||
pd.DataFrame
|
||||
Dataframe of key metrics
|
||||
"""
|
||||
# Request OVERVIEW data
|
||||
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 = 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)
|
||||
df_fa = df_fa.rename(
|
||||
index={
|
||||
"E b i t d a": "EBITDA",
|
||||
"P e ratio": "PE ratio",
|
||||
"P e g ratio": "PEG ratio",
|
||||
"E p s": "EPS",
|
||||
"Return on equity t t m": "Return on equity TTM",
|
||||
"Price to sales ratio t t m": "Price to sales ratio TTM",
|
||||
}
|
||||
)
|
||||
as_key_metrics = [
|
||||
"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",
|
||||
]
|
||||
return df_fa.loc[as_key_metrics]
|
||||
|
||||
return pd.DataFrame()
|
||||
|
||||
|
||||
def get_income_statements(
|
||||
ticker: str, number: int, quarterly: bool = False
|
||||
) -> pd.DataFrame:
|
||||
"""Get income statements for company
|
||||
|
||||
Parameters
|
||||
----------
|
||||
ticker : str
|
||||
Stock ticker
|
||||
number : int
|
||||
Number of past to get
|
||||
quarterly : bool, optional
|
||||
Flag to get quarterly instead of annual, by default False
|
||||
|
||||
Returns
|
||||
-------
|
||||
pd.DataFrame
|
||||
Dataframe of income statements
|
||||
"""
|
||||
url = f"https://www.alphavantage.co/query?function=INCOME_STATEMENT&symbol={ticker}&apikey={cfg.API_KEY_ALPHAVANTAGE}"
|
||||
r = requests.get(url)
|
||||
statements = r.json()
|
||||
if quarterly:
|
||||
# pylint: disable=unbalanced-tuple-unpacking
|
||||
df_fa = pd.DataFrame(statements["quarterlyReports"])
|
||||
else:
|
||||
# pylint: disable=unbalanced-tuple-unpacking
|
||||
df_fa = pd.DataFrame(statements["annualReports"])
|
||||
|
||||
df_fa = df_fa.set_index("fiscalDateEnding")
|
||||
df_fa = df_fa.head(number)
|
||||
df_fa = df_fa.applymap(lambda x: long_number_format(x))
|
||||
return df_fa[::-1].T
|
||||
|
||||
|
||||
def get_balance_sheet(
|
||||
ticker: str, number: int, quarterly: bool = False
|
||||
) -> pd.DataFrame:
|
||||
"""Get balance sheets for company
|
||||
|
||||
Parameters
|
||||
----------
|
||||
ticker : str
|
||||
Stock ticker
|
||||
number : int
|
||||
Number of past to get
|
||||
quarterly : bool, optional
|
||||
Flag to get quarterly instead of annual, by default False
|
||||
|
||||
Returns
|
||||
-------
|
||||
pd.DataFrame
|
||||
Dataframe of income statements
|
||||
"""
|
||||
url = f"https://www.alphavantage.co/query?function=BALANCE_SHEET&symbol={ticker}&apikey={cfg.API_KEY_ALPHAVANTAGE}"
|
||||
r = requests.get(url)
|
||||
statements = r.json()
|
||||
if quarterly:
|
||||
df_fa = pd.DataFrame(statements["quarterlyReports"])
|
||||
else:
|
||||
df_fa = pd.DataFrame(statements["annualReports"])
|
||||
|
||||
df_fa = df_fa.set_index("fiscalDateEnding")
|
||||
df_fa = df_fa.head(number)
|
||||
df_fa = df_fa.applymap(lambda x: long_number_format(x))
|
||||
return df_fa[::-1].T
|
||||
|
||||
|
||||
def get_cash_flow(ticker: str, number: int, quarterly: bool = False) -> pd.DataFrame:
|
||||
"""Get cash flows for company
|
||||
|
||||
Parameters
|
||||
----------
|
||||
ticker : str
|
||||
Stock ticker
|
||||
number : int
|
||||
Number of past to get
|
||||
quarterly : bool, optional
|
||||
Flag to get quarterly instead of annual, by default False
|
||||
|
||||
Returns
|
||||
-------
|
||||
pd.DataFrame
|
||||
Dataframe of income statements
|
||||
"""
|
||||
url = f"https://www.alphavantage.co/query?function=CASH_FLOW&symbol={ticker}&apikey={cfg.API_KEY_ALPHAVANTAGE}"
|
||||
r = requests.get(url)
|
||||
statements = r.json()
|
||||
if quarterly:
|
||||
df_fa = pd.DataFrame(statements["quarterlyReports"])
|
||||
else:
|
||||
df_fa = pd.DataFrame(statements["annualReports"])
|
||||
|
||||
df_fa = df_fa.set_index("fiscalDateEnding")
|
||||
df_fa = df_fa.head(number)
|
||||
df_fa = df_fa.applymap(lambda x: long_number_format(x))
|
||||
return df_fa[::-1].T
|
||||
|
||||
|
||||
def get_earnings(ticker: str, quarterly: bool = False) -> pd.DataFrame:
|
||||
"""Get earnings calendar for ticker
|
||||
|
||||
Parameters
|
||||
----------
|
||||
ticker : str
|
||||
Stock ticker
|
||||
quarterly : bool, optional
|
||||
[Flag to get quarterly and not annual, by default False
|
||||
|
||||
Returns
|
||||
-------
|
||||
pd.DataFrame
|
||||
Dataframe of earnings
|
||||
"""
|
||||
# Request EARNINGS data from Alpha Vantage API
|
||||
s_req = (
|
||||
"https://www.alphavantage.co/query?function=EARNINGS&"
|
||||
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 = pd.json_normalize(result.json())
|
||||
if quarterly:
|
||||
df_fa = pd.DataFrame(df_fa["quarterlyEarnings"][0])
|
||||
df_fa = df_fa[
|
||||
[
|
||||
"fiscalDateEnding",
|
||||
"reportedDate",
|
||||
"reportedEPS",
|
||||
"estimatedEPS",
|
||||
"surprise",
|
||||
"surprisePercentage",
|
||||
]
|
||||
]
|
||||
df_fa = df_fa.rename(
|
||||
columns={
|
||||
"fiscalDateEnding": "Fiscal Date Ending",
|
||||
"reportedEPS": "Reported EPS",
|
||||
"estimatedEPS": "Estimated EPS",
|
||||
"reportedDate": "Reported Date",
|
||||
"surprise": "Surprise",
|
||||
"surprisePercentage": "Surprise Percentage",
|
||||
}
|
||||
)
|
||||
else:
|
||||
df_fa = pd.DataFrame(df_fa["annualEarnings"][0])
|
||||
df_fa = df_fa.rename(
|
||||
columns={
|
||||
"fiscalDateEnding": "Fiscal Date Ending",
|
||||
"reportedEPS": "Reported EPS",
|
||||
}
|
||||
)
|
||||
return df_fa
|
||||
return pd.DataFrame()
|
||||
|
||||
|
||||
def clean_fundamentals_df(df_fa: pd.DataFrame, num: int) -> pd.DataFrame:
|
||||
"""Clean fundamentals dataframe
|
||||
|
||||
Parameters
|
||||
----------
|
||||
df_fa : pd.DataFrame
|
||||
Fundamentals dataframe
|
||||
num : int
|
||||
Number of data rows to display
|
||||
|
||||
Returns
|
||||
----------
|
||||
pd.DataFrame
|
||||
Clean dataframe to output
|
||||
"""
|
||||
# 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
|
||||
|
||||
|
||||
def get_fraud_ratios(ticker: str) -> Tuple[Dict[str, float], float]:
|
||||
"""Get fraud ratios based on fundamentals
|
||||
|
||||
Parameters
|
||||
----------
|
||||
ticker : str
|
||||
Stock ticker
|
||||
|
||||
Returns
|
||||
-------
|
||||
Dict[float]:
|
||||
Dictionary of fraud metrics
|
||||
float:
|
||||
Z score for fraud metrics
|
||||
"""
|
||||
fd = FundamentalData(key=cfg.API_KEY_ALPHAVANTAGE, output_format="pandas")
|
||||
# pylint: disable=unbalanced-tuple-unpacking
|
||||
# pylint: disable=no-member
|
||||
df_cf, _ = fd.get_cash_flow_annual(symbol=ticker)
|
||||
df_bs, _ = fd.get_balance_sheet_annual(symbol=ticker)
|
||||
df_is, _ = fd.get_income_statement_annual(symbol=ticker)
|
||||
df_cf = df_cf.set_index("fiscalDateEnding").iloc[:2]
|
||||
df_bs = df_bs.set_index("fiscalDateEnding").iloc[:2]
|
||||
df_is = df_is.set_index("fiscalDateEnding").iloc[:2]
|
||||
|
||||
ar = df_bs["currentNetReceivables"].apply(lambda x: int(x)).values
|
||||
sales = df_is["totalRevenue"].apply(lambda x: int(x)).values
|
||||
cogs = df_is["costofGoodsAndServicesSold"].apply(lambda x: int(x)).values
|
||||
ni = df_is["netIncome"].apply(lambda x: int(x)).values
|
||||
ca = df_bs["totalCurrentAssets"].apply(lambda x: int(x)).values
|
||||
cl = df_bs["totalCurrentLiabilities"].apply(lambda x: int(x)).values
|
||||
ppe = df_bs["propertyPlantEquipment"].apply(lambda x: int(x)).values
|
||||
cash = df_bs["cashAndCashEquivalentsAtCarryingValue"].apply(lambda x: int(x)).values
|
||||
cash_and_sec = df_bs["cashAndShortTermInvestments"].apply(lambda x: int(x)).values
|
||||
sec = [y - x for (x, y) in zip(cash, cash_and_sec)]
|
||||
ta = df_bs["totalAssets"].apply(lambda x: int(x)).values
|
||||
dep = df_bs["accumulatedDepreciationAmortizationPPE"].apply(lambda x: int(x)).values
|
||||
sga = df_is["sellingGeneralAndAdministrative"].apply(lambda x: int(x)).values
|
||||
tl = df_bs["totalLiabilities"].apply(lambda x: int(x)).values
|
||||
icfo = df_is["netIncomeFromContinuingOperations"].apply(lambda x: int(x)).values
|
||||
cfo = df_cf["operatingCashflow"].apply(lambda x: int(x)).values
|
||||
ratios: Dict = {}
|
||||
ratios["DSRI"] = (ar[0] / sales[0]) / (ar[1] / sales[1])
|
||||
ratios["GMI"] = ((sales[1] - cogs[1]) / sales[1]) / (
|
||||
(sales[0] - cogs[0]) / sales[0]
|
||||
)
|
||||
ratios["AQI"] = (1 - ((ca[0] + ppe[0] + sec[0]) / ta[0])) / (
|
||||
1 - ((ca[1] + ppe[1] + sec[1]) / ta[1])
|
||||
)
|
||||
ratios["SGI"] = sales[0] / sales[1]
|
||||
ratios["DEPI"] = (dep[1] / (ppe[1] + dep[1])) / (dep[0] / (ppe[0] + dep[0]))
|
||||
ratios["SGAI"] = (sga[0] / sales[0]) / (sga[1] / sales[1])
|
||||
ratios["LVGI"] = (tl[0] / ta[0]) / (tl[1] / ta[1])
|
||||
ratios["TATA"] = (icfo[0] - cfo[0]) / ta[0]
|
||||
ratios["MSCORE"] = (
|
||||
-4.84
|
||||
+ (0.92 * ratios["DSRI"])
|
||||
+ (0.58 * ratios["GMI"])
|
||||
+ (0.404 * ratios["AQI"])
|
||||
+ (0.892 * ratios["SGI"])
|
||||
+ (0.115 * ratios["DEPI"] - (0.172 * ratios["SGAI"]))
|
||||
+ (4.679 * ratios["TATA"])
|
||||
- (0.327 * ratios["LVGI"])
|
||||
)
|
||||
|
||||
zscore = (
|
||||
-4.336
|
||||
- (4.513 * (ni[0] / ta[0]))
|
||||
+ (5.679 * (tl[0] / ta[0]))
|
||||
+ (0.004 * (ca[0] / cl[0]))
|
||||
)
|
||||
|
||||
return ratios, zscore
|
||||
@@ -1,669 +1,205 @@
|
||||
""" Alpha Vantage View """
|
||||
__docformat__ = "numpy"
|
||||
|
||||
import argparse
|
||||
from typing import List, Dict
|
||||
import os
|
||||
|
||||
import requests
|
||||
from tabulate import tabulate
|
||||
|
||||
from alpha_vantage.fundamentaldata import FundamentalData
|
||||
import pandas as pd
|
||||
|
||||
from gamestonk_terminal import config_terminal as cfg
|
||||
from gamestonk_terminal.stocks.fundamental_analysis.fa_helper import clean_df_index
|
||||
from gamestonk_terminal.helper_funcs import (
|
||||
check_positive,
|
||||
long_number_format,
|
||||
parse_known_args_and_warn,
|
||||
)
|
||||
from gamestonk_terminal import feature_flags as gtff
|
||||
from gamestonk_terminal.helper_funcs import export_data
|
||||
from gamestonk_terminal.stocks.fundamental_analysis import av_model
|
||||
|
||||
|
||||
def overview(other_args: List[str], ticker: str):
|
||||
def display_overview(ticker: str):
|
||||
"""Alpha Vantage stock ticker overview
|
||||
|
||||
Parameters
|
||||
----------
|
||||
other_args : List[str]
|
||||
argparse other args
|
||||
ticker : str
|
||||
Fundamental analysis ticker symbol
|
||||
"""
|
||||
parser = argparse.ArgumentParser(
|
||||
add_help=False,
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||
prog="overview",
|
||||
description="""
|
||||
Prints an overview about the company. The following fields are expected:
|
||||
Symbol, Asset type, Name, Description, Exchange, Currency, Country, Sector, Industry,
|
||||
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. Also, the C i k field
|
||||
corresponds to Central Index Key, which can be used to search a company on
|
||||
https://www.sec.gov/edgar/searchedgar/cik.htm [Source: Alpha Vantage]
|
||||
""",
|
||||
)
|
||||
|
||||
try:
|
||||
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={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 = pd.json_normalize(result.json())
|
||||
# Keep json data sorting in dataframe
|
||||
df_fa = df_fa[list(result.json().keys())].T
|
||||
df_fa.iloc[5:] = df_fa.iloc[5:].applymap(lambda x: long_number_format(x))
|
||||
clean_df_index(df_fa)
|
||||
df_fa = df_fa.rename(
|
||||
index={
|
||||
"E b i t d a": "EBITDA",
|
||||
"P e ratio": "PE ratio",
|
||||
"P e g ratio": "PEG ratio",
|
||||
"E p s": "EPS",
|
||||
"Revenue per share t t m": "Revenue per share TTM",
|
||||
"Operating margin t t m": "Operating margin TTM",
|
||||
"Return on assets t t m": "Return on assets TTM",
|
||||
"Return on equity t t m": "Return on equity TTM",
|
||||
"Revenue t t m": "Revenue TTM",
|
||||
"Gross profit t t m": "Gross profit TTM",
|
||||
"Diluted e p s t t m": "Diluted EPS TTM",
|
||||
"Quarterly earnings growth y o y": "Quarterly earnings growth YOY",
|
||||
"Quarterly revenue growth y o y": "Quarterly revenue growth YOY",
|
||||
"Trailing p e": "Trailing PE",
|
||||
"Forward p e": "Forward PE",
|
||||
"Price to sales ratio t t m": "Price to sales ratio TTM",
|
||||
"E v to revenue": "EV to revenue",
|
||||
"E v to e b i t d a": "EV to EBITDA",
|
||||
}
|
||||
df_fa = av_model.get_overview(ticker)
|
||||
if df_fa.empty:
|
||||
print(f"No data found from alphavantage for {ticker}.\n")
|
||||
return
|
||||
if gtff.USE_TABULATE_DF:
|
||||
print(
|
||||
tabulate(
|
||||
df_fa.drop(index=["Description"]), headers=[], tablefmt="fancy_grid"
|
||||
)
|
||||
)
|
||||
else:
|
||||
print(df_fa.drop(index=["Description"]).to_string(header=False))
|
||||
|
||||
pd.set_option("display.max_colwidth", None)
|
||||
|
||||
print(df_fa.drop(index=["Description"]).to_string(header=False))
|
||||
print(f"Description: {df_fa.loc['Description'][0]}")
|
||||
print("")
|
||||
else:
|
||||
print(f"Error: {result.status_code}")
|
||||
print("")
|
||||
|
||||
except Exception as e:
|
||||
print(e, "\n")
|
||||
print(f"\nCompany Description:\n\n{df_fa.loc['Description'][0]}")
|
||||
print("")
|
||||
|
||||
|
||||
def key(other_args: List[str], ticker: str):
|
||||
def display_key(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,
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||
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]
|
||||
""",
|
||||
)
|
||||
df_key = av_model.get_key_metrics(ticker)
|
||||
|
||||
try:
|
||||
ns_parser = parse_known_args_and_warn(parser, other_args)
|
||||
if not ns_parser:
|
||||
return
|
||||
if df_key.empty:
|
||||
print("Issue getting key metrics from alpha vantage.")
|
||||
return
|
||||
|
||||
# Request OVERVIEW data
|
||||
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 gtff.USE_TABULATE_DF:
|
||||
print(tabulate(df_key, headers=[], tablefmt="fancy_grid"))
|
||||
else:
|
||||
print(df_key.to_string(header=False))
|
||||
|
||||
# If the returned data was successful
|
||||
if result.status_code == 200:
|
||||
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)
|
||||
df_fa = df_fa.rename(
|
||||
index={
|
||||
"E b i t d a": "EBITDA",
|
||||
"P e ratio": "PE ratio",
|
||||
"P e g ratio": "PEG ratio",
|
||||
"E p s": "EPS",
|
||||
"Return on equity t t m": "Return on equity TTM",
|
||||
"Price to sales ratio t t m": "Price to sales ratio TTM",
|
||||
}
|
||||
)
|
||||
as_key_metrics = [
|
||||
"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",
|
||||
]
|
||||
print(df_fa.loc[as_key_metrics].to_string(header=False))
|
||||
else:
|
||||
print(f"Error: {result.status_code}")
|
||||
print("")
|
||||
|
||||
except Exception as e:
|
||||
print(e, "\n")
|
||||
print("")
|
||||
|
||||
|
||||
def income_statement(other_args: List[str], ticker: str):
|
||||
def display_income_statement(
|
||||
ticker: str, number: int, quarterly: bool = False, export: str = ""
|
||||
):
|
||||
"""Alpha Vantage income statement
|
||||
|
||||
Parameters
|
||||
----------
|
||||
other_args : List[str]
|
||||
argparse other args
|
||||
ticker : str
|
||||
Fundamental analysis ticker symbol
|
||||
number: int
|
||||
Number of past statements
|
||||
quarterly: bool
|
||||
Flag to get quarterly instead of annual
|
||||
export: str
|
||||
Format to export data
|
||||
"""
|
||||
parser = argparse.ArgumentParser(
|
||||
add_help=False,
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||
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,
|
||||
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(
|
||||
"-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.",
|
||||
)
|
||||
df_income = av_model.get_income_statements(ticker, number, quarterly)
|
||||
|
||||
try:
|
||||
ns_parser = parse_known_args_and_warn(parser, other_args)
|
||||
if not ns_parser:
|
||||
return
|
||||
if gtff.USE_TABULATE_DF:
|
||||
print(tabulate(df_income, headers=df_income.columns, tablefmt="fancy_grid"))
|
||||
else:
|
||||
print(df_income.to_string())
|
||||
|
||||
if ns_parser.n_num == 1:
|
||||
pd.set_option("display.max_colwidth", None)
|
||||
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_income_statement_quarterly(symbol=ticker)
|
||||
else:
|
||||
# pylint: disable=unbalanced-tuple-unpacking
|
||||
df_fa, _ = fd.get_income_statement_annual(symbol=ticker)
|
||||
|
||||
df_fa = clean_fundamentals_df(df_fa, num=ns_parser.n_num)
|
||||
print(df_fa)
|
||||
print("")
|
||||
|
||||
except Exception as e:
|
||||
print(e, "\n")
|
||||
print("")
|
||||
export_data(export, os.path.dirname(os.path.abspath(__file__)), "income", df_income)
|
||||
|
||||
|
||||
def balance_sheet(other_args: List[str], ticker: str):
|
||||
"""Alpha Vantage balance sheet
|
||||
def display_balance_sheet(
|
||||
ticker: str, number: int, quarterly: bool = False, export: str = ""
|
||||
):
|
||||
"""Alpha Vantage income statement
|
||||
|
||||
Parameters
|
||||
----------
|
||||
other_args : List[str]
|
||||
argparse other args
|
||||
ticker : str
|
||||
Fundamental analysis ticker symbol
|
||||
number: int
|
||||
Number of past statements
|
||||
quarterly: bool
|
||||
Flag to get quarterly instead of annual
|
||||
export: str
|
||||
Format to export data
|
||||
"""
|
||||
parser = argparse.ArgumentParser(
|
||||
add_help=False,
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||
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.",
|
||||
df_balance = av_model.get_balance_sheet(ticker, number, quarterly)
|
||||
|
||||
if gtff.USE_TABULATE_DF:
|
||||
print(tabulate(df_balance, headers=df_balance.columns, tablefmt="fancy_grid"))
|
||||
else:
|
||||
print(df_balance.to_string())
|
||||
|
||||
print("")
|
||||
export_data(
|
||||
export, os.path.dirname(os.path.abspath(__file__)), "balance", df_balance
|
||||
)
|
||||
|
||||
try:
|
||||
ns_parser = parse_known_args_and_warn(parser, other_args)
|
||||
if not ns_parser:
|
||||
return
|
||||
|
||||
if ns_parser.n_num == 1:
|
||||
pd.set_option("display.max_colwidth", None)
|
||||
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_balance_sheet_quarterly(symbol=ticker)
|
||||
else:
|
||||
# pylint: disable=unbalanced-tuple-unpacking
|
||||
df_fa, _ = fd.get_balance_sheet_annual(symbol=ticker)
|
||||
|
||||
df_fa = clean_fundamentals_df(df_fa, num=ns_parser.n_num)
|
||||
print(df_fa)
|
||||
print("")
|
||||
|
||||
except Exception as e:
|
||||
print(e, "\n")
|
||||
|
||||
|
||||
def cash_flow(other_args: List[str], ticker: str):
|
||||
"""Alpha Vantage cash flow
|
||||
def display_cash_flow(
|
||||
ticker: str, number: int, quarterly: bool = False, export: str = ""
|
||||
):
|
||||
"""Alpha Vantage income statement
|
||||
|
||||
Parameters
|
||||
----------
|
||||
other_args : List[str]
|
||||
argparse other args
|
||||
ticker : str
|
||||
Fundamental analysis ticker symbol
|
||||
number: int
|
||||
Number of past statements
|
||||
quarterly: bool
|
||||
Flag to get quarterly instead of annual
|
||||
export: str
|
||||
Format to export data
|
||||
"""
|
||||
parser = argparse.ArgumentParser(
|
||||
add_help=False,
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||
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.",
|
||||
)
|
||||
df_cash = av_model.get_cash_flow(ticker, number, quarterly)
|
||||
|
||||
try:
|
||||
ns_parser = parse_known_args_and_warn(parser, other_args)
|
||||
if not ns_parser:
|
||||
return
|
||||
if gtff.USE_TABULATE_DF:
|
||||
print(tabulate(df_cash, headers=df_cash.columns, tablefmt="fancy_grid"))
|
||||
else:
|
||||
print(df_cash.to_string())
|
||||
|
||||
if ns_parser.n_num == 1:
|
||||
pd.set_option("display.max_colwidth", None)
|
||||
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=ticker)
|
||||
else:
|
||||
# pylint: disable=unbalanced-tuple-unpacking
|
||||
df_fa, _ = fd.get_cash_flow_annual(symbol=ticker)
|
||||
|
||||
df_fa = clean_fundamentals_df(df_fa, num=ns_parser.n_num)
|
||||
print(df_fa)
|
||||
print("")
|
||||
|
||||
except Exception as e:
|
||||
print(e, "\n")
|
||||
print("")
|
||||
export_data(export, os.path.dirname(os.path.abspath(__file__)), "cash", df_cash)
|
||||
|
||||
|
||||
def earnings(other_args: List[str], ticker: str):
|
||||
def display_earnings(ticker: str, number: int, quarterly: bool = False):
|
||||
"""Alpha Vantage earnings
|
||||
|
||||
Parameters
|
||||
----------
|
||||
other_args : List[str]
|
||||
argparse other args
|
||||
ticker : str
|
||||
Fundamental analysis ticker symbol
|
||||
number:int
|
||||
Number of events to show
|
||||
quarterly: bool
|
||||
Flag to show quarterly instead of annual
|
||||
"""
|
||||
parser = argparse.ArgumentParser(
|
||||
add_help=False,
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||
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]
|
||||
""",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-q",
|
||||
"--quarter",
|
||||
action="store_true",
|
||||
default=False,
|
||||
dest="b_quarter",
|
||||
help="Quarter fundamental data flag.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-n",
|
||||
"--num",
|
||||
action="store",
|
||||
dest="n_num",
|
||||
type=check_positive,
|
||||
default=5,
|
||||
help="Number of latest info",
|
||||
)
|
||||
|
||||
try:
|
||||
ns_parser = parse_known_args_and_warn(parser, other_args)
|
||||
if not ns_parser:
|
||||
return
|
||||
|
||||
if ns_parser.n_num == 1:
|
||||
pd.set_option("display.max_colwidth", None)
|
||||
else:
|
||||
pd.options.display.max_colwidth = 40
|
||||
|
||||
# Request EARNINGS data from Alpha Vantage API
|
||||
s_req = (
|
||||
"https://www.alphavantage.co/query?function=EARNINGS&"
|
||||
f"symbol={ticker}&apikey={cfg.API_KEY_ALPHAVANTAGE}"
|
||||
df_fa = av_model.get_earnings(ticker, quarterly)
|
||||
if df_fa.empty:
|
||||
print("Error getting earnings data.\n")
|
||||
return
|
||||
if gtff.USE_TABULATE_DF:
|
||||
print(
|
||||
tabulate(
|
||||
df_fa.head(number),
|
||||
headers=df_fa.columns,
|
||||
showindex=False,
|
||||
tablefmt="fancy_grid",
|
||||
)
|
||||
)
|
||||
result = requests.get(s_req, stream=True)
|
||||
else:
|
||||
print(df_fa.head(n=number).T.to_string(header=False))
|
||||
|
||||
# If the returned data was successful
|
||||
if result.status_code == 200:
|
||||
df_fa = pd.json_normalize(result.json())
|
||||
if ns_parser.b_quarter:
|
||||
df_fa = pd.DataFrame(df_fa["quarterlyEarnings"][0])
|
||||
df_fa = df_fa[
|
||||
[
|
||||
"fiscalDateEnding",
|
||||
"reportedDate",
|
||||
"reportedEPS",
|
||||
"estimatedEPS",
|
||||
"surprise",
|
||||
"surprisePercentage",
|
||||
]
|
||||
]
|
||||
df_fa = df_fa.rename(
|
||||
columns={
|
||||
"fiscalDateEnding": "Fiscal Date Ending",
|
||||
"reportedEPS": "Reported EPS",
|
||||
"estimatedEPS": "Estimated EPS",
|
||||
"reportedDate": "Reported Date",
|
||||
"surprise": "Surprise",
|
||||
"surprisePercentage": "Surprise Percentage",
|
||||
}
|
||||
)
|
||||
else:
|
||||
df_fa = pd.DataFrame(df_fa["annualEarnings"][0])
|
||||
df_fa = df_fa.rename(
|
||||
columns={
|
||||
"fiscalDateEnding": "Fiscal Date Ending",
|
||||
"reportedEPS": "Reported EPS",
|
||||
}
|
||||
)
|
||||
|
||||
print(df_fa.head(n=ns_parser.n_num).T.to_string(header=False))
|
||||
|
||||
else:
|
||||
print(f"Error: {result.status_code}")
|
||||
print("")
|
||||
|
||||
except Exception as e:
|
||||
print(e, "\n")
|
||||
print("")
|
||||
|
||||
|
||||
def clean_fundamentals_df(df_fa: pd.DataFrame, num: int) -> pd.DataFrame:
|
||||
"""Clean fundamentals dataframe
|
||||
|
||||
Parameters
|
||||
----------
|
||||
df_fa : pd.DataFrame
|
||||
Fundamentals dataframe
|
||||
num : int
|
||||
Number of data rows to display
|
||||
|
||||
Returns
|
||||
----------
|
||||
pd.DataFrame
|
||||
Clean dataframe to output
|
||||
"""
|
||||
# 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
|
||||
|
||||
|
||||
def fraud(other_args: List[str], ticker: str):
|
||||
def display_fraud(ticker: str):
|
||||
"""Fraud indicators for given ticker
|
||||
Parameters
|
||||
----------
|
||||
other_args : List[str]
|
||||
argparse other args
|
||||
ticker : str
|
||||
Fundamental analysis ticker symbol
|
||||
"""
|
||||
parser = argparse.ArgumentParser(
|
||||
add_help=False,
|
||||
formatter_class=argparse.RawTextHelpFormatter,
|
||||
prog="fraud",
|
||||
description=(
|
||||
"Mscore:\n------------------------------------------------\n"
|
||||
"The Beneish model is a statistical model that uses financial ratios calculated with"
|
||||
" accounting data of a specific company in order to check if it is likely (high"
|
||||
" probability) that the reported earnings of the company have been manipulated."
|
||||
" A score of -5 to -2.22 indicated a low chance of fraud, a score of -2.22 to -1.78"
|
||||
" indicates a moderate change of fraud, and a score above -1.78 indicated a high"
|
||||
" chance of fraud.[Source: Wikipedia]\n\nDSRI:\nDays Sales in Receivables Index"
|
||||
" gauges whether receivables and revenue are out of balance, a large number is"
|
||||
" expected to be associated with a higher likelihood that revenues and earnings are"
|
||||
" overstated.\n\nGMI:\nGross Margin Index shows if gross margins are deteriorating."
|
||||
" Research suggests that firms with worsening gross margin are more likely to engage"
|
||||
" in earnings management, therefore there should be a positive correlation between"
|
||||
" GMI and probability of earnings management.\n\nAQI:\nAsset Quality Index measures"
|
||||
" the proportion of assets where potential benefit is less certain. A positive"
|
||||
" relation between AQI and earnings manipulation is expected.\n\nSGI:\nSales Growth"
|
||||
" Index shows the amount of growth companies are having. Higher growth companies are"
|
||||
" more likely to commit fraud so there should be a positive relation between SGI and"
|
||||
" earnings management.\n\nDEPI:\nDepreciation Index is the ratio for the rate of"
|
||||
" depreciation. A DEPI greater than 1 shows that the depreciation rate has slowed and"
|
||||
" is positively correlated with earnings management.\n\nSGAI:\nSales General and"
|
||||
" Administrative Expenses Index measures the change in SG&A over sales. There should"
|
||||
" be a positive relationship between SGAI and earnings management.\n\nLVGI:\nLeverage"
|
||||
" Index represents change in leverage. A LVGI greater than one indicates a lower"
|
||||
" change of fraud.\n\nTATA: \nTotal Accruals to Total Assets is a proxy for the"
|
||||
" extent that cash underlies earnigns. A higher number is associated with a higher"
|
||||
" likelihood of manipulation.\n\n\n"
|
||||
"Zscore:\n------------------------------------------------\n"
|
||||
"The Zmijewski Score is a bankruptcy model used to predict a firm's bankruptcy in two"
|
||||
" years. The ratio uses in the Zmijewski score were determined by probit analysis ("
|
||||
"think of probit as probability unit). In this case, scores less than .5 represent a"
|
||||
" higher probability of default. One of the criticisms that Zmijewski made was that"
|
||||
" other bankruptcy scoring models oversampled distressed firms and favored situations"
|
||||
" with more complete data.[Source: YCharts]"
|
||||
),
|
||||
ratios, zscore = av_model.get_fraud_ratios(ticker)
|
||||
|
||||
if ratios["MSCORE"] > -1.78:
|
||||
chanceM = "high"
|
||||
elif ratios["MSCORE"] > -2.22:
|
||||
chanceM = "moderate"
|
||||
else:
|
||||
chanceM = "low"
|
||||
|
||||
if zscore < 0.5:
|
||||
chanceZ = "high"
|
||||
else:
|
||||
chanceZ = "low"
|
||||
|
||||
print("Mscore Sub Stats:")
|
||||
for rkey, value in ratios.items():
|
||||
if rkey != "MSCORE":
|
||||
print(" ", f"{rkey} : {value:.2f}")
|
||||
|
||||
print(
|
||||
"\n" + "MSCORE: ",
|
||||
f"{ratios['MSCORE']:.2f} ({chanceM} chance of fraud)",
|
||||
)
|
||||
|
||||
try:
|
||||
ns_parser = parse_known_args_and_warn(parser, other_args)
|
||||
|
||||
if not ns_parser:
|
||||
return
|
||||
|
||||
fd = FundamentalData(key=cfg.API_KEY_ALPHAVANTAGE, output_format="pandas")
|
||||
# pylint: disable=unbalanced-tuple-unpacking
|
||||
# pylint: disable=no-member
|
||||
df_cf, _ = fd.get_cash_flow_annual(symbol=ticker)
|
||||
df_bs, _ = fd.get_balance_sheet_annual(symbol=ticker)
|
||||
df_is, _ = fd.get_income_statement_annual(symbol=ticker)
|
||||
df_cf = df_cf.set_index("fiscalDateEnding").iloc[:2]
|
||||
df_bs = df_bs.set_index("fiscalDateEnding").iloc[:2]
|
||||
df_is = df_is.set_index("fiscalDateEnding").iloc[:2]
|
||||
|
||||
ar = df_bs["currentNetReceivables"].apply(lambda x: int(x)).values
|
||||
sales = df_is["totalRevenue"].apply(lambda x: int(x)).values
|
||||
cogs = df_is["costofGoodsAndServicesSold"].apply(lambda x: int(x)).values
|
||||
ni = df_is["netIncome"].apply(lambda x: int(x)).values
|
||||
ca = df_bs["totalCurrentAssets"].apply(lambda x: int(x)).values
|
||||
cl = df_bs["totalCurrentLiabilities"].apply(lambda x: int(x)).values
|
||||
ppe = df_bs["propertyPlantEquipment"].apply(lambda x: int(x)).values
|
||||
cash = (
|
||||
df_bs["cashAndCashEquivalentsAtCarryingValue"]
|
||||
.apply(lambda x: int(x))
|
||||
.values
|
||||
)
|
||||
cash_and_sec = (
|
||||
df_bs["cashAndShortTermInvestments"].apply(lambda x: int(x)).values
|
||||
)
|
||||
sec = [y - x for (x, y) in zip(cash, cash_and_sec)]
|
||||
ta = df_bs["totalAssets"].apply(lambda x: int(x)).values
|
||||
dep = (
|
||||
df_bs["accumulatedDepreciationAmortizationPPE"]
|
||||
.apply(lambda x: int(x))
|
||||
.values
|
||||
)
|
||||
sga = df_is["sellingGeneralAndAdministrative"].apply(lambda x: int(x)).values
|
||||
tl = df_bs["totalLiabilities"].apply(lambda x: int(x)).values
|
||||
icfo = df_is["netIncomeFromContinuingOperations"].apply(lambda x: int(x)).values
|
||||
cfo = df_cf["operatingCashflow"].apply(lambda x: int(x)).values
|
||||
ratios: Dict = {}
|
||||
ratios["DSRI"] = (ar[0] / sales[0]) / (ar[1] / sales[1])
|
||||
ratios["GMI"] = ((sales[1] - cogs[1]) / sales[1]) / (
|
||||
(sales[0] - cogs[0]) / sales[0]
|
||||
)
|
||||
ratios["AQI"] = (1 - ((ca[0] + ppe[0] + sec[0]) / ta[0])) / (
|
||||
1 - ((ca[1] + ppe[1] + sec[1]) / ta[1])
|
||||
)
|
||||
ratios["SGI"] = sales[0] / sales[1]
|
||||
ratios["DEPI"] = (dep[1] / (ppe[1] + dep[1])) / (dep[0] / (ppe[0] + dep[0]))
|
||||
ratios["SGAI"] = (sga[0] / sales[0]) / (sga[1] / sales[1])
|
||||
ratios["LVGI"] = (tl[0] / ta[0]) / (tl[1] / ta[1])
|
||||
ratios["TATA"] = (icfo[0] - cfo[0]) / ta[0]
|
||||
ratios["MSCORE"] = (
|
||||
-4.84
|
||||
+ (0.92 * ratios["DSRI"])
|
||||
+ (0.58 * ratios["GMI"])
|
||||
+ (0.404 * ratios["AQI"])
|
||||
+ (0.892 * ratios["SGI"])
|
||||
+ (0.115 * ratios["DEPI"] - (0.172 * ratios["SGAI"]))
|
||||
+ (4.679 * ratios["TATA"])
|
||||
- (0.327 * ratios["LVGI"])
|
||||
)
|
||||
|
||||
zscore = (
|
||||
-4.336
|
||||
- (4.513 * (ni[0] / ta[0]))
|
||||
+ (5.679 * (tl[0] / ta[0]))
|
||||
+ (0.004 * (ca[0] / cl[0]))
|
||||
)
|
||||
|
||||
if ratios["MSCORE"] > -1.78:
|
||||
chanceM = "high"
|
||||
elif ratios["MSCORE"] > -2.22:
|
||||
chanceM = "moderate"
|
||||
else:
|
||||
chanceM = "low"
|
||||
|
||||
if zscore < 0.5:
|
||||
chanceZ = "high"
|
||||
else:
|
||||
chanceZ = "low"
|
||||
|
||||
print("Mscore Sub Stats:")
|
||||
for rkey, value in ratios.items():
|
||||
if rkey != "MSCORE":
|
||||
print(" ", f"{rkey} : {value:.2f}")
|
||||
|
||||
print(
|
||||
"\n" + "MSCORE: ",
|
||||
f"{ratios['MSCORE']:.2f} ({chanceM} chance of fraud)",
|
||||
)
|
||||
|
||||
print("ZSCORE: ", f"{zscore:.2f} ({chanceZ} chance of bankruptcy)", "\n")
|
||||
|
||||
except Exception as e:
|
||||
print(e, "\n")
|
||||
print("ZSCORE: ", f"{zscore:.2f} ({chanceZ} chance of bankruptcy)", "\n")
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
"""Business Insider Model"""
|
||||
__docformat__ = "numpy"
|
||||
|
||||
import requests
|
||||
from bs4 import BeautifulSoup
|
||||
import pandas as pd
|
||||
from rapidfuzz import fuzz
|
||||
from gamestonk_terminal.helper_funcs import get_user_agent
|
||||
|
||||
|
||||
def get_management(ticker: str) -> pd.DataFrame:
|
||||
"""Get company managers from Business Insider
|
||||
|
||||
Parameters
|
||||
----------
|
||||
ticker : str
|
||||
Stock ticker
|
||||
|
||||
Returns
|
||||
-------
|
||||
pd.DataFrame
|
||||
Dataframe of managers
|
||||
"""
|
||||
url_market_business_insider = (
|
||||
f"https://markets.businessinsider.com/stocks/{ticker.lower()}-stock"
|
||||
)
|
||||
text_soup_market_business_insider = BeautifulSoup(
|
||||
requests.get(
|
||||
url_market_business_insider, headers={"User-Agent": get_user_agent()}
|
||||
).text,
|
||||
"lxml",
|
||||
)
|
||||
|
||||
found_h2s = {}
|
||||
|
||||
for next_h2 in text_soup_market_business_insider.findAll(
|
||||
"h2", {"class": "header-underline"}
|
||||
):
|
||||
next_table = next_h2.find_next_sibling("table", {"class": "table"})
|
||||
|
||||
if next_table:
|
||||
found_h2s[next_h2.text] = next_table
|
||||
|
||||
if found_h2s.get("Management") is None:
|
||||
print(f"No management information in Business Insider for {ticker}")
|
||||
print("")
|
||||
return pd.DataFrame()
|
||||
|
||||
l_titles = []
|
||||
for s_title in found_h2s["Management"].findAll(
|
||||
"td", {"class": "table__td text-right"}
|
||||
):
|
||||
if any(c.isalpha() for c in s_title.text.strip()) and (
|
||||
"USD" not in s_title.text.strip()
|
||||
):
|
||||
l_titles.append(s_title.text.strip())
|
||||
|
||||
l_names = []
|
||||
for s_name in found_h2s["Management"].findAll(
|
||||
"td", {"class": "table__td table--allow-wrap"}
|
||||
):
|
||||
l_names.append(s_name.text.strip())
|
||||
|
||||
df_management = pd.DataFrame(
|
||||
{"Name": l_names[-len(l_titles) :], "Title": l_titles},
|
||||
columns=["Name", "Title"],
|
||||
)
|
||||
|
||||
df_management["Info"] = "-"
|
||||
df_management["Insider Activity"] = "-"
|
||||
df_management = df_management.set_index("Name")
|
||||
|
||||
for s_name in df_management.index:
|
||||
df_management.loc[s_name][
|
||||
"Info"
|
||||
] = f"http://www.google.com/search?q={s_name} {ticker.upper()}".replace(
|
||||
" ", "%20"
|
||||
)
|
||||
|
||||
s_url_base = "https://markets.businessinsider.com"
|
||||
for insider in text_soup_market_business_insider.findAll(
|
||||
"a", {"onclick": "silentTrackPI()"}
|
||||
):
|
||||
for s_name in df_management.index:
|
||||
if fuzz.token_set_ratio(s_name, insider.text.strip()) > 70:
|
||||
df_management.loc[s_name]["Insider Activity"] = (
|
||||
s_url_base + insider.attrs["href"]
|
||||
)
|
||||
return df_management
|
||||
@@ -1,116 +1,46 @@
|
||||
""" Business Insider View """
|
||||
__docformat__ = "numpy"
|
||||
|
||||
import argparse
|
||||
from typing import List
|
||||
import requests
|
||||
from bs4 import BeautifulSoup
|
||||
import pandas as pd
|
||||
from rapidfuzz import fuzz
|
||||
from gamestonk_terminal.helper_funcs import get_user_agent, parse_known_args_and_warn
|
||||
import os
|
||||
import textwrap
|
||||
|
||||
from tabulate import tabulate
|
||||
|
||||
import gamestonk_terminal.feature_flags as gtff
|
||||
from gamestonk_terminal.helper_funcs import export_data
|
||||
from gamestonk_terminal.stocks.fundamental_analysis import business_insider_model
|
||||
|
||||
|
||||
def management(other_args: List[str], ticker: str):
|
||||
def display_management(ticker: str, export: str = ""):
|
||||
"""Display company's managers
|
||||
|
||||
Parameters
|
||||
----------
|
||||
other_args : List[str]
|
||||
argparse other args
|
||||
ticker : str
|
||||
Stock ticker
|
||||
export : str
|
||||
Format to export data
|
||||
"""
|
||||
parser = argparse.ArgumentParser(
|
||||
add_help=False,
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||
prog="mgmt",
|
||||
description="""
|
||||
Print management team. Namely: Name, Title, Information from google and
|
||||
(potentially) Insider Activity page. [Source: Business Insider]
|
||||
""",
|
||||
)
|
||||
df_management = business_insider_model.get_management(ticker)
|
||||
|
||||
try:
|
||||
ns_parser = parse_known_args_and_warn(parser, other_args)
|
||||
if not ns_parser:
|
||||
return
|
||||
names = ["Name"] + list(df_management.columns)
|
||||
|
||||
url_market_business_insider = (
|
||||
f"https://markets.businessinsider.com/stocks/{ticker.lower()}-stock"
|
||||
)
|
||||
text_soup_market_business_insider = BeautifulSoup(
|
||||
requests.get(
|
||||
url_market_business_insider, headers={"User-Agent": get_user_agent()}
|
||||
).text,
|
||||
"lxml",
|
||||
)
|
||||
|
||||
found_h2s = dict()
|
||||
|
||||
for next_h2 in text_soup_market_business_insider.findAll(
|
||||
"h2", {"class": "header-underline"}
|
||||
):
|
||||
next_table = next_h2.find_next_sibling("table", {"class": "table"})
|
||||
|
||||
if next_table:
|
||||
found_h2s[next_h2.text] = next_table
|
||||
|
||||
if found_h2s.get("Management") is None:
|
||||
print(f"No management information in Business Insider for {ticker}")
|
||||
print("")
|
||||
return
|
||||
|
||||
l_titles = []
|
||||
for s_title in found_h2s["Management"].findAll(
|
||||
"td", {"class": "table__td text-right"}
|
||||
):
|
||||
if any(c.isalpha() for c in s_title.text.strip()) and (
|
||||
"USD" not in s_title.text.strip()
|
||||
):
|
||||
l_titles.append(s_title.text.strip())
|
||||
|
||||
l_names = []
|
||||
for s_name in found_h2s["Management"].findAll(
|
||||
"td", {"class": "table__td table--allow-wrap"}
|
||||
):
|
||||
l_names.append(s_name.text.strip())
|
||||
|
||||
df_management = pd.DataFrame(
|
||||
{"Name": l_names[-len(l_titles) :], "Title": l_titles},
|
||||
columns=["Name", "Title"],
|
||||
)
|
||||
|
||||
df_management["Info"] = "-"
|
||||
df_management["Insider Activity"] = "-"
|
||||
df_management = df_management.set_index("Name")
|
||||
|
||||
for s_name in df_management.index:
|
||||
df_management.loc[s_name][
|
||||
"Info"
|
||||
] = f"http://www.google.com/search?q={s_name} {ticker.upper()}".replace(
|
||||
" ", "%20"
|
||||
if gtff.USE_TABULATE_DF:
|
||||
print(
|
||||
tabulate(
|
||||
df_management.applymap(
|
||||
lambda x: "\n".join(textwrap.wrap(x, width=30))
|
||||
if isinstance(x, str)
|
||||
else x
|
||||
),
|
||||
tablefmt="fancy_grid",
|
||||
headers=names,
|
||||
)
|
||||
)
|
||||
else:
|
||||
print(df_management.to_string())
|
||||
|
||||
s_url_base = "https://markets.businessinsider.com"
|
||||
for insider in text_soup_market_business_insider.findAll(
|
||||
"a", {"onclick": "silentTrackPI()"}
|
||||
):
|
||||
for s_name in df_management.index:
|
||||
if fuzz.token_set_ratio(s_name, insider.text.strip()) > 70:
|
||||
df_management.loc[s_name]["Insider Activity"] = (
|
||||
s_url_base + insider.attrs["href"]
|
||||
)
|
||||
|
||||
for ind in df_management.index:
|
||||
s_name = f"{ind}{(max([len(x) for x in df_management.index])-len(ind))*' '}"
|
||||
df_mgmt_title = df_management["Title"]
|
||||
spaces = max(len(x) for x in df_mgmt_title) - len(df_mgmt_title[ind])
|
||||
s_title = f"{df_mgmt_title[ind]}{spaces * ' '}"
|
||||
s_management = f"""{s_name} {s_title} {df_management['Info'][ind]}"""
|
||||
print(s_management)
|
||||
if df_management["Insider Activity"][ind] not in "-":
|
||||
print(f"{df_management['Insider Activity'][ind]}")
|
||||
print("")
|
||||
|
||||
except Exception as e:
|
||||
print(e, "\n")
|
||||
print("")
|
||||
export_data(
|
||||
export, os.path.dirname(os.path.abspath(__file__)), "mgmt", df_management
|
||||
)
|
||||
|
||||
@@ -20,7 +20,12 @@ from gamestonk_terminal.stocks.fundamental_analysis import (
|
||||
market_watch_view,
|
||||
)
|
||||
from gamestonk_terminal import feature_flags as gtff
|
||||
from gamestonk_terminal.helper_funcs import get_flair, parse_known_args_and_warn
|
||||
from gamestonk_terminal.helper_funcs import (
|
||||
EXPORT_ONLY_RAW_DATA_ALLOWED,
|
||||
get_flair,
|
||||
parse_known_args_and_warn,
|
||||
check_positive,
|
||||
)
|
||||
from gamestonk_terminal.menu import session
|
||||
|
||||
# pylint: disable=inconsistent-return-statements
|
||||
@@ -41,7 +46,7 @@ class FundamentalAnalysisController:
|
||||
"analysis",
|
||||
"score",
|
||||
"dcf",
|
||||
"screener",
|
||||
"data",
|
||||
"fraud",
|
||||
"income",
|
||||
"balance",
|
||||
@@ -97,23 +102,28 @@ class FundamentalAnalysisController:
|
||||
intraday = (f"Intraday {self.interval}", "Daily")[self.interval == "1440min"]
|
||||
|
||||
if self.start:
|
||||
help_text = f"\n\n{intraday} Stock: {self.ticker} (from {self.start.strftime('%Y-%m-%d')})"
|
||||
stock_text = f"\n{intraday} Stock: {self.ticker} (from {self.start.strftime('%Y-%m-%d')})"
|
||||
else:
|
||||
help_text = f"\n\n{intraday} Stock: {self.ticker}"
|
||||
stock_text = f"\n{intraday} Stock: {self.ticker}"
|
||||
|
||||
help_text += """
|
||||
Fundamental Analysis:
|
||||
help_text = f"""
|
||||
>>>Fundamental Analysis<<<
|
||||
|
||||
What would you like to do?
|
||||
cls clear screen
|
||||
?/help show this menu again
|
||||
q quit this menu, and shows back to main menu
|
||||
quit quit to abandon program
|
||||
load load a new ticker
|
||||
{stock_text}
|
||||
|
||||
screener screen info about the company [Finviz]
|
||||
data fundamental and technical data of company [FinViz]
|
||||
mgmt management team of the company [Business Insider]
|
||||
analysis analyse SEC filings with the help of machine learning [Elect.us]
|
||||
score investing score from Warren Buffett, Joseph Piotroski and Benjamin Graham [FMP]
|
||||
warnings company warnings according to Sean Seah book [Market Watch]
|
||||
dcf a customizable discounted cash flow created in excel [stockanalysis]
|
||||
|
||||
Yahoo Finance:
|
||||
info information scope of the company
|
||||
shrs shareholders of the company
|
||||
@@ -121,6 +131,7 @@ Yahoo Finance:
|
||||
cal calendar earnings and estimates of the company
|
||||
web open web browser of the company
|
||||
hq open HQ location of the company
|
||||
|
||||
Alpha Vantage:
|
||||
overview overview of the company
|
||||
key company key metrics
|
||||
@@ -129,6 +140,7 @@ Alpha Vantage:
|
||||
cash cash flow of the company
|
||||
earnings earnings dates and reported EPS
|
||||
fraud key fraud ratios
|
||||
|
||||
Other Sources:
|
||||
> fmp profile,quote,enterprise,dcf,income,ratios,growth from FMP
|
||||
"""
|
||||
@@ -204,67 +216,526 @@ Other Sources:
|
||||
|
||||
def call_mgmt(self, other_args: List[str]):
|
||||
"""Process mgmt command"""
|
||||
business_insider_view.management(other_args, self.ticker)
|
||||
parser = argparse.ArgumentParser(
|
||||
add_help=False,
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||
prog="mgmt",
|
||||
description="""
|
||||
Print management team. Namely: Name, Title, Information from google and
|
||||
(potentially) Insider Activity page. [Source: Business Insider]
|
||||
""",
|
||||
)
|
||||
|
||||
def call_screener(self, other_args: List[str]):
|
||||
try:
|
||||
ns_parser = parse_known_args_and_warn(
|
||||
parser, other_args, export_allowed=EXPORT_ONLY_RAW_DATA_ALLOWED
|
||||
)
|
||||
if not ns_parser:
|
||||
return
|
||||
|
||||
business_insider_view.display_management(
|
||||
ticker=self.ticker, export=ns_parser.export
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
print(e, "\n")
|
||||
|
||||
def call_data(self, other_args: List[str]):
|
||||
"""Process screener command"""
|
||||
finviz_view.screener(other_args, self.ticker)
|
||||
parser = argparse.ArgumentParser(
|
||||
add_help=False,
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||
prog="data",
|
||||
description="""
|
||||
Print several metrics about the company. The following fields are expected:
|
||||
Company, Sector, Industry, Country, Index, P/E, EPS (ttm), Insider Own,
|
||||
Shs Outstand, Perf Week, Market Cap, Forward P/E, EPS next Y, Insider Trans,
|
||||
Shs Float, Perf Month, Income, EPS next Q, Inst Own, Short Float, Perf Quarter,
|
||||
Sales, P/S, EPS this Y, Inst Trans, Short Ratio, Perf Half Y, Book/sh, P/B, ROA,
|
||||
Target Price, Perf Year, Cash/sh, P/C, ROE, 52W Range, Perf YTD, P/FCF, EPS past 5Y,
|
||||
ROI, 52W High, Beta, Quick Ratio, Sales past 5Y, Gross Margin, 52W Low, ATR,
|
||||
Employees, Current Ratio, Sales Q/Q, Oper. Margin, RSI (14), Volatility, Optionable,
|
||||
Debt/Eq, EPS Q/Q, Profit Margin, Rel Volume, Prev Close, Shortable, LT Debt/Eq,
|
||||
Earnings, Payout, Avg Volume, Price, Recom, SMA20, SMA50, SMA200, Volume, Change.
|
||||
[Source: Finviz]
|
||||
""",
|
||||
)
|
||||
|
||||
try:
|
||||
ns_parser = parse_known_args_and_warn(
|
||||
parser, other_args, export_allowed=EXPORT_ONLY_RAW_DATA_ALLOWED
|
||||
)
|
||||
if not ns_parser:
|
||||
return
|
||||
|
||||
finviz_view.display_screen_data(self.ticker)
|
||||
|
||||
except Exception as e:
|
||||
print(e, "\n")
|
||||
|
||||
def call_score(self, other_args: List[str]):
|
||||
"""Process score command"""
|
||||
fmp_view.valinvest_score(other_args, self.ticker)
|
||||
parser = argparse.ArgumentParser(
|
||||
add_help=False,
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||
prog="score",
|
||||
description="""
|
||||
Value investing tool based on Warren Buffett, Joseph Piotroski and Benjamin Graham thoughts [Source: FMP]
|
||||
""",
|
||||
)
|
||||
|
||||
try:
|
||||
ns_parser = parse_known_args_and_warn(parser, other_args)
|
||||
if not ns_parser:
|
||||
return
|
||||
fmp_view.valinvest_score(self.ticker)
|
||||
except Exception as e:
|
||||
print(e, "\n")
|
||||
|
||||
def call_info(self, other_args: List[str]):
|
||||
"""Process info command"""
|
||||
yahoo_finance_view.info(other_args, self.ticker)
|
||||
parser = argparse.ArgumentParser(
|
||||
add_help=False,
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||
prog="info",
|
||||
description="""
|
||||
Print information about the company. The following fields are expected:
|
||||
Zip, Sector, Full time employees, Long business summary, City, Phone, State, Country,
|
||||
Website, Max age, Address, Industry, Previous close, Regular market open, Two hundred
|
||||
day average, Payout ratio, Regular market day high, Average daily volume 10 day,
|
||||
Regular market previous close, Fifty day average, Open, Average volume 10 days, Beta,
|
||||
Regular market day low, Price hint, Currency, Trailing PE, Regular market volume,
|
||||
Market cap, Average volume, Price to sales trailing 12 months, Day low, Ask, Ask size,
|
||||
Volume, Fifty two week high, Forward PE, Fifty two week low, Bid, Tradeable, Bid size,
|
||||
Day high, Exchange, Short name, Long name, Exchange timezone name, Exchange timezone
|
||||
short name, Is esg populated, Gmt off set milliseconds, Quote type, Symbol, Message
|
||||
board id, Market, Enterprise to revenue, Profit margins, Enterprise to ebitda, 52 week
|
||||
change, Forward EPS, Shares outstanding, Book value, Shares short, Shares percent
|
||||
shares out, Last fiscal year end, Held percent institutions, Net income to common,
|
||||
Trailing EPS, Sand p52 week change, Price to book, Held percent insiders, Next fiscal
|
||||
year end, Most recent quarter, Short ratio, Shares short previous month date, Float
|
||||
shares, Enterprise value, Last split date, Last split factor, Earnings quarterly growth,
|
||||
Date short interest, PEG ratio, Short percent of float, Shares short prior month,
|
||||
Regular market price, Logo_url. [Source: Yahoo Finance]
|
||||
""",
|
||||
)
|
||||
|
||||
try:
|
||||
ns_parser = parse_known_args_and_warn(parser, other_args)
|
||||
if not ns_parser:
|
||||
return
|
||||
yahoo_finance_view.display_info(self.ticker)
|
||||
|
||||
except Exception as e:
|
||||
print(e, "\n")
|
||||
|
||||
def call_shrs(self, other_args: List[str]):
|
||||
"""Process shrs command"""
|
||||
yahoo_finance_view.shareholders(other_args, self.ticker)
|
||||
parser = argparse.ArgumentParser(
|
||||
add_help=False,
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||
prog="shrs",
|
||||
description="""Print Major, institutional and mutualfunds shareholders.
|
||||
[Source: Yahoo Finance]""",
|
||||
)
|
||||
|
||||
try:
|
||||
ns_parser = parse_known_args_and_warn(parser, other_args)
|
||||
|
||||
if not ns_parser:
|
||||
return
|
||||
|
||||
yahoo_finance_view.display_shareholders(self.ticker)
|
||||
|
||||
except Exception as e:
|
||||
print(e, "\n")
|
||||
|
||||
def call_sust(self, other_args: List[str]):
|
||||
"""Process sust command"""
|
||||
yahoo_finance_view.sustainability(other_args, self.ticker)
|
||||
parser = argparse.ArgumentParser(
|
||||
add_help=False,
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||
prog="sust",
|
||||
description="""
|
||||
Print sustainability values of the company. The following fields are expected:
|
||||
Palmoil, Controversialweapons, Gambling, Socialscore, Nuclear, Furleather, Alcoholic,
|
||||
Gmo, Catholic, Socialpercentile, Peercount, Governancescore, Environmentpercentile,
|
||||
Animaltesting, Tobacco, Totalesg, Highestcontroversy, Esgperformance, Coal, Pesticides,
|
||||
Adult, Percentile, Peergroup, Smallarms, Environmentscore, Governancepercentile,
|
||||
Militarycontract. [Source: Yahoo Finance]
|
||||
""",
|
||||
)
|
||||
|
||||
try:
|
||||
ns_parser = parse_known_args_and_warn(parser, other_args)
|
||||
if not ns_parser:
|
||||
return
|
||||
yahoo_finance_view.display_sustainability(self.ticker)
|
||||
|
||||
except Exception as e:
|
||||
print(e, "\n")
|
||||
|
||||
def call_cal(self, other_args: List[str]):
|
||||
"""Process cal command"""
|
||||
yahoo_finance_view.calendar_earnings(other_args, self.ticker)
|
||||
parser = argparse.ArgumentParser(
|
||||
add_help=False,
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||
prog="cal",
|
||||
description="""
|
||||
Calendar earnings of the company. Including revenue and earnings estimates.
|
||||
[Source: Yahoo Finance]
|
||||
""",
|
||||
)
|
||||
|
||||
try:
|
||||
ns_parser = parse_known_args_and_warn(parser, other_args)
|
||||
if not ns_parser:
|
||||
return
|
||||
|
||||
yahoo_finance_view.display_calendar_earnings(ticker=self.ticker)
|
||||
except Exception as e:
|
||||
print(e, "\n")
|
||||
|
||||
def call_web(self, other_args: List[str]):
|
||||
"""Process web command"""
|
||||
yahoo_finance_view.web(other_args, self.ticker)
|
||||
parser = argparse.ArgumentParser(
|
||||
add_help=False,
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||
prog="web",
|
||||
description="""
|
||||
Opens company's website. [Source: Yahoo Finance]
|
||||
""",
|
||||
)
|
||||
try:
|
||||
ns_parser = parse_known_args_and_warn(parser, other_args)
|
||||
if not ns_parser:
|
||||
return
|
||||
yahoo_finance_view.open_web(self.ticker)
|
||||
except Exception as e:
|
||||
print(e, "\n")
|
||||
|
||||
def call_hq(self, other_args: List[str]):
|
||||
"""Process hq command"""
|
||||
yahoo_finance_view.headquarters(other_args, self.ticker)
|
||||
parser = argparse.ArgumentParser(
|
||||
add_help=False,
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||
prog="hq",
|
||||
description="""
|
||||
Opens in Google Maps HQ location of the company. [Source: Yahoo Finance]
|
||||
""",
|
||||
)
|
||||
|
||||
try:
|
||||
ns_parser = parse_known_args_and_warn(parser, other_args)
|
||||
if not ns_parser:
|
||||
return
|
||||
yahoo_finance_view.open_headquarters_map(self.ticker)
|
||||
except Exception as e:
|
||||
print(e, "\n")
|
||||
|
||||
def call_overview(self, other_args: List[str]):
|
||||
"""Process overview command"""
|
||||
av_view.overview(other_args, self.ticker)
|
||||
parser = argparse.ArgumentParser(
|
||||
add_help=False,
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||
prog="overview",
|
||||
description="""
|
||||
Prints an overview about the company. The following fields are expected:
|
||||
Symbol, Asset type, Name, Description, Exchange, Currency, Country, Sector, Industry,
|
||||
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. Also, the C i k field
|
||||
corresponds to Central Index Key, which can be used to search a company on
|
||||
https://www.sec.gov/edgar/searchedgar/cik.htm [Source: Alpha Vantage]
|
||||
""",
|
||||
)
|
||||
|
||||
try:
|
||||
ns_parser = parse_known_args_and_warn(parser, other_args)
|
||||
if not ns_parser:
|
||||
return
|
||||
|
||||
av_view.display_overview(self.ticker)
|
||||
except Exception as e:
|
||||
print(e, "\n")
|
||||
|
||||
def call_key(self, other_args: List[str]):
|
||||
"""Process overview command"""
|
||||
av_view.key(other_args, self.ticker)
|
||||
parser = argparse.ArgumentParser(
|
||||
add_help=False,
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||
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]
|
||||
""",
|
||||
)
|
||||
try:
|
||||
ns_parser = parse_known_args_and_warn(parser, other_args)
|
||||
if not ns_parser:
|
||||
return
|
||||
av_view.display_key(self.ticker)
|
||||
except Exception as e:
|
||||
print(e, "\n")
|
||||
|
||||
def call_income(self, other_args: List[str]):
|
||||
"""Process income command"""
|
||||
av_view.income_statement(other_args, self.ticker)
|
||||
parser = argparse.ArgumentParser(
|
||||
add_help=False,
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||
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,
|
||||
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(
|
||||
"-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, other_args, export_allowed=EXPORT_ONLY_RAW_DATA_ALLOWED
|
||||
)
|
||||
if not ns_parser:
|
||||
return
|
||||
av_view.display_income_statement(
|
||||
ticker=self.ticker,
|
||||
number=ns_parser.n_num,
|
||||
quarterly=ns_parser.b_quarter,
|
||||
export=ns_parser.export,
|
||||
)
|
||||
except Exception as e:
|
||||
print(e, "\n")
|
||||
|
||||
def call_balance(self, other_args: List[str]):
|
||||
"""Process balance command"""
|
||||
av_view.balance_sheet(other_args, self.ticker)
|
||||
parser = argparse.ArgumentParser(
|
||||
add_help=False,
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||
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 = parse_known_args_and_warn(
|
||||
parser, other_args, export_allowed=EXPORT_ONLY_RAW_DATA_ALLOWED
|
||||
)
|
||||
if not ns_parser:
|
||||
return
|
||||
av_view.display_balance_sheet(
|
||||
ticker=self.ticker,
|
||||
number=ns_parser.n_num,
|
||||
quarterly=ns_parser.b_quarter,
|
||||
export=ns_parser.export,
|
||||
)
|
||||
except Exception as e:
|
||||
print(e, "\n")
|
||||
|
||||
def call_cash(self, other_args: List[str]):
|
||||
"""Process cash command"""
|
||||
av_view.cash_flow(other_args, self.ticker)
|
||||
parser = argparse.ArgumentParser(
|
||||
add_help=False,
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||
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, other_args, export_allowed=EXPORT_ONLY_RAW_DATA_ALLOWED
|
||||
)
|
||||
if not ns_parser:
|
||||
return
|
||||
av_view.display_cash_flow(
|
||||
ticker=self.ticker,
|
||||
number=ns_parser.n_num,
|
||||
quarterly=ns_parser.b_quarter,
|
||||
export=ns_parser.export,
|
||||
)
|
||||
except Exception as e:
|
||||
print(e, "\n")
|
||||
|
||||
def call_earnings(self, other_args: List[str]):
|
||||
"""Process earnings command"""
|
||||
av_view.earnings(other_args, self.ticker)
|
||||
parser = argparse.ArgumentParser(
|
||||
add_help=False,
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||
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]
|
||||
""",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-q",
|
||||
"--quarter",
|
||||
action="store_true",
|
||||
default=False,
|
||||
dest="b_quarter",
|
||||
help="Quarter fundamental data flag.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-n",
|
||||
"--num",
|
||||
action="store",
|
||||
dest="n_num",
|
||||
type=check_positive,
|
||||
default=5,
|
||||
help="Number of latest info",
|
||||
)
|
||||
try:
|
||||
ns_parser = parse_known_args_and_warn(parser, other_args)
|
||||
if not ns_parser:
|
||||
return
|
||||
av_view.display_earnings(
|
||||
ticker=self.ticker,
|
||||
number=ns_parser.n_num,
|
||||
quarterly=ns_parser.b_quarter,
|
||||
)
|
||||
except Exception as e:
|
||||
print(e, "\n")
|
||||
|
||||
def call_fraud(self, other_args: List[str]):
|
||||
"""Process fraud command"""
|
||||
av_view.fraud(other_args, self.ticker)
|
||||
parser = argparse.ArgumentParser(
|
||||
add_help=False,
|
||||
formatter_class=argparse.RawTextHelpFormatter,
|
||||
prog="fraud",
|
||||
description=(
|
||||
"Mscore:\n------------------------------------------------\n"
|
||||
"The Beneish model is a statistical model that uses financial ratios calculated with"
|
||||
" accounting data of a specific company in order to check if it is likely (high"
|
||||
" probability) that the reported earnings of the company have been manipulated."
|
||||
" A score of -5 to -2.22 indicated a low chance of fraud, a score of -2.22 to -1.78"
|
||||
" indicates a moderate change of fraud, and a score above -1.78 indicated a high"
|
||||
" chance of fraud.[Source: Wikipedia]\n\nDSRI:\nDays Sales in Receivables Index"
|
||||
" gauges whether receivables and revenue are out of balance, a large number is"
|
||||
" expected to be associated with a higher likelihood that revenues and earnings are"
|
||||
" overstated.\n\nGMI:\nGross Margin Index shows if gross margins are deteriorating."
|
||||
" Research suggests that firms with worsening gross margin are more likely to engage"
|
||||
" in earnings management, therefore there should be a positive correlation between"
|
||||
" GMI and probability of earnings management.\n\nAQI:\nAsset Quality Index measures"
|
||||
" the proportion of assets where potential benefit is less certain. A positive"
|
||||
" relation between AQI and earnings manipulation is expected.\n\nSGI:\nSales Growth"
|
||||
" Index shows the amount of growth companies are having. Higher growth companies are"
|
||||
" more likely to commit fraud so there should be a positive relation between SGI and"
|
||||
" earnings management.\n\nDEPI:\nDepreciation Index is the ratio for the rate of"
|
||||
" depreciation. A DEPI greater than 1 shows that the depreciation rate has slowed and"
|
||||
" is positively correlated with earnings management.\n\nSGAI:\nSales General and"
|
||||
" Administrative Expenses Index measures the change in SG&A over sales. There should"
|
||||
" be a positive relationship between SGAI and earnings management.\n\nLVGI:\nLeverage"
|
||||
" Index represents change in leverage. A LVGI greater than one indicates a lower"
|
||||
" change of fraud.\n\nTATA: \nTotal Accruals to Total Assets is a proxy for the"
|
||||
" extent that cash underlies earnigns. A higher number is associated with a higher"
|
||||
" likelihood of manipulation.\n\n\n"
|
||||
"Zscore:\n------------------------------------------------\n"
|
||||
"The Zmijewski Score is a bankruptcy model used to predict a firm's bankruptcy in two"
|
||||
" years. The ratio uses in the Zmijewski score were determined by probit analysis ("
|
||||
"think of probit as probability unit). In this case, scores less than .5 represent a"
|
||||
" higher probability of default. One of the criticisms that Zmijewski made was that"
|
||||
" other bankruptcy scoring models oversampled distressed firms and favored situations"
|
||||
" with more complete data.[Source: YCharts]"
|
||||
),
|
||||
)
|
||||
try:
|
||||
ns_parser = parse_known_args_and_warn(parser, other_args)
|
||||
if not ns_parser:
|
||||
return
|
||||
av_view.display_fraud(self.ticker)
|
||||
except Exception as e:
|
||||
print(e, "\n")
|
||||
|
||||
def call_dcf(self, other_args: List[str]):
|
||||
"""Process dcf command"""
|
||||
@@ -272,7 +743,37 @@ Other Sources:
|
||||
|
||||
def call_warnings(self, other_args: List[str]):
|
||||
"""Process warnings command"""
|
||||
market_watch_view.sean_seah_warnings(other_args, self.ticker)
|
||||
parser = argparse.ArgumentParser(
|
||||
add_help=False,
|
||||
prog="warnings",
|
||||
description="""
|
||||
Sean Seah warnings. Check: Consistent historical earnings per share;
|
||||
Consistently high return on equity; Consistently high return on assets; 5x Net
|
||||
Income > Long-Term Debt; and Interest coverage ratio more than 3. See
|
||||
https://www.drwealth.com/gone-fishing-with-buffett-by-sean-seah/comment-page-1/
|
||||
[Source: Market Watch]
|
||||
""",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-d",
|
||||
"--debug",
|
||||
action="store_true",
|
||||
default=False,
|
||||
dest="b_debug",
|
||||
help="print insights into warnings calculation.",
|
||||
)
|
||||
|
||||
try:
|
||||
ns_parser = parse_known_args_and_warn(parser, other_args)
|
||||
if not ns_parser:
|
||||
return
|
||||
|
||||
market_watch_view.display_sean_seah_warnings(
|
||||
ticker=self.ticker, debug=ns_parser.b_debug
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
print(e, "\n")
|
||||
|
||||
def call_fmp(self, _):
|
||||
"""Process fmp command"""
|
||||
|
||||
@@ -12,6 +12,9 @@ from gamestonk_terminal.stocks.fundamental_analysis.financial_modeling_prep impo
|
||||
from gamestonk_terminal import feature_flags as gtff
|
||||
from gamestonk_terminal.helper_funcs import (
|
||||
get_flair,
|
||||
parse_known_args_and_warn,
|
||||
check_positive,
|
||||
EXPORT_ONLY_RAW_DATA_ALLOWED,
|
||||
)
|
||||
from gamestonk_terminal.menu import session
|
||||
|
||||
@@ -20,12 +23,8 @@ class FinancialModelingPrepController:
|
||||
"""Financial Modeling Prep Controller"""
|
||||
|
||||
# Command choices
|
||||
CHOICES = [
|
||||
"cls",
|
||||
"?",
|
||||
"help",
|
||||
"q",
|
||||
"quit",
|
||||
CHOICES = ["cls", "?", "help", "q", "quit"]
|
||||
CHOICES_COMMANDS = [
|
||||
"profile",
|
||||
"quote",
|
||||
"enterprise",
|
||||
@@ -37,6 +36,7 @@ class FinancialModelingPrepController:
|
||||
"ratios",
|
||||
"growth",
|
||||
]
|
||||
CHOICES += CHOICES_COMMANDS
|
||||
|
||||
def __init__(self, ticker: str, start: str, interval: str):
|
||||
"""Constructor
|
||||
@@ -135,43 +135,471 @@ Financial Modeling Prep:
|
||||
|
||||
def call_profile(self, other_args: List[str]):
|
||||
"""Process profile command"""
|
||||
fmp_view.profile(other_args, self.ticker)
|
||||
parser = argparse.ArgumentParser(
|
||||
add_help=False,
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||
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]
|
||||
""",
|
||||
)
|
||||
try:
|
||||
ns_parser = parse_known_args_and_warn(parser, other_args)
|
||||
if not ns_parser:
|
||||
return
|
||||
fmp_view.display_profile(self.ticker)
|
||||
except Exception as e:
|
||||
print(e, "\n")
|
||||
|
||||
def call_quote(self, other_args: List[str]):
|
||||
"""Process quote command"""
|
||||
fmp_view.quote(other_args, self.ticker)
|
||||
parser = argparse.ArgumentParser(
|
||||
add_help=False,
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||
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]
|
||||
""",
|
||||
)
|
||||
try:
|
||||
ns_parser = parse_known_args_and_warn(parser, other_args)
|
||||
if not ns_parser:
|
||||
return
|
||||
fmp_view.display_quote(self.ticker)
|
||||
except Exception as e:
|
||||
print(e, "\n")
|
||||
|
||||
def call_enterprise(self, other_args: List[str]):
|
||||
"""Process income command"""
|
||||
fmp_view.enterprise(other_args, self.ticker)
|
||||
parser = argparse.ArgumentParser(
|
||||
add_help=False,
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||
prog="enterprise",
|
||||
description="""
|
||||
Prints stock price, number of shares, market capitalization and
|
||||
enterprise value over time. The following fields are expected: Add total debt,
|
||||
Enterprise value, Market capitalization, Minus cash and cash equivalents, Number
|
||||
of shares, Stock price, and Symbol. [Source: Financial Modeling Prep]
|
||||
""",
|
||||
)
|
||||
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, other_args, export_allowed=EXPORT_ONLY_RAW_DATA_ALLOWED
|
||||
)
|
||||
if not ns_parser:
|
||||
return
|
||||
|
||||
fmp_view.display_enterprise(
|
||||
ticker=self.ticker,
|
||||
number=ns_parser.n_num,
|
||||
quarterly=ns_parser.b_quarter,
|
||||
export=ns_parser.export,
|
||||
)
|
||||
except Exception as e:
|
||||
print(e, "\n")
|
||||
|
||||
def call_dcf(self, other_args: List[str]):
|
||||
"""Process dcf command"""
|
||||
fmp_view.discounted_cash_flow(other_args, self.ticker)
|
||||
parser = argparse.ArgumentParser(
|
||||
add_help=False,
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||
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]
|
||||
""",
|
||||
)
|
||||
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, other_args, export_allowed=EXPORT_ONLY_RAW_DATA_ALLOWED
|
||||
)
|
||||
if not ns_parser:
|
||||
return
|
||||
fmp_view.display_discounted_cash_flow(
|
||||
ticker=self.ticker,
|
||||
number=ns_parser.n_num,
|
||||
quarterly=ns_parser.b_quarter,
|
||||
export=ns_parser.export,
|
||||
)
|
||||
except Exception as e:
|
||||
print(e, "\n")
|
||||
|
||||
def call_income(self, other_args: List[str]):
|
||||
"""Process income command"""
|
||||
fmp_view.income_statement(other_args, self.ticker)
|
||||
parser = argparse.ArgumentParser(
|
||||
add_help=False,
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||
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]
|
||||
""",
|
||||
)
|
||||
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, other_args, export_allowed=EXPORT_ONLY_RAW_DATA_ALLOWED
|
||||
)
|
||||
if not ns_parser:
|
||||
return
|
||||
fmp_view.display_income_statement(
|
||||
ticker=self.ticker,
|
||||
number=ns_parser.n_num,
|
||||
quarterly=ns_parser.b_quarter,
|
||||
export=ns_parser.export,
|
||||
)
|
||||
except Exception as e:
|
||||
print(e, "\n")
|
||||
|
||||
def call_balance(self, other_args: List[str]):
|
||||
"""Process balance command"""
|
||||
fmp_view.balance_sheet(other_args, self.ticker)
|
||||
parser = argparse.ArgumentParser(
|
||||
add_help=False,
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||
prog="bal",
|
||||
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: Financial Modeling Prep]
|
||||
""",
|
||||
)
|
||||
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, other_args, export_allowed=EXPORT_ONLY_RAW_DATA_ALLOWED
|
||||
)
|
||||
if not ns_parser:
|
||||
return
|
||||
fmp_view.display_balance_sheet(
|
||||
ticker=self.ticker,
|
||||
number=ns_parser.n_num,
|
||||
quarterly=ns_parser.b_quarter,
|
||||
export=ns_parser.export,
|
||||
)
|
||||
except Exception as e:
|
||||
print(e, "\n")
|
||||
|
||||
def call_cash(self, other_args: List[str]):
|
||||
"""Process cash command"""
|
||||
fmp_view.cash_flow(other_args, self.ticker)
|
||||
parser = argparse.ArgumentParser(
|
||||
add_help=False,
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||
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]
|
||||
""",
|
||||
)
|
||||
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, other_args, export_allowed=EXPORT_ONLY_RAW_DATA_ALLOWED
|
||||
)
|
||||
if not ns_parser:
|
||||
return
|
||||
fmp_view.display_cash_flow(
|
||||
ticker=self.ticker,
|
||||
number=ns_parser.n_num,
|
||||
quarterly=ns_parser.b_quarter,
|
||||
export=ns_parser.export,
|
||||
)
|
||||
except Exception as e:
|
||||
print(e, "\n")
|
||||
|
||||
def call_metrics(self, other_args: List[str]):
|
||||
"""Process metrics command"""
|
||||
fmp_view.key_metrics(other_args, self.ticker)
|
||||
parser = argparse.ArgumentParser(
|
||||
add_help=False,
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||
prog="metrics",
|
||||
description="""
|
||||
Prints a list of the key metrics of a company over time. This can be either
|
||||
quarterly or annually. This includes, among other things, Return on Equity (ROE),
|
||||
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 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]
|
||||
""",
|
||||
)
|
||||
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, other_args, export_allowed=EXPORT_ONLY_RAW_DATA_ALLOWED
|
||||
)
|
||||
if not ns_parser:
|
||||
return
|
||||
fmp_view.display_key_metrics(
|
||||
ticker=self.ticker,
|
||||
number=ns_parser.n_num,
|
||||
quarterly=ns_parser.b_quarter,
|
||||
export=ns_parser.export,
|
||||
)
|
||||
except Exception as e:
|
||||
print(e, "\n")
|
||||
|
||||
def call_ratios(self, other_args: List[str]):
|
||||
"""Process cash command"""
|
||||
fmp_view.financial_ratios(other_args, self.ticker)
|
||||
parser = argparse.ArgumentParser(
|
||||
add_help=False,
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||
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]
|
||||
""",
|
||||
)
|
||||
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, other_args, export_allowed=EXPORT_ONLY_RAW_DATA_ALLOWED
|
||||
)
|
||||
if not ns_parser:
|
||||
return
|
||||
fmp_view.display_financial_ratios(
|
||||
ticker=self.ticker,
|
||||
number=ns_parser.n_num,
|
||||
quarterly=ns_parser.b_quarter,
|
||||
export=ns_parser.export,
|
||||
)
|
||||
except Exception as e:
|
||||
print(e, "\n")
|
||||
|
||||
def call_growth(self, other_args: List[str]):
|
||||
"""Process cash command"""
|
||||
fmp_view.financial_statement_growth(other_args, self.ticker)
|
||||
parser = argparse.ArgumentParser(
|
||||
add_help=False,
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||
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]
|
||||
""",
|
||||
)
|
||||
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, other_args, export_allowed=EXPORT_ONLY_RAW_DATA_ALLOWED
|
||||
)
|
||||
if not ns_parser:
|
||||
return
|
||||
fmp_view.display_financial_statement_growth(
|
||||
ticker=self.ticker,
|
||||
number=ns_parser.n_num,
|
||||
quarterly=ns_parser.b_quarter,
|
||||
export=ns_parser.export,
|
||||
)
|
||||
except Exception as e:
|
||||
print(e, "\n")
|
||||
|
||||
|
||||
def menu(ticker: str, start: str, interval: str):
|
||||
|
||||
@@ -0,0 +1,319 @@
|
||||
""" Financial Modeling Prep Model"""
|
||||
__docformat__ = "numpy"
|
||||
from datetime import datetime
|
||||
|
||||
import FundamentalAnalysis as fa # Financial Modeling Prep
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
import valinvest
|
||||
from gamestonk_terminal import config_terminal as cfg
|
||||
from gamestonk_terminal.helper_funcs import long_number_format
|
||||
from gamestonk_terminal.stocks.fundamental_analysis.fa_helper import clean_df_index
|
||||
|
||||
|
||||
def get_score(ticker: str) -> np.number:
|
||||
"""Gets value score from fmp
|
||||
|
||||
Parameters
|
||||
----------
|
||||
ticker : str
|
||||
Stock ticker
|
||||
|
||||
Returns
|
||||
-------
|
||||
np.number
|
||||
Value score
|
||||
"""
|
||||
valstock = valinvest.Fundamental(ticker, cfg.API_KEY_FINANCIALMODELINGPREP)
|
||||
return 100 * (valstock.fscore() / 9)
|
||||
|
||||
|
||||
def get_profile(ticker: str) -> pd.DataFrame:
|
||||
"""Get ticker profile from FMP"""
|
||||
return fa.profile(ticker, cfg.API_KEY_FINANCIALMODELINGPREP)
|
||||
|
||||
|
||||
def get_quote(ticker) -> pd.DataFrame:
|
||||
"""Gets ticker quote from FMP"""
|
||||
df_fa = fa.quote(ticker, cfg.API_KEY_FINANCIALMODELINGPREP)
|
||||
|
||||
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])
|
||||
# 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()}"
|
||||
return df_fa
|
||||
|
||||
|
||||
def get_enterprise(ticker: str, number: int, quarterly: bool = False) -> pd.DataFrame:
|
||||
"""Financial Modeling Prep ticker enterprise
|
||||
|
||||
Parameters
|
||||
----------
|
||||
ticker : str
|
||||
Fundamental analysis ticker symbol
|
||||
number: int
|
||||
Number to get
|
||||
quarterly: bool
|
||||
Flag to get quarterly data
|
||||
|
||||
Returns
|
||||
----------
|
||||
pd.DataFrame:
|
||||
Dataframe of enterprise information
|
||||
"""
|
||||
|
||||
if quarterly:
|
||||
df_fa = fa.enterprise(
|
||||
ticker, cfg.API_KEY_FINANCIALMODELINGPREP, period="quarter"
|
||||
)
|
||||
else:
|
||||
df_fa = fa.enterprise(ticker, cfg.API_KEY_FINANCIALMODELINGPREP)
|
||||
|
||||
df_fa = clean_metrics_df(df_fa, num=number, mask=False)
|
||||
return df_fa
|
||||
|
||||
|
||||
def get_dcf(ticker: str, number: int, quarterly: bool = False) -> pd.DataFrame:
|
||||
"""Get stocks dcf from FMP
|
||||
|
||||
Parameters
|
||||
----------
|
||||
ticker : str
|
||||
Stock ticker
|
||||
number : int
|
||||
Number to get
|
||||
quarterly : bool, optional
|
||||
Flag to get quarterly data, by default False
|
||||
|
||||
Returns
|
||||
-------
|
||||
pd.DataFrame
|
||||
Dataframe of dcf data
|
||||
"""
|
||||
if quarterly:
|
||||
df_fa = fa.discounted_cash_flow(
|
||||
ticker, cfg.API_KEY_FINANCIALMODELINGPREP, period="quarter"
|
||||
)
|
||||
else:
|
||||
df_fa = fa.discounted_cash_flow(ticker, cfg.API_KEY_FINANCIALMODELINGPREP)
|
||||
|
||||
df_fa = clean_metrics_df(df_fa, num=number, mask=False)
|
||||
return df_fa
|
||||
|
||||
|
||||
def get_income(ticker: str, number: int, quarterly: bool = False) -> pd.DataFrame:
|
||||
"""Get income statements
|
||||
|
||||
Parameters
|
||||
----------
|
||||
ticker : str
|
||||
Stock ticker
|
||||
number : int
|
||||
Number to get
|
||||
quarterly : bool, optional
|
||||
Flag to get quarterly data, by default False
|
||||
|
||||
Returns
|
||||
-------
|
||||
pd.DataFrame
|
||||
Dataframe of income statements
|
||||
"""
|
||||
if quarterly:
|
||||
df_fa = fa.income_statement(
|
||||
ticker, cfg.API_KEY_FINANCIALMODELINGPREP, period="quarter"
|
||||
)
|
||||
else:
|
||||
df_fa = fa.income_statement(ticker, cfg.API_KEY_FINANCIALMODELINGPREP)
|
||||
|
||||
df_fa = clean_metrics_df(df_fa, num=number)
|
||||
return df_fa
|
||||
|
||||
|
||||
def get_balance(ticker: str, number: int, quarterly: bool = False) -> pd.DataFrame:
|
||||
"""Get balance sheets
|
||||
|
||||
Parameters
|
||||
----------
|
||||
ticker : str
|
||||
Stock ticker
|
||||
number : int
|
||||
Number to get
|
||||
quarterly : bool, optional
|
||||
Flag to get quarterly data, by default False
|
||||
|
||||
Returns
|
||||
-------
|
||||
pd.DataFrame
|
||||
Dataframe of balance sheets
|
||||
"""
|
||||
if quarterly:
|
||||
df_fa = fa.balance_sheet_statement(
|
||||
ticker, cfg.API_KEY_FINANCIALMODELINGPREP, period="quarter"
|
||||
)
|
||||
else:
|
||||
df_fa = fa.balance_sheet_statement(ticker, cfg.API_KEY_FINANCIALMODELINGPREP)
|
||||
|
||||
df_fa = clean_metrics_df(df_fa, num=number)
|
||||
return df_fa
|
||||
|
||||
|
||||
def get_cash(ticker: str, number: int, quarterly: bool = False) -> pd.DataFrame:
|
||||
"""Get cash flow
|
||||
|
||||
Parameters
|
||||
----------
|
||||
ticker : str
|
||||
Stock ticker
|
||||
number : int
|
||||
Number to get
|
||||
quarterly : bool, optional
|
||||
Flag to get quarterly data, by default False
|
||||
|
||||
Returns
|
||||
-------
|
||||
pd.DataFrame
|
||||
Dataframe of company cash flow
|
||||
"""
|
||||
if quarterly:
|
||||
df_fa = fa.cash_flow_statement(
|
||||
ticker, cfg.API_KEY_FINANCIALMODELINGPREP, period="quarter"
|
||||
)
|
||||
else:
|
||||
df_fa = fa.cash_flow_statement(ticker, cfg.API_KEY_FINANCIALMODELINGPREP)
|
||||
|
||||
df_fa = clean_metrics_df(df_fa, num=number)
|
||||
return df_fa
|
||||
|
||||
|
||||
def get_key_metrics(ticker: str, number: int, quarterly: bool = False) -> pd.DataFrame:
|
||||
"""Get key metrics
|
||||
|
||||
Parameters
|
||||
----------
|
||||
ticker : str
|
||||
Stock ticker
|
||||
number : int
|
||||
Number to get
|
||||
quarterly : bool, optional
|
||||
Flag to get quarterly data, by default False
|
||||
|
||||
Returns
|
||||
-------
|
||||
pd.DataFrame
|
||||
Dataframe of key metrics
|
||||
"""
|
||||
if quarterly:
|
||||
df_fa = fa.key_metrics(
|
||||
ticker, cfg.API_KEY_FINANCIALMODELINGPREP, period="quarter"
|
||||
)
|
||||
else:
|
||||
df_fa = fa.key_metrics(ticker, cfg.API_KEY_FINANCIALMODELINGPREP)
|
||||
|
||||
df_fa = clean_metrics_df(df_fa, num=number)
|
||||
return df_fa
|
||||
|
||||
|
||||
def get_key_ratios(ticker: str, number: int, quarterly: bool = False) -> pd.DataFrame:
|
||||
"""Get key ratios
|
||||
|
||||
Parameters
|
||||
----------
|
||||
ticker : str
|
||||
Stock ticker
|
||||
number : int
|
||||
Number to get
|
||||
quarterly : bool, optional
|
||||
Flag to get quarterly data, by default False
|
||||
|
||||
Returns
|
||||
-------
|
||||
pd.DataFrame
|
||||
Dataframe of key ratios
|
||||
"""
|
||||
if quarterly:
|
||||
df_fa = fa.financial_ratios(
|
||||
ticker, cfg.API_KEY_FINANCIALMODELINGPREP, period="quarter"
|
||||
)
|
||||
else:
|
||||
df_fa = fa.financial_ratios(ticker, cfg.API_KEY_FINANCIALMODELINGPREP)
|
||||
|
||||
df_fa = clean_metrics_df(df_fa, num=number)
|
||||
return df_fa
|
||||
|
||||
|
||||
def get_financial_growth(
|
||||
ticker: str, number: int, quarterly: bool = False
|
||||
) -> pd.DataFrame:
|
||||
"""Get financial statement growth
|
||||
|
||||
Parameters
|
||||
----------
|
||||
ticker : str
|
||||
Stock ticker
|
||||
number : int
|
||||
Number to get
|
||||
quarterly : bool, optional
|
||||
Flag to get quarterly data, by default False
|
||||
|
||||
Returns
|
||||
-------
|
||||
pd.DataFrame
|
||||
Dataframe of financial statement growth
|
||||
"""
|
||||
if quarterly:
|
||||
df_fa = fa.financial_statement_growth(
|
||||
ticker, cfg.API_KEY_FINANCIALMODELINGPREP, period="quarter"
|
||||
)
|
||||
else:
|
||||
df_fa = fa.financial_statement_growth(ticker, cfg.API_KEY_FINANCIALMODELINGPREP)
|
||||
|
||||
df_fa = clean_metrics_df(df_fa, num=number)
|
||||
return df_fa
|
||||
|
||||
|
||||
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()
|
||||
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
|
||||
@@ -1,22 +1,19 @@
|
||||
""" Financial Modeling Prep View """
|
||||
__docformat__ = "numpy"
|
||||
|
||||
import argparse
|
||||
from typing import List
|
||||
from datetime import datetime
|
||||
import os
|
||||
|
||||
import pandas as pd
|
||||
import valinvest
|
||||
import FundamentalAnalysis as fa # Financial Modeling Prep
|
||||
from gamestonk_terminal import config_terminal as cfg
|
||||
from gamestonk_terminal.stocks.fundamental_analysis.fa_helper import clean_df_index
|
||||
from gamestonk_terminal.helper_funcs import (
|
||||
long_number_format,
|
||||
check_positive,
|
||||
parse_known_args_and_warn,
|
||||
from tabulate import tabulate
|
||||
|
||||
from gamestonk_terminal.helper_funcs import export_data
|
||||
from gamestonk_terminal.stocks.fundamental_analysis.financial_modeling_prep import (
|
||||
fmp_model,
|
||||
)
|
||||
import gamestonk_terminal.feature_flags as gtff
|
||||
|
||||
|
||||
def valinvest_score(other_args: List[str], ticker: str):
|
||||
def valinvest_score(ticker: str):
|
||||
"""Value investing tool based on Warren Buffett, Joseph Piotroski and Benjamin Graham thoughts [Source: FMP]
|
||||
|
||||
Parameters
|
||||
@@ -26,30 +23,12 @@ def valinvest_score(other_args: List[str], ticker: str):
|
||||
ticker : str
|
||||
Fundamental analysis ticker symbol
|
||||
"""
|
||||
parser = argparse.ArgumentParser(
|
||||
add_help=False,
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||
prog="score",
|
||||
description="""
|
||||
Value investing tool based on Warren Buffett, Joseph Piotroski and Benjamin Graham thoughts [Source: FMP]
|
||||
""",
|
||||
)
|
||||
|
||||
try:
|
||||
ns_parser = parse_known_args_and_warn(parser, other_args)
|
||||
if not ns_parser:
|
||||
return
|
||||
|
||||
valstock = valinvest.Fundamental(ticker, cfg.API_KEY_FINANCIALMODELINGPREP)
|
||||
score = 100 * (valstock.fscore() / 9)
|
||||
print(f"Score: {score:.2f}".rstrip("0").rstrip(".") + " %")
|
||||
print("")
|
||||
|
||||
except Exception as e:
|
||||
print(e, "\n")
|
||||
score = fmp_model.get_score(ticker)
|
||||
print(f"Score: {score:.2f}".rstrip("0").rstrip(".") + " %")
|
||||
print("")
|
||||
|
||||
|
||||
def profile(other_args: List[str], ticker: str):
|
||||
def display_profile(ticker: str):
|
||||
"""Financial Modeling Prep ticker profile
|
||||
|
||||
Parameters
|
||||
@@ -59,718 +38,289 @@ def profile(other_args: List[str], ticker: str):
|
||||
ticker : str
|
||||
Fundamental analysis ticker symbol
|
||||
"""
|
||||
parser = argparse.ArgumentParser(
|
||||
add_help=False,
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||
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]
|
||||
""",
|
||||
)
|
||||
profile = fmp_model.get_profile(ticker)
|
||||
if gtff.USE_TABULATE_DF:
|
||||
print(
|
||||
tabulate(
|
||||
profile.drop(index=["description", "image"]),
|
||||
headers=[],
|
||||
tablefmt="fancy_grid",
|
||||
)
|
||||
)
|
||||
else:
|
||||
print(profile.drop(index=["description", "image"]).to_string(header=False))
|
||||
|
||||
try:
|
||||
ns_parser = parse_known_args_and_warn(parser, other_args)
|
||||
if not ns_parser:
|
||||
return
|
||||
|
||||
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))
|
||||
print(f"\nImage: {df_fa.loc['Image'][0]}")
|
||||
print(f"\nDescription: {df_fa.loc['Description'][0]}")
|
||||
print("")
|
||||
|
||||
except Exception as e:
|
||||
print(e, "\n")
|
||||
print(f"\nImage: {profile.loc['image'][0]}")
|
||||
print(f"\nDescription: {profile.loc['description'][0]}")
|
||||
print("")
|
||||
|
||||
|
||||
def quote(other_args: List[str], ticker: str):
|
||||
def display_quote(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,
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||
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]
|
||||
""",
|
||||
)
|
||||
|
||||
try:
|
||||
ns_parser = parse_known_args_and_warn(parser, other_args)
|
||||
if not ns_parser:
|
||||
return
|
||||
|
||||
df_fa = fa.quote(ticker, cfg.API_KEY_FINANCIALMODELINGPREP)
|
||||
|
||||
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])
|
||||
# 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:
|
||||
print(e, "\n")
|
||||
quote = fmp_model.get_quote(ticker)
|
||||
if gtff.USE_TABULATE_DF:
|
||||
print(tabulate(quote, headers=[], tablefmt="fancy_grid"))
|
||||
else:
|
||||
print(quote.to_string(header=False))
|
||||
print("")
|
||||
|
||||
|
||||
def enterprise(other_args: List[str], ticker: str):
|
||||
def display_enterprise(
|
||||
ticker: str, number: int, quarterly: bool = False, export: str = ""
|
||||
):
|
||||
"""Financial Modeling Prep ticker enterprise
|
||||
|
||||
Parameters
|
||||
----------
|
||||
other_args : List[str]
|
||||
argparse other args
|
||||
ticker : str
|
||||
Fundamental analysis ticker symbol
|
||||
number: int
|
||||
Number to get
|
||||
quarterly: bool
|
||||
Flag to get quarterly data
|
||||
export: str
|
||||
Format to export data
|
||||
"""
|
||||
parser = argparse.ArgumentParser(
|
||||
add_help=False,
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||
prog="enterprise",
|
||||
description="""
|
||||
Prints stock price, number of shares, market capitalization and
|
||||
enterprise value over time. The following fields are expected: Add total debt,
|
||||
Enterprise value, Market capitalization, Minus cash and cash equivalents, Number
|
||||
of shares, Stock price, and Symbol. [Source: Financial Modeling Prep]
|
||||
""",
|
||||
)
|
||||
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, other_args)
|
||||
if not ns_parser:
|
||||
return
|
||||
|
||||
if ns_parser.n_num == 1:
|
||||
pd.set_option("display.max_colwidth", None)
|
||||
else:
|
||||
pd.options.display.max_colwidth = 40
|
||||
|
||||
if ns_parser.b_quarter:
|
||||
df_fa = fa.enterprise(
|
||||
ticker, cfg.API_KEY_FINANCIALMODELINGPREP, period="quarter"
|
||||
)
|
||||
else:
|
||||
df_fa = fa.enterprise(ticker, cfg.API_KEY_FINANCIALMODELINGPREP)
|
||||
|
||||
df_fa = clean_metrics_df(df_fa, num=ns_parser.n_num, mask=False)
|
||||
print(df_fa)
|
||||
print("")
|
||||
|
||||
except Exception as e:
|
||||
print(e, "\n")
|
||||
df_fa = fmp_model.get_enterprise(ticker, number, quarterly)
|
||||
df_fa = df_fa[df_fa.columns[::-1]]
|
||||
if gtff.USE_TABULATE_DF:
|
||||
print(tabulate(df_fa, headers=df_fa.columns, tablefmt="fancy_grid"))
|
||||
else:
|
||||
print(df_fa.to_string())
|
||||
print("")
|
||||
export_data(export, os.path.dirname(os.path.abspath(__file__)), "enterprise", df_fa)
|
||||
|
||||
|
||||
def discounted_cash_flow(other_args: List[str], ticker: str):
|
||||
def display_discounted_cash_flow(
|
||||
ticker: str, number: int, quarterly: bool = False, export: str = ""
|
||||
):
|
||||
"""Financial Modeling Prep ticker discounted cash flow
|
||||
|
||||
Parameters
|
||||
----------
|
||||
other_args : List[str]
|
||||
argparse other args
|
||||
ticker : str
|
||||
Fundamental analysis ticker symbol
|
||||
number: int
|
||||
Number to get
|
||||
quarterly: bool
|
||||
Flag to get quarterly data
|
||||
export: str
|
||||
Format to export data
|
||||
"""
|
||||
parser = argparse.ArgumentParser(
|
||||
add_help=False,
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||
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]
|
||||
""",
|
||||
)
|
||||
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.",
|
||||
)
|
||||
dcf = fmp_model.get_dcf(ticker, number, quarterly)
|
||||
dcf = dcf[dcf.columns[::-1]]
|
||||
if gtff.USE_TABULATE_DF:
|
||||
print(tabulate(dcf, headers=[], tablefmt="fancy_grid"))
|
||||
else:
|
||||
print(dcf.to_string())
|
||||
|
||||
try:
|
||||
ns_parser = parse_known_args_and_warn(parser, other_args)
|
||||
if not ns_parser:
|
||||
return
|
||||
|
||||
if ns_parser.n_num == 1:
|
||||
pd.set_option("display.max_colwidth", None)
|
||||
else:
|
||||
pd.options.display.max_colwidth = 40
|
||||
|
||||
if ns_parser.b_quarter:
|
||||
df_fa = fa.discounted_cash_flow(
|
||||
ticker, cfg.API_KEY_FINANCIALMODELINGPREP, period="quarter"
|
||||
)
|
||||
else:
|
||||
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)
|
||||
print(df_fa)
|
||||
print("")
|
||||
|
||||
except Exception as e:
|
||||
print(e, "\n")
|
||||
print("")
|
||||
export_data(export, os.path.dirname(os.path.abspath(__file__)), "dcf", dcf)
|
||||
|
||||
|
||||
def income_statement(other_args: List[str], ticker: str):
|
||||
def display_income_statement(
|
||||
ticker: str, number: int, quarterly: bool = False, export: str = ""
|
||||
):
|
||||
"""Financial Modeling Prep ticker income statement
|
||||
|
||||
Parameters
|
||||
----------
|
||||
other_args : List[str]
|
||||
argparse other args
|
||||
ticker : str
|
||||
Fundamental analysis ticker symbol
|
||||
number: int
|
||||
Number to get
|
||||
quarterly: bool
|
||||
Flag to get quarterly data
|
||||
export: str
|
||||
Format to export data
|
||||
"""
|
||||
parser = argparse.ArgumentParser(
|
||||
add_help=False,
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||
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]
|
||||
""",
|
||||
)
|
||||
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, other_args)
|
||||
if not ns_parser:
|
||||
return
|
||||
|
||||
if ns_parser.n_num == 1:
|
||||
pd.set_option("display.max_colwidth", None)
|
||||
else:
|
||||
pd.options.display.max_colwidth = 40
|
||||
|
||||
if ns_parser.b_quarter:
|
||||
df_fa = fa.income_statement(
|
||||
ticker, cfg.API_KEY_FINANCIALMODELINGPREP, period="quarter"
|
||||
income = fmp_model.get_income(ticker, number, quarterly)
|
||||
income = income[income.columns[::-1]]
|
||||
if gtff.USE_TABULATE_DF:
|
||||
print(
|
||||
tabulate(
|
||||
income.drop(index=["Final link", "Link"]),
|
||||
headers=income.columns,
|
||||
tablefmt="fancy_grid",
|
||||
)
|
||||
else:
|
||||
df_fa = fa.income_statement(ticker, cfg.API_KEY_FINANCIALMODELINGPREP)
|
||||
)
|
||||
|
||||
df_fa = clean_metrics_df(df_fa, num=ns_parser.n_num)
|
||||
else:
|
||||
|
||||
print(df_fa.drop(index=["Final link", "Link"]).to_string())
|
||||
print(income.drop(index=["Final link", "Link"]).to_string())
|
||||
|
||||
pd.set_option("display.max_colwidth", None)
|
||||
print("")
|
||||
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:
|
||||
print(e, "\n")
|
||||
pd.set_option("display.max_colwidth", None)
|
||||
print("")
|
||||
print(income.loc["Final link"].to_frame().to_string())
|
||||
print("")
|
||||
print(income.loc["Link"].to_frame().to_string())
|
||||
print("")
|
||||
export_data(export, os.path.dirname(os.path.abspath(__file__)), "income", income)
|
||||
|
||||
|
||||
def balance_sheet(other_args: List[str], ticker: str):
|
||||
def display_balance_sheet(
|
||||
ticker: str, number: int, quarterly: bool = False, export: str = ""
|
||||
):
|
||||
"""Financial Modeling Prep ticker balance sheet
|
||||
|
||||
Parameters
|
||||
----------
|
||||
other_args : List[str]
|
||||
argparse other args
|
||||
ticker : str
|
||||
Fundamental analysis ticker symbol
|
||||
number: int
|
||||
Number to get
|
||||
quarterly: bool
|
||||
Flag to get quarterly data
|
||||
export: str
|
||||
Format to export data
|
||||
"""
|
||||
parser = argparse.ArgumentParser(
|
||||
add_help=False,
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||
prog="bal",
|
||||
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: Financial Modeling Prep]
|
||||
""",
|
||||
)
|
||||
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, other_args)
|
||||
if not ns_parser:
|
||||
return
|
||||
|
||||
if ns_parser.n_num == 1:
|
||||
pd.set_option("display.max_colwidth", None)
|
||||
else:
|
||||
pd.options.display.max_colwidth = 40
|
||||
|
||||
if ns_parser.b_quarter:
|
||||
df_fa = fa.balance_sheet_statement(
|
||||
ticker, cfg.API_KEY_FINANCIALMODELINGPREP, period="quarter"
|
||||
)
|
||||
else:
|
||||
df_fa = fa.balance_sheet_statement(
|
||||
ticker, cfg.API_KEY_FINANCIALMODELINGPREP
|
||||
balance = fmp_model.get_balance(ticker, number, quarterly)
|
||||
balance = balance[balance.columns[::-1]]
|
||||
if gtff.USE_TABULATE_DF:
|
||||
print(
|
||||
tabulate(
|
||||
balance.drop(index=["Final link", "Link"]),
|
||||
headers=balance.columns,
|
||||
tablefmt="fancy_grid",
|
||||
)
|
||||
)
|
||||
|
||||
df_fa = clean_metrics_df(df_fa, num=ns_parser.n_num)
|
||||
else:
|
||||
print(balance.drop(index=["Final link", "Link"]).to_string())
|
||||
|
||||
print(df_fa.drop(index=["Final link", "Link"]).to_string())
|
||||
|
||||
pd.set_option("display.max_colwidth", None)
|
||||
print("")
|
||||
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:
|
||||
print(e, "\n")
|
||||
pd.set_option("display.max_colwidth", None)
|
||||
print("")
|
||||
print(balance.loc["Final link"].to_frame().to_string())
|
||||
print("")
|
||||
print(balance.loc["Link"].to_frame().to_string())
|
||||
print("")
|
||||
export_data(export, os.path.dirname(os.path.abspath(__file__)), "balance", balance)
|
||||
|
||||
|
||||
def cash_flow(other_args: List[str], ticker: str):
|
||||
def display_cash_flow(
|
||||
ticker: str, number: int, quarterly: bool = False, export: str = ""
|
||||
):
|
||||
"""Financial Modeling Prep ticker cash flow
|
||||
|
||||
Parameters
|
||||
----------
|
||||
other_args : List[str]
|
||||
argparse other args
|
||||
ticker : str
|
||||
Fundamental analysis ticker symbol
|
||||
number: int
|
||||
Number to get
|
||||
quarterly: bool
|
||||
Flag to get quarterly data
|
||||
export: str
|
||||
Format to export data
|
||||
"""
|
||||
parser = argparse.ArgumentParser(
|
||||
add_help=False,
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||
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]
|
||||
""",
|
||||
)
|
||||
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, other_args)
|
||||
if not ns_parser:
|
||||
return
|
||||
|
||||
if ns_parser.n_num == 1:
|
||||
pd.set_option("display.max_colwidth", None)
|
||||
else:
|
||||
pd.options.display.max_colwidth = 40
|
||||
|
||||
if ns_parser.b_quarter:
|
||||
df_fa = fa.cash_flow_statement(
|
||||
ticker, cfg.API_KEY_FINANCIALMODELINGPREP, period="quarter"
|
||||
cash = fmp_model.get_cash(ticker, number, quarterly)
|
||||
cash = cash[cash.columns[::-1]]
|
||||
if gtff.USE_TABULATE_DF:
|
||||
print(
|
||||
tabulate(
|
||||
cash.drop(index=["Final link", "Link"]),
|
||||
headers=cash.columns,
|
||||
tablefmt="fancy_grid",
|
||||
)
|
||||
else:
|
||||
df_fa = fa.cash_flow_statement(ticker, cfg.API_KEY_FINANCIALMODELINGPREP)
|
||||
)
|
||||
else:
|
||||
print(cash.drop(index=["Final link", "Link"]).to_string())
|
||||
|
||||
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", None)
|
||||
print("")
|
||||
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:
|
||||
print(e, "\n")
|
||||
pd.set_option("display.max_colwidth", None)
|
||||
print("")
|
||||
print(cash.loc["Final link"].to_frame().to_string())
|
||||
print("")
|
||||
print(cash.loc["Link"].to_frame().to_string())
|
||||
print("")
|
||||
export_data(export, os.path.dirname(os.path.abspath(__file__)), "cash", cash)
|
||||
|
||||
|
||||
def key_metrics(other_args: List[str], ticker: str):
|
||||
def display_key_metrics(
|
||||
ticker: str, number: int, quarterly: bool = False, export: str = ""
|
||||
):
|
||||
"""Financial Modeling Prep ticker key metrics
|
||||
|
||||
Parameters
|
||||
----------
|
||||
other_args : List[str]
|
||||
argparse other args
|
||||
ticker : str
|
||||
Fundamental analysis ticker symbol
|
||||
number: int
|
||||
Number to get
|
||||
quarterly: bool
|
||||
Flag to get quarterly data
|
||||
export: str
|
||||
Format to export data
|
||||
"""
|
||||
parser = argparse.ArgumentParser(
|
||||
add_help=False,
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||
prog="metrics",
|
||||
description="""
|
||||
Prints a list of the key metrics of a company over time. This can be either
|
||||
quarterly or annually. This includes, among other things, Return on Equity (ROE),
|
||||
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 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]
|
||||
""",
|
||||
)
|
||||
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.",
|
||||
key_metrics = fmp_model.get_key_metrics(ticker, number, quarterly)
|
||||
key_metrics = key_metrics[key_metrics.columns[::-1]]
|
||||
if gtff.USE_TABULATE_DF:
|
||||
print(tabulate(key_metrics, headers=key_metrics.columns, tablefmt="fancy_grid"))
|
||||
else:
|
||||
print(key_metrics.to_string())
|
||||
print("")
|
||||
export_data(
|
||||
export, os.path.dirname(os.path.abspath(__file__)), "metrics", key_metrics
|
||||
)
|
||||
|
||||
try:
|
||||
ns_parser = parse_known_args_and_warn(parser, other_args)
|
||||
if not ns_parser:
|
||||
return
|
||||
|
||||
if ns_parser.n_num == 1:
|
||||
pd.set_option("display.max_colwidth", None)
|
||||
else:
|
||||
pd.options.display.max_colwidth = 50
|
||||
|
||||
if ns_parser.b_quarter:
|
||||
df_fa = fa.key_metrics(
|
||||
ticker, cfg.API_KEY_FINANCIALMODELINGPREP, period="quarter"
|
||||
)
|
||||
else:
|
||||
df_fa = fa.key_metrics(ticker, cfg.API_KEY_FINANCIALMODELINGPREP)
|
||||
|
||||
df_fa = clean_metrics_df(df_fa, num=ns_parser.n_num)
|
||||
print(df_fa)
|
||||
print("")
|
||||
|
||||
except Exception as e:
|
||||
print(e, "\n")
|
||||
|
||||
|
||||
def financial_ratios(other_args: List[str], ticker: str):
|
||||
def display_financial_ratios(
|
||||
ticker: str, number: int, quarterly: bool = False, export: str = ""
|
||||
):
|
||||
"""Financial Modeling Prep ticker ratios
|
||||
|
||||
Parameters
|
||||
----------
|
||||
other_args : List[str]
|
||||
argparse other args
|
||||
ticker : str
|
||||
Fundamental analysis ticker symbol
|
||||
number: int
|
||||
Number to get
|
||||
quarterly: bool
|
||||
Flag to get quarterly data
|
||||
export: str
|
||||
Format to export data
|
||||
"""
|
||||
parser = argparse.ArgumentParser(
|
||||
add_help=False,
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||
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]
|
||||
""",
|
||||
)
|
||||
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.",
|
||||
ratios = fmp_model.get_key_ratios(ticker, number, quarterly)
|
||||
ratios = ratios[ratios.columns[::-1]]
|
||||
if gtff.USE_TABULATE_DF:
|
||||
print(tabulate(ratios, headers=ratios.columns, tablefmt="fancy_grid"))
|
||||
else:
|
||||
|
||||
print(ratios.to_string())
|
||||
print("")
|
||||
export_data(
|
||||
export, os.path.dirname(os.path.abspath(__file__)), "grratiosowth", ratios
|
||||
)
|
||||
|
||||
try:
|
||||
ns_parser = parse_known_args_and_warn(parser, other_args)
|
||||
if not ns_parser:
|
||||
return
|
||||
|
||||
if ns_parser.n_num == 1:
|
||||
pd.set_option("display.max_colwidth", None)
|
||||
else:
|
||||
pd.options.display.max_colwidth = 40
|
||||
|
||||
if ns_parser.b_quarter:
|
||||
df_fa = fa.financial_ratios(
|
||||
ticker, cfg.API_KEY_FINANCIALMODELINGPREP, period="quarter"
|
||||
)
|
||||
else:
|
||||
df_fa = fa.financial_ratios(ticker, cfg.API_KEY_FINANCIALMODELINGPREP)
|
||||
|
||||
df_fa = clean_metrics_df(df_fa, num=ns_parser.n_num)
|
||||
print(df_fa)
|
||||
print("")
|
||||
|
||||
except Exception as e:
|
||||
print(e, "\n")
|
||||
|
||||
|
||||
def financial_statement_growth(other_args: List[str], ticker: str):
|
||||
def display_financial_statement_growth(
|
||||
ticker: str, number: int, quarterly: bool = False, export: str = ""
|
||||
):
|
||||
"""Financial Modeling Prep ticker growth
|
||||
|
||||
Parameters
|
||||
----------
|
||||
other_args : List[str]
|
||||
argparse other args
|
||||
ticker : str
|
||||
Fundamental analysis ticker symbol
|
||||
number: int
|
||||
Number to get
|
||||
quarterly: bool
|
||||
Flag to get quarterly data
|
||||
export: str
|
||||
Format to export data
|
||||
"""
|
||||
parser = argparse.ArgumentParser(
|
||||
add_help=False,
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||
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]
|
||||
""",
|
||||
)
|
||||
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.",
|
||||
)
|
||||
growth = fmp_model.get_financial_growth(ticker, number, quarterly)
|
||||
growth = growth[growth.columns[::-1]]
|
||||
if gtff.USE_TABULATE_DF:
|
||||
print(tabulate(growth, headers=growth.columns, tablefmt="fancy_grid"))
|
||||
else:
|
||||
|
||||
try:
|
||||
ns_parser = parse_known_args_and_warn(parser, other_args)
|
||||
if not ns_parser:
|
||||
return
|
||||
|
||||
if ns_parser.n_num == 1:
|
||||
pd.set_option("display.max_colwidth", None)
|
||||
else:
|
||||
pd.options.display.max_colwidth = 50
|
||||
|
||||
if ns_parser.b_quarter:
|
||||
df_fa = fa.financial_statement_growth(
|
||||
ticker, cfg.API_KEY_FINANCIALMODELINGPREP, period="quarter"
|
||||
)
|
||||
else:
|
||||
df_fa = fa.financial_statement_growth(
|
||||
ticker, cfg.API_KEY_FINANCIALMODELINGPREP
|
||||
)
|
||||
|
||||
df_fa = clean_metrics_df(df_fa, num=ns_parser.n_num)
|
||||
print(df_fa)
|
||||
print("")
|
||||
|
||||
except Exception as e:
|
||||
print(e, "\n")
|
||||
|
||||
|
||||
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()
|
||||
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
|
||||
print(growth.to_string())
|
||||
print("")
|
||||
export_data(export, os.path.dirname(os.path.abspath(__file__)), "growth", growth)
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
"""Finviz Model"""
|
||||
__docformat__ = "numpy"
|
||||
|
||||
import finviz
|
||||
import pandas as pd
|
||||
|
||||
|
||||
def get_data(ticker: str) -> pd.DataFrame:
|
||||
"""Get fundamental data from finviz
|
||||
|
||||
Parameters
|
||||
----------
|
||||
ticker : str
|
||||
Stock ticker
|
||||
|
||||
Returns
|
||||
-------
|
||||
pd.DataFrame
|
||||
DataFrame of fundamental data
|
||||
"""
|
||||
d_finviz_stock = finviz.get_stock(ticker)
|
||||
df_fa = pd.DataFrame.from_dict(d_finviz_stock, orient="index", columns=["Values"])
|
||||
return df_fa[df_fa.Values != "-"]
|
||||
@@ -1,55 +1,31 @@
|
||||
""" FinViz View """
|
||||
__docformat__ = "numpy"
|
||||
|
||||
import argparse
|
||||
from typing import List
|
||||
import finviz
|
||||
import pandas as pd
|
||||
import os
|
||||
|
||||
from gamestonk_terminal.helper_funcs import parse_known_args_and_warn
|
||||
from tabulate import tabulate
|
||||
|
||||
from gamestonk_terminal import feature_flags as gtff
|
||||
from gamestonk_terminal.helper_funcs import export_data
|
||||
from gamestonk_terminal.stocks.fundamental_analysis import finviz_model
|
||||
|
||||
|
||||
def screener(other_args: List[str], ticker: str):
|
||||
def display_screen_data(ticker: str, export: str = ""):
|
||||
"""FinViz ticker screener
|
||||
|
||||
Parameters
|
||||
----------
|
||||
other_args : List[str]
|
||||
argparse other args
|
||||
ticker : str
|
||||
Fundamental analysis ticker symbol
|
||||
Stock ticker
|
||||
export : str
|
||||
Format to export data
|
||||
"""
|
||||
parser = argparse.ArgumentParser(
|
||||
add_help=False,
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||
prog="screener",
|
||||
description="""
|
||||
Print several metrics about the company. The following fields are expected:
|
||||
Company, Sector, Industry, Country, Index, P/E, EPS (ttm), Insider Own,
|
||||
Shs Outstand, Perf Week, Market Cap, Forward P/E, EPS next Y, Insider Trans,
|
||||
Shs Float, Perf Month, Income, EPS next Q, Inst Own, Short Float, Perf Quarter,
|
||||
Sales, P/S, EPS this Y, Inst Trans, Short Ratio, Perf Half Y, Book/sh, P/B, ROA,
|
||||
Target Price, Perf Year, Cash/sh, P/C, ROE, 52W Range, Perf YTD, P/FCF, EPS past 5Y,
|
||||
ROI, 52W High, Beta, Quick Ratio, Sales past 5Y, Gross Margin, 52W Low, ATR,
|
||||
Employees, Current Ratio, Sales Q/Q, Oper. Margin, RSI (14), Volatility, Optionable,
|
||||
Debt/Eq, EPS Q/Q, Profit Margin, Rel Volume, Prev Close, Shortable, LT Debt/Eq,
|
||||
Earnings, Payout, Avg Volume, Price, Recom, SMA20, SMA50, SMA200, Volume, Change.
|
||||
[Source: Finviz]
|
||||
""",
|
||||
)
|
||||
fund_data = finviz_model.get_data(ticker)
|
||||
print("")
|
||||
if gtff.USE_TABULATE_DF:
|
||||
print(tabulate(fund_data, tablefmt="fancy_grid", showindex=True))
|
||||
else:
|
||||
print(fund_data.to_string(header=False))
|
||||
|
||||
try:
|
||||
ns_parser = parse_known_args_and_warn(parser, other_args)
|
||||
if not ns_parser:
|
||||
return
|
||||
|
||||
d_finviz_stock = finviz.get_stock(ticker)
|
||||
df_fa = pd.DataFrame.from_dict(
|
||||
d_finviz_stock, orient="index", columns=["Values"]
|
||||
)
|
||||
df_fa = df_fa[df_fa.Values != "-"]
|
||||
print(df_fa.to_string(header=False))
|
||||
print("")
|
||||
|
||||
except Exception as e:
|
||||
print(e, "\n")
|
||||
print("")
|
||||
export_data(export, os.path.dirname(os.path.abspath(__file__)), "data", fund_data)
|
||||
|
||||
@@ -1,12 +1,17 @@
|
||||
""" Fundamental Analysis Market Watch Model """
|
||||
__docformat__ = "numpy"
|
||||
|
||||
import requests
|
||||
import pandas as pd
|
||||
from bs4 import BeautifulSoup
|
||||
import re
|
||||
from typing import List, Tuple
|
||||
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
import requests
|
||||
from bs4 import BeautifulSoup
|
||||
from gamestonk_terminal.helper_funcs import (
|
||||
clean_data_values_to_float,
|
||||
get_user_agent,
|
||||
int_or_round_float,
|
||||
)
|
||||
|
||||
|
||||
@@ -113,3 +118,222 @@ def prepare_df_financials(
|
||||
df_financials.loc[len(df_financials)] = constructed_row
|
||||
|
||||
return df_financials
|
||||
|
||||
|
||||
def get_sean_seah_warnings(
|
||||
ticker: str, debug: bool = False
|
||||
) -> Tuple[pd.DataFrame, List[str], List[str]]:
|
||||
"""Get financial statements and prepare Sean Seah warnings
|
||||
|
||||
Parameters
|
||||
----------
|
||||
ticker : str
|
||||
Ticker to look at
|
||||
debug : bool, optional
|
||||
[description], by default False
|
||||
|
||||
Returns
|
||||
-------
|
||||
pd.DataFrame
|
||||
Dataframe of financials
|
||||
List[str]
|
||||
List of warnings
|
||||
List[str]
|
||||
List of debug messages
|
||||
"""
|
||||
# From INCOME STATEMENT, get: 'EPS (Basic)', 'Net Income', 'Interest Expense', 'EBITDA'
|
||||
url_financials = (
|
||||
f"https://www.marketwatch.com/investing/stock/{ticker}/financials/income"
|
||||
)
|
||||
text_soup_financials = BeautifulSoup(
|
||||
requests.get(url_financials, headers={"User-Agent": get_user_agent()}).text,
|
||||
"lxml",
|
||||
)
|
||||
|
||||
# Define financials columns
|
||||
a_financials_header = []
|
||||
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(
|
||||
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
|
||||
|
||||
l_fin = ["EPS (Basic)", "Net Income", "Interest Expense", "EBITDA"]
|
||||
|
||||
if not all(elem in df_financials["Item"].values for elem in l_fin):
|
||||
return pd.DataFrame(), [], []
|
||||
|
||||
# Set item name as index
|
||||
df_financials = df_financials.set_index("Item")
|
||||
|
||||
df_sean_seah = df_financials.loc[l_fin]
|
||||
|
||||
# From BALANCE SHEET, get: 'Liabilities & Shareholders\' Equity', 'Long-Term Debt'
|
||||
url_financials = (
|
||||
f"https://www.marketwatch.com/investing/stock/{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 = []
|
||||
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"
|
||||
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")
|
||||
|
||||
# Create dataframe to compute meaningful metrics from sean seah book
|
||||
df_sean_seah = df_sean_seah.append(
|
||||
df_financials.loc[
|
||||
[
|
||||
"Total Shareholders' Equity",
|
||||
"Liabilities & Shareholders' Equity",
|
||||
"Long-Term Debt",
|
||||
]
|
||||
]
|
||||
)
|
||||
|
||||
# Clean these metrics by parsing their values to float
|
||||
df_sean_seah = df_sean_seah.applymap(lambda x: clean_data_values_to_float(x))
|
||||
|
||||
# Add additional necessary metrics
|
||||
series = (
|
||||
df_sean_seah.loc["Net Income"] / df_sean_seah.loc["Total Shareholders' Equity"]
|
||||
)
|
||||
series.name = "ROE"
|
||||
df_sean_seah = df_sean_seah.append(series)
|
||||
|
||||
series = df_sean_seah.loc["EBITDA"] / df_sean_seah.loc["Interest Expense"]
|
||||
series.name = "Interest Coverage Ratio"
|
||||
df_sean_seah = df_sean_seah.append(series)
|
||||
|
||||
series = (
|
||||
df_sean_seah.loc["Net Income"]
|
||||
/ df_sean_seah.loc["Liabilities & Shareholders' Equity"]
|
||||
)
|
||||
series.name = "ROA"
|
||||
df_sean_seah = df_sean_seah.append(series)
|
||||
|
||||
n_warnings = 0
|
||||
warnings = []
|
||||
debugged_warnings = []
|
||||
|
||||
if np.any(df_sean_seah.loc["EPS (Basic)"].diff().dropna().values < 0):
|
||||
warnings.append("No consistent historical earnings per share")
|
||||
n_warnings += 1
|
||||
if debug:
|
||||
sa_eps = np.array2string(
|
||||
df_sean_seah.loc["EPS (Basic)"].values,
|
||||
formatter={"float_kind": lambda x: int_or_round_float(x)},
|
||||
)
|
||||
sa_growth = np.array2string(
|
||||
df_sean_seah.loc["EPS (Basic)"].diff().dropna().values,
|
||||
formatter={"float_kind": lambda x: int_or_round_float(x)},
|
||||
)
|
||||
debugged_warnings.append(f"\tEPS: {sa_eps}\n\tGrowth: {sa_growth} < 0")
|
||||
|
||||
if np.any(df_sean_seah.loc["ROE"].values < 0.15):
|
||||
warnings.append("NOT consistently high return on equity")
|
||||
n_warnings += 1
|
||||
if debug:
|
||||
sa_roe = np.array2string(
|
||||
df_sean_seah.loc["ROE"].values,
|
||||
formatter={"float_kind": lambda x: int_or_round_float(x)},
|
||||
)
|
||||
debugged_warnings.append(f"\tROE: {sa_roe} < 0.15")
|
||||
|
||||
if np.any(df_sean_seah.loc["ROA"].values < 0.07):
|
||||
warnings.append("NOT consistently high return on assets")
|
||||
n_warnings += 1
|
||||
if debug:
|
||||
sa_roa = np.array2string(
|
||||
df_sean_seah.loc["ROA"].values,
|
||||
formatter={"float_kind": lambda x: int_or_round_float(x)},
|
||||
)
|
||||
debugged_warnings.append(f"\tROA: {sa_roa} < 0.07")
|
||||
|
||||
if np.any(
|
||||
df_sean_seah.loc["Long-Term Debt"].values
|
||||
> 5 * df_sean_seah.loc["Net Income"].values
|
||||
):
|
||||
warnings.append("5x Net Income < Long-Term Debt")
|
||||
n_warnings += 1
|
||||
if debug:
|
||||
sa_5_net_income = np.array2string(
|
||||
5 * df_sean_seah.loc["Net Income"].values,
|
||||
formatter={"float_kind": lambda x: int_or_round_float(x)},
|
||||
)
|
||||
sa_long_term_debt = np.array2string(
|
||||
df_sean_seah.loc["Long-Term Debt"].values,
|
||||
formatter={"float_kind": lambda x: int_or_round_float(x)},
|
||||
)
|
||||
debugged_warnings.append(
|
||||
f"\t5x NET Income: {sa_5_net_income}\n\tlower than Long-Term Debt: {sa_long_term_debt}"
|
||||
)
|
||||
|
||||
if np.any(df_sean_seah.loc["Interest Coverage Ratio"].values < 3):
|
||||
warnings.append("Interest coverage ratio less than 3")
|
||||
n_warnings += 1
|
||||
if debug:
|
||||
sa_interest_coverage_ratio = np.array2string(
|
||||
100 * df_sean_seah.loc["Interest Coverage Ratio"].values,
|
||||
formatter={"float_kind": lambda x: int_or_round_float(x)},
|
||||
)
|
||||
debugged_warnings.append(
|
||||
f"\tInterest Coverage Ratio: {sa_interest_coverage_ratio} < 3"
|
||||
)
|
||||
|
||||
print("")
|
||||
return (
|
||||
df_sean_seah.applymap(lambda x: int_or_round_float(x)),
|
||||
warnings,
|
||||
debugged_warnings,
|
||||
)
|
||||
|
||||
@@ -6,23 +6,19 @@ So this code is not being used for the time being, it may be at a later stage.
|
||||
__docformat__ = "numpy"
|
||||
|
||||
import argparse
|
||||
import re
|
||||
from typing import List
|
||||
import requests
|
||||
import pandas as pd
|
||||
from bs4 import BeautifulSoup
|
||||
import numpy as np
|
||||
|
||||
from gamestonk_terminal.stocks.fundamental_analysis import market_watch_model as mwm
|
||||
import pandas as pd
|
||||
from tabulate import tabulate
|
||||
|
||||
from gamestonk_terminal import feature_flags as gtff
|
||||
from gamestonk_terminal.helper_funcs import (
|
||||
get_user_agent,
|
||||
financials_colored_values,
|
||||
parse_known_args_and_warn,
|
||||
patch_pandas_text_adjustment,
|
||||
financials_colored_values,
|
||||
clean_data_values_to_float,
|
||||
int_or_round_float,
|
||||
)
|
||||
from gamestonk_terminal import feature_flags as gtff
|
||||
from gamestonk_terminal.stocks.fundamental_analysis import market_watch_model as mwm
|
||||
|
||||
|
||||
# pylint: disable=too-many-branches
|
||||
|
||||
@@ -255,7 +251,7 @@ def cash(other_args: List[str], ticker: str):
|
||||
print(e, "\n")
|
||||
|
||||
|
||||
def sean_seah_warnings(other_args: List[str], ticker: str):
|
||||
def display_sean_seah_warnings(ticker: str, debug: bool = False):
|
||||
"""Display Sean Seah warnings
|
||||
|
||||
Parameters
|
||||
@@ -265,252 +261,33 @@ def sean_seah_warnings(other_args: List[str], ticker: str):
|
||||
ticker : str
|
||||
Stock ticker
|
||||
"""
|
||||
financials, warnings, debugged_warnings = mwm.get_sean_seah_warnings(ticker, debug)
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
add_help=False,
|
||||
prog="warnings",
|
||||
description="""
|
||||
Sean Seah warnings. Check: Consistent historical earnings per share;
|
||||
Consistently high return on equity; Consistently high return on assets; 5x Net
|
||||
Income > Long-Term Debt; and Interest coverage ratio more than 3. See
|
||||
https://www.drwealth.com/gone-fishing-with-buffett-by-sean-seah/comment-page-1/
|
||||
[Source: Market Watch]
|
||||
""",
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"-i",
|
||||
"--info",
|
||||
action="store_true",
|
||||
default=False,
|
||||
dest="b_info",
|
||||
help="provide more information about Sean Seah warning rules.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-d",
|
||||
"--debug",
|
||||
action="store_true",
|
||||
default=False,
|
||||
dest="b_debug",
|
||||
help="print insights into warnings calculation.",
|
||||
)
|
||||
|
||||
try:
|
||||
ns_parser = parse_known_args_and_warn(parser, other_args)
|
||||
if not ns_parser:
|
||||
return
|
||||
|
||||
if ns_parser.b_info:
|
||||
filepath = "fundamental_analysis/info_sean_seah.txt"
|
||||
with open(filepath) as fp:
|
||||
line = fp.readline()
|
||||
while line:
|
||||
print(f"{line.strip()}")
|
||||
line = fp.readline()
|
||||
print("")
|
||||
|
||||
# From INCOME STATEMENT, get: 'EPS (Basic)', 'Net Income', 'Interest Expense', 'EBITDA'
|
||||
url_financials = (
|
||||
f"https://www.marketwatch.com/investing/stock/{ticker}/financials/income"
|
||||
)
|
||||
text_soup_financials = BeautifulSoup(
|
||||
requests.get(url_financials, headers={"User-Agent": get_user_agent()}).text,
|
||||
"lxml",
|
||||
)
|
||||
|
||||
# Define financials columns
|
||||
a_financials_header = []
|
||||
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(
|
||||
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
|
||||
|
||||
l_fin = ["EPS (Basic)", "Net Income", "Interest Expense", "EBITDA"]
|
||||
|
||||
if not all(elem in df_financials["Item"].values for elem in l_fin):
|
||||
print("The source doesn't contain all necessary financial data")
|
||||
print(url_financials, "\n")
|
||||
return
|
||||
|
||||
# Set item name as index
|
||||
df_financials = df_financials.set_index("Item")
|
||||
|
||||
df_sean_seah = df_financials.loc[l_fin]
|
||||
|
||||
# From BALANCE SHEET, get: 'Liabilities & Shareholders\' Equity', 'Long-Term Debt'
|
||||
url_financials = f"https://www.marketwatch.com/investing/stock/{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 = []
|
||||
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"
|
||||
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")
|
||||
|
||||
# Create dataframe to compute meaningful metrics from sean seah book
|
||||
df_sean_seah = df_sean_seah.append(
|
||||
df_financials.loc[
|
||||
[
|
||||
"Total Shareholders' Equity",
|
||||
"Liabilities & Shareholders' Equity",
|
||||
"Long-Term Debt",
|
||||
]
|
||||
]
|
||||
)
|
||||
|
||||
# Clean these metrics by parsing their values to float
|
||||
df_sean_seah = df_sean_seah.applymap(lambda x: clean_data_values_to_float(x))
|
||||
|
||||
# Add additional necessary metrics
|
||||
series = (
|
||||
df_sean_seah.loc["Net Income"]
|
||||
/ df_sean_seah.loc["Total Shareholders' Equity"]
|
||||
)
|
||||
series.name = "ROE"
|
||||
df_sean_seah = df_sean_seah.append(series)
|
||||
|
||||
series = df_sean_seah.loc["EBITDA"] / df_sean_seah.loc["Interest Expense"]
|
||||
series.name = "Interest Coverage Ratio"
|
||||
df_sean_seah = df_sean_seah.append(series)
|
||||
|
||||
series = (
|
||||
df_sean_seah.loc["Net Income"]
|
||||
/ df_sean_seah.loc["Liabilities & Shareholders' Equity"]
|
||||
)
|
||||
series.name = "ROA"
|
||||
df_sean_seah = df_sean_seah.append(series)
|
||||
|
||||
print(df_sean_seah.applymap(lambda x: int_or_round_float(x)).to_string())
|
||||
|
||||
n_warnings = 0
|
||||
print("\nWARNINGS:")
|
||||
|
||||
if np.any(df_sean_seah.loc["EPS (Basic)"].diff().dropna().values < 0):
|
||||
print("NO consistent historical earnings per share")
|
||||
n_warnings += 1
|
||||
if ns_parser.b_debug:
|
||||
sa_eps = np.array2string(
|
||||
df_sean_seah.loc["EPS (Basic)"].values,
|
||||
formatter={"float_kind": lambda x: int_or_round_float(x)},
|
||||
)
|
||||
print(f" EPS: {sa_eps}")
|
||||
sa_growth = np.array2string(
|
||||
df_sean_seah.loc["EPS (Basic)"].diff().dropna().values,
|
||||
formatter={"float_kind": lambda x: int_or_round_float(x)},
|
||||
)
|
||||
print(f" Growth: {sa_growth} < 0")
|
||||
|
||||
if np.any(df_sean_seah.loc["ROE"].values < 0.15):
|
||||
print("NOT consistently high return on equity")
|
||||
n_warnings += 1
|
||||
if ns_parser.b_debug:
|
||||
sa_roe = np.array2string(
|
||||
df_sean_seah.loc["ROE"].values,
|
||||
formatter={"float_kind": lambda x: int_or_round_float(x)},
|
||||
)
|
||||
print(f" ROE: {sa_roe} < 0.15")
|
||||
|
||||
if np.any(df_sean_seah.loc["ROA"].values < 0.07):
|
||||
print("NOT consistently high return on assets")
|
||||
n_warnings += 1
|
||||
if ns_parser.b_debug:
|
||||
sa_roa = np.array2string(
|
||||
df_sean_seah.loc["ROA"].values,
|
||||
formatter={"float_kind": lambda x: int_or_round_float(x)},
|
||||
)
|
||||
print(f" ROA: {sa_roa} < 0.07")
|
||||
|
||||
if np.any(
|
||||
df_sean_seah.loc["Long-Term Debt"].values
|
||||
> 5 * df_sean_seah.loc["Net Income"].values
|
||||
):
|
||||
print("5x Net Income < Long-Term Debt")
|
||||
n_warnings += 1
|
||||
if ns_parser.b_debug:
|
||||
sa_5_net_income = np.array2string(
|
||||
5 * df_sean_seah.loc["Net Income"].values,
|
||||
formatter={"float_kind": lambda x: int_or_round_float(x)},
|
||||
)
|
||||
print(f" 5x NET Income: {sa_5_net_income}")
|
||||
sa_long_term_debt = np.array2string(
|
||||
df_sean_seah.loc["Long-Term Debt"].values,
|
||||
formatter={"float_kind": lambda x: int_or_round_float(x)},
|
||||
)
|
||||
print(f" lower than Long-Term Debt: {sa_long_term_debt}")
|
||||
|
||||
if np.any(df_sean_seah.loc["Interest Coverage Ratio"].values < 3):
|
||||
print("Interest coverage ratio less than 3")
|
||||
n_warnings += 1
|
||||
if ns_parser.b_debug:
|
||||
sa_interest_coverage_ratio = np.array2string(
|
||||
100 * df_sean_seah.loc["Interest Coverage Ratio"].values,
|
||||
formatter={"float_kind": lambda x: int_or_round_float(x)},
|
||||
)
|
||||
print(f" Interest Coverage Ratio: {sa_interest_coverage_ratio} < 3")
|
||||
|
||||
if n_warnings == 0:
|
||||
print("None. Good stonk")
|
||||
|
||||
print("")
|
||||
|
||||
except Exception as e:
|
||||
print(e)
|
||||
print("")
|
||||
if financials.empty:
|
||||
print(f"No financials found for {ticker}\n")
|
||||
return
|
||||
|
||||
if gtff.USE_TABULATE_DF:
|
||||
print(
|
||||
tabulate(
|
||||
financials,
|
||||
headers=financials.columns,
|
||||
tablefmt="fancy_grid",
|
||||
floatfmt=".2f",
|
||||
)
|
||||
)
|
||||
else:
|
||||
print(financials.to_string(()))
|
||||
|
||||
if not warnings:
|
||||
print("No warnings found. Good stonk")
|
||||
return
|
||||
|
||||
messages = (
|
||||
[item for pair in zip(warnings, debugged_warnings) for item in pair]
|
||||
if debug
|
||||
else warnings
|
||||
)
|
||||
|
||||
print("Warnings:\n")
|
||||
print("\n".join(messages), "\n")
|
||||
|
||||
@@ -0,0 +1,205 @@
|
||||
"""Yahoo Finance Model"""
|
||||
__docformat__ = "numpy"
|
||||
|
||||
from datetime import datetime
|
||||
from typing import Tuple
|
||||
import yfinance as yf
|
||||
import pandas as pd
|
||||
from gamestonk_terminal.helper_funcs import (
|
||||
long_number_format,
|
||||
)
|
||||
from gamestonk_terminal.stocks.fundamental_analysis.fa_helper import clean_df_index
|
||||
|
||||
|
||||
def get_info(ticker: str) -> pd.DataFrame:
|
||||
"""Gets ticker info
|
||||
|
||||
Parameters
|
||||
----------
|
||||
ticker : str
|
||||
Stock ticker
|
||||
|
||||
Returns
|
||||
-------
|
||||
pd.DataFrame
|
||||
DataFrame of yfinance information
|
||||
"""
|
||||
stock = yf.Ticker(ticker)
|
||||
df_info = pd.DataFrame(stock.info.items(), columns=["Metric", "Value"])
|
||||
df_info = df_info.set_index("Metric")
|
||||
|
||||
clean_df_index(df_info)
|
||||
|
||||
if "Last split date" in df_info.index and df_info.loc["Last split date"].values[0]:
|
||||
df_info.loc["Last split date"].values[0] = datetime.fromtimestamp(
|
||||
df_info.loc["Last split date"].values[0]
|
||||
).strftime("%d/%m/%Y")
|
||||
|
||||
df_info = df_info.mask(df_info["Value"].astype(str).eq("[]")).dropna()
|
||||
df_info[df_info.index != "Zip"] = df_info[df_info.index != "Zip"].applymap(
|
||||
lambda x: long_number_format(x)
|
||||
)
|
||||
|
||||
df_info = df_info.rename(
|
||||
index={
|
||||
"Address1": "Address",
|
||||
"Average daily volume10 day": "Average daily volume 10 day",
|
||||
"Average volume10days": "Average volume 10 days",
|
||||
"Price to sales trailing12 months": "Price to sales trailing 12 months",
|
||||
}
|
||||
)
|
||||
df_info.index = df_info.index.str.replace("eps", "EPS")
|
||||
df_info.index = df_info.index.str.replace("p e", "PE")
|
||||
df_info.index = df_info.index.str.replace("Peg", "PEG")
|
||||
return df_info
|
||||
|
||||
|
||||
def get_shareholders(ticker: str) -> Tuple[pd.DataFrame, pd.DataFrame, pd.DataFrame]:
|
||||
"""Get shareholders from yahoo
|
||||
|
||||
Parameters
|
||||
----------
|
||||
ticker : str
|
||||
Stock ticker
|
||||
|
||||
Returns
|
||||
-------
|
||||
pd.DataFrame
|
||||
Major holders
|
||||
pd.DataFrame
|
||||
Institutuional holders
|
||||
pd.DataFrame
|
||||
Mutual Fund holders
|
||||
"""
|
||||
stock = yf.Ticker(ticker)
|
||||
|
||||
# Major holders
|
||||
df_major_holders = stock.major_holders
|
||||
df_major_holders[1] = df_major_holders[1].apply(
|
||||
lambda x: x.replace("%", "Percentage")
|
||||
)
|
||||
|
||||
# Institutional holders
|
||||
df_institutional_shareholders = stock.institutional_holders
|
||||
df_institutional_shareholders.columns = (
|
||||
df_institutional_shareholders.columns.str.replace("% Out", "Stake")
|
||||
)
|
||||
df_institutional_shareholders["Shares"] = df_institutional_shareholders[
|
||||
"Shares"
|
||||
].apply(lambda x: long_number_format(x))
|
||||
df_institutional_shareholders["Value"] = df_institutional_shareholders[
|
||||
"Value"
|
||||
].apply(lambda x: long_number_format(x))
|
||||
df_institutional_shareholders["Stake"] = df_institutional_shareholders[
|
||||
"Stake"
|
||||
].apply(lambda x: str(f"{100 * x:.2f}") + " %")
|
||||
|
||||
# Mutualfunds holders
|
||||
df_mutualfund_shareholders = stock.mutualfund_holders
|
||||
df_mutualfund_shareholders.columns = df_mutualfund_shareholders.columns.str.replace(
|
||||
"% Out", "Stake"
|
||||
)
|
||||
df_mutualfund_shareholders["Shares"] = df_mutualfund_shareholders["Shares"].apply(
|
||||
lambda x: long_number_format(x)
|
||||
)
|
||||
df_mutualfund_shareholders["Value"] = df_mutualfund_shareholders["Value"].apply(
|
||||
lambda x: long_number_format(x)
|
||||
)
|
||||
df_mutualfund_shareholders["Stake"] = df_mutualfund_shareholders["Stake"].apply(
|
||||
lambda x: str(f"{100 * x:.2f}") + " %"
|
||||
)
|
||||
|
||||
return df_major_holders, df_institutional_shareholders, df_mutualfund_shareholders
|
||||
|
||||
|
||||
def get_sustainability(ticker) -> pd.DataFrame:
|
||||
"""Get sustainability metrics from yahoo
|
||||
|
||||
Parameters
|
||||
----------
|
||||
ticker : [type]
|
||||
Stock ticker
|
||||
|
||||
Returns
|
||||
-------
|
||||
pd.DataFrame
|
||||
Dataframe of sustainability metrics
|
||||
"""
|
||||
stock = yf.Ticker(ticker)
|
||||
pd.set_option("display.max_colwidth", None)
|
||||
|
||||
df_sustainability = stock.sustainability
|
||||
|
||||
if df_sustainability is None or df_sustainability.empty:
|
||||
return pd.DataFrame()
|
||||
|
||||
clean_df_index(df_sustainability)
|
||||
|
||||
df_sustainability = df_sustainability.rename(
|
||||
index={
|
||||
"Controversialweapons": "Controversial Weapons",
|
||||
"Socialpercentile": "Social Percentile",
|
||||
"Peercount": "Peer Count",
|
||||
"Governancescore": "Governance Score",
|
||||
"Environmentpercentile": "Environment Percentile",
|
||||
"Animaltesting": "Animal Testing",
|
||||
"Highestcontroversy": "Highest Controversy",
|
||||
"Environmentscore": "Environment Score",
|
||||
"Governancepercentile": "Governance Percentile",
|
||||
"Militarycontract": "Military Contract",
|
||||
}
|
||||
)
|
||||
return df_sustainability
|
||||
|
||||
|
||||
def get_calendar_earnings(ticker: str) -> pd.DataFrame:
|
||||
"""Get calendar earnings for ticker
|
||||
|
||||
Parameters
|
||||
----------
|
||||
ticker : [type]
|
||||
Stock ticker
|
||||
|
||||
Returns
|
||||
-------
|
||||
pd.DataFrame
|
||||
Dataframe of calendar earnings
|
||||
"""
|
||||
stock = yf.Ticker(ticker)
|
||||
df_calendar = stock.calendar
|
||||
|
||||
if df_calendar.empty:
|
||||
return pd.DataFrame()
|
||||
|
||||
df_calendar.iloc[0, :] = df_calendar.iloc[0, :].apply(
|
||||
lambda x: x.date().strftime("%m/%d/%Y")
|
||||
)
|
||||
|
||||
df_calendar.iloc[1:, :] = df_calendar.iloc[1:, :].applymap(
|
||||
lambda x: long_number_format(x)
|
||||
)
|
||||
|
||||
return df_calendar
|
||||
|
||||
|
||||
def get_website(ticker: str) -> str:
|
||||
"""Gets website of company from yfinance"""
|
||||
stock = yf.Ticker(ticker)
|
||||
df_info = pd.DataFrame(stock.info.items(), columns=["Metric", "Value"])
|
||||
return df_info[df_info["Metric"] == "website"]["Value"].values[0]
|
||||
|
||||
|
||||
def get_hq(ticker: str) -> str:
|
||||
"""Gets google map url for headquarter"""
|
||||
stock = yf.Ticker(ticker)
|
||||
df_info = pd.DataFrame(stock.info.items(), columns=["Metric", "Value"])
|
||||
df_info = df_info.set_index("Metric")
|
||||
|
||||
maps = "https://www.google.com/maps/search/"
|
||||
for field in ["address1", "address2", "city", "state", "zip", "country"]:
|
||||
if field in df_info.index:
|
||||
maps += (
|
||||
df_info[df_info.index == field]["Value"].values[0].replace(" ", "+")
|
||||
+ ","
|
||||
)
|
||||
return maps[:-1]
|
||||
@@ -1,259 +1,93 @@
|
||||
""" Yahoo Finance View """
|
||||
__docformat__ = "numpy"
|
||||
|
||||
import argparse
|
||||
from typing import List
|
||||
from datetime import datetime
|
||||
import webbrowser
|
||||
import yfinance as yf
|
||||
import pandas as pd
|
||||
from tabulate import tabulate
|
||||
|
||||
from gamestonk_terminal.stocks.fundamental_analysis.fa_helper import clean_df_index
|
||||
from gamestonk_terminal.helper_funcs import (
|
||||
long_number_format,
|
||||
parse_known_args_and_warn,
|
||||
)
|
||||
from gamestonk_terminal.stocks.fundamental_analysis import yahoo_finance_model
|
||||
from gamestonk_terminal import feature_flags as gtff
|
||||
|
||||
|
||||
def headquarters(other_args: List[str], ticker: str):
|
||||
def open_headquarters_map(ticker: str):
|
||||
"""Headquarters location of the company
|
||||
|
||||
Parameters
|
||||
----------
|
||||
other_args : List[str]
|
||||
argparse other args
|
||||
ticker : str
|
||||
Fundamental analysis ticker symbol
|
||||
"""
|
||||
parser = argparse.ArgumentParser(
|
||||
add_help=False,
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||
prog="hq",
|
||||
description="""
|
||||
Opens in Google Maps HQ location of the company. [Source: Yahoo Finance]
|
||||
""",
|
||||
)
|
||||
|
||||
try:
|
||||
ns_parser = parse_known_args_and_warn(parser, other_args)
|
||||
if not ns_parser:
|
||||
return
|
||||
|
||||
stock = yf.Ticker(ticker)
|
||||
df_info = pd.DataFrame(stock.info.items(), columns=["Metric", "Value"])
|
||||
df_info = df_info.set_index("Metric")
|
||||
|
||||
maps = "https://www.google.com/maps/search/"
|
||||
for field in ["address1", "address2", "city", "state", "zip", "country"]:
|
||||
if field in df_info.index:
|
||||
maps += (
|
||||
df_info[df_info.index == field]["Value"].values[0].replace(" ", "+")
|
||||
+ ","
|
||||
)
|
||||
webbrowser.open(maps[:-1])
|
||||
print("")
|
||||
|
||||
except Exception as e:
|
||||
print(e, "\n")
|
||||
webbrowser.open(yahoo_finance_model.get_hq(ticker))
|
||||
print("")
|
||||
|
||||
|
||||
def web(other_args: List[str], ticker: str):
|
||||
def open_web(ticker: str):
|
||||
"""Website of the company
|
||||
|
||||
Parameters
|
||||
----------
|
||||
other_args : List[str]
|
||||
argparse other args
|
||||
ticker : str
|
||||
Fundamental analysis ticker symbol
|
||||
"""
|
||||
parser = argparse.ArgumentParser(
|
||||
add_help=False,
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||
prog="web",
|
||||
description="""
|
||||
Opens company's website. [Source: Yahoo Finance]
|
||||
""",
|
||||
)
|
||||
|
||||
try:
|
||||
ns_parser = parse_known_args_and_warn(parser, other_args)
|
||||
if not ns_parser:
|
||||
return
|
||||
|
||||
stock = yf.Ticker(ticker)
|
||||
df_info = pd.DataFrame(stock.info.items(), columns=["Metric", "Value"])
|
||||
webbrowser.open(df_info[df_info["Metric"] == "website"]["Value"].values[0])
|
||||
print("")
|
||||
|
||||
except Exception as e:
|
||||
print(e, "\n")
|
||||
webbrowser.open(yahoo_finance_model.get_website(ticker))
|
||||
print("")
|
||||
|
||||
|
||||
def info(other_args: List[str], ticker: str):
|
||||
def display_info(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,
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||
prog="info",
|
||||
description="""
|
||||
Print information about the company. The following fields are expected:
|
||||
Zip, Sector, Full time employees, Long business summary, City, Phone, State, Country,
|
||||
Website, Max age, Address, Industry, Previous close, Regular market open, Two hundred
|
||||
day average, Payout ratio, Regular market day high, Average daily volume 10 day,
|
||||
Regular market previous close, Fifty day average, Open, Average volume 10 days, Beta,
|
||||
Regular market day low, Price hint, Currency, Trailing PE, Regular market volume,
|
||||
Market cap, Average volume, Price to sales trailing 12 months, Day low, Ask, Ask size,
|
||||
Volume, Fifty two week high, Forward PE, Fifty two week low, Bid, Tradeable, Bid size,
|
||||
Day high, Exchange, Short name, Long name, Exchange timezone name, Exchange timezone
|
||||
short name, Is esg populated, Gmt off set milliseconds, Quote type, Symbol, Message
|
||||
board id, Market, Enterprise to revenue, Profit margins, Enterprise to ebitda, 52 week
|
||||
change, Forward EPS, Shares outstanding, Book value, Shares short, Shares percent
|
||||
shares out, Last fiscal year end, Held percent institutions, Net income to common,
|
||||
Trailing EPS, Sand p52 week change, Price to book, Held percent insiders, Next fiscal
|
||||
year end, Most recent quarter, Short ratio, Shares short previous month date, Float
|
||||
shares, Enterprise value, Last split date, Last split factor, Earnings quarterly growth,
|
||||
Date short interest, PEG ratio, Short percent of float, Shares short prior month,
|
||||
Regular market price, Logo_url. [Source: Yahoo Finance]
|
||||
""",
|
||||
)
|
||||
summary = ""
|
||||
df_info = yahoo_finance_model.get_info(ticker)
|
||||
if "Long business summary" in df_info.index:
|
||||
summary = df_info.loc["Long business summary"].values[0]
|
||||
df_info = df_info.drop(index=["Long business summary"])
|
||||
|
||||
try:
|
||||
ns_parser = parse_known_args_and_warn(parser, other_args)
|
||||
if not ns_parser:
|
||||
return
|
||||
if gtff.USE_TABULATE_DF:
|
||||
print(tabulate(df_info, headers=[], showindex=True, tablefmt="fancy_grid"))
|
||||
|
||||
stock = yf.Ticker(ticker)
|
||||
df_info = pd.DataFrame(stock.info.items(), columns=["Metric", "Value"])
|
||||
df_info = df_info.set_index("Metric")
|
||||
else:
|
||||
print(df_info.to_string(header=False))
|
||||
|
||||
clean_df_index(df_info)
|
||||
if summary:
|
||||
print("Business Summary:")
|
||||
print(summary)
|
||||
|
||||
if (
|
||||
"Last split date" in df_info.index
|
||||
and df_info.loc["Last split date"].values[0]
|
||||
):
|
||||
df_info.loc["Last split date"].values[0] = datetime.fromtimestamp(
|
||||
df_info.loc["Last split date"].values[0]
|
||||
).strftime("%d/%m/%Y")
|
||||
|
||||
df_info = df_info.mask(df_info["Value"].astype(str).eq("[]")).dropna()
|
||||
df_info[df_info.index != "Zip"] = df_info[df_info.index != "Zip"].applymap(
|
||||
lambda x: long_number_format(x)
|
||||
)
|
||||
|
||||
df_info = df_info.rename(
|
||||
index={
|
||||
"Address1": "Address",
|
||||
"Average daily volume10 day": "Average daily volume 10 day",
|
||||
"Average volume10days": "Average volume 10 days",
|
||||
"Price to sales trailing12 months": "Price to sales trailing 12 months",
|
||||
}
|
||||
)
|
||||
df_info.index = df_info.index.str.replace("eps", "EPS")
|
||||
df_info.index = df_info.index.str.replace("p e", "PE")
|
||||
df_info.index = df_info.index.str.replace("Peg", "PEG")
|
||||
|
||||
pd.set_option("display.max_colwidth", None)
|
||||
|
||||
if "Long business summary" in df_info.index:
|
||||
print(df_info.drop(index=["Long business summary"]).to_string(header=False))
|
||||
print("")
|
||||
print(df_info.loc["Long business summary"].values[0])
|
||||
print("")
|
||||
else:
|
||||
print(df_info.to_string(header=False))
|
||||
print("")
|
||||
|
||||
except Exception as e:
|
||||
print(e, "\n")
|
||||
print("")
|
||||
|
||||
|
||||
def shareholders(other_args: List[str], ticker: str):
|
||||
def display_shareholders(ticker: str):
|
||||
"""Yahoo Finance ticker shareholders
|
||||
|
||||
Parameters
|
||||
----------
|
||||
other_args : List[str]
|
||||
argparse other args
|
||||
ticker : str
|
||||
Fundamental analysis ticker symbol
|
||||
"""
|
||||
(
|
||||
df_major_holders,
|
||||
df_institutional_shareholders,
|
||||
df_mutualfund_shareholders,
|
||||
) = yahoo_finance_model.get_shareholders(ticker)
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
add_help=False,
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||
prog="shrs",
|
||||
description="""Print Major, institutional and mutualfunds shareholders.
|
||||
[Source: Yahoo Finance]""",
|
||||
)
|
||||
|
||||
try:
|
||||
ns_parser = parse_known_args_and_warn(parser, other_args)
|
||||
if not ns_parser:
|
||||
return
|
||||
|
||||
stock = yf.Ticker(ticker)
|
||||
pd.set_option("display.max_colwidth", None)
|
||||
|
||||
# Major holders
|
||||
print("Major holders")
|
||||
df_major_holders = stock.major_holders
|
||||
df_major_holders[1] = df_major_holders[1].apply(
|
||||
lambda x: x.replace("%", "Percentage")
|
||||
)
|
||||
print(df_major_holders.to_string(index=False, header=False))
|
||||
dfs = [df_major_holders, df_institutional_shareholders, df_mutualfund_shareholders]
|
||||
titles = ["Major Holders:\n", "Institutuinal Holders:\n", "Mutual Fund Holders:\n"]
|
||||
print("")
|
||||
for df, title in zip(dfs, titles):
|
||||
print(title)
|
||||
if gtff.USE_TABULATE_DF:
|
||||
print(
|
||||
tabulate(df, headers=df.columns, tablefmt="fancy_grid", showindex=False)
|
||||
)
|
||||
else:
|
||||
print(df.to_string(index=False))
|
||||
print("")
|
||||
|
||||
# Institutional holders
|
||||
print("Institutional holders")
|
||||
df_institutional_shareholders = stock.institutional_holders
|
||||
df_institutional_shareholders.columns = (
|
||||
df_institutional_shareholders.columns.str.replace("% Out", "Stake")
|
||||
)
|
||||
df_institutional_shareholders["Shares"] = df_institutional_shareholders[
|
||||
"Shares"
|
||||
].apply(lambda x: long_number_format(x))
|
||||
df_institutional_shareholders["Value"] = df_institutional_shareholders[
|
||||
"Value"
|
||||
].apply(lambda x: long_number_format(x))
|
||||
df_institutional_shareholders["Stake"] = df_institutional_shareholders[
|
||||
"Stake"
|
||||
].apply(lambda x: str(f"{100 * x:.2f}") + " %")
|
||||
print(df_institutional_shareholders.to_string(index=False))
|
||||
print("")
|
||||
|
||||
# Mutualfunds holders
|
||||
print("Mutualfunds holders")
|
||||
df_mutualfund_shareholders = stock.mutualfund_holders
|
||||
df_mutualfund_shareholders.columns = (
|
||||
df_mutualfund_shareholders.columns.str.replace("% Out", "Stake")
|
||||
)
|
||||
df_mutualfund_shareholders["Shares"] = df_mutualfund_shareholders[
|
||||
"Shares"
|
||||
].apply(lambda x: long_number_format(x))
|
||||
df_mutualfund_shareholders["Value"] = df_mutualfund_shareholders["Value"].apply(
|
||||
lambda x: long_number_format(x)
|
||||
)
|
||||
df_mutualfund_shareholders["Stake"] = df_mutualfund_shareholders["Stake"].apply(
|
||||
lambda x: str(f"{100 * x:.2f}") + " %"
|
||||
)
|
||||
print(df_mutualfund_shareholders.to_string(index=False))
|
||||
print("")
|
||||
|
||||
except Exception as e:
|
||||
print(e, "\n")
|
||||
|
||||
|
||||
def sustainability(other_args: List[str], ticker: str):
|
||||
def display_sustainability(ticker: str):
|
||||
"""Yahoo Finance ticker sustainability
|
||||
|
||||
Parameters
|
||||
@@ -263,112 +97,48 @@ def sustainability(other_args: List[str], ticker: str):
|
||||
ticker : str
|
||||
Fundamental analysis ticker symbol
|
||||
"""
|
||||
parser = argparse.ArgumentParser(
|
||||
add_help=False,
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||
prog="sust",
|
||||
description="""
|
||||
Print sustainability values of the company. The following fields are expected:
|
||||
Palmoil, Controversialweapons, Gambling, Socialscore, Nuclear, Furleather, Alcoholic,
|
||||
Gmo, Catholic, Socialpercentile, Peercount, Governancescore, Environmentpercentile,
|
||||
Animaltesting, Tobacco, Totalesg, Highestcontroversy, Esgperformance, Coal, Pesticides,
|
||||
Adult, Percentile, Peergroup, Smallarms, Environmentscore, Governancepercentile,
|
||||
Militarycontract. [Source: Yahoo Finance]
|
||||
""",
|
||||
)
|
||||
|
||||
try:
|
||||
ns_parser = parse_known_args_and_warn(parser, other_args)
|
||||
if not ns_parser:
|
||||
return
|
||||
df_sustainability = yahoo_finance_model.get_sustainability(ticker)
|
||||
|
||||
stock = yf.Ticker(ticker)
|
||||
pd.set_option("display.max_colwidth", None)
|
||||
if df_sustainability.empty:
|
||||
print("No sustainability data found.")
|
||||
return
|
||||
|
||||
df_sustainability = stock.sustainability
|
||||
|
||||
if df_sustainability is None:
|
||||
print(f"No sustainability information in Yahoo for {ticker}", "\n")
|
||||
return
|
||||
|
||||
if df_sustainability.empty:
|
||||
print(f"No sustainability information in Yahoo for {ticker}", "\n")
|
||||
return
|
||||
|
||||
clean_df_index(df_sustainability)
|
||||
|
||||
df_sustainability = df_sustainability.rename(
|
||||
index={
|
||||
"Controversialweapons": "Controversial Weapons",
|
||||
"Socialpercentile": "Social Percentile",
|
||||
"Peercount": "Peer Count",
|
||||
"Governancescore": "Governance Score",
|
||||
"Environmentpercentile": "Environment Percentile",
|
||||
"Animaltesting": "Animal Testing",
|
||||
"Highestcontroversy": "Highest Controversy",
|
||||
"Environmentscore": "Environment Score",
|
||||
"Governancepercentile": "Governance Percentile",
|
||||
"Militarycontract": "Military Contract",
|
||||
}
|
||||
if gtff.USE_TABULATE_DF:
|
||||
print(
|
||||
tabulate(
|
||||
df_sustainability,
|
||||
headers=[],
|
||||
tablefmt="fancy_grid",
|
||||
showindex=True,
|
||||
)
|
||||
)
|
||||
|
||||
print(df_sustainability.to_string(header=False))
|
||||
print("")
|
||||
|
||||
except Exception as e:
|
||||
print(e, "\n")
|
||||
else:
|
||||
print(df_sustainability.to_sring(index=True))
|
||||
print("")
|
||||
|
||||
|
||||
def calendar_earnings(other_args: List[str], ticker: str):
|
||||
def display_calendar_earnings(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,
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||
prog="cal",
|
||||
description="""
|
||||
Calendar earnings of the company. Including revenue and earnings estimates.
|
||||
[Source: Yahoo Finance]
|
||||
""",
|
||||
)
|
||||
|
||||
try:
|
||||
ns_parser = parse_known_args_and_warn(parser, other_args)
|
||||
if not ns_parser:
|
||||
return
|
||||
|
||||
stock = yf.Ticker(ticker)
|
||||
df_calendar = stock.calendar
|
||||
|
||||
if df_calendar.empty:
|
||||
print(f"No earnings calendar information in Yahoo for {ticker}")
|
||||
print("")
|
||||
return
|
||||
|
||||
df_calendar.iloc[0, 0] = df_calendar.iloc[0, 0].date().strftime("%d/%m/%Y")
|
||||
df_calendar.iloc[:, 0] = df_calendar.iloc[:, 0].apply(
|
||||
lambda x: long_number_format(x)
|
||||
)
|
||||
|
||||
print(f"Earnings Date: {df_calendar.iloc[:, 0]['Earnings Date']}")
|
||||
|
||||
avg = df_calendar.iloc[:, 0]["Earnings Average"]
|
||||
low = df_calendar.iloc[:, 0]["Earnings Low"]
|
||||
high = df_calendar.iloc[:, 0]["Earnings High"]
|
||||
|
||||
print(f"Earnings Estimate Avg: {avg} [{low}, {high}]")
|
||||
df_calendar = yahoo_finance_model.get_calendar_earnings(ticker).T
|
||||
if df_calendar.empty:
|
||||
print("No calendar events found.\n")
|
||||
return
|
||||
if gtff.USE_TABULATE_DF:
|
||||
print(
|
||||
f"Revenue Estimate Avg: {df_calendar.iloc[:, 0]['Revenue Average']} \
|
||||
[{df_calendar.iloc[:, 0]['Revenue Low']}, {df_calendar.iloc[:, 0]['Revenue High']}]"
|
||||
tabulate(
|
||||
df_calendar,
|
||||
showindex=False,
|
||||
headers=df_calendar.columns,
|
||||
tablefmt="fancy_grid",
|
||||
)
|
||||
)
|
||||
print("")
|
||||
|
||||
except Exception as e:
|
||||
print(e, "\n")
|
||||
else:
|
||||
print(df_calendar.to_string(index=False))
|
||||
print("")
|
||||
|
||||
8
notebooks/templates/due_diligence.ipynb
vendored
8
notebooks/templates/due_diligence.ipynb
vendored
@@ -209,7 +209,7 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Annual Income Statement\n",
|
||||
"av.income_statement([], ticker)"
|
||||
"av.display_income_statement(ticker, number=1)"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -230,7 +230,7 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Quarterly Income Statement\n",
|
||||
"av.income_statement([\"-q\"], ticker)"
|
||||
"av.display_income_statement(ticker, number = 1, quarterly=True)"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -251,7 +251,7 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Annual Balance Sheet\n",
|
||||
"av.balance_sheet([], ticker)"
|
||||
"av.display_balance_sheet(ticker, number = 1)"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -272,7 +272,7 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Annual cash flow\n",
|
||||
"av.cash_flow([], ticker)"
|
||||
"av.display_cash_flow(ticker,number=1)"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -69,40 +69,34 @@ class TestAVView(unittest.TestCase):
|
||||
@mock.patch("requests.get", side_effect=mocked_requests_get)
|
||||
def test_av_overview(self, mock_get):
|
||||
# pylint: disable=unused-argument
|
||||
av_view.overview([], "GME")
|
||||
av_view.display_overview("GME")
|
||||
|
||||
@check_print(assert_in="Market capitalization")
|
||||
@mock.patch("requests.get", side_effect=mocked_requests_get)
|
||||
def test_av_key(self, mock_get):
|
||||
# pylint: disable=unused-argument
|
||||
av_view.key([], "GME")
|
||||
av_view.display_key("GME")
|
||||
|
||||
@check_print(assert_in="Gross profit")
|
||||
@check_print(assert_in="netIncome")
|
||||
@mock.patch("requests.get", side_effect=mocked_requests_get)
|
||||
def test_income_statement(self, mock_get):
|
||||
# pylint: disable=unused-argument
|
||||
av_view.income_statement([], "GME")
|
||||
av_view.display_income_statement("GME", 1)
|
||||
|
||||
@check_print(assert_in="Total assets")
|
||||
@check_print(assert_in="commonStockSharesOutstanding")
|
||||
@mock.patch("requests.get", side_effect=mocked_requests_get)
|
||||
def test_balance_sheet(self, mock_get):
|
||||
# pylint: disable=unused-argument
|
||||
av_view.balance_sheet([], "GME")
|
||||
|
||||
@check_print(assert_in="Operating cashflow")
|
||||
@mock.patch("requests.get", side_effect=mocked_requests_get)
|
||||
def test_cash_flow(self, mock_get):
|
||||
# pylint: disable=unused-argument
|
||||
av_view.cash_flow([], "GME")
|
||||
av_view.display_balance_sheet("GME", 1)
|
||||
|
||||
@check_print(assert_in="Reported EPS")
|
||||
@mock.patch("requests.get", side_effect=mocked_requests_get)
|
||||
def test_earnings(self, mock_get):
|
||||
# pylint: disable=unused-argument
|
||||
av_view.earnings([], "GME")
|
||||
av_view.display_earnings("GME", 1)
|
||||
|
||||
@check_print(assert_in="Mscore Sub Stats")
|
||||
@mock.patch("requests.get", side_effect=mocked_requests_get)
|
||||
def test_fraud(self, mock_get):
|
||||
# pylint: disable=unused-argument
|
||||
av_view.fraud([], "GME")
|
||||
av_view.display_fraud("GME")
|
||||
|
||||
@@ -4,7 +4,7 @@ import unittest
|
||||
import vcr
|
||||
|
||||
from gamestonk_terminal.stocks.fundamental_analysis.business_insider_view import (
|
||||
management,
|
||||
display_management,
|
||||
)
|
||||
from tests.helpers import check_print
|
||||
|
||||
@@ -16,4 +16,4 @@ class TestFaBusinessInsiderApi(unittest.TestCase):
|
||||
record_mode="new_episodes",
|
||||
)
|
||||
def test_management(self):
|
||||
management([], "PLTR")
|
||||
display_management("PLTR")
|
||||
|
||||
@@ -1,31 +1,11 @@
|
||||
""" fundamental_analysis/financial_modeling_prep/fmp_view.py tests """
|
||||
import sys
|
||||
import unittest
|
||||
|
||||
# Not testing these tests further. I do not have a fmp key
|
||||
from contextlib import contextmanager
|
||||
|
||||
import vcr
|
||||
|
||||
from gamestonk_terminal.stocks.fundamental_analysis.financial_modeling_prep import (
|
||||
fmp_view,
|
||||
)
|
||||
from tests.helpers import check_print
|
||||
|
||||
|
||||
@contextmanager
|
||||
def replace_stdin(target):
|
||||
orig = sys.stdin
|
||||
sys.stdin = target
|
||||
yield
|
||||
sys.stdin = orig
|
||||
|
||||
|
||||
class TestFMPView(unittest.TestCase):
|
||||
@check_print(assert_in="Ticker should be a NASDAQ")
|
||||
@vcr.use_cassette(
|
||||
"tests/cassettes/test_fa/test_fa_fmp/test_fmp_valinvest.yaml",
|
||||
record_mode="new_episodes",
|
||||
)
|
||||
def test_fmp_valinvest_score(self):
|
||||
fmp_view.valinvest_score([], "GME")
|
||||
self.assertRaises(ValueError, fmp_view.valinvest_score, "GME")
|
||||
|
||||
@@ -5,9 +5,9 @@ import vcr
|
||||
|
||||
# pylint: disable=unused-import
|
||||
from gamestonk_terminal.stocks.fundamental_analysis.yahoo_finance_view import ( # noqa: F401
|
||||
calendar_earnings,
|
||||
info,
|
||||
sustainability,
|
||||
display_calendar_earnings,
|
||||
display_info,
|
||||
display_sustainability,
|
||||
)
|
||||
from tests.helpers import check_print
|
||||
|
||||
@@ -19,15 +19,15 @@ class TestFaYahooFinanceApi(unittest.TestCase):
|
||||
record_mode="new_episodes",
|
||||
)
|
||||
def test_info(self):
|
||||
info([], "PLTR")
|
||||
display_info("PLTR")
|
||||
|
||||
@check_print(assert_in="GME")
|
||||
@check_print(assert_in="Military contract")
|
||||
@vcr.use_cassette(
|
||||
"tests/cassettes/test_fa/test_fa_yahoo/test_sustainability.yaml",
|
||||
record_mode="new_episodes",
|
||||
)
|
||||
def test_sustainability(self):
|
||||
sustainability([], "GME")
|
||||
display_sustainability("AAPL")
|
||||
|
||||
@check_print(assert_in="Earnings Date")
|
||||
@vcr.use_cassette(
|
||||
@@ -35,4 +35,4 @@ class TestFaYahooFinanceApi(unittest.TestCase):
|
||||
record_mode="new_episodes",
|
||||
)
|
||||
def test_calendar_earnings(self):
|
||||
calendar_earnings([], "GME")
|
||||
display_calendar_earnings("GME")
|
||||
|
||||
Reference in New Issue
Block a user