class_docstr: Provides methods for preprocessing the stock price data
  
  Attributes
  ----------
      use_technical_indicator : boolean
          we technical indicator or not
      tech_indicator_list : list
          a list of technical indicator names (modified from neofinrl_config.py)
      use_turbulence : boolean
          use turbulence index or not
      user_defined_feature:boolean
          use user defined features or not
  
  Methods
  -------
  preprocess_data()
      main method to do the feature engineering
class_docstr_tok: ["Provides","methods","for","preprocessing","the","stock","price","data","Attributes","--","--","--","--","--","use_technical_indicator",":","boolean","we","technical","indicator","or","not","tech_indicator_list",":","list","a","list","of","technical","indicator","names","(","modified","from","neofinrl_config.py",")","use_turbulence",":","boolean","use","turbulence","index","or","not","user_defined_feature",":","boolean","use","user","defined","features","or","not","Methods","--","--","--","-","preprocess_data","(",")","main","method","to","do","the","feature","engineering"]
docstr: calculate turbulence index based on dow 30
docstr_tok: ["calculate","turbulence","index","based","on","dow","30"]
code: def calculate_turbulence(self, data):
      """calculate turbulence index based on dow 30"""
      # can add other market assets
      df = data.copy()
      df_price_pivot = df.pivot(
          index="date", columns="tic", values="close"
      )
      # use returns to calculate turbulence
      df_price_pivot = df_price_pivot.pct_change()
  
      unique_date = df.date.unique()
      # start after a year
      start = 252
      turbulence_index = [0] * start
      # turbulence_index = [0]
      count = 0
      for i in range(start, len(unique_date)):
          current_price = df_price_pivot[
              df_price_pivot.index == unique_date[i]
          ]
          # use one year rolling window to calcualte covariance
          hist_price = df_price_pivot[
              (df_price_pivot.index < unique_date[i])
              & (df_price_pivot.index >= unique_date[i - 252])
          ]
          # Drop tickers which has number missing values more than the "oldest" ticker
          filtered_hist_price = hist_price.iloc[
              hist_price.isna().sum().min() :
          ].dropna(axis=1)
  
          cov_temp = filtered_hist_price.cov()
          current_temp = current_price[
              [x for x in filtered_hist_price]
          ] - np.mean(filtered_hist_price, axis=0)
          # cov_temp = hist_price.cov()
          # current_temp=(current_price - np.mean(hist_price,axis=0))
  
          temp = current_temp.values.dot(np.linalg.pinv(cov_temp)).dot(
              current_temp.values.T
          )
          if temp > 0:
              count += 1
              if count > 2:
                  turbulence_temp = temp[0][0]
              else:
                  # avoid large outlier because of the calculation just begins
                  turbulence_temp = 0
          else:
              turbulence_temp = 0
          turbulence_index.append(turbulence_temp)
      try:
          turbulence_index = pd.DataFrame(
              {
                  "date": df_price_pivot.index,
                  "turbulence": turbulence_index,
              }
          )
      except ValueError:
          raise Exception("Turbulence information could not be added.")
      return turbulence_index
  
imports: from __future__ import annotations
  import datetime
  from multiprocessing.sharedctypes import Value
  import numpy
  import pandas
  from stockstats import StockDataFrame
  from finrl import config
  from finrl.meta.preprocessor.yahoodownloader import YahooDownloader
label_desc: Use image node_id 8 for calling the FeatureEngineer obj's underlying member method code with example usage: obj.calculate_turbulence(data) and returns: turbulence_index