class_docstr: Dataset-Based Updater
  
  - Providing updating feature for Updating data based on Qlib Dataset
  
  Assumption
  
  - Based on Qlib dataset
  - The data to be updated is a multi-level index pd.DataFrame. For example label, prediction.
  
      .. code-block::
  
                                   LABEL0
          datetime   instrument
          2021-05-10 SH600000    0.006965
                     SH600004    0.003407
          ...                         ...
          2021-05-28 SZ300498    0.015748
                     SZ300676   -0.001321
class_docstr_tok: ["Dataset-Based","Updater","-","Providing","updating","feature","for","Updating","data","based","on","Qlib","Dataset","Assumption","-","Based","on","Qlib","dataset","-","The","data","to","be","updated","is","a","multi-level","index","pd.DataFrame",".","For","example","label",",","prediction",".","..","code-block",":",":","LABEL0","datetime","instrument","2021-05-10","SH600000","0.006965","SH600004","0.003407","...","...","2021-05-28","SZ300498","0.015748","SZ300676","-0.001321"]
docstr: Init PredUpdater.
  
  Expected behavior in following cases:
  
  - if `to_date` is greater than the max date in the calendar, the data will be updated to the latest date
  - if there are data before `from_date` or after `to_date`, only the data between `from_date` and `to_date` are affected.
  
  Args:
      record : Recorder
      to_date :
          update to prediction to the `to_date`
  
          if to_date is None:
  
              data will updated to the latest date.
      from_date :
          the update will start from `from_date`
  
          if from_date is None:
  
              the updating will occur on the next tick after the latest data in historical data
      hist_ref : int
          Sometimes, the dataset will have historical depends.
          Leave the problem to users to set the length of historical dependency
          If user doesn't specify this parameter, Updater will try to load dataset to automatically determine the hist_ref
  
          .. note::
  
              the start_time is not included in the `hist_ref`; So the `hist_ref` will be `step_len - 1` in most cases
  
      loader_cls : type
          the class to load the model and dataset
docstr_tok: ["Init","PredUpdater",".","Expected","behavior","in","following","cases",":","-","if","`","to_date","`","is","greater","than","the","max","date","in","the","calendar",",","the","data","will","be","updated","to","the","latest","date","-","if","there","are","data","before","`","from_date","`","or","after","`","to_date","`",",","only","the","data","between","`","from_date","`","and","`","to_date","`","are","affected",".","Args",":","record",":","Recorder","to_date",":","update","to","prediction","to","the","`","to_date","`","if","to_date","is","None",":","data","will","updated","to","the","latest","date",".","from_date",":","the","update","will","start","from","`","from_date","`","if","from_date","is","None",":","the","updating","will","occur","on","the","next","tick","after","the","latest","data","in","historical","data","hist_ref",":","int","Sometimes",",","the","dataset","will","have","historical","depends",".","Leave","the","problem","to","users","to","set","the","length","of","historical","dependency","If","user","does","n't","specify","this","parameter",",","Updater","will","try","to","load","dataset","to","automatically","determine","the","hist_ref","..","note",":",":","the","start_time","is","not","included","in","the","`","hist_ref","`",";","So","the","`","hist_ref","`","will","be","`","step_len","-","1","`","in","most","cases","loader_cls",":","type","the","class","to","load","the","model","and","dataset"]
code: def __init__(
      self,
      record: Recorder,
      to_date=None,
      from_date=None,
      hist_ref: Optional[int] = None,
      freq="day",
      fname="pred.pkl",
      loader_cls: type = RMDLoader,
  ):
      """
      Init PredUpdater.
  
      Expected behavior in following cases:
  
      - if `to_date` is greater than the max date in the calendar, the data will be updated to the latest date
      - if there are data before `from_date` or after `to_date`, only the data between `from_date` and `to_date` are affected.
  
      Args:
          record : Recorder
          to_date :
              update to prediction to the `to_date`
  
              if to_date is None:
  
                  data will updated to the latest date.
          from_date :
              the update will start from `from_date`
  
              if from_date is None:
  
                  the updating will occur on the next tick after the latest data in historical data
          hist_ref : int
              Sometimes, the dataset will have historical depends.
              Leave the problem to users to set the length of historical dependency
              If user doesn't specify this parameter, Updater will try to load dataset to automatically determine the hist_ref
  
              .. note::
  
                  the start_time is not included in the `hist_ref`; So the `hist_ref` will be `step_len - 1` in most cases
  
          loader_cls : type
              the class to load the model and dataset
  
      """
      # TODO: automate this hist_ref in the future.
      super().__init__(record=record)
  
      self.to_date = to_date
      self.hist_ref = hist_ref
      self.freq = freq
      self.fname = fname
      self.rmdl = loader_cls(rec=record)
  
      latest_date = D.calendar(freq=freq)[-1]
      if to_date is None:
          to_date = latest_date
      to_date = pd.Timestamp(to_date)
  
      if to_date >= latest_date:
          self.logger.warning(
              f"The given `to_date`({to_date}) is later than `latest_date`({latest_date}). So `to_date` is clipped to `latest_date`."
          )
          to_date = latest_date
      self.to_date = to_date
  
      # FIXME: it will raise error when running routine with delay trainer
      # should we use another prediction updater for delay trainer?
      self.old_data: pd.DataFrame = record.load_object(fname)
      if from_date is None:
          # dropna is for being compatible to some data with future information(e.g. label)
          # The recent label data should be updated together
          self.last_end = (
              self.old_data.dropna()
              .index.get_level_values("datetime")
              .max()
          )
      else:
          self.last_end = get_date_by_shift(
              from_date, -1, align="right"
          )
  
imports: from abc import ABCMeta, abstractmethod
  from typing import Optional
  import pandas
  from qlib import get_module_logger
  from qlib.data import D
  from qlib.data.dataset import Dataset, DatasetH, TSDatasetH
  from qlib.data.dataset.handler import DataHandlerLP
  from qlib.model import Model
  from qlib.utils import get_date_by_shift
  from qlib.workflow.recorder import Recorder
  from qlib.workflow.record_temp import SignalRecord
label_desc: Use image node_id 1 to create a new DSBasedUpdater object from inherited base classes: RecordUpdater with example: obj = DSBasedUpdater(record, to_date, from_date, hist_ref, freq, fname, loader_cls)