mirror of
https://github.com/OpenBB-finance/OpenBB.git
synced 2026-10-27 12:40:35 +00:00
Compare multiple tickers income
This commit is contained in:
@@ -11,6 +11,7 @@ from gamestonk_terminal import feature_flags as gtff
|
||||
from gamestonk_terminal import config_terminal as cfg
|
||||
from gamestonk_terminal.helper_funcs import get_flair, parse_known_args_and_warn
|
||||
from gamestonk_terminal.comparison_analysis import yahoo_finance_api as yf_api
|
||||
from gamestonk_terminal.comparison_analysis import market_watch_api as mw_api
|
||||
from gamestonk_terminal.menu import session
|
||||
from prompt_toolkit.completion import NestedCompleter
|
||||
|
||||
@@ -27,6 +28,7 @@ class ComparisonAnalysisController:
|
||||
"select",
|
||||
"historical",
|
||||
"corr",
|
||||
"income",
|
||||
]
|
||||
|
||||
def __init__(
|
||||
@@ -77,6 +79,8 @@ class ComparisonAnalysisController:
|
||||
print(" historical historical data comparison")
|
||||
print(" corr correlation between similar companies")
|
||||
print("")
|
||||
print(" income income financials comparison")
|
||||
print("")
|
||||
return
|
||||
|
||||
@staticmethod
|
||||
@@ -193,6 +197,10 @@ class ComparisonAnalysisController:
|
||||
other_args, self.stock, self.ticker, self.start, self.interval, self.similar
|
||||
)
|
||||
|
||||
def call_income(self, other_args: List[str]):
|
||||
"""Process income command"""
|
||||
mw_api.compare_income(other_args, self.ticker, self.similar)
|
||||
|
||||
|
||||
def menu(stock: pd.DataFrame, ticker: str, start: datetime, interval: str):
|
||||
"""Comparison Analysis Menu"""
|
||||
|
||||
429
gamestonk_terminal/comparison_analysis/market_watch_api.py
Normal file
429
gamestonk_terminal/comparison_analysis/market_watch_api.py
Normal file
@@ -0,0 +1,429 @@
|
||||
""" Comparison Analysis Market Watch View """
|
||||
__docformat__ = "numpy"
|
||||
|
||||
import argparse
|
||||
import requests
|
||||
import pandas as pd
|
||||
from bs4 import BeautifulSoup
|
||||
from typing import List, Dict, Tuple
|
||||
from gamestonk_terminal.helper_funcs import (
|
||||
get_user_agent,
|
||||
parse_known_args_and_warn,
|
||||
patch_pandas_text_adjustment,
|
||||
financials_colored_values,
|
||||
)
|
||||
from gamestonk_terminal import feature_flags as gtff
|
||||
|
||||
|
||||
def compare_income(other_args: List[str], ticker: str, similar: List[str]):
|
||||
"""Compare income between companies
|
||||
|
||||
Parameters
|
||||
----------
|
||||
other_args : List[str]
|
||||
Command line arguments to be processed with argparse
|
||||
ticker : str
|
||||
Main ticker to compare income
|
||||
similar : List[str]
|
||||
Similar companies to compare income with
|
||||
"""
|
||||
parser = argparse.ArgumentParser(
|
||||
add_help=False,
|
||||
prog="income",
|
||||
description="""
|
||||
Prints either yearly or quarterly income statement the company, and compares
|
||||
it against similar companies. [Source: Market Watch]
|
||||
""",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-s",
|
||||
"--similar",
|
||||
dest="l_similar",
|
||||
type=lambda s: [str(item) for item in s.split(",")],
|
||||
default=[],
|
||||
help="similar companies to compare with.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-a",
|
||||
"--also",
|
||||
dest="l_also",
|
||||
type=lambda s: [str(item) for item in s.split(",")],
|
||||
default=[],
|
||||
help="apart from loaded similar companies also compare with.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-q",
|
||||
"--quarter",
|
||||
action="store_true",
|
||||
default=False,
|
||||
dest="b_quarter",
|
||||
help="Quarter financial data flag.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-t",
|
||||
"--timeframe",
|
||||
dest="s_timeframe",
|
||||
type=str,
|
||||
default=None,
|
||||
help="Specify yearly/quarterly timeframe. Default is last.",
|
||||
)
|
||||
|
||||
try:
|
||||
ns_parser = parse_known_args_and_warn(parser, other_args)
|
||||
if not ns_parser:
|
||||
return
|
||||
|
||||
if ns_parser.l_similar:
|
||||
similar = ns_parser.l_similar
|
||||
|
||||
similar += ns_parser.l_also
|
||||
|
||||
# Add main ticker to similar list of companies
|
||||
similar.insert(0, ticker)
|
||||
|
||||
l_timeframes, ddf_financials = prepare_comparison_financials(
|
||||
similar, "income", ns_parser.b_quarter
|
||||
)
|
||||
|
||||
if ns_parser.s_timeframe:
|
||||
if ns_parser.s_timeframe not in l_timeframes:
|
||||
raise ValueError(
|
||||
f"Timeframe {ns_parser.s_timeframe} should be one of {l_timeframes}"
|
||||
)
|
||||
s_timeframe = ns_parser.s_timeframe
|
||||
else:
|
||||
s_timeframe = l_timeframes[-1]
|
||||
|
||||
df_financials_compared = combine_similar_financials(
|
||||
ddf_financials, similar, s_timeframe
|
||||
)
|
||||
|
||||
if gtff.USE_COLOR:
|
||||
df_financials_compared = df_financials_compared.applymap(
|
||||
financials_colored_values
|
||||
)
|
||||
|
||||
patch_pandas_text_adjustment()
|
||||
pd.set_option("display.max_colwidth", None)
|
||||
pd.set_option("display.max_rows", None)
|
||||
|
||||
df_financials_compared.index.name = s_timeframe
|
||||
print(df_financials_compared.to_string())
|
||||
print("")
|
||||
|
||||
except Exception as e:
|
||||
print(e)
|
||||
print("")
|
||||
return
|
||||
|
||||
|
||||
def balance(l_args, s_ticker):
|
||||
parser = argparse.ArgumentParser(
|
||||
add_help=False,
|
||||
prog="balance",
|
||||
description="""
|
||||
Prints either yearly or quarterly assets from balance sheet of the company.
|
||||
The following fields are expected: Cash & Short Term Investments, Cash & Short Term
|
||||
Investments Growth, Cash Only, Short-Term Investments, Cash & ST Investments / Total
|
||||
Assets, Total Accounts Receivable, Total Accounts Receivable Growth, Accounts
|
||||
Receivables, Net, Accounts Receivables, Gross, Bad Debt/Doubtful Accounts, Other
|
||||
Receivable, Accounts Receivable Turnover, Inventories, Finished Goods, Work in
|
||||
Progress, Raw Materials, Progress Payments & Other, Other Current Assets,
|
||||
Miscellaneous Current Assets, Net Property, Plant & Equipment, Property, Plant &
|
||||
Equipment - Gross, Buildings, Land & Improvements, Computer Software and Equipment,
|
||||
Other Property, Plant & Equipment, Accumulated Depreciation, Total Investments and
|
||||
Advances, Other Long-Term Investments, Long-Term Note Receivables, Intangible Assets,
|
||||
Net Goodwill, Net Other Intangibles, Other Assets.
|
||||
|
||||
Prints either yearly or quarterly liabilities and shareholders' equity from balance
|
||||
sheet of the company. The following fields are expected: ST Debt & Current Portion LT
|
||||
Debt, Short Term Debt, Current Portion of Long Term Debt, Accounts Payable, Accounts
|
||||
Payable Growth, Income Tax Payable, Other Current Liabilities, Dividends Payable,
|
||||
Accrued Payroll, Miscellaneous Current Liabilities, Long-Term Debt, Long-Term Debt
|
||||
excl. Capitalized Leases, Non-Convertible Debt, Convertible Debt, Capitalized Lease
|
||||
Obligations, Provision for Risks & Charges, Deferred Taxes, Deferred Taxes - Credits,
|
||||
Deferred Taxes - Debit, Other Liabilities, Other Liabilities (excl. Deferred Income),
|
||||
Deferred Income, Non-Equity Reserves, Total Liabilities / Total Assets, Preferred Stock
|
||||
(Carrying Value), Redeemable Preferred Stock, Non-Redeemable Preferred Stock, Common
|
||||
Equity (Total), Common Equity/Total Assets, Common Stock Par/Carry Value, Retained
|
||||
Earnings, ESOP Debt Guarantee, Cumulative Translation Adjustment/Unrealized For. Exch.
|
||||
Gain, Unrealized Gain/Loss Marketable Securities, Revaluation Reserves, Treasury Stock,
|
||||
Total Shareholders' Equity, Total Shareholders' Equity / Total Assets, Accumulated
|
||||
Minority Interest, Total Equity, Total Current Assets, Total Assets, Total Current
|
||||
Liabilities, Total Liabilities, and Liabilities & Shareholders' Equity.
|
||||
[Source: Market Watch]
|
||||
""",
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"-q",
|
||||
"--quarter",
|
||||
action="store_true",
|
||||
default=False,
|
||||
dest="b_quarter",
|
||||
help="Quarter fundamental data flag.",
|
||||
)
|
||||
|
||||
try:
|
||||
ns_parser = parse_known_args_and_warn(parser, l_args)
|
||||
if not ns_parser:
|
||||
return
|
||||
|
||||
df_financials = prepare_df_financials(s_ticker, "balance", ns_parser.b_quarter)
|
||||
|
||||
if gtff.USE_COLOR:
|
||||
df_financials = df_financials.applymap(financials_colored_values)
|
||||
|
||||
patch_pandas_text_adjustment()
|
||||
pd.set_option("display.max_colwidth", None)
|
||||
pd.set_option("display.max_rows", None)
|
||||
|
||||
print(df_financials.to_string(index=False))
|
||||
print("")
|
||||
|
||||
except Exception as e:
|
||||
print(e)
|
||||
print("")
|
||||
return
|
||||
|
||||
|
||||
def cash(l_args, s_ticker):
|
||||
parser = argparse.ArgumentParser(
|
||||
add_help=False,
|
||||
prog="cash_flow",
|
||||
description="""
|
||||
Prints either yearly or quarterly cash flow operating activities of the company.
|
||||
The following fields are expected: Net Income before Extraordinaries, Net Income
|
||||
Growth, Depreciation, Depletion & Amortization, Depreciation and Depletion,
|
||||
Amortization of Intangible Assets, Deferred Taxes & Investment Tax Credit, Deferred
|
||||
Taxes, Investment Tax Credit, Other Funds, Funds from Operations, Extraordinaries,
|
||||
Changes in Working Capital, Receivables, Accounts Payable, Other Assets/Liabilities,
|
||||
and Net Operating Cash Flow Growth.
|
||||
Prints either yearly or quarterly cash flow investing activities of the company.
|
||||
The following fields are expected: Capital Expenditures, Capital Expenditures Growth,
|
||||
Capital Expenditures/Sales, Capital Expenditures (Fixed Assets), Capital Expenditures
|
||||
(Other Assets), Net Assets from Acquisitions, Sale of Fixed Assets & Businesses,
|
||||
Purchase/Sale of Investments, Purchase of Investments, Sale/Maturity of Investments,
|
||||
Other Uses, Other Sources, Net Investing Cash Flow Growth.
|
||||
Prints either yearly or quarterly cash flow financing activities of the company.
|
||||
The following fields are expected: Cash Dividends Paid - Total, Common Dividends,
|
||||
Preferred Dividends, Change in Capital Stock, Repurchase of Common & Preferred Stk.,
|
||||
Sale of Common & Preferred Stock, Proceeds from Stock Options, Other Proceeds from Sale
|
||||
of Stock, Issuance/Reduction of Debt, Net, Change in Current Debt, Change in Long-Term
|
||||
Debt, Issuance of Long-Term Debt, Reduction in Long-Term Debt, Other Funds, Other Uses,
|
||||
Other Sources, Net Financing Cash Flow Growth, Net Financing Cash Flow/Sales, Exchange
|
||||
Rate Effect, Miscellaneous Funds, Net Change in Cash, Free Cash Flow, Free Cash Flow
|
||||
Growth, Free Cash Flow Yield, Net Operating Cash Flow, Net Investing Cash Flow, Net
|
||||
Financing Cash Flow.
|
||||
[Source: Market Watch]
|
||||
""",
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"-q",
|
||||
"--quarter",
|
||||
action="store_true",
|
||||
default=False,
|
||||
dest="b_quarter",
|
||||
help="Quarter fundamental data flag.",
|
||||
)
|
||||
|
||||
try:
|
||||
ns_parser = parse_known_args_and_warn(parser, l_args)
|
||||
if not ns_parser:
|
||||
return
|
||||
|
||||
df_financials = prepare_df_financials(s_ticker, "cashflow", ns_parser.b_quarter)
|
||||
|
||||
if gtff.USE_COLOR:
|
||||
df_financials = df_financials.applymap(financials_colored_values)
|
||||
|
||||
patch_pandas_text_adjustment()
|
||||
pd.set_option("display.max_colwidth", None)
|
||||
pd.set_option("display.max_rows", None)
|
||||
|
||||
print(df_financials.to_string(index=False))
|
||||
print("")
|
||||
|
||||
except Exception as e:
|
||||
print(e)
|
||||
print("")
|
||||
return
|
||||
|
||||
|
||||
def prepare_df_financials(
|
||||
ticker: str, statement: str, quarter: bool = False
|
||||
) -> pd.DataFrame:
|
||||
"""Builds a DataFrame with financial statements for a given company
|
||||
|
||||
Parameters
|
||||
----------
|
||||
ticker : str
|
||||
Company's stock ticker
|
||||
statement : str
|
||||
Either income, balance or cashflow
|
||||
quarter : bool, optional
|
||||
Return quarterly financial statements instead of annual, by default False
|
||||
|
||||
Returns
|
||||
-------
|
||||
pd.DataFrame
|
||||
A DataFrame with financial info
|
||||
|
||||
Raises
|
||||
------
|
||||
ValueError
|
||||
If statement is not income, balance or cashflow
|
||||
"""
|
||||
financial_urls = {
|
||||
"income": {
|
||||
"quarter": "https://www.marketwatch.com/investing/stock/{}/financials/income/quarter",
|
||||
"annual": "https://www.marketwatch.com/investing/stock/{}/financials/income",
|
||||
},
|
||||
"balance": {
|
||||
"quarter": "https://www.marketwatch.com/investing/stock/{}/financials/balance-sheet/quarter",
|
||||
"annual": "https://www.marketwatch.com/investing/stock/{}/financials/balance-sheet",
|
||||
},
|
||||
"cashflow": {
|
||||
"quarter": "https://www.marketwatch.com/investing/stock/{}/financials/cash-flow/quarter",
|
||||
"annual": "https://www.marketwatch.com/investing/stock/{}/financials/cash-flow",
|
||||
},
|
||||
}
|
||||
|
||||
if statement not in financial_urls.keys():
|
||||
raise ValueError(f"type {statement} is not in {financial_urls.keys()}")
|
||||
|
||||
if quarter:
|
||||
period = "quarter"
|
||||
else:
|
||||
period = "annual"
|
||||
|
||||
text_soup_financials = BeautifulSoup(
|
||||
requests.get(
|
||||
financial_urls[statement][period].format(ticker),
|
||||
headers={"User-Agent": get_user_agent()},
|
||||
).text,
|
||||
"lxml",
|
||||
)
|
||||
|
||||
# Define financials columns
|
||||
a_financials_header = list()
|
||||
for financials_header in text_soup_financials.findAll(
|
||||
"th", {"class": "overflow__heading"}
|
||||
):
|
||||
a_financials_header.append(financials_header.text.strip("\n").split("\n")[0])
|
||||
|
||||
s_header_end_trend = ("5-year trend", "5- qtr trend")[quarter]
|
||||
df_financials = pd.DataFrame(
|
||||
columns=a_financials_header[0 : a_financials_header.index(s_header_end_trend)]
|
||||
)
|
||||
|
||||
find_table = text_soup_financials.findAll(
|
||||
"div", {"class": "element element--table table--fixed financials"}
|
||||
)
|
||||
|
||||
if not find_table:
|
||||
return df_financials
|
||||
|
||||
financials_rows = find_table[0].findAll(
|
||||
"tr", {"class": ["table__row is-highlighted", "table__row"]}
|
||||
)
|
||||
|
||||
for a_row in financials_rows:
|
||||
constructed_row = list()
|
||||
financial_columns = a_row.findAll(
|
||||
"td", {"class": ["overflow__cell", "overflow__cell fixed--column"]}
|
||||
)
|
||||
|
||||
if not financial_columns:
|
||||
continue
|
||||
|
||||
for a_column in financial_columns:
|
||||
column_to_text = a_column.text.strip()
|
||||
if "\n" in column_to_text:
|
||||
column_to_text = column_to_text.split("\n")[0]
|
||||
|
||||
if column_to_text == "":
|
||||
continue
|
||||
constructed_row.append(column_to_text)
|
||||
|
||||
df_financials.loc[len(df_financials)] = constructed_row
|
||||
|
||||
return df_financials
|
||||
|
||||
|
||||
def prepare_comparison_financials(
|
||||
similar: List[str], statement: str, quarter: bool
|
||||
) -> Tuple[List[str], Dict[str, pd.DataFrame]]:
|
||||
"""Builds a dictionary of DataFrame with financial statements for list of tickers
|
||||
|
||||
Parameters
|
||||
----------
|
||||
similar : List[str]
|
||||
List of similar stock tickers
|
||||
statement : str
|
||||
Either income, balance or cashflow
|
||||
quarter : bool
|
||||
Return quarterly financial statements instead of annual, by default False
|
||||
|
||||
Returns
|
||||
-------
|
||||
List[str]
|
||||
List of index headers
|
||||
Dict[str, pd.DataFrame]
|
||||
A dictionary of DataFrame with financial info from list of similar tickers
|
||||
"""
|
||||
|
||||
financials = {}
|
||||
# Get financial dataframe of each company
|
||||
for symbol in similar:
|
||||
financials[symbol] = prepare_df_financials(
|
||||
symbol, statement, quarter
|
||||
).set_index("Item")
|
||||
|
||||
items = []
|
||||
# Get common headers between tickers
|
||||
for symbol in similar:
|
||||
if len(financials[symbol].columns) > len(items):
|
||||
items = financials[symbol].columns
|
||||
|
||||
# Add columns with N/A when data is not available, to have similar columns
|
||||
for symbol in similar:
|
||||
if len(financials[symbol].columns) < len(items):
|
||||
for item in items:
|
||||
if item not in financials[symbol].columns:
|
||||
financials[symbol][item] = "N/A"
|
||||
financials[symbol] = financials[symbol].reindex(sorted(items), axis=1)
|
||||
|
||||
return list(items), financials
|
||||
|
||||
|
||||
def combine_similar_financials(
|
||||
financials: Dict[str, pd.DataFrame],
|
||||
similar: List[str],
|
||||
timeframe: str,
|
||||
) -> pd.DataFrame:
|
||||
"""Builds a DataFrame with financial statements from a certain timeframe of a list of tickers
|
||||
|
||||
Parameters
|
||||
----------
|
||||
Dict[str, pd.DataFrame]
|
||||
A dictionary of DataFrame with financial info from list of similar tickers
|
||||
similar : List[str]
|
||||
List of similar stock tickers
|
||||
statement : str
|
||||
Either income, balance or cashflow
|
||||
|
||||
Returns
|
||||
-------
|
||||
pd.DataFrame
|
||||
A DataFrame with financial statements from a certain timeframe of a list of tickers
|
||||
"""
|
||||
|
||||
compare_financials = financials[similar[0]][timeframe].to_frame()
|
||||
compare_financials.rename(columns={timeframe: similar[0]}, inplace=True)
|
||||
|
||||
for symbol in similar[1:]:
|
||||
compare_financials[symbol] = financials[symbol][timeframe]
|
||||
|
||||
return compare_financials
|
||||
@@ -293,7 +293,9 @@ def parse_known_args_and_warn(parser, l_args):
|
||||
|
||||
|
||||
def financials_colored_values(val: str) -> str:
|
||||
if sum(c.isalpha() for c in val) < 2:
|
||||
if val == "N/A":
|
||||
val = f"{Fore.YELLOW}{val}{Style.RESET_ALL}"
|
||||
elif sum(c.isalpha() for c in val) < 2:
|
||||
if "%" in val:
|
||||
if "-" in val:
|
||||
val = f"{Fore.RED}{val}{Style.RESET_ALL}"
|
||||
|
||||
Reference in New Issue
Block a user