code: import requests
  import pandas as pd
  import ftplib
  import io
  import re
  import json
  import datetime
  
  try:
      from requests_html import HTMLSession
  except Exception:
      print("""Warning - Certain functionality 
               requires requests_html, which is not installed.
               
               Install using: 
               pip install requests_html
               
               After installation, you may have to restart your Python session.""")
  
      
  base_url = "https://query1.finance.yahoo.com/v8/finance/chart/"
  
  def build_url(ticker, start_date = None, end_date = None, interval = "1d"):
      
      if end_date is None:  
          end_seconds = int(pd.Timestamp("now").timestamp())
          
      else:
          end_seconds = int(pd.Timestamp(end_date).timestamp())
          
      if start_date is None:
          start_seconds = 7223400    
          
      else:
          start_seconds = int(pd.Timestamp(start_date).timestamp())
      
      site = base_url + ticker
      
      params = {"period1": start_seconds, "period2": end_seconds,
                "interval": interval.lower(), "events": "div,splits"}
      
      
      return site, params
  
  
  def force_float(elt):
      
      try:
          return float(elt)
      except:
          return elt
      
  def _convert_to_numeric(s):
  
      if "M" in s:
          s = s.strip("M")
          return force_float(s) * 1_000_000
      
      if "B" in s:
          s = s.strip("B")
          return force_float(s) * 1_000_000_000
      
      return force_float(s)
  
  
  def get_data(ticker, start_date = None, end_date = None, index_as_date = True,
               interval = "1d", headers = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36'}
  ):
      '''Downloads historical stock price data into a pandas data frame.  Interval
         must be "1d", "1wk", "1mo", or "1m" for daily, weekly, monthly, or minute data.
         Intraday minute data is limited to 7 days.
      
         @param: ticker
         @param: start_date = None
         @param: end_date = None
         @param: index_as_date = True
         @param: interval = "1d"
      '''
      
      if interval not in ("1d", "1wk", "1mo", "1m"):
          raise AssertionError("interval must be of of '1d', '1wk', '1mo', or '1m'")
      
      
      # build and connect to URL
      site, params = build_url(ticker, start_date, end_date, interval)
      resp = requests.get(site, params = params, headers = headers)
      
      
      if not resp.ok:
          raise AssertionError(resp.json())
          
      
      # get JSON response
      data = resp.json()
      
      # get open / high / low / close data
      frame = pd.DataFrame(data["chart"]["result"][0]["indicators"]["quote"][0])
  
      # get the date info
      temp_time = data["chart"]["result"][0]["timestamp"]
  
      if interval != "1m":
      
          # add in adjclose
          frame["adjclose"] = data["chart"]["result"][0]["indicators"]["adjclose"][0]["adjclose"]   
          frame.index = pd.to_datetime(temp_time, unit = "s")
          frame.index = frame.index.map(lambda dt: dt.floor("d"))
          frame = frame[["open", "high", "low", "close", "adjclose", "volume"]]
              
      else:
  
          frame.index = pd.to_datetime(temp_time, unit = "s")
          frame = frame[["open", "high", "low", "close", "volume"]]
          
          
      frame['ticker'] = ticker.upper()
      
      if not index_as_date:  
          frame = frame.reset_index()
          frame.rename(columns = {"index": "date"}, inplace = True)
          
      return frame
  
  
  
  def tickers_sp500(include_company_data = False):
      '''Downloads list of tickers currently listed in the S&P 500 '''
      # get list of all S&P 500 stocks
      sp500 = pd.read_html("https://en.wikipedia.org/wiki/List_of_S%26P_500_companies")[0]
      sp500["Symbol"] = sp500["Symbol"].str.replace(".", "-", regex=True)
  
      if include_company_data:
          return sp500
  
      sp_tickers = sp500.Symbol.tolist()
      sp_tickers = sorted(sp_tickers)
      
      return sp_tickers
  
  
  def tickers_nasdaq(include_company_data = False):
      
      '''Downloads list of tickers currently listed in the NASDAQ'''
      
      ftp = ftplib.FTP("ftp.nasdaqtrader.com")
      ftp.login()
      ftp.cwd("SymbolDirectory")
      
      r = io.BytesIO()
      ftp.retrbinary('RETR nasdaqlisted.txt', r.write)
      
      if include_company_data:
          r.seek(0)
          data = pd.read_csv(r, sep = "|")
          return data
      
      info = r.getvalue().decode()
      splits = info.split("|")
      
      
      tickers = [x for x in splits if "\r\n" in x]
      tickers = [x.split("\r\n")[1] for x in tickers if "NASDAQ" not in x != "\r\n"]
      tickers = [ticker for ticker in tickers if "File" not in ticker]    
      
      ftp.close()    
  
      return tickers
      
      
  
  def tickers_other(include_company_data = False):
      '''Downloads list of tickers currently listed in the "otherlisted.txt"
         file on "ftp.nasdaqtrader.com" '''
      ftp = ftplib.FTP("ftp.nasdaqtrader.com")
      ftp.login()
      ftp.cwd("SymbolDirectory")
      
      r = io.BytesIO()
      ftp.retrbinary('RETR otherlisted.txt', r.write)
      
      if include_company_data:
          r.seek(0)
          data = pd.read_csv(r, sep = "|")
          return data
      
      info = r.getvalue().decode()
      splits = info.split("|")    
      
      tickers = [x for x in splits if "\r\n" in x]
      tickers = [x.split("\r\n")[1] for x in tickers]
      tickers = [ticker for ticker in tickers if "File" not in ticker]        
      
      ftp.close()    
  
      return tickers
      
      
  def tickers_dow(include_company_data = False):
      
      '''Downloads list of currently traded tickers on the Dow'''
  
      site = "https://en.wikipedia.org/wiki/Dow_Jones_Industrial_Average"
      
      table = pd.read_html(site, attrs = {"id":"constituents"})[0]
      
      if include_company_data:
          return table
  
      dow_tickers = sorted(table['Symbol'].tolist())
      
      return dow_tickers    
      
  
  def tickers_ibovespa(include_company_data = False):
      
      '''Downloads list of currently traded tickers on the Ibovespa, Brazil'''
  
      table = pd.read_html("https://pt.wikipedia.org/wiki/Lista_de_companhias_citadas_no_Ibovespa")[0]
      table.columns = ["Symbol", "Share", "Sector", "Type", "Site"]
      
      if include_company_data:
          return table
      
      ibovespa_tickers = sorted(table.Symbol.tolist())
      
      return ibovespa_tickers 
  
  
  
  def tickers_nifty50(include_company_data = False, headers = {'User-agent': 'Mozilla/5.0'}):
  
      '''Downloads list of currently traded tickers on the NIFTY 50, India'''
  
      site = "https://finance.yahoo.com/quote/%5ENSEI/components?p=%5ENSEI"
      table = pd.read_html(requests.get(site, headers=headers).text)[0]
      
      if include_company_data:
          return table
      
      nifty50 = sorted(table['Symbol'].tolist())
  
      return nifty50
  
  def tickers_niftybank():
      ''' Currently traded tickers on the NIFTY BANK, India '''
      
      niftybank = ['AXISBANK', 'KOTAKBANK', 'HDFCBANK', 'SBIN', 'BANKBARODA', 'INDUSINDBK', 'PNB', 'IDFCFIRSTB', 'ICICIBANK', 'RBLBANK', 'FEDERALBNK', 'BANDHANBNK']
      
      return niftybank
  
  
  
  def tickers_ftse100(include_company_data = False):
      
      '''Downloads a list of the tickers traded on the FTSE 100 index'''
      
      table = pd.read_html("https://en.wikipedia.org/wiki/FTSE_100_Index", attrs = {"id": "constituents"})[0]
      
      if include_company_data:
          return table
      
      return sorted(table.EPIC.tolist())
      
  
  def tickers_ftse250(include_company_data = False):
      
      
      '''Downloads a list of the tickers traded on the FTSE 250 index'''
      
      table = pd.read_html("https://en.wikipedia.org/wiki/FTSE_250_Index", attrs = {"id": "constituents"})[0]
      
      table.columns = ["Company", "Ticker"]
      
      if include_company_data:
          return table
      
      return sorted(table.Ticker.tolist())
      
  
  
  
  def get_quote_table(ticker , dict_result = True, headers = {'User-agent': 'Mozilla/5.0'}): 
      
      '''Scrapes data elements found on Yahoo Finance's quote page 
         of input ticker
      
         @param: ticker
         @param: dict_result = True
      '''
  
      site = "https://finance.yahoo.com/quote/" + ticker + "?p=" + ticker
      
      tables = pd.read_html(requests.get(site, headers=headers).text)
      
      data = tables[0].append(tables[1])
  
      data.columns = ["attribute" , "value"]
      
      quote_price = pd.DataFrame(["Quote Price", get_live_price(ticker)]).transpose()
      quote_price.columns = data.columns.copy()
      
      data = data.append(quote_price)
      
      data = data.sort_values("attribute")
      
      data = data.drop_duplicates().reset_index(drop = True)
      
      data["value"] = data.value.map(force_float)
  
      if dict_result:
          
          result = {key : val for key,val in zip(data.attribute , data.value)}
          return result
          
      return data    
      
      
  def get_stats(ticker, headers = {'User-agent': 'Mozilla/5.0'}):
      
      '''Scrapes information from the statistics tab on Yahoo Finance 
         for an input ticker 
      
         @param: ticker
      '''
  
      stats_site = "https://finance.yahoo.com/quote/" + ticker + \
                   "/key-statistics?p=" + ticker
      
  
      tables = pd.read_html(requests.get(stats_site, headers=headers).text)
      
      tables = [table for table in tables[1:] if table.shape[1] == 2]
      
      table = tables[0]
      for elt in tables[1:]:
          table = table.append(elt)
  
      table.columns = ["Attribute" , "Value"]
      
      table = table.reset_index(drop = True)
      
      return table
  
  
  def get_stats_valuation(ticker, headers = {'User-agent': 'Mozilla/5.0'}):
      
      '''Scrapes Valuation Measures table from the statistics tab on Yahoo Finance 
         for an input ticker 
      
         @param: ticker
      '''
  
      stats_site = "https://finance.yahoo.com/quote/" + ticker + \
                   "/key-statistics?p=" + ticker
      
      
      tables = pd.read_html(requests.get(stats_site, headers=headers).text)
      
      tables = [table for table in tables if "Trailing P/E" in table.iloc[:,0].tolist()]
      
      
      table = tables[0].reset_index(drop = True)
      
      return table
  
  
  
  
  
  def _parse_json(url, headers = {'User-agent': 'Mozilla/5.0'}):
      html = requests.get(url=url, headers = headers).text
  
      json_str = html.split('root.App.main =')[1].split(
          '(this)')[0].split(';\n}')[0].strip()
      
      try:
          data = json.loads(json_str)[
              'context']['dispatcher']['stores']['QuoteSummaryStore']
      except:
          return '{}'
      else:
          # return data
          new_data = json.dumps(data).replace('{}', 'null')
          new_data = re.sub(r'\{[\'|\"]raw[\'|\"]:(.*?),(.*?)\}', r'\1', new_data)
  
          json_info = json.loads(new_data)
  
          return json_info
  
  
  def _parse_table(json_info):
  
      df = pd.DataFrame(json_info)
      
      if df.empty:
          return df
      
      del df["maxAge"]
  
      df.set_index("endDate", inplace=True)
      df.index = pd.to_datetime(df.index, unit="s")
   
      df = df.transpose()
      df.index.name = "Breakdown"
  
      return df
  
  
  def get_income_statement(ticker, yearly = True):
      
      '''Scrape income statement from Yahoo Finance for a given ticker
      
         @param: ticker
      '''
      
      income_site = "https://finance.yahoo.com/quote/" + ticker + \
              "/financials?p=" + ticker
  
      json_info = _parse_json(income_site)
      
      if yearly:
          temp = json_info["incomeStatementHistory"]["incomeStatementHistory"]
      else:
          temp = json_info["incomeStatementHistoryQuarterly"]["incomeStatementHistory"]
      
      return _parse_table(temp)      
          
  
  def get_balance_sheet(ticker, yearly = True):
      
      '''Scrapes balance sheet from Yahoo Finance for an input ticker 
      
         @param: ticker
      '''    
      
      balance_sheet_site = "https://finance.yahoo.com/quote/" + ticker + \
                           "/balance-sheet?p=" + ticker
      
  
      json_info = _parse_json(balance_sheet_site)
      
      try:
          if yearly:
              temp = json_info["balanceSheetHistory"]["balanceSheetStatements"]
          else:
              temp = json_info["balanceSheetHistoryQuarterly"]["balanceSheetStatements"]
      except:
          temp = []
          
      return _parse_table(temp)      
  
  
  def get_cash_flow(ticker, yearly = True):
      
      '''Scrapes the cash flow statement from Yahoo Finance for an input ticker 
      
         @param: ticker
      '''
      
      cash_flow_site = "https://finance.yahoo.com/quote/" + \
              ticker + "/cash-flow?p=" + ticker
      
      
      json_info = _parse_json(cash_flow_site)
      
      if yearly:
          temp = json_info["cashflowStatementHistory"]["cashflowStatements"]
      else:
          temp = json_info["cashflowStatementHistoryQuarterly"]["cashflowStatements"]
          
      return _parse_table(temp)      
  
  
  def get_financials(ticker, yearly = True, quarterly = True):
  
      '''Scrapes financials data from Yahoo Finance for an input ticker, including
         balance sheet, cash flow statement, and income statement.  Returns dictionary
         of results.
      
         @param: ticker
         @param: yearly = True
         @param: quarterly = True
      '''
  
      if not yearly and not quarterly:
          raise AssertionError("yearly or quarterly must be True")
      
      financials_site = "https://finance.yahoo.com/quote/" + ticker + \
              "/financials?p=" + ticker
              
      json_info = _parse_json(financials_site)
      
      result = {}
      
      if yearly:
  
          temp = json_info["incomeStatementHistory"]["incomeStatementHistory"]
          table = _parse_table(temp)
          result["yearly_income_statement"] = table
      
          temp = json_info["balanceSheetHistory"]["balanceSheetStatements"]
          table = _parse_table(temp)
          result["yearly_balance_sheet"] = table
          
          temp = json_info["cashflowStatementHistory"]["cashflowStatements"]
          table = _parse_table(temp)
          result["yearly_cash_flow"] = table
  
      if quarterly:
          temp = json_info["incomeStatementHistoryQuarterly"]["incomeStatementHistory"]
          table = _parse_table(temp)
          result["quarterly_income_statement"] = table
      
          temp = json_info["balanceSheetHistoryQuarterly"]["balanceSheetStatements"]
          table = _parse_table(temp)
          result["quarterly_balance_sheet"] = table
          
          temp = json_info["cashflowStatementHistoryQuarterly"]["cashflowStatements"]
          table = _parse_table(temp)
          result["quarterly_cash_flow"] = table
  
          
      return result
  
  
  def get_holders(ticker, headers = {'User-agent': 'Mozilla/5.0'}):
      
      '''Scrapes the Holders page from Yahoo Finance for an input ticker 
      
         @param: ticker
      '''    
      
      holders_site = "https://finance.yahoo.com/quote/" + \
                      ticker + "/holders?p=" + ticker
      
          
      tables = pd.read_html(requests.get(holders_site, headers=headers).text)
      
         
      table_names = ["Major Holders" , "Direct Holders (Forms 3 and 4)" ,
                     "Top Institutional Holders" , "Top Mutual Fund Holders"]
       
      
      table_mapper = {key : val for key,val in zip(table_names , tables)}
                     
                     
      return table_mapper       
  
  def get_analysts_info(ticker, headers = {'User-agent': 'Mozilla/5.0'}):
      
      '''Scrapes the Analysts page from Yahoo Finance for an input ticker 
      
         @param: ticker
      '''    
      
      
      analysts_site = "https://finance.yahoo.com/quote/" + ticker + \
                       "/analysts?p=" + ticker
      
      tables = pd.read_html(requests.get(analysts_site, headers=headers).text)
      
      table_names = [table.columns[0] for table in tables]
  
      table_mapper = {key : val for key , val in zip(table_names , tables)}
      
  
      return table_mapper
          
  
  def get_live_price(ticker):
      
      '''Gets the live price of input ticker
      
         @param: ticker
      '''    
      
      df = get_data(ticker, end_date = pd.Timestamp.today() + pd.DateOffset(10))
      
      
      return df.close[-1]
      
      
  def _raw_get_daily_info(site):
         
      session = HTMLSession()
      
      resp = session.get(site)
      
      tables = pd.read_html(resp.html.raw_html)  
      
      df = tables[0].copy()
      
      df.columns = tables[0].columns
      
      del df["52 Week Range"]
      
      df["% Change"] = df["% Change"].map(lambda x: float(x.strip("%+").replace(",", "")))
       
  
      fields_to_change = [x for x in df.columns.tolist() if "Vol" in x \
                          or x == "Market Cap"]
      
      for field in fields_to_change:
          
          if type(df[field][0]) == str:
              df[field] = df[field].map(_convert_to_numeric)
              
      session.close()
      
      return df
      
  
  def get_day_most_active(count: int = 100):
  
      return _raw_get_daily_info(f"https://finance.yahoo.com/most-active?offset=0&count={count}")
  
  
  def get_day_gainers(count: int = 100):
  
      return _raw_get_daily_info(f"https://finance.yahoo.com/gainers?offset=0&count={count}")
  
  
  def get_day_losers(count: int = 100):
  
      return _raw_get_daily_info(f"https://finance.yahoo.com/losers?offset=0&count={count}")
  
  
  def get_top_crypto():
      
      '''Gets the top 100 Cryptocurrencies by Market Cap'''      
  
      session = HTMLSession()
      
      resp = session.get("https://finance.yahoo.com/cryptocurrencies?offset=0&count=100")
      
      tables = pd.read_html(resp.html.raw_html)               
                      
      df = tables[0].copy()
  
      
      df["% Change"] = df["% Change"].map(lambda x: float(str(x).strip("%").\
                                                                 strip("+").\
                                                                 replace(",", "")))
      del df["52 Week Range"]
      del df["1 Day Chart"]
      
      fields_to_change = [x for x in df.columns.tolist() if "Volume" in x \
                          or x == "Market Cap" or x == "Circulating Supply"]
      
      for field in fields_to_change:
          
          if type(df[field][0]) == str:
              df[field] = df[field].map(lambda x: _convert_to_numeric(str(x)))
              
              
      session.close()        
                  
      return df
                      
          
  def get_dividends(ticker, start_date = None, end_date = None, index_as_date = True, 
                    headers = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36'}
  ):
      '''Downloads historical dividend data into a pandas data frame.
      
         @param: ticker
         @param: start_date = None
         @param: end_date = None
         @param: index_as_date = True
      '''
      
      # build and connect to URL
      site, params = build_url(ticker, start_date, end_date, "1d")
      resp = requests.get(site, params = params, headers = headers)
      
      
      if not resp.ok:
          return pd.DataFrame()
          
      
      # get JSON response
      data = resp.json()
      
      # check if there is data available for dividends
      if "events" not in data["chart"]["result"][0] or "dividends" not in data["chart"]["result"][0]['events']:
          return pd.DataFrame()
      
      # get the dividend data
      frame = pd.DataFrame(data["chart"]["result"][0]['events']['dividends'])
      
      frame = frame.transpose()
          
      frame.index = pd.to_datetime(frame.index, unit = "s")
      frame.index = frame.index.map(lambda dt: dt.floor("d"))
      
      # sort in chronological order
      frame = frame.sort_index()
          
      frame['ticker'] = ticker.upper()
      
      # remove old date column
      frame = frame.drop(columns='date')
      
      frame = frame.rename({'amount': 'dividend'}, axis = 'columns')
      
      if not index_as_date:  
          frame = frame.reset_index()
          frame.rename(columns = {"index": "date"}, inplace = True)
          
      return frame
  
  
  
  def get_splits(ticker, start_date = None, end_date = None, index_as_date = True,
                 headers = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36'}
  ):
      '''Downloads historical stock split data into a pandas data frame.
      
         @param: ticker
         @param: start_date = None
         @param: end_date = None
         @param: index_as_date = True
      '''
      
      # build and connect to URL
      site, params = build_url(ticker, start_date, end_date, "1d")
      resp = requests.get(site, params = params, headers = headers)
      
      
      if not resp.ok:
          raise AssertionError(resp.json())
          
      
      # get JSON response
      data = resp.json()
      
      # check if there is data available for events
      if "events" not in data["chart"]["result"][0]:
          raise AssertionError("There is no data available on stock events, or none have occured") 
  
      # check if there is data available for splits
      if "splits" not in data["chart"]["result"][0]['events']:
          raise AssertionError("There is no data available on stock splits, or none have occured")
      
      # get the split data
      frame = pd.DataFrame(data["chart"]["result"][0]['events']['splits'])
      
      frame = frame.transpose()
          
      frame.index = pd.to_datetime(frame.index, unit = "s")
      frame.index = frame.index.map(lambda dt: dt.floor("d"))
      
      # sort in to chronological order
      frame = frame.sort_index()
          
      frame['ticker'] = ticker.upper()
      
      # remove unnecessary columns
      frame = frame.drop(columns=['date', 'denominator', 'numerator'])
      
      if not index_as_date:  
          frame = frame.reset_index()
          frame.rename(columns = {"index": "date"}, inplace = True)
          
      return frame
          
          
  
  
  def get_earnings(ticker):
      
      '''Scrapes earnings data from Yahoo Finance for an input ticker 
      
         @param: ticker
      '''
  
      result = {
          "quarterly_results": pd.DataFrame(),
          "yearly_revenue_earnings": pd.DataFrame(),
          "quarterly_revenue_earnings": pd.DataFrame()
      }
  
      financials_site = "https://finance.yahoo.com/quote/" + ticker + \
          "/financials?p=" + ticker
  
      json_info = _parse_json(financials_site)
  
      if "earnings" not in json_info:
          return result
  
      temp = json_info["earnings"]
  
      if temp == None:
          return result
      
      result["quarterly_results"] = pd.DataFrame.from_dict(temp["earningsChart"]["quarterly"])
      
      result["yearly_revenue_earnings"] = pd.DataFrame.from_dict(temp["financialsChart"]["yearly"])
      
      result["quarterly_revenue_earnings"] = pd.DataFrame.from_dict(temp["financialsChart"]["quarterly"])
      
      return result
  
  
  
  ### Earnings functions
  def _parse_earnings_json(url, headers = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36'}
  ):
          resp = requests.get(url, headers = headers)
          
          content = resp.content.decode(encoding='utf-8', errors='strict')
          
          page_data = [row for row in content.split(
              '\n') if row.startswith('root.App.main = ')][0][:-1]
          
          page_data = page_data.split('root.App.main = ', 1)[1]
          
          return json.loads(page_data)
  
  def get_next_earnings_date(ticker):
          
      base_earnings_url = 'https://finance.yahoo.com/quote'
      new_url = base_earnings_url + "/" + ticker
  
      parsed_result = _parse_earnings_json(new_url)
      
      temp = parsed_result['context']['dispatcher']['stores']['QuoteSummaryStore']['calendarEvents']['earnings']['earningsDate'][0]['raw']
  
      return datetime.datetime.fromtimestamp(temp)
  
  
  def get_earnings_history(ticker):
      
          '''Inputs: @ticker
             Returns the earnings calendar history of the input ticker with 
             EPS actual vs. expected data.'''
  
          url = 'https://finance.yahoo.com/calendar/earnings?symbol=' + ticker
           
          result = _parse_earnings_json(url)
          
          return result["context"]["dispatcher"]["stores"]["ScreenerResultsStore"]["results"]["rows"]
  
  
  
  def get_earnings_for_date(date, offset = 0, count = 1):
  
      '''Inputs: @date
         Returns a dictionary of stock tickers with earnings expected on the
         input date.  The dictionary contains the expected EPS values for each
         stock if available.'''
      
      base_earnings_url = 'https://finance.yahoo.com/calendar/earnings'
      
      if offset >= count:
          return []
      
      temp = pd.Timestamp(date)
      date = temp.strftime("%Y-%m-%d")
  
      dated_url = '{0}?day={1}&offset={2}&size={3}'.format(
          base_earnings_url, date, offset, 100)
      
      result = _parse_earnings_json(dated_url)
      
      stores = result['context']['dispatcher']['stores']
      
      earnings_count = stores['ScreenerCriteriaStore']['meta']['total']
  
      new_offset = offset + 100
      
      more_earnings = get_earnings_for_date(date, new_offset, earnings_count)
      
      current_earnings = stores['ScreenerResultsStore']['results']['rows']
  
      total_earnings = current_earnings + more_earnings
  
      return total_earnings
  
  
  def get_earnings_in_date_range(start_date, end_date):
  
          '''Inputs: @start_date
                     @end_date
                     
             Returns the stock tickers with expected EPS data for all dates in the
             input range (inclusive of the start_date and end_date.'''
      
          earnings_data = []
  
          days_diff = pd.Timestamp(end_date) - pd.Timestamp(start_date)
          days_diff = days_diff.days
  
          
          current_date = pd.Timestamp(start_date)
          
          dates = [current_date + datetime.timedelta(diff) for diff in range(days_diff + 1)]
          dates = [d.strftime("%Y-%m-%d") for d in dates]
   
          i = 0
          while i < len(dates):
              try:
                  earnings_data += get_earnings_for_date(dates[i])
              except Exception:
                  pass
              
              i += 1
              
          return earnings_data
  
  
  def get_currencies(headers = {'User-agent': 'Mozilla/5.0'}):
      
      '''Returns the currencies table from Yahoo Finance'''
      
      site = "https://finance.yahoo.com/currencies"
      tables = pd.read_html(requests.get(site, headers=headers).text)
      
      result = tables[0]
      
      return result
  
  
  def get_futures(headers = {'User-agent': 'Mozilla/5.0'}):
      
      '''Returns the futures table from Yahoo Finance'''
      
      site = "https://finance.yahoo.com/commodities"
      tables = pd.read_html(requests.get(site, headers=headers).text)
      
      result = tables[0]
      
      return result
  
  
  def get_undervalued_large_caps(headers = {'User-agent': 'Mozilla/5.0'}):
      
      '''Returns the undervalued large caps table from Yahoo Finance'''
      
      site = "https://finance.yahoo.com/screener/predefined/undervalued_large_caps?offset=0&count=100"
      
      tables = pd.read_html(requests.get(site, headers=headers).text)
      
      result = tables[0]
      
      return result
  
  
  def get_quote_data(ticker, headers = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36'}
  ):
      
      '''Inputs: @ticker
      
         Returns a dictionary containing over 70 elements corresponding to the 
         input ticker, including company name, book value, moving average data,
         pre-market / post-market price (when applicable), and more.'''
      
      site = "https://query1.finance.yahoo.com/v7/finance/quote?symbols=" + ticker
      
      resp = requests.get(site, headers = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36'}
  )
      
      if not resp.ok:
          raise AssertionError("""Invalid response from server.  Check if ticker is
                                valid.""")
      
      
      json_result = resp.json()
      info = json_result["quoteResponse"]["result"]
      
      return info[0]
      
  
  def get_market_status():
      
      '''Returns the current state of the market - PRE, POST, OPEN, or CLOSED'''
      
      quote_data = get_quote_data("^dji")
  
      return quote_data["marketState"]
  
  def get_premarket_price(ticker):
  
      '''Inputs: @ticker
      
         Returns the current pre-market price of the input ticker
         (returns value if pre-market price is available.'''
      
      quote_data = get_quote_data(ticker)
      
      if "preMarketPrice" in quote_data:
          return quote_data["preMarketPrice"]
          
      raise AssertionError("Premarket price not currently available.")
  
  def get_postmarket_price(ticker):
  
      '''Inputs: @ticker
      
         Returns the current post-market price of the input ticker
         (returns value if pre-market price is available.'''
      
      quote_data = get_quote_data(ticker)
      
      if "postMarketPrice" in quote_data:
          return quote_data["postMarketPrice"]
      
      raise AssertionError("Postmarket price not currently available.")
      
  
  # Company Information Functions
  def get_company_info(ticker):
      '''Scrape the company information for a ticker
  
         @param: ticker
      '''
      site = f"https://finance.yahoo.com/quote/{ticker}/profile?p={ticker}"
      json_info = _parse_json(site)
      json_info = json_info["assetProfile"]
      info_frame = pd.DataFrame.from_dict(json_info,
                                          orient="index",
                                          columns=["Value"])
      info_frame = info_frame.drop("companyOfficers", axis="index")
      info_frame.index.name = "Breakdown"
      return info_frame
  
  
  def get_company_officers(ticker):
      '''Scrape the company information and return a table of the officers
  
         @param: ticker
      '''
      site = f"https://finance.yahoo.com/quote/{ticker}/profile?p={ticker}"
      json_info = _parse_json(site)
      json_info = json_info["assetProfile"]["companyOfficers"]
      info_frame = pd.DataFrame.from_dict(json_info)
      info_frame = info_frame.set_index("name")
      return info_frame
  
apis: pandas.read_csv pandas.DataFrame pandas.read_html pandas.Timestamp.today pandas.to_datetime pandas.DateOffset pandas.Timestamp pandas.DataFrame.from_dict