microsoft/qlib · error · ValueError
Execution volume is invalid: {exec_vol} (position = {self.po
Error message
Execution volume is invalid: {exec_vol} (position = {self.position}) What it means
Runtime sanity check in `SimpleOrderExecutionSimulator.step` (qlib/rl/order_execution/simulator_simple.py:169). After applying the execution volumes for this tick, either the resulting position went below `-EPS` (over-sold beyond holdings/order size) or some individual execution volume was negative. It means the action interpreter produced volumes inconsistent with the order and simulator state.
Source
Thrown at qlib/rl/order_execution/simulator_simple.py:169
----------
amount
The amount you wish to deal. The simulator doesn't guarantee all the amount to be successfully dealt.
"""
assert not self.done()
self.market_price = self.market_vol = None # avoid misuse
exec_vol = self._split_exec_vol(amount)
assert self.market_price is not None
assert self.market_vol is not None
ticks_position = self.position - np.cumsum(exec_vol)
self.position -= exec_vol.sum()
if abs(self.position) < 1e-6:
self.position = 0.0
if self.position < -EPS or (exec_vol < -EPS).any():
raise ValueError(f"Execution volume is invalid: {exec_vol} (position = {self.position})")
# Get time index available for this step
time_index = self._get_ticks_slice(self.cur_time, self._next_time())
self.history_exec = self._dataframe_append(
self.history_exec,
SAOEMetrics(
# It should have the same keys with SAOEMetrics,
# but the values do not necessarily have the annotated type.
# Some values could be vectorized (e.g., exec_vol).
stock_id=self.order.stock_id,
datetime=time_index,
direction=self.order.direction,
market_volume=self.market_vol,
market_price=self.market_price,
amount=exec_vol,
inner_amount=exec_vol,
deal_amount=exec_vol,View on GitHub (pinned to 79633dd950)
Solutions
- In the interpreter's `action_to_simulator_action`, clip volumes to `[0, remaining_position]` (and `>= 0`) before returning.
- Compute volumes as differences of cumulative ratios (`cumsum[i] - cumsum[i-1]`) rather than independent ratios so they sum exactly to the order amount.
- Print `self.position` and `exec_vol` in a debug run to find the first step where the invariant breaks and inspect the policy's raw action for that step.
Example fix
// before exec_vol = amount # amount may exceed remaining position or be negative // after exec_vol = np.clip(amount, 0.0, self.position) # never over-sell, never negative
Defensive patterns
Strategy: validation
Validate before calling
import numpy as np
EPS = 1e-6
def sanitize_exec_vol(exec_vol: np.ndarray, remaining: float) -> np.ndarray:
exec_vol = np.clip(exec_vol, 0.0, None) # no negative volume
exec_vol = np.minimum(exec_vol, remaining) # never exceed remaining position
return exec_vol Type guard
def exec_vol_valid(exec_vol, remaining: float, eps: float = 1e-6) -> bool:
import numpy as np
exec_vol = np.asarray(exec_vol)
return bool((exec_vol >= -eps).all() and exec_vol.sum() <= remaining + eps) Try / catch
try:
sim.step(action)
except ValueError as e:
if "Execution volume is invalid" in str(e):
log.error("over-sell at step %d: position=%s", sim.cur_step, sim.position)
raise
raise Prevention
- Always clip interpreter output volumes to [0, remaining_order_amount].
- Derive per-tick volumes from cumulative-ratio differences, not independent ratios.
- Log position and exec_vol every step during strategy debugging.
When it happens
Trigger: An ActionInterpreter whose converted action sums to more than the remaining order amount (position goes negative), or a twins/split scheme yielding a negative volume component. Also triggered by a policy outputting extreme actions that survive the interpreter without clipping.
Common situations: Custom order-execution interpreters that forget to clamp per-tick volumes; orders smaller than the minimum execution unit; floating-point drift accumulating over many steps when volumes are computed by ratios instead of differences.
Related errors
- Order direction cannot be none when deal_price_type is not c
- Unexpected order direction: {direction}
- Unexpected order direction: {direction}
- {} not in current position
- only have {} {}, require {}
AI-assisted analysis of microsoft/qlib@79633dd950 (2026-08-15).
Data as JSON: /api/errors/84fe3be91abce96c.
Report an issue: GitHub.