code: def add_technical_indicators(
      self,
      df,
      pair_list,
      tech_indicator_list=[
          "macd",
          "boll_ub",
          "boll_lb",
          "rsi_30",
          "dx_30",
          "close_30_sma",
          "close_60_sma",
      ],
  ):
      df = df.dropna()
      df = df.copy()
      column_list = [
          pair_list,
          ["open", "high", "low", "close", "volume"]
          + (tech_indicator_list),
      ]
      column = pd.MultiIndex.from_product(column_list)
      index_list = df.index
      dataset = pd.DataFrame(columns=column, index=index_list)
      for pair in pair_list:
          pair_column = pd.MultiIndex.from_product(
              [[pair], ["open", "high", "low", "close", "volume"]]
          )
          dataset[pair_column] = df[pair]
          temp_df = df[pair].reset_index().sort_values(by=["index"])
          temp_df = temp_df.rename(columns={"index": "date"})
          crypto_df = Sdf.retype(temp_df.copy())
          for indicator in tech_indicator_list:
              temp_indicator = crypto_df[indicator].values.tolist()
              dataset[(pair, indicator)] = temp_indicator
      print("Succesfully add technical indicators")
      return dataset
  
file_path: FinRL/finrl/meta/data_processors/processor_ccxt.py
imports: from __future__ import annotations
  import calendar
  from datetime import datetime
  import ccxt
  import numpy
  import pandas
  from stockstats import StockDataFrame
label_desc: Use image node_id 3 for calling the CCXTEngineer obj's underlying member method code with example usage: obj.add_technical_indicators(df, pair_list, tech_indicator_list) and returns: dataset