mirror of
https://github.com/OpenBB-finance/OpenBB.git
synced 2026-10-27 20:42:26 +00:00
Refactor due-diligence menu to new refactoring style (#681)
* refactor finviz * start refactor business insider * fix business insider new refactoring * refactor FMP view * refactor market watch in due diligence * refactor finnhub on dd * CSI market in dd refactored * fix test * fix dd report * fix test * fix test * fix test * fix test * fix rating yaml * try to fix the test_rating * try for the 1000time * remove the test for now... * fix again requirements.txt * refactor code after review * merge main to ref-dd branch
This commit is contained in:
@@ -0,0 +1,201 @@
|
||||
""" Business Insider Model """
|
||||
__docformat__ = "numpy"
|
||||
|
||||
import json
|
||||
import re
|
||||
from typing import Tuple
|
||||
import requests
|
||||
import pandas as pd
|
||||
from bs4 import BeautifulSoup
|
||||
from gamestonk_terminal.helper_funcs import (
|
||||
get_user_agent,
|
||||
)
|
||||
|
||||
|
||||
def get_price_target_from_analysts(ticker: str) -> pd.DataFrame:
|
||||
"""Get analysts' price targets for a given stock. [Source: Business Insider]
|
||||
|
||||
Parameters
|
||||
----------
|
||||
ticker : str
|
||||
Ticker symbol
|
||||
|
||||
Returns
|
||||
-------
|
||||
pd.DataFrame
|
||||
Analysts data
|
||||
"""
|
||||
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",
|
||||
)
|
||||
|
||||
d_analyst_data = None
|
||||
for script in text_soup_market_business_insider.find_all("script"):
|
||||
# Get Analyst data
|
||||
if "window.analyseChartConfigs.push" in str(script):
|
||||
# Extract config data:
|
||||
s_analyst_data = str(script).split("config: ", 1)[1].split(",\r\n", 1)[0]
|
||||
d_analyst_data = json.loads(s_analyst_data)
|
||||
break
|
||||
|
||||
df_analyst_data = pd.DataFrame.from_dict(d_analyst_data["Markers"]) # type: ignore
|
||||
df_analyst_data = df_analyst_data[
|
||||
["DateLabel", "Company", "InternalRating", "PriceTarget"]
|
||||
]
|
||||
df_analyst_data.columns = ["Date", "Company", "Rating", "Price Target"]
|
||||
# df_analyst_data
|
||||
df_analyst_data["Rating"].replace(
|
||||
{"gut": "BUY", "neutral": "HOLD", "schlecht": "SELL"}, inplace=True
|
||||
)
|
||||
df_analyst_data["Date"] = pd.to_datetime(df_analyst_data["Date"])
|
||||
df_analyst_data = df_analyst_data.set_index("Date")
|
||||
|
||||
return df_analyst_data
|
||||
|
||||
|
||||
def get_estimates(ticker: str) -> Tuple[pd.DataFrame, pd.DataFrame, pd.DataFrame]:
|
||||
"""Get analysts' estimates for a given ticker. [Source: Business Insider]
|
||||
|
||||
Parameters
|
||||
----------
|
||||
ticker : str
|
||||
Ticker to get analysts' estimates
|
||||
|
||||
Returns
|
||||
-------
|
||||
df_year_estimates : pd.DataFrame
|
||||
Year estimates
|
||||
df_quarter_earnings : pd.DataFrame
|
||||
Quarter earnings estimates
|
||||
df_quarter_revenues : pd.DataFrame
|
||||
Quarter revenues estimates
|
||||
"""
|
||||
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",
|
||||
)
|
||||
|
||||
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)
|
||||
|
||||
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)
|
||||
|
||||
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)
|
||||
|
||||
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())
|
||||
|
||||
# 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
|
||||
|
||||
# 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_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.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'
|
||||
|
||||
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"]
|
||||
)
|
||||
|
||||
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"]
|
||||
)
|
||||
|
||||
return df_year_estimates, df_quarter_earnings, df_quarter_revenues
|
||||
@@ -1,20 +1,14 @@
|
||||
""" Business Insider View """
|
||||
__docformat__ = "numpy"
|
||||
|
||||
import argparse
|
||||
from typing import List
|
||||
import json
|
||||
import re
|
||||
import os
|
||||
from pandas.core.frame import DataFrame
|
||||
import requests
|
||||
import matplotlib.pyplot as plt
|
||||
import pandas as pd
|
||||
from pandas.plotting import register_matplotlib_converters
|
||||
from bs4 import BeautifulSoup
|
||||
import matplotlib.pyplot as plt
|
||||
from tabulate import tabulate
|
||||
from gamestonk_terminal.stocks.due_diligence import business_insider_model
|
||||
from gamestonk_terminal.helper_funcs import (
|
||||
check_positive,
|
||||
get_user_agent,
|
||||
parse_known_args_and_warn,
|
||||
export_data,
|
||||
)
|
||||
from gamestonk_terminal import feature_flags as gtff
|
||||
|
||||
@@ -22,78 +16,49 @@ register_matplotlib_converters()
|
||||
|
||||
|
||||
def price_target_from_analysts(
|
||||
other_args: List[str], stock: DataFrame, ticker: str, start: str, interval: str
|
||||
ticker: str,
|
||||
start: str,
|
||||
interval: str,
|
||||
stock: DataFrame,
|
||||
num: int,
|
||||
raw: bool,
|
||||
export: str,
|
||||
):
|
||||
"""Display analysts' price targets for a given stock
|
||||
"""Display analysts' price targets for a given stock. [Source: Business Insider]
|
||||
|
||||
Parameters
|
||||
----------
|
||||
other_args : List[str]
|
||||
argparse other args - ["-n", "10"]
|
||||
stock : DataFrame
|
||||
Due diligence stock dataframe
|
||||
ticker : str
|
||||
Due diligence ticker symbol
|
||||
start : str
|
||||
Start date of the stock data
|
||||
interval : str
|
||||
Stock data interval
|
||||
stock : DataFrame
|
||||
Due diligence stock dataframe
|
||||
num : int
|
||||
Number of latest price targets from analysts to print
|
||||
raw : bool
|
||||
Display raw data only
|
||||
export : str
|
||||
Export dataframe data to csv,json,xlsx file
|
||||
"""
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
add_help=False,
|
||||
prog="pt",
|
||||
description="""Prints price target from analysts. [Source: Business Insider]""",
|
||||
)
|
||||
df_analyst_data = business_insider_model.get_price_target_from_analysts(ticker)
|
||||
|
||||
parser.add_argument(
|
||||
"-n",
|
||||
"--num",
|
||||
action="store",
|
||||
dest="n_num",
|
||||
type=check_positive,
|
||||
default=10,
|
||||
help="number of latest price targets from analysts to print.",
|
||||
)
|
||||
|
||||
try:
|
||||
ns_parser = parse_known_args_and_warn(parser, other_args)
|
||||
if not ns_parser:
|
||||
return
|
||||
|
||||
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",
|
||||
if raw:
|
||||
df_analyst_data.index = df_analyst_data.index.strftime("%d/%m/%Y")
|
||||
print(
|
||||
tabulate(
|
||||
df_analyst_data.sort_index(ascending=False).head(num),
|
||||
headers=df_analyst_data.columns,
|
||||
floatfmt=".2f",
|
||||
showindex=True,
|
||||
tablefmt="fancy_grid",
|
||||
)
|
||||
)
|
||||
|
||||
d_analyst_data = None
|
||||
for script in text_soup_market_business_insider.find_all("script"):
|
||||
# Get Analyst data
|
||||
if "window.analyseChartConfigs.push" in str(script):
|
||||
# Extract config data:
|
||||
s_analyst_data = (
|
||||
str(script).split("config: ", 1)[1].split(",\r\n", 1)[0]
|
||||
)
|
||||
d_analyst_data = json.loads(s_analyst_data)
|
||||
break
|
||||
|
||||
df_analyst_data = pd.DataFrame.from_dict(d_analyst_data["Markers"]) # type: ignore
|
||||
df_analyst_data = df_analyst_data[
|
||||
["DateLabel", "Company", "InternalRating", "PriceTarget"]
|
||||
]
|
||||
df_analyst_data.columns = ["Date", "Company", "Rating", "Price Target"]
|
||||
# df_analyst_data
|
||||
df_analyst_data["Rating"].replace(
|
||||
{"gut": "BUY", "neutral": "HOLD", "schlecht": "SELL"}, inplace=True
|
||||
)
|
||||
df_analyst_data["Date"] = pd.to_datetime(df_analyst_data["Date"])
|
||||
df_analyst_data = df_analyst_data.set_index("Date")
|
||||
|
||||
else:
|
||||
# Slice start of ratings
|
||||
if start:
|
||||
df_analyst_data = df_analyst_data[start:] # type: ignore
|
||||
@@ -116,195 +81,85 @@ def price_target_from_analysts(
|
||||
plt.title(f"{ticker} (Time Series) and Price Target")
|
||||
plt.xlim(stock.index[0], stock.index[-1])
|
||||
plt.xlabel("Time")
|
||||
plt.ylabel("Share Price ($)")
|
||||
plt.ylabel("Share Price")
|
||||
plt.grid(b=True, which="major", color="#666666", linestyle="-")
|
||||
plt.minorticks_on()
|
||||
plt.grid(b=True, which="minor", color="#999999", linestyle="-", alpha=0.2)
|
||||
|
||||
if gtff.USE_ION:
|
||||
plt.ion()
|
||||
|
||||
plt.show()
|
||||
print("")
|
||||
print("")
|
||||
|
||||
pd.set_option("display.max_colwidth", None)
|
||||
print(
|
||||
df_analyst_data.sort_index(ascending=False)
|
||||
.head(ns_parser.n_num)
|
||||
.to_string()
|
||||
)
|
||||
print("")
|
||||
|
||||
except Exception as e:
|
||||
print(e)
|
||||
print("")
|
||||
return
|
||||
export_data(
|
||||
export,
|
||||
os.path.dirname(os.path.abspath(__file__)),
|
||||
"pt",
|
||||
df_analyst_data,
|
||||
)
|
||||
|
||||
|
||||
def estimates(other_args: List[str], ticker: str):
|
||||
"""Display analysts' estimates for a given ticker
|
||||
def estimates(ticker: str, export: str):
|
||||
"""Display analysts' estimates for a given ticker. [Source: Business Insider]
|
||||
|
||||
Parameters
|
||||
----------
|
||||
other_args : List[str]
|
||||
argparse other args
|
||||
ticker : str
|
||||
Due diligence ticker symbol
|
||||
Ticker to get analysts' estimates
|
||||
export : str
|
||||
Export dataframe data to csv,json,xlsx file
|
||||
"""
|
||||
(
|
||||
df_year_estimates,
|
||||
df_quarter_earnings,
|
||||
df_quarter_revenues,
|
||||
) = business_insider_model.get_estimates(ticker)
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
add_help=False,
|
||||
prog="est",
|
||||
description="""Yearly estimates and quarter earnings/revenues [Source: Business Insider]""",
|
||||
print(
|
||||
tabulate(
|
||||
df_year_estimates,
|
||||
headers=df_year_estimates.columns,
|
||||
floatfmt=".2f",
|
||||
showindex=True,
|
||||
tablefmt="fancy_grid",
|
||||
),
|
||||
)
|
||||
|
||||
try:
|
||||
ns_parser = parse_known_args_and_warn(parser, other_args)
|
||||
if not ns_parser:
|
||||
return
|
||||
|
||||
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",
|
||||
print("")
|
||||
print(
|
||||
tabulate(
|
||||
df_quarter_earnings,
|
||||
headers=df_quarter_earnings.columns,
|
||||
floatfmt=".2f",
|
||||
showindex=True,
|
||||
tablefmt="fancy_grid",
|
||||
),
|
||||
)
|
||||
print("")
|
||||
print(
|
||||
tabulate(
|
||||
df_quarter_revenues,
|
||||
headers=df_quarter_revenues.columns,
|
||||
floatfmt=".2f",
|
||||
showindex=True,
|
||||
tablefmt="fancy_grid",
|
||||
)
|
||||
)
|
||||
print("")
|
||||
|
||||
l_estimates_year_header = []
|
||||
l_estimates_quarter_header = []
|
||||
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)
|
||||
|
||||
l_estimates_year_metric = []
|
||||
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)
|
||||
|
||||
l_estimates_quarter_metric = []
|
||||
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)
|
||||
|
||||
d_metric_year = dict()
|
||||
d_metric_quarter_earnings = dict()
|
||||
d_metric_quarter_revenues = dict()
|
||||
l_metrics = []
|
||||
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())
|
||||
|
||||
# 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 = []
|
||||
idx_y = idx
|
||||
|
||||
# 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 = []
|
||||
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 = []
|
||||
n_metrics += 1
|
||||
|
||||
df_year_estimates = pd.DataFrame.from_dict(
|
||||
d_metric_year, orient="index", columns=l_estimates_year_header
|
||||
)
|
||||
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.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'
|
||||
|
||||
l_quarter = []
|
||||
l_date = []
|
||||
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.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"]
|
||||
)
|
||||
|
||||
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"]
|
||||
)
|
||||
|
||||
print(df_year_estimates.to_string())
|
||||
print("")
|
||||
print("QUARTER ESTIMATES EARNINGS")
|
||||
print(df_quarter_earnings.to_string())
|
||||
print("")
|
||||
print("QUARTER ESTIMATES REVENUES")
|
||||
print(df_quarter_revenues.to_string())
|
||||
print("")
|
||||
|
||||
print(
|
||||
text_soup_market_business_insider.find(
|
||||
"div", {"class": "text_right instrument-description"}
|
||||
).text.strip()
|
||||
)
|
||||
print("")
|
||||
|
||||
except Exception as e:
|
||||
print(e)
|
||||
print("")
|
||||
return
|
||||
export_data(
|
||||
export,
|
||||
os.path.dirname(os.path.abspath(__file__)),
|
||||
"pt_year",
|
||||
df_year_estimates,
|
||||
)
|
||||
export_data(
|
||||
export,
|
||||
os.path.dirname(os.path.abspath(__file__)),
|
||||
"pt_qtr_earnings",
|
||||
df_quarter_earnings,
|
||||
)
|
||||
export_data(
|
||||
export,
|
||||
os.path.dirname(os.path.abspath(__file__)),
|
||||
"pt_qtr_revenues",
|
||||
df_quarter_revenues,
|
||||
)
|
||||
|
||||
65
gamestonk_terminal/stocks/due_diligence/csimarket_model.py
Normal file
65
gamestonk_terminal/stocks/due_diligence/csimarket_model.py
Normal file
@@ -0,0 +1,65 @@
|
||||
"""CSIMarket Model"""
|
||||
__docformat__ = "numpy"
|
||||
|
||||
from bs4 import BeautifulSoup
|
||||
import requests
|
||||
|
||||
|
||||
def get_suppliers(ticker: str) -> str:
|
||||
"""Get suppliers from ticker provided. [Source: CSIMarket]
|
||||
|
||||
Parameters
|
||||
----------
|
||||
ticker: str
|
||||
Ticker to select suppliers from
|
||||
|
||||
Returns
|
||||
-------
|
||||
str
|
||||
Suppliers for ticker provided
|
||||
"""
|
||||
# TODO: This link has a lot more data that we can display
|
||||
# TODO: We could at least sort the tickers based on market cap
|
||||
url_supply_chain = (
|
||||
f"https://csimarket.com/stocks/competitionNO3.php?supply&code={ticker.upper()}"
|
||||
)
|
||||
text_supplier_chain = BeautifulSoup(requests.get(url_supply_chain).text, "lxml")
|
||||
|
||||
l_supplier = list()
|
||||
for supplier in text_supplier_chain.findAll(
|
||||
"td", {"class": "plavat svjetlirub dae al"}
|
||||
):
|
||||
l_supplier.append(supplier.text)
|
||||
|
||||
if l_supplier:
|
||||
return f"List of Suppliers: {', '.join(l_supplier)}\n"
|
||||
return "No suppliers found.\n"
|
||||
|
||||
|
||||
def get_customers(ticker: str) -> str:
|
||||
"""Print customers from ticker provided
|
||||
|
||||
Parameters
|
||||
----------
|
||||
ticker: str
|
||||
Ticker to select customers from
|
||||
|
||||
Returns
|
||||
-------
|
||||
str
|
||||
Customers for ticker provided
|
||||
"""
|
||||
# TODO: This link has a lot more data that we can display
|
||||
# TODO: We could at least sort the tickers based on market cap
|
||||
url_customer_chain = (
|
||||
f"https://csimarket.com/stocks/custexNO.php?markets&code={ticker.upper()}"
|
||||
)
|
||||
text_customer_chain = BeautifulSoup(requests.get(url_customer_chain).text, "lxml")
|
||||
|
||||
l_customer = list()
|
||||
for customer in text_customer_chain.findAll("td", {"class": "plava svjetlirub"}):
|
||||
l_customer.append(customer.text)
|
||||
|
||||
if l_customer:
|
||||
return f"List of Customers: {', '.join(l_customer)}\n"
|
||||
return "No customers found.\n"
|
||||
@@ -1,94 +1,51 @@
|
||||
"""Stockgrid DD View"""
|
||||
"""CSIMarket View"""
|
||||
__docformat__ = "numpy"
|
||||
|
||||
import argparse
|
||||
from typing import List
|
||||
from bs4 import BeautifulSoup
|
||||
import requests
|
||||
import os
|
||||
import pandas as pd
|
||||
from gamestonk_terminal.stocks.due_diligence import csimarket_model
|
||||
from gamestonk_terminal.helper_funcs import (
|
||||
parse_known_args_and_warn,
|
||||
export_data,
|
||||
)
|
||||
|
||||
|
||||
def suppliers(ticker: str, other_args: List[str]):
|
||||
"""Print suppliers from ticker provided
|
||||
def suppliers(ticker: str, export: str):
|
||||
"""Display suppliers from ticker provided. [Source: CSIMarket]
|
||||
|
||||
Parameters
|
||||
----------
|
||||
ticker: str
|
||||
Ticker to select suppliers from
|
||||
other_args : List[str]
|
||||
Argparse arguments
|
||||
|
||||
export : str
|
||||
Export dataframe data to csv,json,xlsx file
|
||||
"""
|
||||
parser = argparse.ArgumentParser(
|
||||
prog="supplier",
|
||||
add_help=False,
|
||||
description="List of suppliers from ticker provided. [Source: CSIMarket]",
|
||||
tickers = csimarket_model.get_suppliers(ticker)
|
||||
print(tickers)
|
||||
|
||||
export_data(
|
||||
export,
|
||||
os.path.dirname(os.path.abspath(__file__)),
|
||||
"supplier",
|
||||
pd.DataFrame(tickers.split(",")),
|
||||
)
|
||||
try:
|
||||
ns_parser = parse_known_args_and_warn(parser, other_args)
|
||||
if not ns_parser:
|
||||
return
|
||||
|
||||
# TODO: This link has a lot more data that we can display
|
||||
url_supply_chain = f"https://csimarket.com/stocks/competitionNO3.php?supply&code={ticker.upper()}"
|
||||
text_supplier_chain = BeautifulSoup(requests.get(url_supply_chain).text, "lxml")
|
||||
|
||||
l_supplier = []
|
||||
for supplier in text_supplier_chain.findAll(
|
||||
"td", {"class": "plavat svjetlirub dae al"}
|
||||
):
|
||||
l_supplier.append(supplier.text)
|
||||
|
||||
if l_supplier:
|
||||
print("List of Suppliers: " + ", ".join(l_supplier) + "\n")
|
||||
else:
|
||||
print("No suppliers found.\n")
|
||||
|
||||
except Exception as e:
|
||||
print(e, "\n")
|
||||
|
||||
|
||||
def customers(ticker: str, other_args: List[str]):
|
||||
"""Print customers from ticker provided
|
||||
def customers(ticker: str, export: str):
|
||||
"""Display customers from ticker provided. [Source: CSIMarket]
|
||||
|
||||
Parameters
|
||||
----------
|
||||
ticker: str
|
||||
Ticker to select customers from
|
||||
other_args : List[str]
|
||||
Argparse arguments
|
||||
|
||||
export : str
|
||||
Export dataframe data to csv,json,xlsx file
|
||||
"""
|
||||
parser = argparse.ArgumentParser(
|
||||
prog="customer",
|
||||
add_help=False,
|
||||
description="List of customers from ticker provided. [Source: CSIMarket]",
|
||||
tickers = csimarket_model.get_customers(ticker)
|
||||
print(tickers)
|
||||
|
||||
export_data(
|
||||
export,
|
||||
os.path.dirname(os.path.abspath(__file__)),
|
||||
"customer",
|
||||
pd.DataFrame(tickers.split(",")),
|
||||
)
|
||||
try:
|
||||
ns_parser = parse_known_args_and_warn(parser, other_args)
|
||||
if not ns_parser:
|
||||
return
|
||||
|
||||
# TODO: This link has a lot more data that we can display
|
||||
url_customer_chain = (
|
||||
f"https://csimarket.com/stocks/custexNO.php?markets&code={ticker.upper()}"
|
||||
)
|
||||
text_customer_chain = BeautifulSoup(
|
||||
requests.get(url_customer_chain).text, "lxml"
|
||||
)
|
||||
|
||||
l_customer = []
|
||||
for customer in text_customer_chain.findAll(
|
||||
"td", {"class": "plava svjetlirub"}
|
||||
):
|
||||
l_customer.append(customer.text)
|
||||
|
||||
if l_customer:
|
||||
print("List of Customers: " + ", ".join(l_customer) + "\n")
|
||||
else:
|
||||
print("No customers found.\n")
|
||||
|
||||
except Exception as e:
|
||||
print(e, "\n")
|
||||
|
||||
@@ -8,15 +8,19 @@ from pandas.core.frame import DataFrame
|
||||
from prompt_toolkit.completion import NestedCompleter
|
||||
|
||||
from gamestonk_terminal.stocks.due_diligence import (
|
||||
financial_modeling_prep_view,
|
||||
fmp_view,
|
||||
business_insider_view,
|
||||
finviz_view,
|
||||
market_watch_view,
|
||||
marketwatch_view,
|
||||
finnhub_view,
|
||||
csimarket_view,
|
||||
)
|
||||
from gamestonk_terminal import feature_flags as gtff
|
||||
from gamestonk_terminal.helper_funcs import get_flair
|
||||
from gamestonk_terminal.helper_funcs import (
|
||||
get_flair,
|
||||
parse_known_args_and_warn,
|
||||
check_positive,
|
||||
)
|
||||
from gamestonk_terminal.menu import session
|
||||
|
||||
|
||||
@@ -30,30 +34,34 @@ class DueDiligenceController:
|
||||
"help",
|
||||
"q",
|
||||
"quit",
|
||||
]
|
||||
|
||||
CHOICES_COMMANDS = [
|
||||
"sec",
|
||||
"rating",
|
||||
"pt",
|
||||
"rot",
|
||||
"est",
|
||||
"analyst",
|
||||
"sec",
|
||||
"supplier",
|
||||
"customer",
|
||||
]
|
||||
|
||||
CHOICES += CHOICES_COMMANDS
|
||||
|
||||
def __init__(self, ticker: str, start: str, interval: str, stock: DataFrame):
|
||||
"""Constructor
|
||||
|
||||
Parameters
|
||||
----------
|
||||
stock : DataFrame
|
||||
Due diligence stock dataframe
|
||||
ticker : str
|
||||
Due diligence ticker symbol
|
||||
start : str
|
||||
Start date of the stock data
|
||||
interval : str
|
||||
Stock data interval
|
||||
stock : DataFrame
|
||||
Due diligence stock dataframe
|
||||
"""
|
||||
self.ticker = ticker
|
||||
self.start = start
|
||||
@@ -68,39 +76,40 @@ class DueDiligenceController:
|
||||
|
||||
def print_help(self):
|
||||
"""Print help"""
|
||||
print(
|
||||
"https://github.com/GamestonkTerminal/GamestonkTerminal/tree/main/gamestonk_terminal/stocks/due_diligence"
|
||||
)
|
||||
intraday = (f"Intraday {self.interval}", "Daily")[self.interval == "1440min"]
|
||||
|
||||
if self.start:
|
||||
print(
|
||||
f"\n{intraday} Stock: {self.ticker} (from {self.start.strftime('%Y-%m-%d')})"
|
||||
)
|
||||
s_intraday = (f"Intraday {self.interval}", "Daily")[self.interval == "1440min"]
|
||||
if self.ticker and self.start:
|
||||
stock_text = f"{s_intraday} Stock: {self.ticker} (from {self.start.strftime('%Y-%m-%d')})"
|
||||
else:
|
||||
print(f"\n{intraday} Stock: {self.ticker}")
|
||||
stock_text = f"{s_intraday} Stock: {self.ticker}"
|
||||
|
||||
print("\nDue Diligence:")
|
||||
print(" cls clear screen")
|
||||
print(" ?/help show this menu again")
|
||||
print(" q quit this menu, and shows back to main menu")
|
||||
print(" quit quit to abandon program")
|
||||
print("")
|
||||
print(" analyst analyst prices and ratings of the company [Finviz]")
|
||||
print(
|
||||
" rating rating of the company from strong sell to strong buy [FMP]"
|
||||
)
|
||||
print(" pt price targets over time [Business Insider]")
|
||||
print(
|
||||
" rot rating over timefrom strong sell to strong buy [Finnhub]"
|
||||
)
|
||||
print(
|
||||
" est quarter and year analysts earnings estimates [Business Insider]"
|
||||
)
|
||||
print(" sec SEC filings [Market Watch]")
|
||||
print(" supplier list of suppliers [csimarket]")
|
||||
print(" customer list of customers [csimarket]")
|
||||
print("")
|
||||
help_text = f"""https://github.com/GamestonkTerminal/GamestonkTerminal/tree/main/gamestonk_terminal/stocks/due_diligence
|
||||
|
||||
Due Diligence:
|
||||
cls clear screen
|
||||
?/help show this menu again
|
||||
q quit this menu, and shows back to main menu
|
||||
quit quit to abandon program
|
||||
|
||||
{stock_text}
|
||||
|
||||
Finviz:
|
||||
analyst analyst prices and ratings of the company
|
||||
FMP:
|
||||
rating rating over time (daily)
|
||||
Finnhub:
|
||||
rot number of analysts ratings over time (monthly)
|
||||
Business Insider:
|
||||
pt price targets over time
|
||||
est quarter and year analysts earnings estimates
|
||||
Market Watch:
|
||||
sec SEC filings
|
||||
csimarket:
|
||||
supplier list of suppliers
|
||||
customer list of customers
|
||||
"""
|
||||
|
||||
print(help_text)
|
||||
|
||||
def switch(self, an_input: str):
|
||||
"""Process and dispatch input
|
||||
@@ -148,37 +157,308 @@ class DueDiligenceController:
|
||||
|
||||
def call_analyst(self, other_args: List[str]):
|
||||
"""Process analyst command"""
|
||||
finviz_view.analyst(other_args, self.ticker)
|
||||
parser = argparse.ArgumentParser(
|
||||
add_help=False,
|
||||
prog="analyst",
|
||||
description="""
|
||||
Print analyst prices and ratings of the company. The following fields are expected:
|
||||
date, analyst, category, price from, price to, and rating. [Source: Finviz]
|
||||
""",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--export",
|
||||
choices=["csv", "json", "xlsx"],
|
||||
default="",
|
||||
type=str,
|
||||
dest="export",
|
||||
help="Export dataframe data to csv,json,xlsx file",
|
||||
)
|
||||
try:
|
||||
ns_parser = parse_known_args_and_warn(parser, other_args)
|
||||
if not ns_parser:
|
||||
return
|
||||
|
||||
finviz_view.analyst(ticker=self.ticker, export=ns_parser.export)
|
||||
|
||||
except Exception as e:
|
||||
print(e, "\n")
|
||||
|
||||
def call_pt(self, other_args: List[str]):
|
||||
"""Process pt command"""
|
||||
business_insider_view.price_target_from_analysts(
|
||||
other_args, self.stock, self.ticker, self.start, self.interval
|
||||
parser = argparse.ArgumentParser(
|
||||
add_help=False,
|
||||
prog="pt",
|
||||
description="""Prints price target from analysts. [Source: Business Insider]""",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--raw",
|
||||
action="store_true",
|
||||
dest="raw",
|
||||
help="Only output raw data",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-n",
|
||||
"--num",
|
||||
action="store",
|
||||
dest="n_num",
|
||||
type=check_positive,
|
||||
default=10,
|
||||
help="Number of latest price targets from analysts to print.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--export",
|
||||
choices=["csv", "json", "xlsx"],
|
||||
default="",
|
||||
type=str,
|
||||
dest="export",
|
||||
help="Export dataframe data to csv,json,xlsx file",
|
||||
)
|
||||
|
||||
def call_rot(self, other_args: List[str]):
|
||||
"""Process rot command"""
|
||||
finnhub_view.rating_over_time(other_args, self.ticker)
|
||||
try:
|
||||
ns_parser = parse_known_args_and_warn(parser, other_args)
|
||||
if not ns_parser:
|
||||
return
|
||||
|
||||
business_insider_view.price_target_from_analysts(
|
||||
ticker=self.ticker,
|
||||
start=self.start,
|
||||
interval=self.interval,
|
||||
stock=self.stock,
|
||||
num=ns_parser.n_num,
|
||||
raw=ns_parser.raw,
|
||||
export=ns_parser.export,
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
print(e, "\n")
|
||||
|
||||
def call_est(self, other_args: List[str]):
|
||||
"""Process est command"""
|
||||
business_insider_view.estimates(other_args, self.ticker)
|
||||
parser = argparse.ArgumentParser(
|
||||
add_help=False,
|
||||
prog="est",
|
||||
description="""Yearly estimates and quarter earnings/revenues. [Source: Business Insider]""",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--export",
|
||||
choices=["csv", "json", "xlsx"],
|
||||
default="",
|
||||
type=str,
|
||||
dest="export",
|
||||
help="Export dataframe data to csv,json,xlsx file",
|
||||
)
|
||||
try:
|
||||
ns_parser = parse_known_args_and_warn(parser, other_args)
|
||||
if not ns_parser:
|
||||
return
|
||||
|
||||
business_insider_view.estimates(
|
||||
ticker=self.ticker,
|
||||
export=ns_parser.export,
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
print(e, "\n")
|
||||
|
||||
def call_rot(self, other_args: List[str]):
|
||||
"""Process rot command"""
|
||||
parser = argparse.ArgumentParser(
|
||||
add_help=False,
|
||||
prog="rot",
|
||||
description="""
|
||||
Rating over time (monthly). [Source: Finnhub]
|
||||
""",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-n",
|
||||
"--num",
|
||||
action="store",
|
||||
dest="n_num",
|
||||
type=check_positive,
|
||||
default=10,
|
||||
help="number of last months",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--raw",
|
||||
action="store_true",
|
||||
dest="raw",
|
||||
help="Only output raw data",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--export",
|
||||
choices=["csv", "json", "xlsx"],
|
||||
default="",
|
||||
type=str,
|
||||
dest="export",
|
||||
help="Export dataframe data to csv,json,xlsx file",
|
||||
)
|
||||
try:
|
||||
if other_args:
|
||||
if "-" not in other_args[0]:
|
||||
other_args.insert(0, "-n")
|
||||
|
||||
ns_parser = parse_known_args_and_warn(parser, other_args)
|
||||
if not ns_parser:
|
||||
return
|
||||
|
||||
finnhub_view.rating_over_time(
|
||||
ticker=self.ticker,
|
||||
num=ns_parser.n_num,
|
||||
raw=ns_parser.raw,
|
||||
export=ns_parser.export,
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
print(e, "\n")
|
||||
|
||||
def call_rating(self, other_args: List[str]):
|
||||
"""Process rating command"""
|
||||
financial_modeling_prep_view.rating(other_args, self.ticker)
|
||||
parser = argparse.ArgumentParser(
|
||||
add_help=False,
|
||||
prog="rating",
|
||||
description="""
|
||||
Based on specific ratios, prints information whether the company
|
||||
is a (strong) buy, neutral or a (strong) sell. The following fields are expected:
|
||||
P/B, ROA, DCF, P/E, ROE, and D/E. [Source: Financial Modeling Prep]
|
||||
""",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-n",
|
||||
"--num",
|
||||
action="store",
|
||||
dest="n_num",
|
||||
type=check_positive,
|
||||
default=10,
|
||||
help="number of last days to display ratings",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--export",
|
||||
choices=["csv", "json", "xlsx"],
|
||||
default="",
|
||||
type=str,
|
||||
dest="export",
|
||||
help="Export dataframe data to csv,json,xlsx file",
|
||||
)
|
||||
|
||||
try:
|
||||
if other_args:
|
||||
if "-" not in other_args[0]:
|
||||
other_args.insert(0, "-n")
|
||||
|
||||
ns_parser = parse_known_args_and_warn(parser, other_args)
|
||||
if not ns_parser:
|
||||
return
|
||||
|
||||
fmp_view.rating(
|
||||
ticker=self.ticker,
|
||||
num=ns_parser.n_num,
|
||||
export=ns_parser.export,
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
print(e, "\n")
|
||||
|
||||
def call_sec(self, other_args: List[str]):
|
||||
"""Process sec command"""
|
||||
market_watch_view.sec_fillings(other_args, self.ticker)
|
||||
parser = argparse.ArgumentParser(
|
||||
add_help=False,
|
||||
prog="sec",
|
||||
description="""
|
||||
Prints SEC filings of the company. The following fields are expected: Filing Date,
|
||||
Document Date, Type, Category, Amended, and Link. [Source: Market Watch]
|
||||
""",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-n",
|
||||
"--num",
|
||||
action="store",
|
||||
dest="n_num",
|
||||
type=check_positive,
|
||||
default=5,
|
||||
help="number of latest SEC filings.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--export",
|
||||
choices=["csv", "json", "xlsx"],
|
||||
default="",
|
||||
type=str,
|
||||
dest="export",
|
||||
help="Export dataframe data to csv,json,xlsx file",
|
||||
)
|
||||
|
||||
try:
|
||||
if other_args:
|
||||
if "-" not in other_args[0]:
|
||||
other_args.insert(0, "-n")
|
||||
|
||||
ns_parser = parse_known_args_and_warn(parser, other_args)
|
||||
if not ns_parser:
|
||||
return
|
||||
|
||||
marketwatch_view.sec_filings(
|
||||
ticker=self.ticker,
|
||||
num=ns_parser.n_num,
|
||||
export=ns_parser.export,
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
print(e, "\n")
|
||||
|
||||
def call_supplier(self, other_args: List[str]):
|
||||
"""Process supplier command"""
|
||||
csimarket_view.suppliers(self.ticker, other_args)
|
||||
parser = argparse.ArgumentParser(
|
||||
prog="supplier",
|
||||
add_help=False,
|
||||
description="List of suppliers from ticker provided. [Source: CSIMarket]",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--export",
|
||||
choices=["csv", "json", "xlsx"],
|
||||
default="",
|
||||
type=str,
|
||||
dest="export",
|
||||
help="Export dataframe data to csv,json,xlsx file",
|
||||
)
|
||||
try:
|
||||
ns_parser = parse_known_args_and_warn(parser, other_args)
|
||||
if not ns_parser:
|
||||
return
|
||||
|
||||
csimarket_view.suppliers(
|
||||
ticker=self.ticker,
|
||||
export=ns_parser.export,
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
print(e, "\n")
|
||||
|
||||
def call_customer(self, other_args: List[str]):
|
||||
"""Process customer command"""
|
||||
csimarket_view.customers(self.ticker, other_args)
|
||||
parser = argparse.ArgumentParser(
|
||||
prog="customer",
|
||||
add_help=False,
|
||||
description="List of customers from ticker provided. [Source: CSIMarket]",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--export",
|
||||
choices=["csv", "json", "xlsx"],
|
||||
default="",
|
||||
type=str,
|
||||
dest="export",
|
||||
help="Export dataframe data to csv,json,xlsx file",
|
||||
)
|
||||
try:
|
||||
ns_parser = parse_known_args_and_warn(parser, other_args)
|
||||
if not ns_parser:
|
||||
return
|
||||
|
||||
csimarket_view.customers(
|
||||
ticker=self.ticker,
|
||||
export=ns_parser.export,
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
print(e, "\n")
|
||||
|
||||
|
||||
def menu(ticker: str, start: str, interval: str, stock: DataFrame):
|
||||
@@ -186,14 +466,14 @@ def menu(ticker: str, start: str, interval: str, stock: DataFrame):
|
||||
|
||||
Parameters
|
||||
----------
|
||||
stock : DataFrame
|
||||
Due diligence stock dataframe
|
||||
ticker : str
|
||||
Due diligence ticker symbol
|
||||
start : str
|
||||
Start date of the stock data
|
||||
interval : str
|
||||
Stock data interval
|
||||
stock : DataFrame
|
||||
Due diligence stock dataframe
|
||||
"""
|
||||
|
||||
dd_controller = DueDiligenceController(ticker, start, interval, stock)
|
||||
|
||||
@@ -1,78 +0,0 @@
|
||||
""" Financial Modeling Prep View """
|
||||
__docformat__ = "numpy"
|
||||
|
||||
import argparse
|
||||
from typing import List
|
||||
from tabulate import tabulate
|
||||
import FundamentalAnalysis as fa
|
||||
from gamestonk_terminal import config_terminal as cfg
|
||||
from gamestonk_terminal.helper_funcs import parse_known_args_and_warn, check_positive
|
||||
|
||||
|
||||
def rating(other_args: List[str], ticker: str):
|
||||
"""Display ratings for a given ticker
|
||||
|
||||
Parameters
|
||||
----------
|
||||
other_args : List[str]
|
||||
argparse other args
|
||||
ticker : str
|
||||
Stock ticker
|
||||
"""
|
||||
parser = argparse.ArgumentParser(
|
||||
add_help=False,
|
||||
prog="rating",
|
||||
description="""
|
||||
Based on specific ratios, prints information whether the company
|
||||
is a (strong) buy, neutral or a (strong) sell. The following fields are expected:
|
||||
P/B, ROA, DCF, P/E, ROE, and D/E. [Source: Financial Modeling Prep]
|
||||
""",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-n",
|
||||
"--num",
|
||||
action="store",
|
||||
dest="n_num",
|
||||
type=check_positive,
|
||||
default=10,
|
||||
help="number of regions to plot that show highest interest.",
|
||||
)
|
||||
|
||||
try:
|
||||
ns_parser = parse_known_args_and_warn(parser, other_args)
|
||||
if not ns_parser:
|
||||
return
|
||||
|
||||
df_fa = fa.rating(ticker, cfg.API_KEY_FINANCIALMODELINGPREP)
|
||||
|
||||
# TODO: This could be displayed in a nice rating plot over time
|
||||
|
||||
l_recoms = [col for col in df_fa.columns if "Recommendation" in col]
|
||||
l_recoms_show = [
|
||||
recom.replace("rating", "")
|
||||
.replace("Details", "")
|
||||
.replace("Recommendation", " Recommendation")
|
||||
for recom in l_recoms
|
||||
]
|
||||
print(
|
||||
tabulate(
|
||||
df_fa[l_recoms].head(ns_parser.n_num),
|
||||
headers=l_recoms_show,
|
||||
floatfmt=".2f",
|
||||
showindex=True,
|
||||
tablefmt="fancy_grid",
|
||||
)
|
||||
)
|
||||
print("")
|
||||
|
||||
except KeyError:
|
||||
print(
|
||||
f"Financialmodelingprep.com is returning empty response the ticker {ticker}."
|
||||
)
|
||||
print("")
|
||||
return
|
||||
|
||||
except Exception as e:
|
||||
print(e)
|
||||
print("")
|
||||
return
|
||||
28
gamestonk_terminal/stocks/due_diligence/finnhub_model.py
Normal file
28
gamestonk_terminal/stocks/due_diligence/finnhub_model.py
Normal file
@@ -0,0 +1,28 @@
|
||||
""" Finnhub Model """
|
||||
__docformat__ = "numpy"
|
||||
|
||||
import requests
|
||||
import pandas as pd
|
||||
from gamestonk_terminal import config_terminal as cfg
|
||||
|
||||
|
||||
def get_rating_over_time(ticker: str) -> pd.DataFrame:
|
||||
"""Get rating over time data. [Source: Finnhub]
|
||||
|
||||
Parameters
|
||||
----------
|
||||
ticker : str
|
||||
Ticker to get ratings from
|
||||
|
||||
Returns
|
||||
-------
|
||||
pd.DataFrame
|
||||
Get dataframe with ratings
|
||||
"""
|
||||
response = requests.get(
|
||||
f"https://finnhub.io/api/v1/stock/recommendation?symbol={ticker}&token={cfg.API_FINNHUB_KEY}"
|
||||
)
|
||||
if response.status_code == 200:
|
||||
return pd.DataFrame(response.json())
|
||||
|
||||
return pd.DataFrame()
|
||||
@@ -1,42 +1,19 @@
|
||||
import argparse
|
||||
from typing import List
|
||||
import requests
|
||||
""" Finnhub View """
|
||||
__docformat__ = "numpy"
|
||||
|
||||
import os
|
||||
from tabulate import tabulate
|
||||
import pandas as pd
|
||||
from matplotlib import pyplot as plt
|
||||
from pandas.plotting import register_matplotlib_converters
|
||||
from gamestonk_terminal import config_terminal as cfg
|
||||
from gamestonk_terminal.helper_funcs import (
|
||||
parse_known_args_and_warn,
|
||||
plot_autoscale,
|
||||
)
|
||||
from gamestonk_terminal.stocks.due_diligence import finnhub_model
|
||||
from gamestonk_terminal.helper_funcs import plot_autoscale, export_data
|
||||
from gamestonk_terminal.config_plot import PLOT_DPI
|
||||
from gamestonk_terminal import feature_flags as gtff
|
||||
|
||||
register_matplotlib_converters()
|
||||
|
||||
|
||||
def get_rating_over_time(ticker: str) -> pd.DataFrame:
|
||||
"""Get rating over time
|
||||
|
||||
Parameters
|
||||
----------
|
||||
ticker : str
|
||||
Ticker to get ratings from
|
||||
|
||||
Returns
|
||||
-------
|
||||
pd.DataFrame
|
||||
Get dataframe with economic calendar events
|
||||
"""
|
||||
response = requests.get(
|
||||
f"https://finnhub.io/api/v1/stock/recommendation?symbol={ticker}&token={cfg.API_FINNHUB_KEY}"
|
||||
)
|
||||
if response.status_code == 200:
|
||||
return pd.DataFrame(response.json())
|
||||
|
||||
return pd.DataFrame()
|
||||
|
||||
|
||||
def plot_rating_over_time(rot: pd.DataFrame, ticker: str):
|
||||
"""Plot rating over time
|
||||
|
||||
@@ -46,7 +23,6 @@ def plot_rating_over_time(rot: pd.DataFrame, ticker: str):
|
||||
Rating over time
|
||||
ticker : str
|
||||
Ticker associated with ratings
|
||||
|
||||
"""
|
||||
plt.figure(figsize=plot_autoscale(), dpi=PLOT_DPI)
|
||||
|
||||
@@ -65,6 +41,7 @@ def plot_rating_over_time(rot: pd.DataFrame, ticker: str):
|
||||
plt.xlabel("Time")
|
||||
plt.ylabel("Rating")
|
||||
plt.legend(["Strong Buy", "Buy", "Hold", "Sell", "Strong Sell"])
|
||||
plt.gcf().autofmt_xdate()
|
||||
|
||||
if gtff.USE_ION:
|
||||
plt.ion()
|
||||
@@ -72,37 +49,56 @@ def plot_rating_over_time(rot: pd.DataFrame, ticker: str):
|
||||
plt.show()
|
||||
|
||||
|
||||
def rating_over_time(other_args: List[str], ticker: str):
|
||||
"""Rating over time
|
||||
def rating_over_time(ticker: str, num: int, raw: bool, export: str):
|
||||
"""Rating over time (monthly). [Source: Finnhub]
|
||||
|
||||
Parameters
|
||||
----------
|
||||
other_args : List[str]
|
||||
Command line arguments to be processed with argparse
|
||||
ticker : str
|
||||
Ticker to get ratings from
|
||||
num : int
|
||||
Number of last months ratings to show
|
||||
raw : bool
|
||||
Display raw data only
|
||||
export : str
|
||||
Export dataframe data to csv,json,xlsx file
|
||||
"""
|
||||
parser = argparse.ArgumentParser(
|
||||
add_help=False,
|
||||
prog="rot",
|
||||
description="""
|
||||
Rating over time. [Source: https://finnhub.io]
|
||||
""",
|
||||
df_rot = finnhub_model.get_rating_over_time(ticker)
|
||||
|
||||
if df_rot.empty:
|
||||
print("No ratings over time found", "\n")
|
||||
return
|
||||
|
||||
if raw:
|
||||
d_cols = {
|
||||
"strongSell": "Strong Sell",
|
||||
"sell": "Sell",
|
||||
"hold": "Hold",
|
||||
"buy": "Buy",
|
||||
"strongBuy": "Strong Buy",
|
||||
}
|
||||
df_rot_raw = (
|
||||
df_rot[["period", "strongSell", "sell", "hold", "buy", "strongBuy"]]
|
||||
.rename(columns=d_cols)
|
||||
.head(num)
|
||||
)
|
||||
print(
|
||||
tabulate(
|
||||
df_rot_raw,
|
||||
headers=df_rot_raw.columns,
|
||||
floatfmt=".2f",
|
||||
showindex=False,
|
||||
tablefmt="fancy_grid",
|
||||
)
|
||||
)
|
||||
else:
|
||||
plot_rating_over_time(df_rot.head(num), ticker)
|
||||
|
||||
print("")
|
||||
|
||||
export_data(
|
||||
export,
|
||||
os.path.dirname(os.path.abspath(__file__)),
|
||||
"rot",
|
||||
df_rot,
|
||||
)
|
||||
|
||||
try:
|
||||
ns_parser = parse_known_args_and_warn(parser, other_args)
|
||||
if not ns_parser:
|
||||
return
|
||||
|
||||
df_rot = get_rating_over_time(ticker)
|
||||
|
||||
if df_rot.empty:
|
||||
print("No ratings over time found\n")
|
||||
return
|
||||
|
||||
plot_rating_over_time(df_rot, ticker)
|
||||
print("")
|
||||
|
||||
except Exception as e:
|
||||
print(e, "\n")
|
||||
|
||||
43
gamestonk_terminal/stocks/due_diligence/finviz_model.py
Normal file
43
gamestonk_terminal/stocks/due_diligence/finviz_model.py
Normal file
@@ -0,0 +1,43 @@
|
||||
""" Finviz Model """
|
||||
__docformat__ = "numpy"
|
||||
|
||||
from typing import Dict
|
||||
import finviz
|
||||
import pandas as pd
|
||||
from pandas.core.frame import DataFrame
|
||||
|
||||
|
||||
def get_news(ticker: str) -> Dict:
|
||||
"""Get news from Finviz
|
||||
|
||||
Parameters
|
||||
----------
|
||||
ticker : str
|
||||
Stock ticker
|
||||
|
||||
Returns
|
||||
-------
|
||||
Dict
|
||||
News
|
||||
"""
|
||||
return finviz.get_news(ticker)
|
||||
|
||||
|
||||
def get_analyst_data(ticker: str) -> DataFrame:
|
||||
"""Get analyst data. [Source: Finviz]
|
||||
|
||||
Parameters
|
||||
----------
|
||||
ticker : str
|
||||
Stock ticker
|
||||
|
||||
Returns
|
||||
-------
|
||||
df_fa: DataFrame
|
||||
Analyst price targets
|
||||
"""
|
||||
d_finviz_analyst_price = finviz.get_analyst_price_targets(ticker)
|
||||
df_fa = pd.DataFrame.from_dict(d_finviz_analyst_price)
|
||||
df_fa.set_index("date", inplace=True)
|
||||
|
||||
return df_fa
|
||||
@@ -1,17 +1,12 @@
|
||||
""" FinViz View """
|
||||
""" Finviz View """
|
||||
__docformat__ = "numpy"
|
||||
|
||||
import argparse
|
||||
from typing import List
|
||||
import os
|
||||
from colorama import Fore, Style
|
||||
import finviz
|
||||
import pandas as pd
|
||||
from pandas.core.frame import DataFrame
|
||||
from gamestonk_terminal.helper_funcs import (
|
||||
check_positive,
|
||||
patch_pandas_text_adjustment,
|
||||
parse_known_args_and_warn,
|
||||
)
|
||||
from tabulate import tabulate
|
||||
from gamestonk_terminal.stocks.due_diligence import finviz_model
|
||||
from gamestonk_terminal.helper_funcs import export_data
|
||||
from gamestonk_terminal import feature_flags as gtff
|
||||
|
||||
|
||||
def category_color_red_green(val: str) -> str:
|
||||
@@ -32,133 +27,63 @@ def category_color_red_green(val: str) -> str:
|
||||
return Fore.GREEN + val + Style.RESET_ALL
|
||||
if val == "Downgrade":
|
||||
return Fore.RED + val + Style.RESET_ALL
|
||||
if val == "Reiterated":
|
||||
return Fore.YELLOW + val + Style.RESET_ALL
|
||||
return val
|
||||
|
||||
|
||||
def news(other_args: List[str], ticker: str):
|
||||
def news(ticker: str, num: int):
|
||||
"""Display news for a given stock ticker
|
||||
|
||||
Parameters
|
||||
----------
|
||||
other_args : List[str]
|
||||
argparse other args - ["-n", "10"]
|
||||
ticker : str
|
||||
Stock ticker
|
||||
num : int
|
||||
Number of latest news being printed
|
||||
"""
|
||||
d_finviz_news = finviz_model.get_news(ticker)
|
||||
i = 0
|
||||
for s_news_title, s_news_link in {*d_finviz_news}:
|
||||
print(f"-> {s_news_title}")
|
||||
print(f"{s_news_link}\n")
|
||||
i += 1
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
add_help=False,
|
||||
prog="news",
|
||||
description="""
|
||||
Prints latest news about company, including title and web link. [Source: Finviz]
|
||||
""",
|
||||
)
|
||||
if i > (num - 1):
|
||||
break
|
||||
|
||||
parser.add_argument(
|
||||
"-n",
|
||||
"--num",
|
||||
action="store",
|
||||
dest="n_num",
|
||||
type=check_positive,
|
||||
default=5,
|
||||
help="Number of latest news being printed.",
|
||||
)
|
||||
|
||||
try:
|
||||
ns_parser = parse_known_args_and_warn(parser, other_args)
|
||||
if not ns_parser:
|
||||
return
|
||||
|
||||
d_finviz_news = finviz.get_news(ticker)
|
||||
i = 0
|
||||
for s_news_title, s_news_link in {*d_finviz_news}:
|
||||
print(f"-> {s_news_title}")
|
||||
print(f"{s_news_link}\n")
|
||||
i += 1
|
||||
|
||||
if i > (ns_parser.n_num - 1):
|
||||
break
|
||||
|
||||
print("")
|
||||
|
||||
except Exception as e:
|
||||
print(e)
|
||||
print("")
|
||||
return
|
||||
print("")
|
||||
|
||||
|
||||
def analyst_df(ticker: str) -> DataFrame:
|
||||
"""[summary]
|
||||
def analyst(ticker: str, export: str):
|
||||
"""Display analyst ratings. [Source: Finviz]
|
||||
|
||||
Parameters
|
||||
----------
|
||||
ticker : str
|
||||
Stock ticker
|
||||
|
||||
Returns
|
||||
-------
|
||||
DataFrame
|
||||
[description]
|
||||
export : str
|
||||
Export dataframe data to csv,json,xlsx file
|
||||
"""
|
||||
df = finviz_model.get_analyst_data(ticker)
|
||||
|
||||
try:
|
||||
d_finviz_analyst_price = finviz.get_analyst_price_targets(ticker)
|
||||
df_fa = pd.DataFrame.from_dict(d_finviz_analyst_price)
|
||||
df_fa.set_index("date", inplace=True)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
print("Encountered a potential connectivity issue trying to access Finviz.")
|
||||
if gtff.USE_COLOR:
|
||||
df["category"] = df["category"].apply(category_color_red_green)
|
||||
|
||||
return df_fa
|
||||
|
||||
|
||||
def analyst(other_args, ticker):
|
||||
"""Display analyst ratings
|
||||
|
||||
Parameters
|
||||
----------
|
||||
other_args : [type]
|
||||
argparse other args
|
||||
ticker : [type]
|
||||
Stock ticker
|
||||
"""
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
add_help=False,
|
||||
prog="analyst",
|
||||
description="""
|
||||
Print analyst prices and ratings of the company. The following fields are expected:
|
||||
date, analyst, category, price from, price to, and rating. [Source: Finviz]
|
||||
""",
|
||||
print(
|
||||
tabulate(
|
||||
df,
|
||||
headers=df.columns,
|
||||
floatfmt=".2f",
|
||||
showindex=True,
|
||||
tablefmt="fancy_grid",
|
||||
),
|
||||
"\n",
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"-c",
|
||||
"--color",
|
||||
action="store",
|
||||
dest="n_color",
|
||||
type=int,
|
||||
choices=[0, 1],
|
||||
default=1,
|
||||
help="Add / remove color",
|
||||
export_data(
|
||||
export,
|
||||
os.path.dirname(os.path.abspath(__file__)),
|
||||
"analyst",
|
||||
df,
|
||||
)
|
||||
|
||||
try:
|
||||
ns_parser = parse_known_args_and_warn(parser, other_args)
|
||||
if not ns_parser:
|
||||
return
|
||||
|
||||
df_fa = analyst_df(ticker)
|
||||
|
||||
if ns_parser.n_color == 1:
|
||||
df_fa["category"] = df_fa["category"].apply(category_color_red_green)
|
||||
|
||||
patch_pandas_text_adjustment()
|
||||
|
||||
print(df_fa)
|
||||
print("")
|
||||
|
||||
except Exception as e:
|
||||
print(e)
|
||||
print("")
|
||||
return
|
||||
|
||||
22
gamestonk_terminal/stocks/due_diligence/fmp_model.py
Normal file
22
gamestonk_terminal/stocks/due_diligence/fmp_model.py
Normal file
@@ -0,0 +1,22 @@
|
||||
""" Financial Modeling Prep Model """
|
||||
__docformat__ = "numpy"
|
||||
|
||||
import pandas as pd
|
||||
import FundamentalAnalysis as fa
|
||||
from gamestonk_terminal import config_terminal as cfg
|
||||
|
||||
|
||||
def get_rating(ticker: str) -> pd.DataFrame:
|
||||
"""Get ratings for a given ticker. [Source: Financial Modeling Prep]
|
||||
|
||||
Parameters
|
||||
----------
|
||||
ticker : str
|
||||
Stock ticker
|
||||
|
||||
Returns
|
||||
-------
|
||||
pd.DataFrame
|
||||
Rating data
|
||||
"""
|
||||
return fa.rating(ticker, cfg.API_KEY_FINANCIALMODELINGPREP)
|
||||
52
gamestonk_terminal/stocks/due_diligence/fmp_view.py
Normal file
52
gamestonk_terminal/stocks/due_diligence/fmp_view.py
Normal file
@@ -0,0 +1,52 @@
|
||||
""" Financial Modeling Prep View """
|
||||
__docformat__ = "numpy"
|
||||
|
||||
import os
|
||||
from tabulate import tabulate
|
||||
from gamestonk_terminal.helper_funcs import export_data
|
||||
from gamestonk_terminal.stocks.due_diligence import fmp_model
|
||||
|
||||
|
||||
def rating(ticker: str, num: int, export: str):
|
||||
"""Display ratings for a given ticker. [Source: Financial Modeling Prep]
|
||||
|
||||
Parameters
|
||||
----------
|
||||
ticker : str
|
||||
Stock ticker
|
||||
num : int
|
||||
Number of last days ratings to display
|
||||
export : str
|
||||
Export dataframe data to csv,json,xlsx file
|
||||
"""
|
||||
df = fmp_model.get_rating(ticker)
|
||||
|
||||
# TODO: This could be displayed in a nice rating plot over time
|
||||
# TODO: Add coloring to table
|
||||
|
||||
if not df.empty:
|
||||
l_recoms = [col for col in df.columns if "Recommendation" in col]
|
||||
l_recoms_show = [
|
||||
recom.replace("rating", "")
|
||||
.replace("Details", "")
|
||||
.replace("Recommendation", "")
|
||||
for recom in l_recoms
|
||||
]
|
||||
l_recoms_show[0] = "Rating"
|
||||
print(
|
||||
tabulate(
|
||||
df[l_recoms].head(num),
|
||||
headers=l_recoms_show,
|
||||
floatfmt=".2f",
|
||||
showindex=True,
|
||||
tablefmt="fancy_grid",
|
||||
)
|
||||
)
|
||||
print("")
|
||||
|
||||
export_data(
|
||||
export,
|
||||
os.path.dirname(os.path.abspath(__file__)),
|
||||
"rot",
|
||||
df,
|
||||
)
|
||||
64
gamestonk_terminal/stocks/due_diligence/marketwatch_model.py
Normal file
64
gamestonk_terminal/stocks/due_diligence/marketwatch_model.py
Normal file
@@ -0,0 +1,64 @@
|
||||
""" Market Watch Model """
|
||||
__docformat__ = "numpy"
|
||||
|
||||
import requests
|
||||
import pandas as pd
|
||||
from bs4 import BeautifulSoup
|
||||
from gamestonk_terminal.helper_funcs import get_user_agent
|
||||
|
||||
# pylint: disable=too-many-branches
|
||||
|
||||
|
||||
def get_sec_filings(ticker: str) -> pd.DataFrame:
|
||||
"""Get SEC filings for a given stock ticker. [Source: Market Watch]
|
||||
|
||||
Parameters
|
||||
----------
|
||||
ticker : str
|
||||
Stock ticker
|
||||
|
||||
Returns
|
||||
-------
|
||||
df_financials : pd.DataFrame
|
||||
SEC filings data
|
||||
"""
|
||||
|
||||
pd.set_option("display.max_colwidth", None)
|
||||
|
||||
url_financials = (
|
||||
f"https://www.marketwatch.com/investing/stock/{ticker}/financials/secfilings"
|
||||
)
|
||||
|
||||
text_soup_financials = BeautifulSoup(
|
||||
requests.get(url_financials, headers={"User-Agent": get_user_agent()}).text,
|
||||
"lxml",
|
||||
)
|
||||
|
||||
# a_financials_header = list()
|
||||
df_financials = None
|
||||
b_ready_to_process_info = False
|
||||
soup_financials = text_soup_financials.findAll("tr", {"class": "table__row"})
|
||||
for financials_info in soup_financials:
|
||||
a_financials = financials_info.text.split("\n")
|
||||
|
||||
# If header has been processed and dataframe created ready to populate the SEC information
|
||||
if b_ready_to_process_info:
|
||||
l_financials_info = [a_financials[2]]
|
||||
l_financials_info.extend(a_financials[5:-1])
|
||||
l_financials_info.append(financials_info.a["href"])
|
||||
# Append data values to financials
|
||||
df_financials.loc[len(df_financials.index)] = l_financials_info # type: ignore
|
||||
|
||||
if "Filing Date" in a_financials:
|
||||
l_financials_header = [a_financials[2]]
|
||||
l_financials_header.extend(a_financials[5:-1])
|
||||
l_financials_header.append("Link")
|
||||
|
||||
df_financials = pd.DataFrame(columns=l_financials_header)
|
||||
df_financials.set_index("Filing Date")
|
||||
b_ready_to_process_info = True
|
||||
|
||||
# Set Filing Date as index
|
||||
df_financials = df_financials.set_index("Filing Date") # type: ignore
|
||||
|
||||
return df_financials
|
||||
41
gamestonk_terminal/stocks/due_diligence/marketwatch_view.py
Normal file
41
gamestonk_terminal/stocks/due_diligence/marketwatch_view.py
Normal file
@@ -0,0 +1,41 @@
|
||||
""" Market Watch View """
|
||||
__docformat__ = "numpy"
|
||||
|
||||
import os
|
||||
from tabulate import tabulate
|
||||
from gamestonk_terminal.helper_funcs import export_data
|
||||
from gamestonk_terminal.stocks.due_diligence import marketwatch_model
|
||||
|
||||
# pylint: disable=too-many-branches
|
||||
|
||||
|
||||
def sec_filings(ticker: str, num: int, export: str):
|
||||
"""Display SEC filings for a given stock ticker. [Source: Market Watch]
|
||||
|
||||
Parameters
|
||||
----------
|
||||
ticker : str
|
||||
Stock ticker
|
||||
num : int
|
||||
Number of ratings to display
|
||||
export : str
|
||||
Export dataframe data to csv,json,xlsx file
|
||||
"""
|
||||
df_financials = marketwatch_model.get_sec_filings(ticker)
|
||||
print(
|
||||
tabulate(
|
||||
df_financials.head(num),
|
||||
headers=df_financials.columns,
|
||||
floatfmt=".2f",
|
||||
showindex=True,
|
||||
tablefmt="fancy_grid",
|
||||
)
|
||||
)
|
||||
print("")
|
||||
|
||||
export_data(
|
||||
export,
|
||||
os.path.dirname(os.path.abspath(__file__)),
|
||||
"sec",
|
||||
df_financials,
|
||||
)
|
||||
47
notebooks/templates/due_diligence.ipynb
vendored
47
notebooks/templates/due_diligence.ipynb
vendored
@@ -3,7 +3,7 @@
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "collaborative-pharmacology",
|
||||
"id": "phantom-facility",
|
||||
"metadata": {
|
||||
"collapsed": true
|
||||
},
|
||||
@@ -27,7 +27,7 @@
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "future-association",
|
||||
"id": "compact-count",
|
||||
"metadata": {
|
||||
"collapsed": true,
|
||||
"tags": [
|
||||
@@ -44,7 +44,7 @@
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "oriental-wells",
|
||||
"id": "possible-constraint",
|
||||
"metadata": {
|
||||
"collapsed": true
|
||||
},
|
||||
@@ -56,7 +56,7 @@
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "fitted-affect",
|
||||
"id": "local-preference",
|
||||
"metadata": {
|
||||
"collapsed": true
|
||||
},
|
||||
@@ -75,20 +75,20 @@
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "black-latvia",
|
||||
"id": "undefined-stadium",
|
||||
"metadata": {
|
||||
"collapsed": true
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from gamestonk_terminal.common.technical_analysis import trendline_api as trend\n",
|
||||
"from gamestonk_terminal.stocks.due_diligence import finviz_view as finviz"
|
||||
"from gamestonk_terminal.stocks.due_diligence import finviz_view"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "loved-dietary",
|
||||
"id": "competitive-membership",
|
||||
"metadata": {
|
||||
"collapsed": true
|
||||
},
|
||||
@@ -109,7 +109,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "transparent-change",
|
||||
"id": "temporal-clerk",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Candle View"
|
||||
@@ -118,7 +118,7 @@
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "ruled-marks",
|
||||
"id": "transsexual-trance",
|
||||
"metadata": {
|
||||
"collapsed": true
|
||||
},
|
||||
@@ -148,7 +148,7 @@
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "ahead-return",
|
||||
"id": "convenient-great",
|
||||
"metadata": {
|
||||
"collapsed": true
|
||||
},
|
||||
@@ -161,7 +161,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "amber-hayes",
|
||||
"id": "political-intake",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Analyst Targets"
|
||||
@@ -170,20 +170,19 @@
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "conservative-baking",
|
||||
"id": "numerous-begin",
|
||||
"metadata": {
|
||||
"collapsed": true
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"df_fa = finviz.analyst_df(ticker)\n",
|
||||
"print(df_fa.to_string())"
|
||||
"finviz_view.analyst(ticker=ticker, no_color=False)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "moderate-dealer",
|
||||
"id": "nuclear-trailer",
|
||||
"metadata": {
|
||||
"collapsed": true
|
||||
},
|
||||
@@ -194,7 +193,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "victorian-classic",
|
||||
"id": "written-lease",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Annual Income Statement"
|
||||
@@ -203,7 +202,7 @@
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "three-vegetation",
|
||||
"id": "played-vancouver",
|
||||
"metadata": {
|
||||
"collapsed": true
|
||||
},
|
||||
@@ -215,7 +214,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "collected-deployment",
|
||||
"id": "smooth-forge",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Quarterly Income Statement"
|
||||
@@ -224,7 +223,7 @@
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "grateful-minnesota",
|
||||
"id": "juvenile-throw",
|
||||
"metadata": {
|
||||
"collapsed": true
|
||||
},
|
||||
@@ -236,7 +235,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "angry-somerset",
|
||||
"id": "passive-nerve",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Annual Balance Sheet"
|
||||
@@ -245,7 +244,7 @@
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "fifty-angola",
|
||||
"id": "nominated-empire",
|
||||
"metadata": {
|
||||
"collapsed": true
|
||||
},
|
||||
@@ -257,7 +256,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "typical-fundamentals",
|
||||
"id": "special-bargain",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Annual Cash Flow"
|
||||
@@ -266,7 +265,7 @@
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "magnetic-throat",
|
||||
"id": "focused-thanks",
|
||||
"metadata": {
|
||||
"collapsed": true
|
||||
},
|
||||
@@ -279,7 +278,7 @@
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "instructional-skating",
|
||||
"id": "sought-phase",
|
||||
"metadata": {
|
||||
"collapsed": true
|
||||
},
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
interactions:
|
||||
- request:
|
||||
body: null
|
||||
headers:
|
||||
Connection:
|
||||
- close
|
||||
Host:
|
||||
- financialmodelingprep.com
|
||||
User-Agent:
|
||||
- Python-urllib/3.8
|
||||
method: GET
|
||||
uri: https://financialmodelingprep.com/api/v3/historical-rating/PLTR?apikey=REPLACE_ME
|
||||
response:
|
||||
body:
|
||||
string: '{"Error Message" : "Invalid API KEY. Please retry or visit our documentation
|
||||
to create one FREE https://financialmodelingprep.com/developer/docs"}'
|
||||
headers:
|
||||
Access-Control-Allow-Headers:
|
||||
- origin, content-type, accept, Authorization, authorization
|
||||
Access-Control-Allow-Methods:
|
||||
- GET, OPTIONS
|
||||
Access-Control-Allow-Origin:
|
||||
- '*'
|
||||
Access-Control-Max-Age:
|
||||
- '3600'
|
||||
Connection:
|
||||
- close
|
||||
Content-Length:
|
||||
- '146'
|
||||
Content-Type:
|
||||
- application/json;charset=UTF-8
|
||||
Date:
|
||||
- Thu, 12 Aug 2021 19:14:33 GMT
|
||||
Server:
|
||||
- nginx/1.14.0 (Ubuntu)
|
||||
status:
|
||||
code: 200
|
||||
message: ''
|
||||
version: 1
|
||||
1621
tests/cassettes/test_main/test_main_helper/test_check_api_keys.yaml
vendored
Normal file
1621
tests/cassettes/test_main/test_main_helper/test_check_api_keys.yaml
vendored
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,14 +0,0 @@
|
||||
""" fundamental_analysis/business_insider_api.py tests """
|
||||
import unittest
|
||||
|
||||
import vcr
|
||||
|
||||
from gamestonk_terminal.stocks.due_diligence.financial_modeling_prep_view import rating
|
||||
from tests.helpers import check_print
|
||||
|
||||
|
||||
class TestDdFinancialModelingPrepView(unittest.TestCase):
|
||||
@check_print(assert_in="Invalid API KEY")
|
||||
@vcr.use_cassette("tests/cassettes/test_dd/test_financial_model/test_rating.yaml")
|
||||
def test_rating(self):
|
||||
rating([], "PLTR")
|
||||
@@ -3,7 +3,7 @@ import unittest
|
||||
|
||||
import vcr
|
||||
|
||||
from gamestonk_terminal.stocks.due_diligence.finviz_view import analyst
|
||||
from gamestonk_terminal.stocks.due_diligence.finviz_model import get_analyst_data
|
||||
from tests.helpers import check_print
|
||||
|
||||
|
||||
@@ -11,4 +11,5 @@ class TestDdFinvizApi(unittest.TestCase):
|
||||
@check_print(assert_in="category")
|
||||
@vcr.use_cassette("tests/cassettes/test_dd/test_finzin/test_analyst.yaml")
|
||||
def test_analyst(self):
|
||||
analyst([], "PLTR")
|
||||
df = get_analyst_data(ticker="PLTR")
|
||||
print(df.to_string())
|
||||
|
||||
Reference in New Issue
Block a user