docstr: Parameters
  ----------
  save_dir: str
      instrument save dir
  max_workers: int
      workers, default 1; Concurrent number, default is 1; when collecting data, it is recommended that max_workers be set to 1
  max_collector_count: int
      default 2
  delay: float
      time.sleep(delay), default 0
  interval: str
      freq, value from [1min, 1d], default 1d
  start: str
      start datetime, default None
  end: str
      end datetime, default None
  check_data_length: int
      check data length, if not None and greater than 0, each symbol will be considered complete if its data length is greater than or equal to this value, otherwise it will be fetched again, the maximum number of fetches being (max_collector_count). By default None.
  limit_nums: int
      using for debug, by default None
code: def __init__(
      self,
      save_dir: [str, Path],
      start=None,
      end=None,
      interval="1d",
      max_workers=1,
      max_collector_count=2,
      delay=0,
      check_data_length: int = None,
      limit_nums: int = None,
  ):
      """
  
      Parameters
      ----------
      save_dir: str
          instrument save dir
      max_workers: int
          workers, default 1; Concurrent number, default is 1; when collecting data, it is recommended that max_workers be set to 1
      max_collector_count: int
          default 2
      delay: float
          time.sleep(delay), default 0
      interval: str
          freq, value from [1min, 1d], default 1d
      start: str
          start datetime, default None
      end: str
          end datetime, default None
      check_data_length: int
          check data length, if not None and greater than 0, each symbol will be considered complete if its data length is greater than or equal to this value, otherwise it will be fetched again, the maximum number of fetches being (max_collector_count). By default None.
      limit_nums: int
          using for debug, by default None
      """
      self.save_dir = Path(save_dir).expanduser().resolve()
      self.save_dir.mkdir(parents=True, exist_ok=True)
  
      self.delay = delay
      self.max_workers = max_workers
      self.max_collector_count = max_collector_count
      self.mini_symbol_map = {}
      self.interval = interval
      self.check_data_length = max(
          int(check_data_length)
          if check_data_length is not None
          else 0,
          0,
      )
  
      self.start_datetime = self.normalize_start_datetime(start)
      self.end_datetime = self.normalize_end_datetime(end)
  
      self.instrument_list = sorted(set(self.get_instrument_list()))
  
      if limit_nums is not None:
          try:
              self.instrument_list = self.instrument_list[
                  : int(limit_nums)
              ]
          except Exception as e:
              logger.warning(
                  f"Cannot use limit_nums={limit_nums}, the parameter will be ignored"
              )
  
imports: import abc
  import time
  import datetime
  import importlib
  from pathlib import Path
  from typing import Type, Iterable
  from concurrent.futures import ProcessPoolExecutor
  import pandas
  from tqdm import tqdm
  from loguru import logger
  from joblib import Parallel, delayed
  from qlib.utils import code_to_fname
label_desc: Use image node_id 1 to create a new BaseCollector object from inherited base classes: abc with example: obj = BaseCollector(save_dir, start, end, interval, max_workers, max_collector_count, delay, check_data_length, limit_nums)