{"record":{"id":"5cd72d29b1796728","repo":"microsoft/qlib","slug":"atomic-executor-doesn-t-support-specify-range-lim","errorCode":null,"errorMessage":"atomic executor doesn't support specify `range_limit`","messagePattern":"atomic executor doesn't support specify `range_limit`","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"qlib/backtest/executor.py","lineNumber":268,"sourceCode":"        execute_result : List[object]\n            the executed result for trade decision.\n            ** NOTE!!!! **:\n            1) This is necessary,  The return value of generator will be used in NestedExecutor\n            2) Please note the executed results are not merged.\n\n        Yields\n        -------\n        object\n            trade decision\n        \"\"\"\n\n        if self.track_data:\n            yield trade_decision\n\n        atomic = not issubclass(self.__class__, NestedExecutor)  # issubclass(A, A) is True\n\n        if atomic and trade_decision.get_range_limit(default_value=None) is not None:\n            raise ValueError(\"atomic executor doesn't support specify `range_limit`\")\n\n        if self._settle_type != BasePosition.ST_NO:\n            self.trade_account.current_position.settle_start(self._settle_type)\n\n        obj = self._collect_data(trade_decision=trade_decision, level=level)\n\n        if isinstance(obj, GeneratorType):\n            yield_res = yield from obj\n            assert isinstance(yield_res, tuple) and len(yield_res) == 2\n            res, kwargs = yield_res\n        else:\n            # Some concrete executor don't have inner decisions\n            res, kwargs = obj\n\n        trade_start_time, trade_end_time = self.trade_calendar.get_step_time()\n        # Account will not be changed in this function\n        self.trade_account.update_bar_end(\n            trade_start_time,","sourceCodeStart":250,"sourceCodeEnd":286,"githubUrl":"https://github.com/microsoft/qlib/blob/79633dd9506ea689e5400dea0197717b5b3d74b7/qlib/backtest/executor.py#L250-L286","documentation":"BaseExecutor.execute_folder/check: an atomic executor (one that is not a NestedExecutor subclass) executes decisions within a single step and cannot honor a range_limit spanning multiple steps. If a decision passed to an atomic executor reports a non-None get_range_limit(default_value=None), the mismatch is a programming error and ValueError is raised.","triggerScenarios":"Registering SimulatorExecutor (atomic) as the innermost executor while the strategy's decisions carry a trade_range/range_limit; configuring an executor stack where a decision with a range limit reaches a non-nested executor; subclassing BaseExecutor without inheriting NestedExecutor.","commonSituations":"Custom executor classes deriving from BaseExecutor directly and fed decisions from NestedExecutor-style strategies; mismatched executor/strategy configs in backtest yaml.","solutions":["Ensure decisions with a trade_range are executed by NestedExecutor levels, with only range-limit-free decisions reaching atomic executors","If your custom executor supports multi-step execution, inherit from NestedExecutor instead of BaseExecutor","Strip trade_range (set decision.trade_range = None) before handing the decision to an atomic executor if the whole-step semantics are acceptable"],"exampleFix":"# before\n# SimulatorExecutor (atomic) receives decision with trade_range -> ValueError\nres = sim_executor.run(execution_strategy, level=0)\n# after\n# route through a NestedExecutor for the outer level\nres = nested_executor.run(execution_strategy, level=0)","handlingStrategy":"validation","validationCode":"from qlib.backtest.executor import NestedExecutor\natomic = not isinstance(executor, NestedExecutor)\nif atomic and decision.get_range_limit(default_value=None) is not None:\n    decision.trade_range = None  # or route the decision to a nested executor instead\nexecutor.run(...)  # proceed","typeGuard":"from qlib.backtest.executor import NestedExecutor\ndef is_atomic(executor) -> bool:\n    return not isinstance(executor, NestedExecutor)","tryCatchPattern":null,"preventionTips":["Keep range-limited decisions on NestedExecutor levels of the stack","Subclass NestedExecutor, not BaseExecutor, for multi-step custom executors"],"tags":["qlib","executor","range-limit","nested-executor"],"backgroundTag":null,"analyzedSha":"79633dd9506ea689e5400dea0197717b5b3d74b7","analyzedAt":"2026-08-15T07:01:27.511Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}