{ "cells": [ { "cell_type": "code", "execution_count": 1, "metadata": { "colab": {}, "colab_type": "code", "id": "tb0GFfOqXX3W" }, "outputs": [], "source": [ "import threading\n", "import requests\n", "import json\n", "import datetime\n", "from pathlib import Path\n", "\n", "\n", "class TickerInfo:\n", " \"\"\"\n", " TickerInfo can be used to get real-time financial information about assets listed in any global exchange. The module\n", " is powered with Yahoo Finance, and the tickers that can be used with TickerInfo are solely the ones permitted\n", " on Yahoo Finance.\n", "\n", "\n", " How to use TickerInfo?\n", " Instantiate TickerInfo as an object and call its functions for results. Consider the example code below:\n", "\n", " >>> tickerInfo = TickerInfo()\n", " >>> tickerInfo.get_current_price(\"GOOG\")\n", " 1431.72\n", " >>> tickerInfo,get_purchase_recommendation(\"GOOG\")\n", " 1.3\n", "\n", " \"\"\"\n", " def __init__(self):\n", " self.memoized_scraped_data = {}\n", " self.info_keys = {}\n", " self.SCRAPER_MAIN_URL_TAG = \"finance_scrape_url_main\"\n", " self.SCRAPER_URL_PARAMS_TAG = \"finance_scrape_url_params\"\n", "\n", " self.config = {\n", " \"finance_scrape_url_main\": \"https://query2.finance.yahoo.com/v10/finance/quoteSummary/\",\n", " \"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\"\n", "}\n", "\n", " def ____core_parse_helper(self, ticker):\n", " \"\"\" Scrapes Yahoo Finance to retrieve data about an asset ticker.\n", "\n", " :param ticker: (String) Asset ticker for globally listed companies, as supported by Yahoo Finance\n", " :return: (dict) Scraped data about asset ticker\n", " \"\"\"\n", "\n", " if not isinstance(ticker, str):\n", " raise TypeError(\"ticker parameter is not a String\")\n", "\n", " query_url = self.config[self.SCRAPER_MAIN_URL_TAG] + ticker + self.config[self.SCRAPER_URL_PARAMS_TAG]\n", " summary_json_response = requests.get(query_url)\n", "\n", " final_scraped_information = {}\n", " json_loaded_summary = json.loads(summary_json_response.text)\n", " if json_loaded_summary is None \\\n", " or \"quoteSummary\" not in json_loaded_summary\\\n", " or \"result\" not in json_loaded_summary[\"quoteSummary\"]\\\n", " or len(json_loaded_summary[\"quoteSummary\"][\"result\"]) == 0:\n", " return None\n", "\n", " core = json_loaded_summary[\"quoteSummary\"][\"result\"][0]\n", " processing_sets = [core[factor] for factor in core.keys()]\n", "\n", " if \"calendarEvents\" in core:\n", " if 'earnings' in core[\"calendarEvents\"]:\n", " processing_sets.append(core[\"calendarEvents\"]['earnings'])\n", "\n", " for ps in processing_sets:\n", " for x in list(ps.keys()):\n", " if isinstance(ps[x], dict):\n", " if len(ps[x]) == 0:\n", " ps[x] = None\n", " elif 'raw' in ps[x]:\n", " ps[x] = ps[x]['raw']\n", "\n", " if isinstance(ps[x], list):\n", " ps[x] = [y['fmt'] for y in ps[x] if 'fmt' in y]\n", "\n", " final_scraped_information.update(ps)\n", "\n", " self.memoized_scraped_data[ticker] = (\n", " datetime.datetime.now(),\n", " final_scraped_information\n", " )\n", "\n", " self.info_keys[ticker] = final_scraped_information.keys()\n", "\n", " return final_scraped_information\n", "\n", " def __core_parse(self, ticker):\n", " \"\"\" Wrapper function on top of scraper function to assist with memoization process\n", "\n", " :param ticker: (String) Asset ticker for globally listed companies, as supported by Yahoo Finance\n", " :return: (dict) Scraped data about asset ticker\n", " \"\"\"\n", "\n", " if ticker in self.memoized_scraped_data:\n", " data_tuple = self.memoized_scraped_data[ticker]\n", "\n", " first_time = data_tuple[0]\n", " later_time = datetime.datetime.now()\n", " difference = later_time - first_time\n", " seconds_in_day = 24 * 60 * 60\n", "\n", " if divmod(difference.days * seconds_in_day + difference.seconds, 60)[0] < 15:\n", " thread = threading.Thread(target=self.____core_parse_helper, args=(ticker,))\n", " thread.start()\n", "\n", " return data_tuple[1]\n", "\n", " return self.____core_parse_helper(ticker)\n", "\n", " def get_available_data_tags(self, ticker):\n", " \"\"\" Returns a list of available data for an asset ticker, as found in Yahoo Finance.\n", "\n", " :param ticker: (String) Asset ticker for globally listed companies, as supported by Yahoo Finance\n", " :return: (list) tags available for an asset ticker; Returns None if the information is not available\n", " \"\"\"\n", "\n", " if not isinstance(ticker, str):\n", " raise TypeError(\"ticker parameter is not a String\")\n", "\n", " if ticker not in self.info_keys:\n", " self.get_company_data(ticker)\n", "\n", " return self.info_keys[ticker]\n", "\n", " def get_data_from_tag(self, ticker, tag):\n", " \"\"\" Returns available data for an asset ticker and a provided tag, as found in Yahoo Finance.\n", "\n", " :param ticker: (String) Asset ticker for globally listed companies, as supported by Yahoo Finance\n", " :param tag: (String) Data tag that is to be retrieved from Yahoo Finance. For a list of\n", " available data tags call TickerInfo.get_available_data_tags(tag)\n", " :return: (int or String) data associated with asset ticker and provided tag; Returns None if the information is\n", " not available\n", " \"\"\"\n", "\n", " if not isinstance(ticker, str):\n", " raise TypeError(\"ticker parameter is not a String\")\n", "\n", " if not isinstance(tag, str):\n", " raise TypeError(\"tag parameter is not a String\")\n", "\n", " if ticker not in self.info_keys:\n", " self.get_company_data(ticker)\n", "\n", " # print(\"KYAS:\" , self.memoized_scraped_data[ticker][1])\n", "\n", " return self.memoized_scraped_data[ticker][1][tag] if tag in self.memoized_scraped_data[ticker][1] else None\n", "\n", " def get_company_data(self, ticker):\n", " \"\"\" Returns a dictionary of data associated with the asset ticker, as found in Yahoo Finance. For a list of\n", " available data tags call TickerInfo.get_available_data_tags(tag).\n", "\n", " :param ticker: (String) Asset ticker for globally listed companies, as supported by Yahoo Finance\n", " :return: (dict) data associated with asset ticker; Returns None if the information is not available\n", " \"\"\"\n", "\n", " if not isinstance(ticker, str):\n", " raise TypeError(\"ticker parameter is not a String\")\n", "\n", " core = self.__core_parse(ticker)\n", "\n", " if core is None or len(core) == 0:\n", " return None\n", "\n", " beta = core[\"beta\"] if \"beta\" in core else None\n", " if beta is None:\n", " beta = core[\"beta3Year\"] if \"beta3Year\" in core else None\n", "\n", " del core[\"beta3Year\"]\n", "\n", " core[\"beta\"] = beta\n", "\n", " return core if core is None else core\n", "\n", " def get_industry(self, ticker):\n", " \"\"\" Returns the industry of the company that is represented by the asset ticker. If the ticker is not of a stock\n", " the function will return None\n", "\n", " :param ticker: (String) Asset ticker for globally listed companies, as supported by Yahoo Finance\n", " :return: (String) the industry of the company represented by the asset ticker; Returns None if the information\n", " is not available\n", " \"\"\"\n", "\n", " if not isinstance(ticker, str):\n", " raise TypeError(\"ticker parameter is not a String\")\n", "\n", " core = self.__core_parse(ticker)\n", " return core if core is None else core[\"industry\"]\n", "\n", " def get_sector(self, ticker):\n", " \"\"\" Returns the sector of the company that is represented by the asset ticker. If the ticker is not of a stock,\n", " the function will return None\n", "\n", " :param ticker: (String) Asset ticker for globally listed companies, as supported by Yahoo Finance\n", " :return: (String) the sector of the company represented by the asset ticker; Returns None if the information is\n", " not available\n", " \"\"\"\n", "\n", " if not isinstance(ticker, str):\n", " raise TypeError(\"ticker parameter is not a String\")\n", "\n", " core = self.__core_parse(ticker)\n", " return core if core is None else core[\"sector\"]\n", "\n", " def get_current_price(self, ticker):\n", " \"\"\" Returns the current price of the asset\n", "\n", "\n", " :param ticker: (String) Asset ticker for globally listed companies, as supported by Yahoo Finance\n", " :return: (int) current price; Returns None if the information is not available\n", " \"\"\"\n", "\n", " if not isinstance(ticker, str):\n", " raise TypeError(\"ticker parameter is not a String\")\n", "\n", " core = self.__core_parse(ticker)\n", " return core if core is None else core[\"currentPrice\"]\n", "\n", " def get_ytd(self, ticker):\n", " \"\"\" Returns the year-to-date return of the requested asset\n", "\n", "\n", " :param ticker: (String) Asset ticker for globally listed companies, as supported by Yahoo Finance\n", " :return: (int) year-to-date return; Returns None if the information is not available\n", " \"\"\"\n", "\n", " if not isinstance(ticker, str):\n", " raise TypeError(\"ticker parameter is not a String\")\n", "\n", " core = self.__core_parse(ticker)\n", " print(core)\n", " return core if core is None else core['ytdReturn']\n", "\n", " def get_beta(self, ticker):\n", " \"\"\" Provides the beta coefficient for a given asset ticker. If the asset is a bond, the function returns the\n", " 3-year beta coefficient\n", "\n", "\n", " :param ticker: (String) Asset ticker for globally listed companies, as supported by Yahoo Finance\n", " :return: (int) beta coefficient; Returns None if the information is not available\n", " \"\"\"\n", "\n", " core = self.__core_parse(ticker)\n", "\n", " beta = core[\"beta\"] if \"beta\" in core else None\n", " if beta is None:\n", " beta = core[\"beta3Year\"] if \"beta3Year\" in core else None\n", "\n", " return beta\n", "\n", " def get_purchase_recommendation(self, ticker):\n", " \"\"\" Provides analysts recommendation for purchasing a stock.\n", " 1 – Strong Buy\n", " 2 – Buy\n", " 3 – Hold\n", " 4 – Underperform\n", " 5 – Sell\n", "\n", "\n", " :param ticker: (String) Asset ticker for globally listed companies, as supported by Yahoo Finance\n", " :return: (int) the number representation of stock purchase recommendation; Returns None if the information is\n", " not available\n", " \"\"\"\n", "\n", " if not isinstance(ticker, str):\n", " raise TypeError(\"ticker parameter is not a String\")\n", "\n", " core = self.__core_parse(ticker) \n", " return core if core is None else core[\"recommendationMean\"]" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "colab": {}, "colab_type": "code", "id": "sbNk2b5lV8QE" }, "outputs": [], "source": [ "from datax.tools.finance import TickerInfo" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "uduv-BSTXLet" }, "source": [ "Demo 1: Basic Features" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "colab": {}, "colab_type": "code", "id": "lnySHSNlWCU0" }, "outputs": [], "source": [ "# Setting up the demo\n", "tickerInfo = TickerInfo()\n", "stock_ticker = \"AAPL\" # This is the Apple's Stock Ticker (as listed in NASDAQ)" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 34 }, "colab_type": "code", "id": "BbofTsNIWQhP", "outputId": "65e811cb-bdff-4246-e7ae-3ffbe3cff5e6" }, "outputs": [ { "data": { "text/plain": [ "356.69" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Gets the current stock price of AAPL stock\n", "tickerInfo.get_current_price(stock_ticker)" ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 34 }, "colab_type": "code", "id": "GGOjWZGjWwqF", "outputId": "19d803bb-b42a-4be1-8d04-7d319cf14c33" }, "outputs": [ { "data": { "text/plain": [ "1.170435" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Gets the current beta coefficient of AAPL stock\n", "tickerInfo.get_beta(stock_ticker)" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 34 }, "colab_type": "code", "id": "xLsiSbOpWxCW", "outputId": "35c9e0a8-f03a-474d-ecfe-94a0025de92b" }, "outputs": [ { "data": { "text/plain": [ "2.0" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Gets the current purchase recommednation of AAPL stock\n", "tickerInfo.get_purchase_recommendation(stock_ticker)" ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 34 }, "colab_type": "code", "id": "N0UIWpDSW0eI", "outputId": "6e10620a-67c6-4551-b563-6b06f20e81af" }, "outputs": [ { "data": { "text/plain": [ "'Consumer Electronics'" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Gets the industry of the company Apple\n", "tickerInfo.get_industry(stock_ticker)" ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 34 }, "colab_type": "code", "id": "Mjz_WADuW0hj", "outputId": "762dcb41-2e6b-40b7-8f35-f3b4ab69559e" }, "outputs": [ { "data": { "text/plain": [ "'Technology'" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Gets the sector of the company Apple\n", "tickerInfo.get_sector(stock_ticker)" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "Yqf8uKK3XJ9a" }, "source": [ "Demo 2: Advanced Features" ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 71 }, "colab_type": "code", "id": "Tr8dttUeXTUH", "outputId": "2cc376b8-d894-4109-e328-85930755e61f" }, "outputs": [ { "data": { "text/plain": [ "(115,\n", " 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']))" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Gets all the financial and company-related statistics that are available\n", "len(tickerInfo.get_available_data_tags(stock_ticker)), tickerInfo.get_available_data_tags(stock_ticker)" ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 34 }, "colab_type": "code", "id": "PU2LbuTxYamS", "outputId": "7bcbdbd3-5c84-4e10-a1bb-98fc9c9935b4" }, "outputs": [ { "data": { "text/plain": [ "137000" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Gets the associated information for the selected tag\n", "selected_tag = \"fullTimeEmployees\"\n", "tickerInfo.get_data_from_tag(stock_ticker, selected_tag)" ] }, { "cell_type": "code", "execution_count": 15, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 1000 }, "colab_type": "code", "id": "Z4XsEcVTYrYi", "outputId": "05f3deaa-de4f-48e6-9cf9-53b5c9049415" }, "outputs": [ { "data": { "text/plain": [ "address1 One Apple Park Way\n", "city Cupertino\n", "state CA\n", "zip 95014\n", "country United States\n", "phone 408-996-1010\n", "website http://www.apple.com\n", "industry Consumer Electronics\n", "sector Technology\n", "longBusinessSummary Apple Inc. designs, manufactures, and markets ...\n", "fullTimeEmployees 137000\n", "companyOfficers []\n", "auditRisk 1\n", "boardRisk 1\n", "compensationRisk 3\n", "shareHolderRightsRisk 1\n", "overallRisk 1\n", "governanceEpochDate 1591920000\n", "compensationAsOfEpochDate 1577750400\n", "maxAge 86400\n", "trend []\n", "cashflowStatements []\n", "earningsChart {'quarterly': [{'date': '2Q2019', 'actual': {'...\n", "financialsChart {'yearly': [{'date': 2016, 'revenue': {'raw': ...\n", "financialCurrency USD\n", "earnings {'earningsDate': ['2020-07-28', '2020-08-03'],...\n", "exDividendDate 1588896000\n", "dividendDate 1589414400\n", "history []\n", "priceHint 2\n", " ... \n", "targetMedianPrice 330\n", "recommendationMean 2\n", "recommendationKey buy\n", "numberOfAnalystOpinions 37\n", "totalCash 94051000320\n", "totalCashPerShare 21.699\n", "ebitda 77305004032\n", "totalDebt 118760996864\n", "quickRatio 1.298\n", "currentRatio 1.496\n", "totalRevenue 267980996608\n", "debtToEquity 151.433\n", "revenuePerShare 60.097\n", "returnOnAssets 0.12377\n", "returnOnEquity 0.62094\n", "grossProfits 98392000000\n", "freeCashflow 45040123904\n", "operatingCashflow 75373002752\n", "earningsGrowth 0.037\n", "revenueGrowth 0.005\n", "grossMargins 0.3811\n", "ebitdaMargins 0.28847\n", "operatingMargins 0.24476\n", "earningsDate [2020-07-28, 2020-08-03]\n", "earningsAverage 2\n", "earningsLow 1.55\n", "earningsHigh 2.47\n", "revenueAverage 51498300000\n", "revenueLow 42799000000\n", "revenueHigh 55838000000\n", "Length: 114, dtype: object" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Gets all the information available for AAPL\n", "import pandas as pd\n", "data = tickerInfo.get_company_data(stock_ticker)\n", "\n", "pd.Series(data)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "colab": {}, "colab_type": "code", "id": "t06eEfzDy5ls" }, "outputs": [], "source": [] } ], "metadata": { "colab": { "collapsed_sections": [], "name": "Finance Library.ipynb", "provenance": [] }, "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.6.1" } }, "nbformat": 4, "nbformat_minor": 2 }