docstr: parse instruments, eg: csi300.txt
  
  Examples
  -------
      $ python collector.py parse_instruments --index_name CSI300 --qlib_dir ~/.qlib/qlib_data/cn_data
docstr_tok: ["parse","instruments",",","eg",":","csi300.txt","Examples","--","--","--","-","$","python","collector.py","parse_instruments","--","index_name","CSI300","--","qlib_dir","~\/.qlib\/qlib_data\/cn_data"]
code: def parse_instruments(self):
      """parse instruments, eg: csi300.txt
  
      Examples
      -------
          $ python collector.py parse_instruments --index_name CSI300 --qlib_dir ~/.qlib/qlib_data/cn_data
      """
      logger.info(
          f"start parse {self.index_name.lower()} companies....."
      )
      instruments_columns = [
          self.SYMBOL_FIELD_NAME,
          self.START_DATE_FIELD,
          self.END_DATE_FIELD,
      ]
      changers_df = self.get_changes()
      new_df = self.get_new_companies()
      if new_df is None or new_df.empty:
          raise ValueError(
              f"get new companies error: {self.index_name}"
          )
      new_df = new_df.copy()
      logger.info("parse history companies by changes......")
      for _row in tqdm(
          changers_df.sort_values(
              self.DATE_FIELD_NAME, ascending=False
          ).itertuples(index=False)
      ):
          if _row.type == self.ADD:
              min_end_date = new_df.loc[
                  new_df[self.SYMBOL_FIELD_NAME] == _row.symbol,
                  self.END_DATE_FIELD,
              ].min()
              new_df.loc[
                  (new_df[self.END_DATE_FIELD] == min_end_date)
                  & (new_df[self.SYMBOL_FIELD_NAME] == _row.symbol),
                  self.START_DATE_FIELD,
              ] = _row.date
          else:
              _tmp_df = pd.DataFrame(
                  [[_row.symbol, self.bench_start_date, _row.date]],
                  columns=instruments_columns,
              )
              new_df = pd.concat([new_df, _tmp_df], sort=False)
  
      inst_df = new_df.loc[:, instruments_columns]
      _inst_prefix = self.INST_PREFIX.strip()
      if _inst_prefix:
          inst_df["save_inst"] = inst_df[self.SYMBOL_FIELD_NAME].apply(
              lambda x: f"{_inst_prefix}{x}"
          )
      inst_df = self.format_datetime(inst_df)
      inst_df.to_csv(
          self.instruments_dir.joinpath(
              f"{self.index_name.lower()}.txt"
          ),
          sep="\t",
          index=False,
          header=None,
      )
      logger.info(
          f"parse {self.index_name.lower()} companies finished."
      )
  
file_path: qlib/scripts/data_collector/index.py
imports: import sys
  import abc
  from pathlib import Path
  from typing import List
  import pandas
  from tqdm import tqdm
  from loguru import logger
  from data_collector.utils import get_trading_date_by_shift
label_desc: Use image node_id 9 for calling the IndexBase obj's underlying member method code with example usage: obj.parse_instruments() without return types