code: def clean_data(self, df):
      df = df[["time", "open", "high", "low", "close", "volume", "tic"]]
      # remove 16:00 data
      tic_list = np.unique(df["tic"].values)
      ary = df.values
      rows_1600 = []
      for i in range(ary.shape[0]):
          row = ary[i]
          time = row[0]
          if str(time)[-8:] == "16:00:00":
              rows_1600.append(i)
  
      df = df.drop(rows_1600)
      df = df.sort_values(by=["tic", "time"])
  
      # check missing rows
      tic_dic = {}
      for tic in tic_list:
          tic_dic[tic] = [0, 0]
      ary = df.values
      for i in range(ary.shape[0]):
          row = ary[i]
          volume = row[5]
          tic = row[6]
          if volume != 0:
              tic_dic[tic][0] += 1
          tic_dic[tic][1] += 1
      constant = np.unique(df["time"].values).shape[0]
      nan_tics = []
      for tic in tic_dic:
          if tic_dic[tic][1] != constant:
              nan_tics.append(tic)
      # fill missing rows
      normal_time = np.unique(df["time"].values)
  
      df2 = df.copy()
      for tic in nan_tics:
          tic_time = df[df["tic"] == tic]["time"].values
          missing_time = []
          for i in normal_time:
              if i not in tic_time:
                  missing_time.append(i)
          for time in missing_time:
              temp_df = pd.DataFrame(
                  [[time, np.nan, np.nan, np.nan, np.nan, 0, tic]],
                  columns=[
                      "time",
                      "open",
                      "high",
                      "low",
                      "close",
                      "volume",
                      "tic",
                  ],
              )
              # df2 = df2.append(temp_df, ignore_index=True)
              df2 = pd.concat([df2, temp_df], axis=0, ignore_index=True)
  
      # fill nan data
      df = df2.sort_values(by=["tic", "time"])
      for i in range(df.shape[0]):
          if float(df.iloc[i]["volume"]) == 0:
              previous_close = df.iloc[i - 1]["close"]
              if str(previous_close) == "nan":
                  raise ValueError("Error nan price")
              df.iloc[i, 1] = previous_close
              df.iloc[i, 2] = previous_close
              df.iloc[i, 3] = previous_close
              df.iloc[i, 4] = previous_close
      # check if nan
      ary = df[["open", "high", "low", "close", "volume"]].values
      assert not np.isnan(np.min(ary))
      # final preprocess
      df = df[["time", "open", "high", "low", "close", "volume", "tic"]]
      df = df.reset_index(drop=True)
      print("Data clean finished")
      return df
  
file_path: FinRL/finrl/meta/data_processors/processor_wrds.py
imports: from __future__ import annotations
  import datetime
  import exchange_calendars
  import numpy
  import pandas
  import pytz
  import wrds
  from stockstats import StockDataFrame
label_desc: Use image node_id 4 for calling the WrdsProcessor obj's underlying member method code with example usage: obj.clean_data(df) and returns: df