class_docstr: Trade decisions are made by strategy and executed by executor
  
  Motivation:
      Here are several typical scenarios for `BaseTradeDecision`
  
      Case 1:
      1. Outer strategy makes a decision. The decision is not available at the start of current interval
      2. After a period of time, the decision are updated and become available
      3. The inner strategy try to get the decision and start to execute the decision according to `get_range_limit`
      Case 2:
      1. The outer strategy's decision is available at the start of the interval
      2. Same as `case 1.3`
class_docstr_tok: ["Trade","decisions","are","made","by","strategy","and","executed","by","executor","Motivation",":","Here","are","several","typical","scenarios","for","`","BaseTradeDecision","`","Case","1",":","1",".","Outer","strategy","makes","a","decision",".","The","decision","is","not","available","at","the","start","of","current","interval","2",".","After","a","period","of","time",",","the","decision","are","updated","and","become","available","3",".","The","inner","strategy","try","to","get","the","decision","and","start","to","execute","the","decision","according","to","`","get_range_limit","`","Case","2",":","1",".","The","outer","strategy","'s","decision","is","available","at","the","start","of","the","interval","2",".","Same","as","`","case","1.3","`"]
docstr: get the range limit based on data calendar
  
  NOTE: it is **total** range limit instead of a single step
  
  The following assumptions are made
  1) The frequency of the exchange in common_infra is the same as the data calendar
  2) Users want the index mod by **day** (i.e. 240 min)
  
  Parameters
  ----------
  rtype: str
      - "full": return the full limitation of the decision in the day
      - "step": return the limitation of current step
  
  raise_error: bool
      True: raise error if no trade_range is set
      False: return full trade calendar.
  
      It is useful in following cases
      - users want to follow the order specific trading time range when decision level trade range is not
        available. Raising NotImplementedError to indicates that range limit is not available
  
  Returns
  -------
  Tuple[int, int]:
      the range limit in data calendar
  
  Raises
  ------
  NotImplementedError:
      If the following criteria meet
      1) the decision can't provide a unified start and end
      2) raise_error is True
code: def get_data_cal_range_limit(
      self, rtype: str = "full", raise_error: bool = False
  ) -> Tuple[int, int]:
      """
      get the range limit based on data calendar
  
      NOTE: it is **total** range limit instead of a single step
  
      The following assumptions are made
      1) The frequency of the exchange in common_infra is the same as the data calendar
      2) Users want the index mod by **day** (i.e. 240 min)
  
      Parameters
      ----------
      rtype: str
          - "full": return the full limitation of the decision in the day
          - "step": return the limitation of current step
  
      raise_error: bool
          True: raise error if no trade_range is set
          False: return full trade calendar.
  
          It is useful in following cases
          - users want to follow the order specific trading time range when decision level trade range is not
            available. Raising NotImplementedError to indicates that range limit is not available
  
      Returns
      -------
      Tuple[int, int]:
          the range limit in data calendar
  
      Raises
      ------
      NotImplementedError:
          If the following criteria meet
          1) the decision can't provide a unified start and end
          2) raise_error is True
      """
      # potential performance issue
      day_start = pd.Timestamp(self.start_time.date())
      day_end = epsilon_change(day_start + pd.Timedelta(days=1))
      freq = self.strategy.trade_exchange.freq
      _, _, day_start_idx, day_end_idx = Cal.locate_index(
          day_start, day_end, freq=freq
      )
      if self.trade_range is None:
          if raise_error:
              raise NotImplementedError(
                  f"There is no trade_range in this case"
              )
          else:
              return 0, day_end_idx - day_start_idx
      else:
          if rtype == "full":
              val_start, val_end = self.trade_range.clip_time_range(
                  day_start, day_end
              )
          elif rtype == "step":
              val_start, val_end = self.trade_range.clip_time_range(
                  self.start_time, self.end_time
              )
          else:
              raise ValueError(
                  f"This type of input {rtype} is not supported"
              )
          _, _, start_idx, end_index = Cal.locate_index(
              val_start, val_end, freq=freq
          )
          return start_idx - day_start_idx, end_index - day_start_idx
  
imports: from __future__ import annotations
  from abc import abstractmethod
  from datetime import time
  from enum import IntEnum
  from typing import TYPE_CHECKING, Any, ClassVar, Generic, List, Optional, Tuple, TypeVar, Union, cast
  from qlib.backtest.utils import TradeCalendarManager
  from qlib.data.data import Cal
  from qlib.log import get_module_logger
  from qlib.utils.time import concat_date_time, epsilon_change
  from dataclasses import dataclass
  import numpy
  import pandas
label_desc: Use image node_id 6 for calling the BaseTradeDecision obj's underlying member method code with example usage: obj.get_data_cal_range_limit(rtype, raise_error) and returns: unknown,  unknown, int,  unknown