class_docstr: The motivation of Rolling Module
  - It only focus **offlinely** turn a specific task to rollinng
  - To make the implementation easier, following factors are ignored.
      - The tasks is dependent (e.g. time series).
  
  Related modules and difference from me:
  - MetaController: It is learning how to handle a task (e.g. learning to learn).
      - But rolling is about how to split a single task into tasks in time series and run them.
  - OnlineStrategy: It is focusing on serving a model, the model can be updated time dependently in time.
      - Rolling is much simpler and is only for testing rolling models offline. It does not want to share the interface with OnlineStrategy.
  
  The code about rolling is shared in `task_generator` & `RollingGen` level between me and the above modules
  But it is for different purpose, so other parts are not shared.
  
  
  .. code-block:: shell
  
      # here is an typical use case of the module.
      python -m qlib.contrib.rolling.base --conf_path <path to the yaml> run
  
  **NOTE**
  before running the example, please clean your previous results with following command
  - `rm -r mlruns`
  - Because it is very hard to permanently delete a experiment (it will be moved into .trash and raise error when creating experiment with same name).
class_docstr_tok: ["The","motivation","of","Rolling","Module","-","It","only","focus","*","*","offlinely","*","*","turn","a","specific","task","to","rollinng","-","To","make","the","implementation","easier",",","following","factors","are","ignored",".","-","The","tasks","is","dependent","(","e.g",".","time","series",")",".","Related","modules","and","difference","from","me",":","-","MetaController",":","It","is","learning","how","to","handle","a","task","(","e.g",".","learning","to","learn",")",".","-","But","rolling","is","about","how","to","split","a","single","task","into","tasks","in","time","series","and","run","them",".","-","OnlineStrategy",":","It","is","focusing","on","serving","a","model",",","the","model","can","be","updated","time","dependently","in","time",".","-","Rolling","is","much","simpler","and","is","only","for","testing","rolling","models","offline",".","It","does","not","want","to","share","the","interface","with","OnlineStrategy",".","The","code","about","rolling","is","shared","in","`","task_generator","`","&","`","RollingGen","`","level","between","me","and","the","above","modules","But","it","is","for","different","purpose",",","so","other","parts","are","not","shared",".","..","code-block",":",":","shell","#","here","is","an","typical","use","case","of","the","module",".","python","-m","qlib.contrib.rolling.base","--","conf_path","<","path","to","the","yaml",">","run","*","*","NOTE","*","*","before","running","the","example",",","please","clean","your","previous","results","with","following","command","-","`","rm","-r","mlruns","`","-","Because","it","is","very","hard","to","permanently","delete","a","experiment","(","it","will","be","moved","into",".trash","and","raise","error","when","creating","experiment","with","same","name",")","."]
docstr: Parameters
  ----------
  conf_path : str
      Path to the config for rolling.
  exp_name : Optional[str]
      The exp name of the outputs (Output is a record which contains the concatenated predictions of rolling records).
  horizon: Optional[int] = 20,
      The horizon of the prediction target.
      This is used to override the prediction horizon of the file.
  h_path : Optional[str]
      the dumped data handler;
      It may come from other data source. It will override the data handler in the config.
  test_end : Optional[str]
      the test end for the data. It is typically used together with the handler
      You can do the same thing with task_ext_conf in a more complicated way
  train_start : Optional[str]
      the train start for the data.  It is typically used together with the handler.
      You can do the same thing with task_ext_conf in a more complicated way
  task_ext_conf : Optional[dict]
      some option to update the task config.
  rolling_exp : Optional[str]
      The name for the experiments for rolling.
      It will contains a lot of record in an experiment. Each record corresponds to a specific rolling.
      Please note that it is different from the final experiments
