text: from datetime import datetime, timedelta
  import re
  
  import pandas as pd
  
  from yahooquery.base import _YahooFinance
  from yahooquery.utils import _convert_to_timestamp, _flatten_list, _history_dataframe
  
  
  class Ticker(_YahooFinance):
      """
      Base class for interacting with Yahoo Finance API
  
      Arguments
      ----------
      symbols: str or list
          Symbol or list collection of symbols
  
      Keyword Arguments
      -----------------
      asynchronous: bool, default False, optional
          Defines whether the requests are made synchronously or asynchronously.
      backoff_factor: float, default 0.3, optional
          A factor, in seconds, to apply between attempts after a second try.
          Done only when there is a failed request and error code is in the
          status_forcelist
      country: str, default 'united states', optional
          This allows you to alter the following query parameters that are
          sent with each request:  lang, region, and corsDomain.
      formatted: bool, default False, optional
          Quantitative values are given as dictionaries with at least two
          keys:  'raw' and 'fmt'.  The 'raw' key expresses value numerically
          and the 'fmt' key expresses the value as a string.  See Notes for more
          detail
      max_workers: int, default 8, optional
          Defines the number of workers used to make asynchronous requests.
          This only matters when asynchronous=True
      proxies: dict, default None, optional
          Allows for the session to use a proxy when making requests
      retry: int, default 5, optional
          Number of times to retry on a failed request
      status_forcelist: list, default [404, 429, 500, 502, 503, 504], optional
          A set of integer HTTP status codes taht we should force a retry on
      timeout: int, default 5, optional
          Stop waiting for a response after a given number of seconds
      user_agent: str, default random.choice, optional
          A browser's user-agent string that is sent with the headers on each
          request
      validate: bool, default False, optional
          Validate existence of symbols during instantiation
      verify: bool or str, default True, optional
          Used to verify SSL certificates for HTTPS requests.  Can either be
          a boolean, in which case it controsl whether we verify the server's
          TLS certificate, or a string in which case it must be a path to a CA
          bundle to use.
  
      Notes
      -----
      When formatted is set to True, all quote_summary modules will return as
      dictionaries.  There are two reasons for this:
  
      1. Quantitative values are expressed as dictionaries.  For example:
  
         "totalPay": {
             "raw": 115554666,
             "fmt": "11.56M",
             "longFmt": "11,555,466"
         }
  
         When formatted is set to False, the _format_data method will return
         the value in the "raw" key.
  
      2. Dates are either expressed as timestamps:
  
         "governanceEpochDate": 1570147200
  
         Or as dictionaries:
  
          "exDividendDate": {
              "raw": 1573084800,
              "fmt": "2019-11-07"
          }
  
          When formatted is set to False, the _format_data method will return the
          date expressed in the format YYYY-MM-DD by either converting from the
          timestamp or retrieving the "fmt" key.
      """
  
      def __init__(self, symbols, **kwargs):
          super(Ticker, self).__init__(**kwargs)
          self.symbols = symbols
          self.invalid_symbols = None
          if kwargs.get("validate"):
              self.validation
  
      def _quote_summary(self, modules):
          kwargs = {}
          params = {"modules": ",".join(modules)}
          if len(modules) == 1:
              kwargs.update({"addl_key": modules[0]})
          data = self._get_data(key="quoteSummary", params=params, **kwargs)
          dates = _flatten_list(
              [self._MODULES_DICT[module]["convert_dates"] for module in modules]
          )
          return data if self.formatted else self._format_data(data, dates)
  
      def _quote_summary_dataframe(self, module, **kwargs):
          data = self._quote_summary([module])
          if not kwargs.get("data_filter"):
              data_filter = self._MODULES_DICT[module]["filter"]
              kwargs.update({"data_filter": data_filter})
          return self._to_dataframe(data, **kwargs)
  
      def _to_dataframe(self, data, **kwargs):
          if not self.formatted:
              dataframes = []
              try:
                  for symbol in self.symbols:
                      final_data = (
                          data[symbol][kwargs.get("data_filter")]
                          if kwargs.get("data_filter")
                          else data[symbol]
                      )
                      if kwargs.get("from_dict"):
                          df = pd.DataFrame(
                              [(k, v) for d in final_data for k, v in d.items()]
                          )
                          df.set_index(0, inplace=True)
                          df.columns = [symbol]
                      else:
                          df = pd.DataFrame(final_data)
                      dataframes.append(df)
                  if kwargs.get("from_dict", False):
                      df = pd.concat(dataframes, axis=1)
                  else:
                      df = pd.concat(
                          dataframes,
                          keys=self.symbols,
                          names=["symbol", "row"],
                          sort=False,
                      )
                  return df
              except TypeError:
                  return data
          else:
              return data
  
      @property
      def all_modules(self):
          """
          Returns all quoteSummary modules, indexed by module title
          for each symbol
  
          Notes
          -----
          Only returns JSON
          """
          return self._quote_summary(
              self._CONFIG["quoteSummary"]["query"]["modules"]["options"]
          )
  
      def get_modules(self, modules):
          """
          Obtain specific quoteSummary modules for given symbol(s)
  
          Parameters
          ----------
          modules: list or str
              Desired modules for retrieval
  
          Notes
          -----
          Only returns JSON
  
          Raises
          ------
          ValueError
              If invalid module is specified
          """
          all_modules = self._CONFIG["quoteSummary"]["query"]["modules"]["options"]
          if not isinstance(modules, list):
              modules = re.findall(r"[a-zA-Z]+", modules)
          if any(elem not in all_modules for elem in modules):
              raise ValueError(
                  """
                  One of {} is not a valid value.  Valid values are {}.
              """.format(
                      ", ".join(modules), ", ".join(all_modules)
                  )
              )
          return self._quote_summary(modules)
  
      @property
      def asset_profile(self):
          """Asset Profile
  
          Geographical and business summary data for given symbol(s).
  
          Returns
          -------
          dict
              assetProfile module data
          """
          return self._quote_summary(["assetProfile"])
  
      @property
      def calendar_events(self):
          """Calendar Events
  
          Earnings and Revenue expectations for upcoming earnings date for given
          symbol(s)
  
          Returns
          -------
          dict
              calendarEvents module data
          """
          return self._quote_summary(["calendarEvents"])
  
      @property
      def earnings(self):
          """Earnings
  
          Historical earnings data for given symbol(s)
  
          Returns
          -------
          dict
              earnings module data
          """
          return self._quote_summary(["earnings"])
  
      @property
      def earnings_trend(self):
          """Earnings Trend
  
          Historical trend data for earnings and revenue estimations for given
          symbol(s)
  
          Returns
          -------
          dict
              earningsTrend module data
          """
          return self._quote_summary(["earningsTrend"])
  
      @property
      def esg_scores(self):
          """ESG Scores
  
          Data related to a given symbol(s) environmental, social, and
          governance metrics
  
          Returns
          -------
          dict
              esgScores module data
          """
          return self._quote_summary(["esgScores"])
  
      @property
      def financial_data(self):
          """Financial Data
  
          Financial KPIs for given symbol(s)
  
          Returns
          -------
          dict
              financialData module data
          """
          return self._quote_summary(["financialData"])
  
      def news(self, count=25, start=None):
          """News articles related to given symbol(s)
  
          Obtain news articles related to a given symbol(s).  Data includes
          the title of the article, summary, url, author_name, publisher
  
          Parameters
          ----------
          count: int
              Desired number of news items to return
          start: str or datetime
              Date to begin retrieving news items.  If date is a str, utilize
              the following format: YYYY-MM-DD.
  
          Notes
          -----
          It's recommended to use only one symbol for this property as the data
          returned does not distinguish between what symbol the news stories
          belong to
  
          Returns
          -------
          dict
          """
          if start:
              start = _convert_to_timestamp(start)
          return self._chunk_symbols(
              "news", params={"count": count, "start": start}, list_result=True
          )
  
      @property
      def index_trend(self):
          """Index Trend
  
          Trend data related given symbol(s) index, specificially PE and PEG
          ratios
  
          Returns
          -------
          dict
              indexTrend module data
          """
          return self._quote_summary(["indexTrend"])
  
      @property
      def industry_trend(self):
          """Industry Trend
  
          Seems to be deprecated
  
          Returns
          -------
          dict
              industryTrend module data
          """
          return self._quote_summary(["industryTrend"])
  
      @property
      def key_stats(self):
          """Key Statistics
  
          KPIs for given symbol(s) (PE, enterprise value, EPS, EBITA, and more)
  
          Returns
          -------
          dict
              defaultKeyStatistics module data
          """
          return self._quote_summary(["defaultKeyStatistics"])
  
      @property
      def major_holders(self):
          """Major Holders
  
          Data showing breakdown of owners of given symbol(s), insiders,
          institutions, etc.
  
          Returns
          -------
          dict
              majorHoldersBreakdown module data
          """
          return self._quote_summary(["majorHoldersBreakdown"])
  
      @property
      def page_views(self):
          """Page Views
  
          Short, Mid, and Long-term trend data regarding a symbol(s) page views
  
          Returns
          -------
          dict
              pageViews module data
          """
          return self._quote_summary(["pageViews"])
  
      @property
      def price(self):
          """Price
  
          Detailed pricing data for given symbol(s), exchange, quote type,
          currency, market cap, pre / post market data, etc.
  
          Returns
          -------
          dict
              price module data
          """
          return self._quote_summary(["price"])
  
      @property
      def quote_type(self):
          """Quote Type
  
          Stock exchange specific data for given symbol(s)
  
          Returns
          -------
          dict
              quoteType module data
          """
          return self._quote_summary(["quoteType"])
  
      @property
      def quotes(self):
          """Quotes
  
          Retrieve quotes for multiple symbols with one call
  
          Notes
          -----
          There will be more than one request if passing in more than 1,500
          symbols.  A 414 error code (URI Too long) will occur otherwise.
  
          Returns
          -------
          dict
          """
          data = self._chunk_symbols("quotes", list_result=True)
          try:
              return {item.pop("symbol"): item for item in data}
          except AttributeError:
              return data
  
      @property
      def recommendations(self):
          """Recommendations
  
          Retrieve the top 5 symbols that are similar to a given symbol
  
          Returns
          -------
          dict
          """
          return self._get_data("recommendations")
  
      @property
      def share_purchase_activity(self):
          """Share Purchase Activity
  
          High-level buy / sell data for given symbol(s) insiders
  
          Returns
          -------
          dict
              netSharePurchaseActivity module data
          """
          return self._quote_summary(["netSharePurchaseActivity"])
  
      @property
      def summary_detail(self):
          """Summary Detail
  
          Contains similar data to price endpoint
  
          Returns
          -------
          dict
              summaryDetail module data
          """
          return self._quote_summary(["summaryDetail"])
  
      @property
      def summary_profile(self):
          """Summary Profile
  
          Data related to given symbol(s) location and business summary
  
          Returns
          -------
          dict
              summaryProfile module data
          """
          return self._quote_summary(["summaryProfile"])
  
      @property
      def technical_insights(self):
          """Technical Insights
  
          Technical trading information as well as company metrics related
          to innovativeness, sustainability, and hiring.  Metrics can also
          be compared against the company's sector
  
          Returns
          -------
          dict
          """
          return self._get_data("insights")
  
      def _financials(
          self, financials_type, frequency=None, premium=False, types=None, trailing=True
      ):
          try:
              time_dict = self.FUNDAMENTALS_TIME_ARGS[frequency[:1].lower()]
              prefix = time_dict["prefix"]
              period_type = time_dict["period_type"]
          except KeyError as e:
              raise (e)
          except TypeError:
              prefix = ""
              period_type = ""
          key = "fundamentals_premium" if premium else "fundamentals"
          types = types or self._CONFIG[key]["query"]["type"]["options"][financials_type]
          if trailing:
              prefixed_types = ["{}{}".format(prefix, t) for t in types] + [
                  "trailing{}".format(t) for t in types
              ]
          else:
              prefixed_types = ["{}{}".format(prefix, t) for t in types]
          data = self._get_data(
              key, {"type": ",".join(prefixed_types)}, **{"list_result": True}
          )
          dataframes = []
          try:
              for k in data.keys():
                  if isinstance(data[k], str) or data[k][0].get("description"):
                      return data
                  dataframes.extend(
                      [
                          self._financials_dataframes(data[k][i], period_type)
                          for i in range(len(data[k]))
                      ]
                  )
          except AttributeError:
              return data
          try:
              df = pd.concat(dataframes, sort=False)
              if prefix:
                  ls = [prefix, "trailing"] if trailing else [prefix]
                  for p in ls:
                      df["dataType"] = df["dataType"].apply(lambda x: str(x).lstrip(p))
                  df["asOfDate"] = pd.to_datetime(df["asOfDate"], format="%Y-%m-%d")
                  df = df.pivot_table(
                      index=["symbol", "asOfDate", "periodType"],
                      columns="dataType",
                      values="reportedValue",
                  )
                  return pd.DataFrame(df.to_records()).set_index("symbol")
              else:
                  df["sourceDate"] = pd.to_datetime(df["sourceDate"], format="%Y-%m-%d")
                  df.rename(columns={"sourceDate": "date"}, inplace=True)
                  df.set_index(["symbol", "date"], inplace=True)
                  return df
          except ValueError:
              return "{} data unavailable for {}".format(
                  financials_type.replace("_", " ").title(), ", ".join(self._symbols)
              )
  
      def _financials_dataframes(self, data, period_type):
          data_type = data["meta"]["type"][0]
          symbol = data["meta"]["symbol"][0]
          try:
              df = pd.DataFrame.from_records(data[data_type])
              if period_type:
                  df["reportedValue"] = df["reportedValue"].apply(
                      lambda x: x.get("raw") if isinstance(x, dict) else x
                  )
                  df["dataType"] = data_type
                  df["symbol"] = symbol
              else:
                  df["symbol"] = symbol
                  df["parentTopics"] = df["parentTopics"].apply(
                      lambda x: x[0].get("topicLabel")
                  )
              return df
          except KeyError:
              # No data is available for that type
              pass
  
      def all_financial_data(self, frequency="a"):
          """
          Retrieve all financial data, including income statement,
          balance sheet, cash flow, and valuation measures.
  
          Notes
          -----
          The trailing twelve month (TTM) data is not available through this
          method
  
          Parameters
          ----------
          frequency: str, default 'a', optional
              Specify either annual or quarterly.  Value should be 'a' or 'q'.
          """
          types = _flatten_list(
              [self.FUNDAMENTALS_OPTIONS[option] for option in self.FUNDAMENTALS_OPTIONS]
          )
          return self._financials("cash_flow", frequency, types=types, trailing=False)
  
      def get_financial_data(self, types, frequency="a", trailing=True):
          """
          Obtain specific data from either cash flow, income statement,
          balance sheet, or valuation measures.
  
          Notes
          -----
          See available options to pass to method through FUNDAMENTALS_OPTIONS
  
          Parameters
          ----------
          types: list or str
              Desired types of data for retrieval
          frequency: str, default 'a', optional
              Specify either annual or quarterly.  Value should be 'a' or 'q'.
          trailing: bool, default True, optional
              Specify whether or not you'd like trailing twelve month (TTM)
              data returned
  
          Raises
          ------
          ValueError
              If invalid type is specified
          """
          if not isinstance(types, list):
              types = re.findall(r"[a-zA-Z]+", types)
          return self._financials("cash_flow", frequency, types=types, trailing=trailing)
  
      @property
      def corporate_events(self):
          return self._financials(
              "cash_flow", frequency=None, types=self.CORPORATE_EVENTS, trailing=False
          )
  
      @property
      def corporate_guidance(self):
          """"""
          return self._financials(
              "cash_flow",
              frequency=None,
              types=["sigdev_corporate_guidance"],
              trailing=False,
          )
  
      @property
      def valuation_measures(self):
          """Valuation Measures
          Retrieves valuation measures for most recent four quarters as well
          as the most recent date
  
          Notes
          -----
          Only quarterly data is available for non-premium subscribers
          """
          return self._financials("valuation", "q")
  
      def balance_sheet(self, frequency="a", trailing=True):
          """Balance Sheet
  
          Retrieves balance sheet data for most recent four quarters or most
          recent four years as well as trailing 12 months.
  
          Parameters
          ----------
          frequency: str, default 'a', optional
              Specify either annual or quarterly balance sheet.  Value should
              be 'a' or 'q'.
          trailing: bool, default True, optional
              Specify whether or not you'd like trailing twelve month (TTM)
              data returned
  
          Returns
          -------
          pandas.DataFrame
          """
          return self._financials("balance_sheet", frequency, trailing=trailing)
  
      def cash_flow(self, frequency="a", trailing=True):
          """Cash Flow
  
          Retrieves cash flow data for most recent four quarters or most
          recent four years as well as the trailing 12 months
  
          Parameters
          ----------
          frequency: str, default 'a', optional
              Specify either annual or quarterly cash flow statement.  Value
              should be 'a' or 'q'.
          trailing: bool, default True, optional
              Specify whether or not you'd like trailing twelve month (TTM)
              data returned
  
          Returns
          -------
          pandas.DataFrame
          """
          return self._financials("cash_flow", frequency, trailing=trailing)
  
      @property
      def company_officers(self):
          """Company Officers
  
          Retrieves top executives for given symbol(s) and their total pay
          package.  Uses the assetProfile module to retrieve data
  
          Returns
          -------
          pandas.DataFrame
              assetProfile module data
          """
          data = self._quote_summary(["assetProfile"])
          return self._to_dataframe(data, data_filter="companyOfficers")
  
      @property
      def earning_history(self):
          """Earning History
  
          Data related to historical earnings (actual vs. estimate) for given
          symbol(s)
  
          Returns
          -------
          pandas.DataFrame
              earningsHistory module data
          """
          return self._quote_summary_dataframe("earningsHistory")
  
      @property
      def fund_ownership(self):
          """Fund Ownership
  
          Data related to top 10 owners of a given symbol(s)
  
          Returns
          -------
          pandas.DataFrame
              fundOwnership module data
          """
          return self._quote_summary_dataframe("fundOwnership")
  
      @property
      def grading_history(self):
          """Grading History
  
          Data related to upgrades / downgrades by companies for a given
          symbol(s)
  
          Returns
          -------
          pandas.DataFrame
              upgradeDowngradeHistory module data
          """
          return self._quote_summary_dataframe("upgradeDowngradeHistory")
  
      def income_statement(self, frequency="a", trailing=True):
          """Income Statement
  
          Retrieves income statement data for most recent four quarters or most
          recent four years as well as trailing 12 months.
  
          Parameters
          ----------
          frequency: str, default 'a', optional
              Specify either annual or quarterly income statement.  Value should
              be 'a' or 'q'.
          trailing: bool, default True, optional
              Specify whether or not you'd like trailing twelve month (TTM)
              data returned
  
          Returns
          -------
          pandas.DataFrame
          """
          return self._financials("income_statement", frequency, trailing=trailing)
  
      @property
      def insider_holders(self):
          """Insider Holders
  
          Data related to stock holdings of a given symbol(s) insiders
  
          Returns
          -------
          pandas.DataFrame
              insiderHolders module data
          """
          return self._quote_summary_dataframe("insiderHolders")
  
      @property
      def insider_transactions(self):
          """Insider Transactions
  
          Data related to transactions by insiders for a given symbol(s)
  
          Returns
          -------
          pandas.DataFrame
              insiderTransactions module data
          """
          return self._quote_summary_dataframe("insiderTransactions")
  
      @property
      def institution_ownership(self):
          """Institution Ownership
  
          Top 10 owners of a given symbol(s)
  
          Returns
          -------
          pandas.DataFrame
              institutionOwnership module data
          """
          return self._quote_summary_dataframe("institutionOwnership")
  
      @property
      def recommendation_trend(self):
          """Recommendation Trend
  
          Data related to historical recommendations (buy, hold, sell) for a
          given symbol(s)
  
          Returns
          -------
          pandas.DataFrame
              recommendationTrend module data
          """
          return self._quote_summary_dataframe("recommendationTrend")
  
      @property
      def sec_filings(self):
          """SEC Filings
  
          Historical SEC filings for a given symbol(s)
  
          Returns
          -------
          pandas.DataFrame
              secFilings endpoint data
          """
          return self._quote_summary_dataframe("secFilings")
  
      # FUND SPECIFIC
  
      def _fund_holdings(self, holding_type):
          data = self.fund_holding_info
          for symbol in self.symbols:
              try:
                  data[symbol] = data[symbol][holding_type]
              except TypeError:
                  pass
          return data
  
      @property
      def fund_bond_holdings(self):
          """Fund Bond Holdings
  
          Retrieves aggregated maturity and duration information for a given
          symbol(s)
  
          .. warning:: This endpoint will only return data for specific
                       securities (funds and etfs)
  
          Returns
          -------
          dict
              topHoldings module data subset
          """
          return self._fund_holdings("bondHoldings")
  
      @property
      def fund_category_holdings(self):
          """Fund Category Holdings
  
          High-level holding breakdown (cash, bonds, equity, etc.) for a given
          symbol(s)
  
          .. warning:: This endpoint will only return data for specific
                       securities (funds and etfs)
  
          Returns
          -------
          pandas.DataFrame
              topHoldings module data subset
          """
          data_dict = self._quote_summary(["topHoldings"])
          for symbol in self.symbols:
              for key in self._FUND_DETAILS:
                  try:
                      del data_dict[symbol][key]
                  except TypeError:
                      return data_dict
          return pd.DataFrame(
              [pd.Series(data_dict[symbol]) for symbol in self.symbols],
              index=self.symbols,
          )
  
      @property
      def fund_equity_holdings(self):
          """Fund Equity Holdings
  
          Retrieves aggregated priceTo____ data for a given symbol(s)
  
          .. warning:: This endpoint will only return data for specific
                       securities (funds and etfs)
  
          Returns
          -------
          dict
              topHoldings module data subset
          """
          return self._fund_holdings("equityHoldings")
  
      @property
      def fund_performance(self):
          """Fund Performance
  
          Historical return data for a given symbol(s) and symbol(s) specific
          category
  
          .. warning:: This endpoint will only return data for specific
                       securities (funds and etfs)
  
          Returns
          -------
          pandas.DataFrame
              fundPerformance module data
          """
          return self._quote_summary(["fundPerformance"])
  
      @property
      def fund_profile(self):
          """Fund Profile
  
          Summary level information for a given symbol(s)
  
          .. warning:: This endpoint will only return data for specific
                       securities (funds and etfs)
  
          Returns
          -------
          pandas.DataFrame
              fundProfile endpoint data
          """
          return self._quote_summary(["fundProfile"])
  
      @property
      def fund_holding_info(self):
          """Fund Holding Information
  
          Contains information for a funds top holdings, bond ratings, bond
          holdings, equity holdings, sector weightings, and category breakdown
  
          .. warning:: This endpoint will only return data for specific
                       securities (funds and etfs)
  
          Returns
          -------
          dict
              topHoldings module data
          """
          return self._quote_summary(["topHoldings"])
  
      @property
      def fund_top_holdings(self):
          """Fund Top Holdings
  
          Retrieves Top 10 holdings for a given symbol(s)
  
          .. warning:: This endpoint will only return data for specific
                       securities (funds and etfs)
  
          Returns
          -------
          pandas.DataFrame
              topHoldings module data subset
          """
          return self._quote_summary_dataframe("topHoldings", data_filter="holdings")
  
      @property
      def fund_bond_ratings(self):
          """Fund Bond Ratings
  
          Retrieves aggregated bond rating data for a given symbol(s)
  
          .. warning:: This endpoint will only return data for specific
                       securities (funds and etfs)
  
          Returns
          -------
          pandas.DataFrame
              topHoldings module data subset
          """
          return self._quote_summary_dataframe(
              "topHoldings", data_filter="bondRatings", from_dict=True
          )
  
      @property
      def fund_sector_weightings(self):
          """Fund Sector Weightings
  
          Retrieves aggregated sector weightings for a given symbol(s)
  
          .. warning:: This endpoint will only return data for specific
                       securities (funds and etfs)
  
          Returns
          -------
          pandas.DataFrame
              topHoldings module data subset
          """
          return self._quote_summary_dataframe(
              "topHoldings", data_filter="sectorWeightings", from_dict=True
          )
  
      # PREMIUM
      def p_all_financial_data(self, frequency="a"):
          """
          Retrieve all financial data, including income statement,
          balance sheet, cash flow, and valuation measures.
  
          Notes
          -----
          The trailing twelve month (TTM) data is not available through this
          method
  
          You must be subscribed to Yahoo Finance Premium and be logged in
          for this method to return any data
  
          Parameters
          ----------
          frequency: str, default 'a', optional
              Specify either annual or quarterly.  Value should be 'a' or 'q'.
          """
          types = _flatten_list(
              [self.FUNDAMENTALS_OPTIONS[option] for option in self.FUNDAMENTALS_OPTIONS]
          )
          return self._financials(
              "cash_flow", frequency, premium=True, types=types, trailing=False
          )
  
      def p_get_financial_data(self, types, frequency="a", trailing=True):
          """
          Obtain specific data from either cash flow, income statement,
          balance sheet, or valuation measures.
  
          Notes
          -----
          See available options to pass to method through FUNDAMENTALS_OPTIONS
  
          You must be subscribed to Yahoo Finance Premium and be logged in
          for this method to return any data
  
          Parameters
          ----------
          types: list or str
              Desired types of data for retrieval
          frequency: str, default 'a', optional
              Specify either annual or quarterly balance sheet.  Value should
              be 'a' or 'q'.
          trailing: bool, default True, optional
              Specify whether or not you'd like trailing twelve month (TTM)
              data returned
          """
          if not isinstance(types, list):
              types = re.findall(r"[a-zA-Z]+", types)
          return self._financials(
              "cash_flow", frequency, True, types=types, trailing=trailing
          )
  
      def p_balance_sheet(self, frequency="a", trailing=True):
          """Balance Sheet
  
          Retrieves balance sheet data for most recent four quarters or most
          recent four years as well as trailing 12 months.
  
          Parameters
          ----------
          frequency: str, default 'A', optional
              Specify either annual or quarterly balance sheet.  Value should
              be 'a' or 'q'.
          trailing: bool, default True, optional
              Specify whether or not you'd like trailing twelve month (TTM)
              data returned
  
          Notes
          -----
          You must be subscribed to Yahoo Finance Premium and be logged in
          for this method to return any data
  
          Returns
          -------
          pandas.DataFrame
          """
          return self._financials(
              "balance_sheet", frequency, premium=True, trailing=trailing
          )
  
      def p_cash_flow(self, frequency="a", trailing=True):
          """Cash Flow
  
          Retrieves cash flow data for most recent four quarters or most
          recent four years as well as the trailing 12 months
  
          Parameters
          ----------
          frequency: str, default 'a', optional
              Specify either annual or quarterly cash flow statement.  Value
              should be 'a' or 'q'.
          trailing: bool, default True, optional
              Specify whether or not you'd like trailing twelve month (TTM)
              data returned
  
          Notes
          -----
          You must be subscribed to Yahoo Finance Premium and be logged in
          for this method to return any data
  
          Returns
          -------
          pandas.DataFrame
          """
          return self._financials("cash_flow", frequency, premium=True, trailing=trailing)
  
      @property
      def p_corporate_events(self):
          return self._financials(
              "cash_flow",
              frequency=None,
              premium=True,
              types=self.CORPORATE_EVENTS,
              trailing=False,
          )
  
      def p_income_statement(self, frequency="a", trailing=True):
          """Income Statement
  
          Retrieves income statement data for most recent four quarters or most
          recent four years as well as trailing 12 months.
  
          Parameters
          ----------
          frequency: str, default 'A', optional
              Specify either annual or quarterly income statement.  Value should
              be 'a' or 'q'.
          trailing: bool, default True, optional
              Specify whether or not you'd like trailing twelve month (TTM)
              data returned
  
          Notes
          -----
          You must be subscribed to Yahoo Finance Premium and be logged in
          for this method to return any data
  
          Returns
          -------
          pandas.DataFrame
          """
          return self._financials(
              "income_statement", frequency, premium=True, trailing=trailing
          )
  
      @property
      def p_company_360(self):
          return self._get_data("company360")
  
      @property
      def p_technical_insights(self):
          return self._get_data("premium_insights")
  
      @property
      def p_portal(self):
          return self._chunk_symbols("premium_portal")
  
      def p_reports(self, report_id):
          return self._get_data("reports", {"reportId": report_id})
  
      def p_ideas(self, idea_id):
          return self._get_data("trade_ideas", {"ideaId": idea_id})
  
      @property
      def p_technical_events(self):
          return self._get_data("technical_events")
  
      def p_valuation_measures(self, frequency="q"):
          """Valuation Measures
          Retrieves valuation measures for all available dates for given
          symbol(s)
          """
          return self._financials("valuation", frequency, premium=True)
  
      @property
      def p_value_analyzer(self):
          return self._chunk_symbols("value_analyzer")
  
      @property
      def p_value_analyzer_drilldown(self):
          return self._get_data("value_analyzer_drilldown")
  
      # HISTORICAL PRICE DATA
      def history(
          self,
          period="ytd",
          interval="1d",
          start=None,
          end=None,
          adj_timezone=True,
          adj_ohlc=False,
      ):
          """
          Historical pricing data
  
          Pulls historical pricing data for a given symbol(s)
  
          Parameters
          ----------
          period: str, default ytd, optional
              Length of time
          interval: str, default 1d, optional
              Time between data points
          start: str or datetime.datetime, default None, optional
              Specify a starting point to pull data from.  Can be expressed as a
              string with the format YYYY-MM-DD or as a datetime object
          end: str of datetime.datetime, default None, optional
              Specify a ending point to pull data from.  Can be expressed as a
              string with the format YYYY-MM-DD or as a datetime object.
          adj_timezone: bool, default True, optional
              Specify whether or not to apply the GMT offset to the timestamp
              received from the API.  If True, the datetimeindex will be adjusted
              to the specified ticker's timezone.
          adj_ohlc: bool, default False, optional
              Calculates an adjusted open, high, low and close prices according
              to split and dividend information
  
          Returns
          -------
          pandas.DataFrame
              historical pricing data
          """
          config = self._CONFIG["chart"]
          intervals = config["query"]["interval"]["options"]
          if start or period is None or period.lower() == "max":
              start = _convert_to_timestamp(start)
              end = _convert_to_timestamp(end, start=False)
              params = {"period1": start, "period2": end}
          else:
              params = {"range": period.lower()}
          if interval not in intervals:
              raise ValueError(
                  "Interval values must be one of {}".format(", ".join(intervals))
              )
          params["interval"] = interval.lower()
          if params["interval"] == "1m" and period == "1mo":
              df = self._history_1m(adj_timezone, adj_ohlc)
          else:
              data = self._get_data("chart", params)
              df = self._historical_data_to_dataframe(data, params, adj_timezone)
          if adj_ohlc and "adjclose" in df:
              df = self._adjust_ohlc(df)
          return df
  
      def _history_1m(self, adj_timezone=True, adj_ohlc=False):
          params = {"interval": "1m"}
          today = datetime.today()
          dates = [
              _convert_to_timestamp((today - timedelta(7 * x)).date()) for x in range(5)
          ]
          dataframes = []
          for i in range(len(dates) - 1):
              params["period1"] = dates[i + 1]
              params["period2"] = dates[i]
              data = self._get_data("chart", params)
              dataframes.append(
                  self._historical_data_to_dataframe(data, params, adj_timezone)
              )
          df = pd.concat(dataframes, sort=True)
          df.sort_values(by=["symbol", "date"], inplace=True)
          df.fillna(value=0, inplace=True)
          return df
  
      def _historical_data_to_dataframe(self, data, params, adj_timezone):
          d = {}
          for symbol in self._symbols:
              if "timestamp" in data[symbol]:
                  d[symbol] = _history_dataframe(data, symbol, params, adj_timezone)
              else:
                  d[symbol] = data[symbol]
          if all(isinstance(d[key], pd.DataFrame) for key in d):
              df = pd.concat(d, names=["symbol", "date"], sort=False)
              if "dividends" in df.columns:
                  df["dividends"].fillna(0, inplace=True)
              if "splits" in df.columns:
                  df["splits"].fillna(0, inplace=True)
              return df
          return d
  
      def _adjust_ohlc(self, df):
          adjust = df["close"] / df["adjclose"]
          for col in ["open", "high", "low"]:
              df[col] = df[col] / adjust
          del df["close"]
          df.rename(columns={"adjclose": "close"}, inplace=True)
          return df
  
      @property
      def option_chain(self):
          data = self._get_data("options", {"getAllData": True})
          dataframes = []
          for symbol in self._symbols:
              try:
                  if data[symbol]["options"]:
                      dataframes.append(
                          self._option_dataframe(data[symbol]["options"], symbol)
                      )
              except TypeError:
                  pass
          if dataframes:
              df = pd.concat(dataframes, sort=False)
              df.set_index(["symbol", "expiration", "optionType"], inplace=True)
              df.rename_axis(["symbol", "expiration", "optionType"], inplace=True)
              df.fillna(0, inplace=True)
              df.sort_index(level=["symbol", "expiration", "optionType"], inplace=True)
              return df
          return "No option chain data found"
  
      def _option_dataframe(self, data, symbol):
          dataframes = []
          for optionType in ["calls", "puts"]:
              df = pd.concat(
                  [pd.DataFrame(data[i][optionType]) for i in range(len(data))],
                  sort=False,
              )
              df["optionType"] = optionType
              dataframes.append(df)
          df = pd.concat(dataframes, sort=False)
          df["symbol"] = symbol
          try:
              df["expiration"] = pd.to_datetime(df["expiration"], unit="s")
              df["lastTradeDate"] = pd.to_datetime(df["lastTradeDate"], unit="s")
          except ValueError:
              df["expiration"] = [d.get("fmt") for d in df["expiration"]]
          except KeyError:
              pass
          return df
  