mirror of
https://github.com/OpenBB-finance/OpenBB.git
synced 2026-10-27 12:40:35 +00:00
Add income,cashflow,balance comparison
This commit is contained in:
@@ -29,6 +29,8 @@ class ComparisonAnalysisController:
|
||||
"historical",
|
||||
"corr",
|
||||
"income",
|
||||
"balance",
|
||||
"cash",
|
||||
]
|
||||
|
||||
def __init__(
|
||||
@@ -80,6 +82,8 @@ class ComparisonAnalysisController:
|
||||
print(" corr correlation between similar companies")
|
||||
print("")
|
||||
print(" income income financials comparison")
|
||||
print(" balance balance financials comparison")
|
||||
print(" cash cash financials comparison")
|
||||
print("")
|
||||
return
|
||||
|
||||
@@ -126,7 +130,7 @@ class ComparisonAnalysisController:
|
||||
"-s",
|
||||
"--similar",
|
||||
dest="l_similar",
|
||||
type=lambda s: [str(item) for item in s.split(",")],
|
||||
type=lambda s: [str(item).upper() for item in s.split(",")],
|
||||
default=[],
|
||||
help="similar companies to compare with.",
|
||||
)
|
||||
@@ -201,6 +205,14 @@ class ComparisonAnalysisController:
|
||||
"""Process income command"""
|
||||
mw_api.compare_income(other_args, self.ticker, self.similar)
|
||||
|
||||
def call_balance(self, other_args: List[str]):
|
||||
"""Process balance command"""
|
||||
mw_api.compare_balance(other_args, self.ticker, self.similar)
|
||||
|
||||
def call_cash(self, other_args: List[str]):
|
||||
"""Process cash command"""
|
||||
mw_api.compare_cashflow(other_args, self.ticker, self.similar)
|
||||
|
||||
|
||||
def menu(stock: pd.DataFrame, ticker: str, start: datetime, interval: str):
|
||||
"""Comparison Analysis Menu"""
|
||||
|
||||
@@ -39,15 +39,15 @@ def compare_income(other_args: List[str], ticker: str, similar: List[str]):
|
||||
"-s",
|
||||
"--similar",
|
||||
dest="l_similar",
|
||||
type=lambda s: [str(item) for item in s.split(",")],
|
||||
default=[],
|
||||
type=lambda s: [str(item).upper() for item in s.split(",")],
|
||||
default=similar,
|
||||
help="similar companies to compare with.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-a",
|
||||
"--also",
|
||||
dest="l_also",
|
||||
type=lambda s: [str(item) for item in s.split(",")],
|
||||
type=lambda s: [str(item).upper() for item in s.split(",")],
|
||||
default=[],
|
||||
help="apart from loaded similar companies also compare with.",
|
||||
)
|
||||
@@ -73,29 +73,31 @@ def compare_income(other_args: List[str], ticker: str, similar: List[str]):
|
||||
if not ns_parser:
|
||||
return
|
||||
|
||||
if ns_parser.l_similar:
|
||||
similar = ns_parser.l_similar
|
||||
|
||||
similar += ns_parser.l_also
|
||||
l_similar = ns_parser.l_similar
|
||||
l_similar += ns_parser.l_also
|
||||
|
||||
# Add main ticker to similar list of companies
|
||||
similar.insert(0, ticker)
|
||||
l_similar.insert(0, ticker)
|
||||
|
||||
l_timeframes, ddf_financials = prepare_comparison_financials(
|
||||
similar, "income", ns_parser.b_quarter
|
||||
l_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}"
|
||||
f"Timeframe selected should be one of {', '.join(l_timeframes)}"
|
||||
)
|
||||
s_timeframe = ns_parser.s_timeframe
|
||||
else:
|
||||
s_timeframe = l_timeframes[-1]
|
||||
|
||||
print(
|
||||
f"Other available {('yearly', 'quarterly')[ns_parser.b_quarter]} timeframes are: {', '.join(l_timeframes)}\n"
|
||||
)
|
||||
|
||||
df_financials_compared = combine_similar_financials(
|
||||
ddf_financials, similar, s_timeframe
|
||||
ddf_financials, l_similar, s_timeframe, ns_parser.b_quarter
|
||||
)
|
||||
|
||||
if gtff.USE_COLOR:
|
||||
@@ -107,147 +109,224 @@ def compare_income(other_args: List[str], ticker: str, similar: List[str]):
|
||||
pd.set_option("display.max_colwidth", None)
|
||||
pd.set_option("display.max_rows", None)
|
||||
|
||||
df_financials_compared.index.name = s_timeframe
|
||||
if not ns_parser.b_quarter:
|
||||
df_financials_compared.index.name = s_timeframe
|
||||
|
||||
print(df_financials_compared.to_string())
|
||||
print("")
|
||||
|
||||
except Exception as e:
|
||||
print(e)
|
||||
print("")
|
||||
print(e, "\n")
|
||||
return
|
||||
|
||||
|
||||
def balance(l_args, s_ticker):
|
||||
def compare_balance(other_args: List[str], ticker: str, similar: List[str]):
|
||||
"""Compare balance 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="balance",
|
||||
prog="compare_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]
|
||||
Prints either yearly or quarterly balance 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).upper() for item in s.split(",")],
|
||||
default=similar,
|
||||
help="similar companies to compare with.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-a",
|
||||
"--also",
|
||||
dest="l_also",
|
||||
type=lambda s: [str(item).upper() 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 fundamental data flag.",
|
||||
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, l_args)
|
||||
ns_parser = parse_known_args_and_warn(parser, other_args)
|
||||
if not ns_parser:
|
||||
return
|
||||
|
||||
df_financials = prepare_df_financials(s_ticker, "balance", ns_parser.b_quarter)
|
||||
l_similar = ns_parser.l_similar
|
||||
l_similar += ns_parser.l_also
|
||||
|
||||
# Add main ticker to similar list of companies
|
||||
l_similar.insert(0, ticker)
|
||||
|
||||
l_timeframes, ddf_financials = prepare_comparison_financials(
|
||||
l_similar, "balance", ns_parser.b_quarter
|
||||
)
|
||||
|
||||
if ns_parser.s_timeframe:
|
||||
if ns_parser.s_timeframe not in l_timeframes:
|
||||
raise ValueError(
|
||||
f"Timeframe selected should be one of {', '.join(l_timeframes)}"
|
||||
)
|
||||
s_timeframe = ns_parser.s_timeframe
|
||||
else:
|
||||
s_timeframe = l_timeframes[-1]
|
||||
|
||||
print(
|
||||
f"Other available {('yearly', 'quarterly')[ns_parser.b_quarter]} timeframes are: {', '.join(l_timeframes)}\n"
|
||||
)
|
||||
|
||||
df_financials_compared = combine_similar_financials(
|
||||
ddf_financials, l_similar, s_timeframe, ns_parser.b_quarter
|
||||
)
|
||||
|
||||
if gtff.USE_COLOR:
|
||||
df_financials = df_financials.applymap(financials_colored_values)
|
||||
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)
|
||||
|
||||
print(df_financials.to_string(index=False))
|
||||
if not ns_parser.b_quarter:
|
||||
df_financials_compared.index.name = s_timeframe
|
||||
|
||||
print(df_financials_compared.to_string())
|
||||
print("")
|
||||
|
||||
except Exception as e:
|
||||
print(e)
|
||||
print("")
|
||||
print(e, "\n")
|
||||
return
|
||||
|
||||
|
||||
def cash(l_args, s_ticker):
|
||||
def compare_cashflow(other_args: List[str], ticker: str, similar: List[str]):
|
||||
"""Compare balance 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="cash_flow",
|
||||
prog="compare_cashflow",
|
||||
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]
|
||||
Prints either yearly or quarterly cash 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).upper() for item in s.split(",")],
|
||||
default=similar,
|
||||
help="similar companies to compare with.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-a",
|
||||
"--also",
|
||||
dest="l_also",
|
||||
type=lambda s: [str(item).upper() 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 fundamental data flag.",
|
||||
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, l_args)
|
||||
ns_parser = parse_known_args_and_warn(parser, other_args)
|
||||
if not ns_parser:
|
||||
return
|
||||
|
||||
df_financials = prepare_df_financials(s_ticker, "cashflow", ns_parser.b_quarter)
|
||||
l_similar = ns_parser.l_similar
|
||||
l_similar += ns_parser.l_also
|
||||
|
||||
# Add main ticker to similar list of companies
|
||||
l_similar.insert(0, ticker)
|
||||
|
||||
l_timeframes, ddf_financials = prepare_comparison_financials(
|
||||
l_similar, "cashflow", ns_parser.b_quarter
|
||||
)
|
||||
|
||||
if ns_parser.s_timeframe:
|
||||
if ns_parser.s_timeframe not in l_timeframes:
|
||||
raise ValueError(
|
||||
f"Timeframe selected should be one of {', '.join(l_timeframes)}"
|
||||
)
|
||||
s_timeframe = ns_parser.s_timeframe
|
||||
else:
|
||||
s_timeframe = l_timeframes[-1]
|
||||
|
||||
print(
|
||||
f"Other available {('yearly', 'quarterly')[ns_parser.b_quarter]} timeframes are: {', '.join(l_timeframes)}\n"
|
||||
)
|
||||
|
||||
df_financials_compared = combine_similar_financials(
|
||||
ddf_financials, l_similar, s_timeframe, ns_parser.b_quarter
|
||||
)
|
||||
|
||||
if gtff.USE_COLOR:
|
||||
df_financials = df_financials.applymap(financials_colored_values)
|
||||
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)
|
||||
|
||||
print(df_financials.to_string(index=False))
|
||||
if not ns_parser.b_quarter:
|
||||
df_financials_compared.index.name = s_timeframe
|
||||
|
||||
print(df_financials_compared.to_string())
|
||||
print("")
|
||||
|
||||
except Exception as e:
|
||||
print(e)
|
||||
print("")
|
||||
print(e, "\n")
|
||||
return
|
||||
|
||||
|
||||
@@ -381,19 +460,23 @@ def prepare_comparison_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
|
||||
if quarter:
|
||||
items = financials[similar[0]].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)
|
||||
else:
|
||||
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
|
||||
|
||||
@@ -402,28 +485,52 @@ def combine_similar_financials(
|
||||
financials: Dict[str, pd.DataFrame],
|
||||
similar: List[str],
|
||||
timeframe: str,
|
||||
quarter: bool,
|
||||
) -> pd.DataFrame:
|
||||
"""Builds a DataFrame with financial statements from a certain timeframe of a list of tickers
|
||||
|
||||
Parameters
|
||||
----------
|
||||
Dict[str, pd.DataFrame]
|
||||
financials : 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
|
||||
|
||||
quarter : bool
|
||||
False for yearly data, True for quarterly
|
||||
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)
|
||||
# Quarter data is a bit more confusing for comparison due to the fact that
|
||||
# the reports may occur at slight different moments. Hence we rely on the
|
||||
# order set by the Market Watch website
|
||||
|
||||
for symbol in similar[1:]:
|
||||
compare_financials[symbol] = financials[symbol][timeframe]
|
||||
if quarter:
|
||||
compare_financials = financials[similar[0]][timeframe].to_frame()
|
||||
compare_financials.rename(columns={timeframe: similar[0]}, inplace=True)
|
||||
earnings_dates = [timeframe]
|
||||
idx = len(financials[similar[0]].columns) - list(
|
||||
financials[similar[0]].columns
|
||||
).index(timeframe)
|
||||
|
||||
for symbol in similar[1:]:
|
||||
report_quarter_date = list(financials[symbol].columns)[-idx]
|
||||
earnings_dates.append(report_quarter_date)
|
||||
compare_financials[symbol] = financials[symbol][report_quarter_date]
|
||||
|
||||
compare_financials.columns = pd.MultiIndex.from_tuples(
|
||||
zip(earnings_dates, compare_financials.columns),
|
||||
)
|
||||
|
||||
else:
|
||||
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,8 +293,8 @@ def parse_known_args_and_warn(parser, l_args):
|
||||
|
||||
|
||||
def financials_colored_values(val: str) -> str:
|
||||
if val == "N/A":
|
||||
val = f"{Fore.YELLOW}{val}{Style.RESET_ALL}"
|
||||
if val == "N/A" or str(val) == "nan":
|
||||
val = f"{Fore.YELLOW}N/A{Style.RESET_ALL}"
|
||||
elif sum(c.isalpha() for c in val) < 2:
|
||||
if "%" in val:
|
||||
if "-" in val:
|
||||
@@ -303,6 +303,7 @@ def financials_colored_values(val: str) -> str:
|
||||
val = f"{Fore.GREEN}{val}{Style.RESET_ALL}"
|
||||
elif "(" in val:
|
||||
val = f"{Fore.RED}{val}{Style.RESET_ALL}"
|
||||
|
||||
return val
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user