docstr_tok: ["Parameters","--","--","--","--","--","conf_path",":","str","Path","to","the","config","for","rolling",".","exp_name",":","Optional","[","str","]","The","exp","name","of","the","outputs","(","Output","is","a","record","which","contains","the","concatenated","predictions","of","rolling","records",")",".","horizon",":","Optional","[","int","]","=","20",",","The","horizon","of","the","prediction","target",".","This","is","used","to","override","the","prediction","horizon","of","the","file",".","h_path",":","Optional","[","str","]","the","dumped","data","handler",";","It","may","come","from","other","data","source",".","It","will","override","the","data","handler","in","the","config",".","test_end",":","Optional","[","str","]","the","test","end","for","the","data",".","It","is","typically","used","together","with","the","handler","You","can","do","the","same","thing","with","task_ext_conf","in","a","more","complicated","way","train_start",":","Optional","[","str","]","the","train","start","for","the","data",".","It","is","typically","used","together","with","the","handler",".","You","can","do","the","same","thing","with","task_ext_conf","in","a","more","complicated","way","task_ext_conf",":","Optional","[","dict","]","some","option","to","update","the","task","config",".","rolling_exp",":","Optional","[","str","]","The","name","for","the","experiments","for","rolling",".","It","will","contains","a","lot","of","record","in","an","experiment",".","Each","record","corresponds","to","a","specific","rolling",".","Please","note","that","it","is","different","from","the","final","experiments"]
code: def __init__(
      self,
      conf_path: Union[str, Path],
      exp_name: Optional[str] = None,
      horizon: Optional[int] = 20,
      step: int = 20,
      h_path: Optional[str] = None,
      train_start: Optional[str] = None,
      test_end: Optional[str] = None,
      task_ext_conf: Optional[dict] = None,
      rolling_exp: Optional[str] = None,
  ) -> None:
      """
      Parameters
      ----------
      conf_path : str
          Path to the config for rolling.
      exp_name : Optional[str]
          The exp name of the outputs (Output is a record which contains the concatenated predictions of rolling records).
      horizon: Optional[int] = 20,
          The horizon of the prediction target.
          This is used to override the prediction horizon of the file.
      h_path : Optional[str]
          the dumped data handler;
          It may come from other data source. It will override the data handler in the config.
      test_end : Optional[str]
          the test end for the data. It is typically used together with the handler
          You can do the same thing with task_ext_conf in a more complicated way
      train_start : Optional[str]
          the train start for the data.  It is typically used together with the handler.
          You can do the same thing with task_ext_conf in a more complicated way
      task_ext_conf : Optional[dict]
          some option to update the task config.
      rolling_exp : Optional[str]
          The name for the experiments for rolling.
          It will contains a lot of record in an experiment. Each record corresponds to a specific rolling.
          Please note that it is different from the final experiments
      """
      self.logger = get_module_logger("Rolling")
      self.conf_path = Path(conf_path)
      self.exp_name = exp_name
      self._rid = None  # the final combined recorder id in `exp_name`
  
      self.step = step
      assert (
          horizon is not None
      ), "Current version does not support extracting horizon from the underlying dataset"
      self.horizon = horizon
      if rolling_exp is None:
          datetime_suffix = pd.Timestamp.now().strftime("%Y%m%d%H%M%S")
          self.rolling_exp = f"rolling_models_{datetime_suffix}"
      else:
          self.rolling_exp = rolling_exp
          self.logger.warning(
              "Using user specifiied name for rolling models. So the experiment names duplicateds. "
              "Please manually remove your experiment for rolling model with command like `rm -r mlruns`."
              " Otherwise it will prevents the creating of experimen with same name"
          )
      self.train_start = train_start
      self.test_end = test_end
      self.task_ext_conf = task_ext_conf
      self.h_path = h_path
  
imports: from copy import deepcopy
  from pathlib import Path
  from typing import List, Optional, Union
  import fire
  import pandas
  import yaml
  from qlib import auto_init
  from qlib.log import get_module_logger
  from qlib.model.ens.ensemble import RollingEnsemble
  from qlib.model.trainer import TrainerR
  from qlib.utils import get_cls_kwargs, init_instance_by_config
  from qlib.utils.data import update_config
  from qlib.workflow import R
  from qlib.workflow.record_temp import SignalRecord
  from qlib.workflow.task.collect import RecorderCollector
  from qlib.workflow.task.gen import RollingGen, task_generator
  from qlib.workflow.task.utils import replace_task_handler_with_cache
label_desc: Use image node_id 1 to create a new Rolling object  with example: obj = Rolling(conf_path, exp_name, horizon, step, h_path, train_start, test_end, task_ext_conf, rolling_exp)