{"record":{"id":"2bedb87814b11576","repo":"microsoft/qlib","slug":"only-have-require","errorCode":null,"errorMessage":"only have {} {}, require {}","messagePattern":"only have (.+?) (.+?), require (.+?)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"qlib/backtest/position.py","lineNumber":368,"sourceCode":"        self.position[\"cash\"] -= trade_val + cost\n\n    def _sell_stock(self, stock_id: str, trade_val: float, cost: float, trade_price: float) -> None:\n        trade_amount = trade_val / trade_price\n        if stock_id not in self.position:\n            raise KeyError(\"{} not in current position\".format(stock_id))\n        else:\n            if np.isclose(self.position[stock_id][\"amount\"], trade_amount):\n                # Selling all the stocks\n                # we use np.isclose instead of abs(<the final amount>) <= 1e-5  because `np.isclose` consider both\n                # relative amount and absolute amount\n                # Using abs(<the final amount>) <= 1e-5 will result in error when the amount is large\n                self._del_stock(stock_id)\n            else:\n                # decrease the amount of stock\n                self.position[stock_id][\"amount\"] -= trade_amount\n                # check if to delete\n                if self.position[stock_id][\"amount\"] < -1e-5:\n                    raise ValueError(\n                        \"only have {} {}, require {}\".format(\n                            self.position[stock_id][\"amount\"] + trade_amount,\n                            stock_id,\n                            trade_amount,\n                        ),\n                    )\n\n        new_cash = trade_val - cost\n        if self._settle_type == self.ST_CASH:\n            self.position[\"cash_delay\"] += new_cash\n        elif self._settle_type == self.ST_NO:\n            self.position[\"cash\"] += new_cash\n        else:\n            raise NotImplementedError(f\"This type of input is not supported\")\n\n    def _del_stock(self, stock_id: str) -> None:\n        del self.position[stock_id]\n","sourceCodeStart":350,"sourceCodeEnd":386,"githubUrl":"https://github.com/microsoft/qlib/blob/79633dd9506ea689e5400dea0197717b5b3d74b7/qlib/backtest/position.py#L350-L386","documentation":"Position._sell_stock raises ValueError('only have {held} {stock}, require {asked}') when subtracting the sold amount drives the holding below -1e-5, i.e. the sell order amount exceeds what the position holds beyond floating-point tolerance. The message reconstructs the pre-trade holding (final + trade_amount) for debugging.","triggerScenarios":"update_order with a SELL whose trade_amount (trade_val/trade_price) exceeds self.position[stock_id]['amount'] by more than np.isclose tolerance; typical when the strategy rounds lots (e.g. board lots of 100) upward or sells the full position computed with a different price than the deal price.","commonSituations":"Amount computed from close price but filled at a slippage-adjusted deal_price so trade_amount > held amount; strategies that sell 'all shares' using yesterday's amount after dividends/splits; numerical drift in repeated fractional sells.","solutions":["Cap sell amounts at the current holding: amount = min(desired, position.get_stock_amount(stock))","For full exits rely on np.isclose tolerance: pass the exact current amount, or trade the whole position value","Align the price used to size the sell with the exchange's deal_price/limit thresholds"],"exampleFix":"# before\nsell_val = position.get_stock_amount(stock) * ref_price  # ref_price != deal price\n\n# after\namount = position.get_stock_amount(stock)\nsell_val = amount * deal_price  # exact full-position sell, hits np.isclose branch","handlingStrategy":"validation","validationCode":"held = position.get_stock_amount(order.stock_id)\nif order.direction == Order.SELL and abs(order.amount_delta) > held + 1e-5:\n    order.amount = held  # clip to holdings","typeGuard":null,"tryCatchPattern":"try:\n    position.update_order(order, trade_val, cost, trade_price)\nexcept ValueError as e:\n    logger.warning(\"clipping oversell: %s\", e)","preventionTips":["Size full-exit sells with the exact current amount","Use the same price source for sizing and dealing","Clip sell amounts to get_stock_amount before submitting"],"tags":["qlib","backtest","position","oversell","order-execution"],"backgroundTag":null,"analyzedSha":"79633dd9506ea689e5400dea0197717b5b3d74b7","analyzedAt":"2026-08-15T07:01:27.511Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}