import threading
import requests
import json
import datetime
from pathlib import Path
class TickerInfo:
"""
TickerInfo can be used to get real-time financial information about assets listed in any global exchange. The module
is powered with Yahoo Finance, and the tickers that can be used with TickerInfo are solely the ones permitted
on Yahoo Finance.
How to use TickerInfo?
Instantiate TickerInfo as an object and call its functions for results. Consider the example code below:
>>> tickerInfo = TickerInfo()
>>> tickerInfo.get_current_price("GOOG")
1431.72
>>> tickerInfo,get_purchase_recommendation("GOOG")
1.3
"""
def __init__(self):
self.memoized_scraped_data = {}
self.info_keys = {}
self.SCRAPER_MAIN_URL_TAG = "finance_scrape_url_main"
self.SCRAPER_URL_PARAMS_TAG = "finance_scrape_url_params"
self.config = {
"finance_scrape_url_main": "https://query2.finance.yahoo.com/v10/finance/quoteSummary/",
"finance_scrape_url_params": "?formatted=true&lang=en-US®ion=US&modules=summaryProfile%2CfinancialData%2CrecommendationTrend%2CupgradeDowngradeHistory%2Cearnings%2CdefaultKeyStatistics%2CbalanceSheetHistory%2CassetProfile%2CcashflowStatementHistory%2CincomeStatementHistory%2CcalendarEvents&corsDomain=finance.yahoo.com"
}
def ____core_parse_helper(self, ticker):
""" Scrapes Yahoo Finance to retrieve data about an asset ticker.
:param ticker: (String) Asset ticker for globally listed companies, as supported by Yahoo Finance
:return: (dict) Scraped data about asset ticker
"""
if not isinstance(ticker, str):
raise TypeError("ticker parameter is not a String")
query_url = self.config[self.SCRAPER_MAIN_URL_TAG] + ticker + self.config[self.SCRAPER_URL_PARAMS_TAG]
summary_json_response = requests.get(query_url)
final_scraped_information = {}
json_loaded_summary = json.loads(summary_json_response.text)
if json_loaded_summary is None \
or "quoteSummary" not in json_loaded_summary\
or "result" not in json_loaded_summary["quoteSummary"]\
or len(json_loaded_summary["quoteSummary"]["result"]) == 0:
return None
core = json_loaded_summary["quoteSummary"]["result"][0]
processing_sets = [core[factor] for factor in core.keys()]
if "calendarEvents" in core:
if 'earnings' in core["calendarEvents"]:
processing_sets.append(core["calendarEvents"]['earnings'])
for ps in processing_sets:
for x in list(ps.keys()):
if isinstance(ps[x], dict):
if len(ps[x]) == 0:
ps[x] = None
elif 'raw' in ps[x]:
ps[x] = ps[x]['raw']
if isinstance(ps[x], list):
ps[x] = [y['fmt'] for y in ps[x] if 'fmt' in y]
final_scraped_information.update(ps)
self.memoized_scraped_data[ticker] = (
datetime.datetime.now(),
final_scraped_information
)
self.info_keys[ticker] = final_scraped_information.keys()
return final_scraped_information
def __core_parse(self, ticker):
""" Wrapper function on top of scraper function to assist with memoization process
:param ticker: (String) Asset ticker for globally listed companies, as supported by Yahoo Finance
:return: (dict) Scraped data about asset ticker
"""
if ticker in self.memoized_scraped_data:
data_tuple = self.memoized_scraped_data[ticker]
first_time = data_tuple[0]
later_time = datetime.datetime.now()
difference = later_time - first_time
seconds_in_day = 24 * 60 * 60
if divmod(difference.days * seconds_in_day + difference.seconds, 60)[0] < 15:
thread = threading.Thread(target=self.____core_parse_helper, args=(ticker,))
thread.start()
return data_tuple[1]
return self.____core_parse_helper(ticker)
def get_available_data_tags(self, ticker):
""" Returns a list of available data for an asset ticker, as found in Yahoo Finance.
:param ticker: (String) Asset ticker for globally listed companies, as supported by Yahoo Finance
:return: (list) tags available for an asset ticker; Returns None if the information is not available
"""
if not isinstance(ticker, str):
raise TypeError("ticker parameter is not a String")
if ticker not in self.info_keys:
self.get_company_data(ticker)
return self.info_keys[ticker]
def get_data_from_tag(self, ticker, tag):
""" Returns available data for an asset ticker and a provided tag, as found in Yahoo Finance.
:param ticker: (String) Asset ticker for globally listed companies, as supported by Yahoo Finance
:param tag: (String) Data tag that is to be retrieved from Yahoo Finance. For a list of
available data tags call TickerInfo.get_available_data_tags(tag)
:return: (int or String) data associated with asset ticker and provided tag; Returns None if the information is
not available
"""
if not isinstance(ticker, str):
raise TypeError("ticker parameter is not a String")
if not isinstance(tag, str):
raise TypeError("tag parameter is not a String")
if ticker not in self.info_keys:
self.get_company_data(ticker)
# print("KYAS:" , self.memoized_scraped_data[ticker][1])
return self.memoized_scraped_data[ticker][1][tag] if tag in self.memoized_scraped_data[ticker][1] else None
def get_company_data(self, ticker):
""" Returns a dictionary of data associated with the asset ticker, as found in Yahoo Finance. For a list of
available data tags call TickerInfo.get_available_data_tags(tag).
:param ticker: (String) Asset ticker for globally listed companies, as supported by Yahoo Finance
:return: (dict) data associated with asset ticker; Returns None if the information is not available
"""
if not isinstance(ticker, str):
raise TypeError("ticker parameter is not a String")
core = self.__core_parse(ticker)
if core is None or len(core) == 0:
return None
beta = core["beta"] if "beta" in core else None
if beta is None:
beta = core["beta3Year"] if "beta3Year" in core else None
del core["beta3Year"]
core["beta"] = beta
return core if core is None else core
def get_industry(self, ticker):
""" Returns the industry of the company that is represented by the asset ticker. If the ticker is not of a stock
the function will return None
:param ticker: (String) Asset ticker for globally listed companies, as supported by Yahoo Finance
:return: (String) the industry of the company represented by the asset ticker; Returns None if the information
is not available
"""
if not isinstance(ticker, str):
raise TypeError("ticker parameter is not a String")
core = self.__core_parse(ticker)
return core if core is None else core["industry"]
def get_sector(self, ticker):
""" Returns the sector of the company that is represented by the asset ticker. If the ticker is not of a stock,
the function will return None
:param ticker: (String) Asset ticker for globally listed companies, as supported by Yahoo Finance
:return: (String) the sector of the company represented by the asset ticker; Returns None if the information is
not available
"""
if not isinstance(ticker, str):
raise TypeError("ticker parameter is not a String")
core = self.__core_parse(ticker)
return core if core is None else core["sector"]
def get_current_price(self, ticker):
""" Returns the current price of the asset
:param ticker: (String) Asset ticker for globally listed companies, as supported by Yahoo Finance
:return: (int) current price; Returns None if the information is not available
"""
if not isinstance(ticker, str):
raise TypeError("ticker parameter is not a String")
core = self.__core_parse(ticker)
return core if core is None else core["currentPrice"]
def get_ytd(self, ticker):
""" Returns the year-to-date return of the requested asset
:param ticker: (String) Asset ticker for globally listed companies, as supported by Yahoo Finance
:return: (int) year-to-date return; Returns None if the information is not available
"""
if not isinstance(ticker, str):
raise TypeError("ticker parameter is not a String")
core = self.__core_parse(ticker)
print(core)
return core if core is None else core['ytdReturn']
def get_beta(self, ticker):
""" Provides the beta coefficient for a given asset ticker. If the asset is a bond, the function returns the
3-year beta coefficient
:param ticker: (String) Asset ticker for globally listed companies, as supported by Yahoo Finance
:return: (int) beta coefficient; Returns None if the information is not available
"""
core = self.__core_parse(ticker)
beta = core["beta"] if "beta" in core else None
if beta is None:
beta = core["beta3Year"] if "beta3Year" in core else None
return beta
def get_purchase_recommendation(self, ticker):
""" Provides analysts recommendation for purchasing a stock.
1 – Strong Buy
2 – Buy
3 – Hold
4 – Underperform
5 – Sell
:param ticker: (String) Asset ticker for globally listed companies, as supported by Yahoo Finance
:return: (int) the number representation of stock purchase recommendation; Returns None if the information is
not available
"""
if not isinstance(ticker, str):
raise TypeError("ticker parameter is not a String")
core = self.__core_parse(ticker)
return core if core is None else core["recommendationMean"]
from datax.tools.finance import TickerInfo
Demo 1: Basic Features
# Setting up the demo
tickerInfo = TickerInfo()
stock_ticker = "AAPL" # This is the Apple's Stock Ticker (as listed in NASDAQ)
# Gets the current stock price of AAPL stock
tickerInfo.get_current_price(stock_ticker)
356.69
# Gets the current beta coefficient of AAPL stock
tickerInfo.get_beta(stock_ticker)
1.170435
# Gets the current purchase recommednation of AAPL stock
tickerInfo.get_purchase_recommendation(stock_ticker)
2.0
# Gets the industry of the company Apple
tickerInfo.get_industry(stock_ticker)
'Consumer Electronics'
# Gets the sector of the company Apple
tickerInfo.get_sector(stock_ticker)
'Technology'
Demo 2: Advanced Features
# Gets all the financial and company-related statistics that are available
len(tickerInfo.get_available_data_tags(stock_ticker)), tickerInfo.get_available_data_tags(stock_ticker)
(115, dict_keys(['address1', 'city', 'state', 'zip', 'country', 'phone', 'website', 'industry', 'sector', 'longBusinessSummary', 'fullTimeEmployees', 'companyOfficers', 'auditRisk', 'boardRisk', 'compensationRisk', 'shareHolderRightsRisk', 'overallRisk', 'governanceEpochDate', 'compensationAsOfEpochDate', 'maxAge', 'trend', 'cashflowStatements', 'earningsChart', 'financialsChart', 'financialCurrency', 'earnings', 'exDividendDate', 'dividendDate', 'history', 'priceHint', 'enterpriseValue', 'forwardPE', 'profitMargins', 'floatShares', 'sharesOutstanding', 'sharesShort', 'sharesShortPriorMonth', 'sharesShortPreviousMonthDate', 'dateShortInterest', 'sharesPercentSharesOut', 'heldPercentInsiders', 'heldPercentInstitutions', 'shortRatio', 'shortPercentOfFloat', 'beta', 'morningStarOverallRating', 'morningStarRiskRating', 'category', 'bookValue', 'priceToBook', 'annualReportExpenseRatio', 'ytdReturn', 'beta3Year', 'totalAssets', 'yield', 'fundFamily', 'fundInceptionDate', 'legalType', 'threeYearAverageReturn', 'fiveYearAverageReturn', 'priceToSalesTrailing12Months', 'lastFiscalYearEnd', 'nextFiscalYearEnd', 'mostRecentQuarter', 'earningsQuarterlyGrowth', 'revenueQuarterlyGrowth', 'netIncomeToCommon', 'trailingEps', 'forwardEps', 'pegRatio', 'lastSplitFactor', 'lastSplitDate', 'enterpriseToRevenue', 'enterpriseToEbitda', '52WeekChange', 'SandP52WeekChange', 'lastDividendValue', 'lastCapGain', 'annualHoldingsTurnover', 'balanceSheetStatements', 'incomeStatementHistory', 'currentPrice', 'targetHighPrice', 'targetLowPrice', 'targetMeanPrice', 'targetMedianPrice', 'recommendationMean', 'recommendationKey', 'numberOfAnalystOpinions', 'totalCash', 'totalCashPerShare', 'ebitda', 'totalDebt', 'quickRatio', 'currentRatio', 'totalRevenue', 'debtToEquity', 'revenuePerShare', 'returnOnAssets', 'returnOnEquity', 'grossProfits', 'freeCashflow', 'operatingCashflow', 'earningsGrowth', 'revenueGrowth', 'grossMargins', 'ebitdaMargins', 'operatingMargins', 'earningsDate', 'earningsAverage', 'earningsLow', 'earningsHigh', 'revenueAverage', 'revenueLow', 'revenueHigh']))
# Gets the associated information for the selected tag
selected_tag = "fullTimeEmployees"
tickerInfo.get_data_from_tag(stock_ticker, selected_tag)
137000
# Gets all the information available for AAPL
import pandas as pd
data = tickerInfo.get_company_data(stock_ticker)
pd.Series(data)
address1 One Apple Park Way city Cupertino state CA zip 95014 country United States phone 408-996-1010 website http://www.apple.com industry Consumer Electronics sector Technology longBusinessSummary Apple Inc. designs, manufactures, and markets ... fullTimeEmployees 137000 companyOfficers [] auditRisk 1 boardRisk 1 compensationRisk 3 shareHolderRightsRisk 1 overallRisk 1 governanceEpochDate 1591920000 compensationAsOfEpochDate 1577750400 maxAge 86400 trend [] cashflowStatements [] earningsChart {'quarterly': [{'date': '2Q2019', 'actual': {'... financialsChart {'yearly': [{'date': 2016, 'revenue': {'raw': ... financialCurrency USD earnings {'earningsDate': ['2020-07-28', '2020-08-03'],... exDividendDate 1588896000 dividendDate 1589414400 history [] priceHint 2 ... targetMedianPrice 330 recommendationMean 2 recommendationKey buy numberOfAnalystOpinions 37 totalCash 94051000320 totalCashPerShare 21.699 ebitda 77305004032 totalDebt 118760996864 quickRatio 1.298 currentRatio 1.496 totalRevenue 267980996608 debtToEquity 151.433 revenuePerShare 60.097 returnOnAssets 0.12377 returnOnEquity 0.62094 grossProfits 98392000000 freeCashflow 45040123904 operatingCashflow 75373002752 earningsGrowth 0.037 revenueGrowth 0.005 grossMargins 0.3811 ebitdaMargins 0.28847 operatingMargins 0.24476 earningsDate [2020-07-28, 2020-08-03] earningsAverage 2 earningsLow 1.55 earningsHigh 2.47 revenueAverage 51498300000 revenueLow 42799000000 revenueHigh 55838000000 Length: 114, dtype: object