Fixed incorrect data display using stocks/fa/est command (#4940)

* Removed empty row in OpenBB SDK table under Installation

* Revamped `get_estimates` function

* Linting

* Fixed bugs, tests and modified args

* Fixed test
This commit is contained in:
Pratyush Shukla
2023-05-02 01:53:59 +05:30
committed by GitHub
parent c603a360ec
commit 3d7b934d16
8 changed files with 103 additions and 163 deletions

2
README.md vendored
View File

@@ -80,7 +80,7 @@ If you wish to install the OpenBB Terminal or the OpenBB SDK, please use one of
|:-|:-|
|[PyPI](https://docs.openbb.co/terminal/installation/pypi)|If you wish to use the OpenBB SDK in Python or Jupyter Notebooks|
|[Source](https://docs.openbb.co/terminal/installation/source)|If you wish to contribute to the development of the OpenBB Terminal|
nbsp;|
<!-- nbsp;| -->
## 2. Contributing

View File

@@ -3,7 +3,6 @@ __docformat__ = "numpy"
import json
import logging
import re
from typing import Tuple
import pandas as pd
@@ -193,120 +192,61 @@ def get_estimates(symbol: str) -> Tuple[pd.DataFrame, pd.DataFrame, pd.DataFrame
"lxml",
)
l_estimates_year_header = list()
l_estimates_quarter_header = list()
for estimates_header in text_soup_market_business_insider.findAll(
"th", {"class": "table__th text-right"}
):
s_estimates_header = estimates_header.text.strip()
if s_estimates_header.isdigit():
l_estimates_year_header.append(s_estimates_header)
elif ("in %" not in s_estimates_header) and ("Job" not in s_estimates_header):
l_estimates_quarter_header.append(s_estimates_header)
# Get all tables and convert them to list of pandas dataframes
tables = text_soup_market_business_insider.find_all("table")
list_df = pd.read_html(str(tables))
l_estimates_year_metric = list()
for estimates_year_metric in text_soup_market_business_insider.findAll(
"td", {"class": "table__td black"}
):
l_estimates_year_metric.append(estimates_year_metric.text)
# Get year estimates
df_year_estimates = list_df[3]
l_year_estimates_columns = df_year_estimates.columns.tolist()
l_year_estimates_columns[0] = "YEARLY ESTIMATES"
df_year_estimates.columns = l_year_estimates_columns
df_year_estimates.set_index("YEARLY ESTIMATES", inplace=True)
l_estimates_quarter_metric = list()
for estimates_quarter_metric in text_soup_market_business_insider.findAll(
"td", {"class": "table__td font-color-dim-gray"}
):
l_estimates_quarter_metric.append(estimates_quarter_metric.text)
df_quarter = list_df[4]
date_row = dict()
d_metric_year = dict()
d_metric_quarter_earnings = dict()
d_metric_quarter_revenues = dict()
l_metrics = list()
n_metrics = 0
b_year = True
for idx, metric_value in enumerate(
text_soup_market_business_insider.findAll(
"td", {"class": "table__td text-right"}
)
):
if b_year:
# YEAR metrics
l_metrics.append(metric_value.text.strip())
# Get quarter earnings estimates
df_quarter_earnings = df_quarter.iloc[0:5, :].reset_index(drop=True).copy()
df_quarter_earnings.drop(index=0, inplace=True)
l_quarter_earnings_columns = df_quarter_earnings.columns.tolist()
l_quarter_earnings_columns[0] = "QUARTER EARNINGS ESTIMATES"
date_row["QUARTER EARNINGS ESTIMATES"] = "Date"
# Check if we have processed all year metrics
if n_metrics > len(l_estimates_year_metric) - 1:
b_year = False
n_metrics = 0
l_metrics = list()
idx_y = idx
# Adding Date info to add to dataframe
for col in l_quarter_earnings_columns[1:]:
key = col.split("ending")[0].strip()
value = col[col.find("ending") :].strip()
date_row[key] = value
# Add value to dictionary
if (idx + 1) % len(l_estimates_year_header) == 0:
d_metric_year[l_estimates_year_metric[n_metrics]] = l_metrics
l_metrics = list()
n_metrics += 1
if not b_year:
# QUARTER metrics
l_metrics.append(metric_value.text.strip())
# Check if we have processed all quarter metrics
if n_metrics > len(l_estimates_quarter_metric) - 1:
break
# Add value to dictionary
if (idx - idx_y + 1) % len(l_estimates_quarter_header) == 0:
if n_metrics < 4:
d_metric_quarter_earnings[
l_estimates_quarter_metric[n_metrics]
] = l_metrics
else:
d_metric_quarter_revenues[
l_estimates_quarter_metric[n_metrics - 4]
] = l_metrics
l_metrics = list()
n_metrics += 1
df_year_estimates = pd.DataFrame.from_dict(
d_metric_year, orient="index", columns=l_estimates_year_header
df_quarter_earnings.columns = date_row.keys()
date_row = pd.DataFrame(date_row, index=[0])
df_quarter_earnings = pd.concat([date_row, df_quarter_earnings]).reset_index(
drop=True
)
df_year_estimates.index.name = "YEARLY ESTIMATES"
df_quarter_earnings = pd.DataFrame.from_dict(
d_metric_quarter_earnings,
orient="index",
columns=l_estimates_quarter_header,
df_quarter_earnings.set_index("QUARTER EARNINGS ESTIMATES", inplace=True)
# Setting date_row to empty dict object
date_row = dict()
# Get quarter revenues estimates
df_quarter_revenues = df_quarter.iloc[5:, :].reset_index(drop=True).copy()
df_quarter_revenues.drop(index=0, inplace=True)
l_quarter_revenues_columns = df_quarter_revenues.columns.tolist()
l_quarter_revenues_columns[0] = "QUARTER REVENUES ESTIMATES"
date_row["QUARTER REVENUES ESTIMATES"] = "Date"
# Adding Date info to add to dataframe
for col in l_quarter_revenues_columns[1:]:
key = col.split("ending")[0].strip()
value = col[col.find("ending") :].strip()
date_row[key] = value
df_quarter_revenues.columns = date_row.keys()
date_row = pd.DataFrame(date_row, index=[0])
df_quarter_revenues = pd.concat([date_row, df_quarter_revenues]).reset_index(
drop=True
)
# df_quarter_earnings.index.name = 'Earnings'
df_quarter_revenues = pd.DataFrame.from_dict(
d_metric_quarter_revenues,
orient="index",
columns=l_estimates_quarter_header,
)
# df_quarter_revenues.index.name = 'Revenues'
if not df_quarter_earnings.empty:
l_quarter = list()
l_date = list()
for quarter_title in df_quarter_earnings.columns:
l_quarter.append(re.split(" ending", quarter_title)[0])
if len(re.split(" ending", quarter_title)) == 2:
l_date.append(
"ending " + re.split(" ending", quarter_title)[1].strip()
)
else:
l_date.append("-")
df_quarter_earnings.index.name = "QUARTER EARNINGS ESTIMATES"
df_quarter_earnings.columns = l_quarter
df_quarter_earnings.loc["Date"] = l_date
df_quarter_earnings = df_quarter_earnings.reindex(
["Date", "No. of Analysts", "Average Estimate", "Year Ago", "Publish Date"]
)
if not df_quarter_revenues.empty:
df_quarter_revenues.index.name = "QUARTER REVENUES ESTIMATES"
df_quarter_revenues.columns = l_quarter
df_quarter_revenues.loc["Date"] = l_date
df_quarter_revenues = df_quarter_revenues.reindex(
["Date", "No. of Analysts", "Average Estimate", "Year Ago", "Publish Date"]
)
df_quarter_revenues.set_index("QUARTER REVENUES ESTIMATES", inplace=True)
return df_year_estimates, df_quarter_earnings, df_quarter_revenues

View File

@@ -215,7 +215,7 @@ def display_estimates(
df_quarter_revenues,
) = business_insider_model.get_estimates(symbol)
if estimate == "annualearnings":
if estimate == "annual_earnings":
print_rich_table(
df_year_estimates,
headers=list(df_year_estimates.columns),
@@ -231,7 +231,7 @@ def display_estimates(
sheet_name,
)
elif estimate == "quarterearnings":
elif estimate == "quarter_earnings":
print_rich_table(
df_quarter_earnings,
headers=list(df_quarter_earnings.columns),
@@ -247,7 +247,7 @@ def display_estimates(
sheet_name,
)
elif estimate == "annualrevenue":
elif estimate == "quarter_revenues":
print_rich_table(
df_quarter_revenues,
headers=list(df_quarter_revenues.columns),

View File

@@ -92,7 +92,7 @@ class FundamentalAnalysisController(StockBaseController):
PATH = "/stocks/fa/"
SHRS_CHOICES = ["major", "institutional", "mutualfund"]
ESTIMATE_CHOICES = ["annualrevenue", "annualearnings", "quarterearnings"]
ESTIMATE_CHOICES = ["annual_earnings", "quarter_earnings", "quarter_revenues"]
CHOICES_GENERATION = True
def __init__(
@@ -1858,7 +1858,7 @@ class FundamentalAnalysisController(StockBaseController):
help="Estimates to get",
dest="estimate",
choices=self.ESTIMATE_CHOICES,
default="annualearnings",
default="annual_earnings",
)
ns_parser = self.parse_known_args_and_warn(
parser, other_args, EXPORT_ONLY_RAW_DATA_ALLOWED

View File

@@ -1,28 +1,28 @@
YEARLY ESTIMATES,2023,2024,2025,2026,2027
Revenue,"103,351","135,186","168,507",-,-
Revenue,103351,135186,168507,-,-
Dividend,0.00,0.00,0.00,-,-
Dividend Yield (in %),-,-,-,-,-
EPS,4.08,5.65,6.91,5.83,6.98
P/E Ratio,45.95,33.21,27.13,32.17,26.86
EBIT,"14,600","21,973","27,740","30,032","44,029"
EBITDA,"19,429","27,963","38,063","37,754","38,937"
Net Profit,"13,681","19,370","23,763","21,385","26,126"
Net Profit Adjusted,"13,713","19,366","23,746","21,385","26,126"
Pre-Tax Profit,"14,437","22,015","28,932","29,404","31,787"
Net Profit (Adjusted),"14,363","22,392","29,878","29,404","31,787"
EBIT,14600,21973,27740,30032,44029
EBITDA,19429,27963,38063,37754,38937
Net Profit,13681,19370,23763,21385,26126
Net Profit Adjusted,13713,19366,23746,21385,26126
Pre-Tax Profit,14437,22015,28932,29404,31787
Net Profit (Adjusted),14363,22392,29878,29404,31787
EPS (Non-GAAP) ex. SOE,4.08,5.65,6.91,5.83,6.98
EPS (GAAP),3.49,5.25,6.18,5.73,6.65
Gross Income,"23,184","32,468","40,980","37,949","42,464"
Cash Flow from Investing,"-7,935","-9,482","-10,201","-12,681",-
Cash Flow from Operations,"19,523","24,129","27,935","29,376","35,875"
Gross Income,23184,32468,40980,37949,42464
Cash Flow from Investing,-7935,-9482,-10201,-12681,-
Cash Flow from Operations,19523,24129,27935,29376,35875
Cash Flow from Financing,-478,-810,100,-,-
Cash Flow per Share,4.92,7.39,6.94,-,-
Free Cash Flow,"10,236","14,300","15,203","18,405","22,501"
Free Cash Flow,10236,14300,15203,18405,22501
Free Cash Flow per Share,2.84,4.55,4.61,6.10,-
Book Value per Share,17.00,22.50,28.90,31.25,-
Net Debt,"-24,814","-36,525","-52,052",-,-
Research & Development Exp.,"3,565","4,327","4,852","5,192","5,250"
Capital Expenditure,"7,692","8,522","8,950","9,832",-
"Selling, General & Admin. Exp.","4,614","5,569","6,495","6,145","5,725"
Shareholder’s Equity,"57,825","76,028","97,431","99,807",-
Total Assets,"99,781","126,117","153,798","155,216",-
Net Debt,-24814,-36525,-52052,-,-
Research & Development Exp.,3565,4327,4852,5192,5250
Capital Expenditure,7692,8522,8950,9832,-
"Selling, General & Admin. Exp.",4614,5569,6495,6145,5725
Shareholder’s Equity,57825,76028,97431,99807,-
Total Assets,99781,126117,153798,155216,-
1 YEARLY ESTIMATES 2023 2024 2025 2026 2027
2 Revenue 103,351 103351 135,186 135186 168,507 168507 - -
3 Dividend 0.00 0.00 0.00 - -
4 Dividend Yield (in %) - - - - -
5 EPS 4.08 5.65 6.91 5.83 6.98
6 P/E Ratio 45.95 33.21 27.13 32.17 26.86
7 EBIT 14,600 14600 21,973 21973 27,740 27740 30,032 30032 44,029 44029
8 EBITDA 19,429 19429 27,963 27963 38,063 38063 37,754 37754 38,937 38937
9 Net Profit 13,681 13681 19,370 19370 23,763 23763 21,385 21385 26,126 26126
10 Net Profit Adjusted 13,713 13713 19,366 19366 23,746 23746 21,385 21385 26,126 26126
11 Pre-Tax Profit 14,437 14437 22,015 22015 28,932 28932 29,404 29404 31,787 31787
12 Net Profit (Adjusted) 14,363 14363 22,392 22392 29,878 29878 29,404 29404 31,787 31787
13 EPS (Non-GAAP) ex. SOE 4.08 5.65 6.91 5.83 6.98
14 EPS (GAAP) 3.49 5.25 6.18 5.73 6.65
15 Gross Income 23,184 23184 32,468 32468 40,980 40980 37,949 37949 42,464 42464
16 Cash Flow from Investing -7,935 -7935 -9,482 -9482 -10,201 -10201 -12,681 -12681 -
17 Cash Flow from Operations 19,523 19523 24,129 24129 27,935 27935 29,376 29376 35,875 35875
18 Cash Flow from Financing -478 -810 100 - -
19 Cash Flow per Share 4.92 7.39 6.94 - -
20 Free Cash Flow 10,236 10236 14,300 14300 15,203 15203 18,405 18405 22,501 22501
21 Free Cash Flow per Share 2.84 4.55 4.61 6.10 -
22 Book Value per Share 17.00 22.50 28.90 31.25 -
23 Net Debt -24,814 -24814 -36,525 -36525 -52,052 -52052 - -
24 Research & Development Exp. 3,565 3565 4,327 4327 4,852 4852 5,192 5192 5,250 5250
25 Capital Expenditure 7,692 7692 8,522 8522 8,950 8950 9,832 9832 -
26 Selling, General & Admin. Exp. 4,614 4614 5,569 5569 6,495 6495 6,145 6145 5,725 5725
27 Shareholder’s Equity 57,825 57825 76,028 76028 97,431 97431 99,807 99807 -
28 Total Assets 99,781 99781 126,117 126117 153,798 153798 155,216 155216 -

View File

@@ -83,5 +83,5 @@ def test_price_target_from_analysts_plt():
@pytest.mark.record_stdout
def test_estimates():
business_insider_view.display_estimates(
symbol="TSLA", estimate="annualearnings", export=None
symbol="TSLA", estimate="annual_earnings", export=None
)

View File

@@ -575,7 +575,7 @@ def test_call_func_expect_queue(expected_queue, queue, func):
[],
{
"symbol": "TSLA",
"estimate": "annualearnings",
"estimate": "annual_earnings",
"export": "",
"sheet_name": None,
},

View File

@@ -1,29 +1,29 @@
2023 2024 2025 2026 2027
YEARLY ESTIMATES
Revenue 103,418 135,351 168,507 194,661 295,169
Dividend 0.00 0.00 0.00 - -
Dividend Yield (in %) - - - - -
EPS 4.07 5.65 6.91 5.83 6.89
P/E Ratio 50.51 36.42 29.74 35.29 29.83
EBIT 14,555 21,972 27,741 30,025 43,704
EBITDA 19,519 27,962 38,066 37,741 38,504
Net Profit 13,506 19,372 23,768 21,372 25,801
Net Profit Adjusted 13,533 19,368 23,752 21,372 25,801
Pre-Tax Profit 14,454 22,034 28,932 29,404 31,787
Net Profit (Adjusted) 14,363 22,392 29,878 29,404 31,787
EPS (Non-GAAP) ex. SOE 4.07 5.65 6.91 5.83 6.89
EPS (GAAP) 3.47 5.25 6.18 5.72 6.54
Gross Income 23,115 32,466 40,982 37,942 41,972
Cash Flow from Investing -7,935 -9,482 -10,201 -12,681 -
Cash Flow from Operations 19,523 24,129 27,935 29,376 35,875
Cash Flow from Financing -478 -810 100 - -
Cash Flow per Share 4.92 7.39 6.94 - -
Free Cash Flow 10,541 14,300 15,203 18,405 22,501
Free Cash Flow per Share 2.84 4.55 4.61 6.10 -
Book Value per Share 17.00 22.50 28.90 31.25 -
Net Debt -24,814 -36,525 -52,052 - -
Research & Development Exp. 3,555 4,325 4,846 5,179 5,162
Capital Expenditure 7,672 8,522 8,950 9,832 -
Selling, General & Admin. Exp. 4,618 5,572 6,500 6,160 5,755
Shareholder’s Equity 57,825 76,028 97,431 99,807 -
Total Assets 99,781 126,117 153,798 155,216 -
2023 2024 2025 2026 2027
YEARLY ESTIMATES
Revenue 103418 135351 168507 194661 295169
Dividend 0.00 0.00 0.00 - -
Dividend Yield (in %) - - - - -
EPS 4.07 5.65 6.91 5.83 6.89
P/E Ratio 50.51 36.42 29.74 35.29 29.83
EBIT 14555 21972 27741 30025 43704
EBITDA 19519 27962 38066 37741 38504
Net Profit 13506 19372 23768 21372 25801
Net Profit Adjusted 13533 19368 23752 21372 25801
Pre-Tax Profit 14454 22034 28932 29404 31787
Net Profit (Adjusted) 14363 22392 29878 29404 31787
EPS (Non-GAAP) ex. SOE 4.07 5.65 6.91 5.83 6.89
EPS (GAAP) 3.47 5.25 6.18 5.72 6.54
Gross Income 23115 32466 40982 37942 41972
Cash Flow from Investing -7935 -9482 -10201 -12681 -
Cash Flow from Operations 19523 24129 27935 29376 35875
Cash Flow from Financing -478 -810 100 - -
Cash Flow per Share 4.92 7.39 6.94 - -
Free Cash Flow 10541 14300 15203 18405 22501
Free Cash Flow per Share 2.84 4.55 4.61 6.10 -
Book Value per Share 17.00 22.50 28.90 31.25 -
Net Debt -24814 -36525 -52052 - -
Research & Development Exp. 3555 4325 4846 5179 5162
Capital Expenditure 7672 8522 8950 9832 -
Selling, General & Admin. Exp. 4618 5572 6500 6160 5755
Shareholder’s Equity 57825 76028 97431 99807 -
Total Assets 99781 126117 153798 155216 -