class_docstr: Nested Executor with inner strategy and executor
  - At each time `execute` is called, it will call the inner strategy and executor to execute the `trade_decision`
      in a higher frequency env.
code: def _collect_data(
      self,
      trade_decision: BaseTradeDecision,
      level: int = 0,
  ) -> Generator[Any, Any, Tuple[List[object], dict]]:
      execute_result = []
      inner_order_indicators = []
      decision_list = []
      # NOTE:
      # - this is necessary to calculating the steps in sub level
      # - more detailed information will be set into trade decision
      self._init_sub_trading(trade_decision)
  
      _inner_execute_result = None
      while not self.inner_executor.finished():
          trade_decision = self._update_trade_decision(trade_decision)
  
          if trade_decision.empty() and self._skip_empty_decision:
              # give one chance for outer strategy to update the strategy
              # - For updating some information in the sub executor (the strategy have no knowledge of the inner
              #   executor when generating the decision)
              break
  
          sub_cal: TradeCalendarManager = (
              self.inner_executor.trade_calendar
          )
  
          # NOTE: make sure get_start_end_idx is after `self._update_trade_decision`
          start_idx, end_idx = get_start_end_idx(
              sub_cal, trade_decision
          )
          if (
              not self._align_range_limit
              or start_idx <= sub_cal.get_trade_step() <= end_idx
          ):
              # if force align the range limit, skip the steps outside the decision range limit
  
              res = self.inner_strategy.generate_trade_decision(
                  _inner_execute_result
              )
  
              # NOTE: !!!!!
              # the two lines below is for a special case in RL
              # To solve the conflicts below
              # - Normally, user will create a strategy and embed it into Qlib's executor and simulator interaction
              #   loop For a _nested qlib example_, (Qlib Strategy) <=> (Qlib Executor[(inner Qlib Strategy) <=>
              #   (inner Qlib Executor)])
              # - However, RL-based framework has it's own script to run the loop
              #   For an _RL learning example_, (RL Policy) <=> (RL Env[(inner Qlib Executor)])
              # To make it possible to run  _nested qlib example_ and _RL learning example_ together, the solution
              # below is proposed
              # - The entry script follow the example of  _RL learning example_ to be compatible with all kinds of
              #   RL Framework
              # - Each step of (RL Env) will make (inner Qlib Executor) one step forward
              #     - (inner Qlib Strategy) is a proxy strategy, it will give the program control right to (RL Env)
              #       by `yield from` and wait for the action from the policy
              # So the two lines below is the implementation of yielding control rights
              if isinstance(res, GeneratorType):
                  res = yield from res
  
              _inner_trade_decision: BaseTradeDecision = res
  
              trade_decision.mod_inner_decision(
                  _inner_trade_decision
              )  # propagate part of decision information
  
              # NOTE sub_cal.get_step_time() must be called before collect_data in case of step shifting
              decision_list.append(
                  (_inner_trade_decision, *sub_cal.get_step_time())
              )
  
              # NOTE: Trade Calendar will step forward in the follow line
              _inner_execute_result = (
                  yield from self.inner_executor.collect_data(
                      trade_decision=_inner_trade_decision,
                      level=level + 1,
                  )
              )
              assert isinstance(_inner_execute_result, list)
              self.post_inner_exe_step(_inner_execute_result)
              execute_result.extend(_inner_execute_result)
  
              inner_order_indicators.append(
                  self.inner_executor.trade_account.get_trade_indicator().get_order_indicator(
                      raw=True
                  ),
              )
          else:
              # do nothing and just step forward
              sub_cal.step()
  
      # Let inner strategy know that the outer level execution is done.
      self.inner_strategy.post_upper_level_exe_step()
  
      return execute_result, {
          "inner_order_indicators": inner_order_indicators,
          "decision_list": decision_list,
      }
  
imports: from __future__ import annotations
  import copy
  from abc import abstractmethod
  from collections import defaultdict
  from types import GeneratorType
  from typing import Any, Dict, Generator, List, Tuple, Union, cast
  import pandas
  from qlib.backtest.account import Account
  from qlib.backtest.position import BasePosition
  from qlib.log import get_module_logger
  from ..strategy.base import BaseStrategy
  from ..utils import init_instance_by_config
  from .decision import BaseTradeDecision, Order
  from .exchange import Exchange
  from .utils import CommonInfrastructure, LevelInfrastructure, TradeCalendarManager, get_start_end_idx
label_desc: Use image node_id 5 for calling the NestedExecutor obj's underlying member method code with example usage: obj._collect_data(trade_decision, level) and returns: execute_result,  dict