Files
OpenBB/openbb_terminal/stocks/fundamental_analysis/seeking_alpha_model.py
Colin Delahunty ee34a1f278 Feature/add isort linter (#4114)
* Fixed isort

* Fixed issues

* FIxed linters

---------

Co-authored-by: James Maslek <jmaslek11@gmail.com>
2023-02-04 21:24:47 -05:00

344 lines
11 KiB
Python

""" Seeking Alpha Model """
__docformat__ = "numpy"
import logging
import pandas as pd
import requests
from openbb_terminal.decorators import log_start_end
from openbb_terminal.helper_funcs import lambda_long_number_format
logger = logging.getLogger(__name__)
@log_start_end(log=logger)
def get_estimates_eps(ticker: str) -> pd.DataFrame:
"""Takes the ticker, asks for seekingalphaID and gets eps estimates
Parameters
----------
ticker: str
ticker of company
Returns
-------
pd.DataFrame
eps estimates for the next 10yrs
Examples
--------
>>> from openbb_terminal.sdk import openbb
>>> openbb.stocks.fa.epsfc("AAPL")
"""
url = "https://seekingalpha.com/api/v3/symbol_data/estimates"
querystring = {
"estimates_data_items": "eps_normalized_actual,eps_normalized_consensus_low,eps_normalized_consensus_mean,"
"eps_normalized_consensus_high,eps_normalized_num_of_estimates",
"period_type": "annual",
"relative_periods": "-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11",
}
# add ticker_ids for the ticker
seek_id = get_seekingalpha_id(ticker)
querystring["ticker_ids"] = seek_id
payload = ""
headers = {
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:106.0) Gecko/20100101 Firefox/106.0",
"Accept": "*/*",
"Accept-Language": "de,en-US;q=0.7,en;q=0.3",
"Accept-Encoding": "gzip, deflate, br",
"Sec-Fetch-Dest": "empty",
"Sec-Fetch-Mode": "cors",
"Sec-Fetch-Site": "same-origin",
"Connection": "keep-alive",
}
# semi random user agent -- disabled and static user agent because it might be the reason for 403
# headers["User-Agent"] = get_user_agent()
response = requests.request(
"GET", url, data=payload, headers=headers, params=querystring
)
# init
output = pd.DataFrame(
columns=[
"fiscalyear",
"consensus_mean",
"change %",
"analysts",
"actual",
"consensus_low",
"consensus_high",
]
)
# if no estimations exist, response is empty "reviews" and "reviews"
# {"revisions":{},"estimates":{}}
try:
seek_object = response.json()["estimates"][str(seek_id)]
items = len(seek_object["eps_normalized_num_of_estimates"].keys())
for i in range(0, items - 3):
# python_dict
eps_estimates = {}
eps_estimates["fiscalyear"] = seek_object[
"eps_normalized_num_of_estimates"
][str(i)][0]["period"]["fiscalyear"]
eps_estimates["analysts"] = seek_object["eps_normalized_num_of_estimates"][
str(i)
][0]["dataitemvalue"]
try:
eps_estimates["actual"] = seek_object["eps_normalized_actual"][str(i)][
0
]["dataitemvalue"]
except Exception:
eps_estimates["actual"] = 0
eps_estimates["consensus_low"] = seek_object[
"eps_normalized_consensus_low"
][str(i)][0]["dataitemvalue"]
eps_estimates["consensus_high"] = seek_object[
"eps_normalized_consensus_high"
][str(i)][0]["dataitemvalue"]
eps_estimates["consensus_mean"] = seek_object[
"eps_normalized_consensus_mean"
][str(i)][0]["dataitemvalue"]
try:
this = float(eps_estimates["consensus_mean"])
try:
prev = float(
seek_object["eps_normalized_actual"][str(i - 1)][0][
"dataitemvalue"
]
)
except Exception:
prev = float(
seek_object["eps_normalized_consensus_mean"][str(i - 1)][0][
"dataitemvalue"
]
)
percent = ((this / prev) - 1) * 100
except Exception:
percent = 0
eps_estimates["change %"] = percent
# format correction (before return, so calculation still works)
eps_estimates["consensus_mean"] = lambda_long_number_format(
float(eps_estimates["consensus_mean"])
)
eps_estimates["consensus_low"] = lambda_long_number_format(
float(eps_estimates["consensus_low"])
)
eps_estimates["consensus_high"] = lambda_long_number_format(
float(eps_estimates["consensus_high"])
)
eps_estimates["actual"] = lambda_long_number_format(
float(eps_estimates["actual"])
)
# df append replacement
new_row = pd.DataFrame(eps_estimates, index=[0])
output = pd.concat([output, new_row])
except Exception:
return pd.DataFrame()
return output
@log_start_end(log=logger)
def get_estimates_rev(ticker: str) -> pd.DataFrame:
"""Takes the ticker, asks for seekingalphaID and gets rev estimates
Parameters
----------
ticker: str
ticker of company
Returns
-------
pd.DataFrame
rev estimates for the next 10yrs
Examples
--------
>>> from openbb_terminal.sdk import openbb
>>> openbb.stocks.fa.revfc("AAPL")
"""
url = "https://seekingalpha.com/api/v3/symbol_data/estimates"
querystring = {
"estimates_data_items": "revenue_actual,revenue_consensus_low,revenue_consensus_mean,"
"revenue_consensus_high,revenue_num_of_estimates",
"period_type": "annual",
"relative_periods": "-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11",
}
# add ticker_ids for the ticker
seek_id = get_seekingalpha_id(ticker)
querystring["ticker_ids"] = seek_id
payload = ""
headers = {
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:106.0) Gecko/20100101 Firefox/106.0",
"Accept": "*/*",
"Accept-Language": "de,en-US;q=0.7,en;q=0.3",
"Accept-Encoding": "gzip, deflate, br",
"Sec-Fetch-Dest": "empty",
"Sec-Fetch-Mode": "cors",
"Sec-Fetch-Site": "same-origin",
"Connection": "keep-alive",
"TE": "trailers",
}
# semi random user agent -- disabled and static user agent because it might be the reason for 403
# headers["User-Agent"] = get_user_agent()
response = requests.request(
"GET", url, data=payload, headers=headers, params=querystring
)
# init
# pd.empty should deliver true if no data-rows are added
output = pd.DataFrame(
columns=[
"fiscalyear",
"consensus_mean",
"change %",
"analysts",
"actual",
"consensus_low",
"consensus_high",
]
)
# if no estimations exist, response is empty "reviews" and "reviews"
# {"revisions":{},"estimates":{}}
try:
seek_object = response.json()["estimates"][seek_id]
items = len(seek_object["revenue_num_of_estimates"].keys())
for i in range(0, items - 3):
# python_dict
revenue_estimates = {}
revenue_estimates["fiscalyear"] = seek_object["revenue_num_of_estimates"][
str(i)
][0]["period"]["fiscalyear"]
revenue_estimates["consensus_mean"] = seek_object["revenue_consensus_mean"][
str(i)
][0]["dataitemvalue"]
revenue_estimates["analysts"] = seek_object["revenue_num_of_estimates"][
str(i)
][0]["dataitemvalue"]
if i < 1:
revenue_estimates["actual"] = seek_object["revenue_actual"][str(i)][0][
"dataitemvalue"
]
else:
revenue_estimates["actual"] = 0
revenue_estimates["consensus_low"] = seek_object["revenue_consensus_low"][
str(i)
][0]["dataitemvalue"]
revenue_estimates["consensus_high"] = seek_object["revenue_consensus_high"][
str(i)
][0]["dataitemvalue"]
try:
this = float(revenue_estimates["consensus_mean"])
# if actual revenue is available, take it for the calc
try:
prev = float(
seek_object["revenue_actual"][str(i - 1)][0]["dataitemvalue"]
)
except Exception:
prev = float(
seek_object["revenue_consensus_mean"][str(i - 1)][0][
"dataitemvalue"
]
)
percent = ((this / prev) - 1) * 100
except Exception:
percent = float(0)
revenue_estimates["change %"] = percent
# format correction (before return, so calculation still works)
revenue_estimates["consensus_mean"] = lambda_long_number_format(
float(revenue_estimates["consensus_mean"])
)
revenue_estimates["consensus_low"] = lambda_long_number_format(
float(revenue_estimates["consensus_low"])
)
revenue_estimates["consensus_high"] = lambda_long_number_format(
float(revenue_estimates["consensus_high"])
)
revenue_estimates["actual"] = lambda_long_number_format(
float(revenue_estimates["actual"])
)
# df append replacement
new_row = pd.DataFrame(revenue_estimates, index=[0])
output = pd.concat([output, new_row])
except Exception:
return pd.DataFrame()
return output
@log_start_end(log=logger)
def get_seekingalpha_id(ticker: str) -> str:
"""Takes the ticker, asks for seekingalphaID and returns it
Parameters
----------
ticker: str
ticker of company
Returns
-------
str:
seekingalphaID - to be used for further API calls
"""
url = "https://seekingalpha.com/api/v3/searches"
querystring = {
"filter[type]": "symbols",
"filter[list]": "all",
"page[size]": "1",
}
querystring["filter[query]"] = ticker
payload = ""
headers = {
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:106.0) Gecko/20100101 Firefox/106.0",
"Accept": "*/*",
"Accept-Language": "de,en-US;q=0.7,en;q=0.3",
"Accept-Encoding": "gzip, deflate, br",
"Sec-Fetch-Dest": "empty",
"Sec-Fetch-Mode": "cors",
"Sec-Fetch-Site": "same-origin",
"Referer": "https://seekingalpha.com/",
"Connection": "keep-alive",
# "TE": "trailers",
}
response = requests.request(
"GET", url, data=payload, headers=headers, params=querystring
)
try:
seekingalphaID = str(response.json()["symbols"][0]["id"])
except Exception:
# for some reason no mapping possible
seekingalphaID = "0"
return seekingalphaID