microsoft/qlib · error · ValueError

tradable_weight is {}, can not greater than 1.

Error message

tradable_weight is {}, can not greater than 1.

What it means

After summing the weights of tradable stocks, the method rejects weight books whose tradable total exceeds 1 (tolerance 1e-5) with ValueError. Because amounts are computed as cash * weight / tradable_weight, a total above 1 would over-allocate the cash; weights of non-tradable stocks are excluded from the sum, so the error means the tradable subset alone is over-allocated.

Source

Thrown at qlib/backtest/exchange.py:567

        start_time : the start time point of the step
        end_time : the end time point of the step
        direction : the direction of the deal price for estimating the amount
                    # NOTE: this function is used for calculating target position. So the default direction is buy
        """

        # calculate the total weight of tradable value
        tradable_weight = 0.0
        for stock_id, wp in weight_position.items():
            if self.is_stock_tradable(stock_id=stock_id, start_time=start_time, end_time=end_time):
                # weight_position must be greater than 0 and less than 1
                if wp < 0 or wp > 1:
                    raise ValueError(
                        "weight_position is {}, " "weight_position is not in the range of (0, 1).".format(wp),
                    )
                tradable_weight += wp

        if tradable_weight - 1.0 >= 1e-5:
            raise ValueError("tradable_weight is {}, can not greater than 1.".format(tradable_weight))

        amount_dict = {}
        for stock_id in weight_position:
            if weight_position[stock_id] > 0.0 and self.is_stock_tradable(
                stock_id=stock_id,
                start_time=start_time,
                end_time=end_time,
            ):
                amount_dict[stock_id] = (
                    cash
                    * weight_position[stock_id]
                    / tradable_weight
                    // self.get_deal_price(
                        stock_id=stock_id,
                        start_time=start_time,
                        end_time=end_time,
                        direction=direction,
                    )

View on GitHub (pinned to 79633dd950)

Solutions

  1. Normalize weights to sum <= 1: total = sum(w.values()); weights = {k: v / total for k, v in weights.items()}
  2. Scale down: weights = {k: v * 0.99 / total for k, v in weights.items()} if you want a cash buffer
  3. Verify which stocks count as tradable if the sum looks fine but still fails (suspended/limit-hit stocks change the tradable subset only by exclusion, so recheck the raw sum)

Example fix

# before
amounts = exch.get_amount_from_weight({'A': 0.7, 'B': 0.6}, ...)
# after
raw = {'A': 0.7, 'B': 0.6}
total = sum(raw.values())
weights = {k: v / total for k, v in raw.items()}
amounts = exch.get_amount_from_weight(weights, ...)
Defensive patterns

Strategy: validation

Validate before calling

total = sum(weight_position.values())
if total > 1.0:
    weight_position = {k: v / total for k, v in weight_position.items()}
assert sum(weight_position.values()) <= 1.0 + 1e-5

Type guard

def weights_normalized(w: dict) -> bool:
    return sum(w.values()) <= 1.0 + 1e-5

Prevention

When it happens

Trigger: weight_position summing to more than 1 (e.g. 0.6 + 0.6), or all-in allocations where a data error makes extra stocks count as tradable.

Common situations: Model outputs not normalized (raw softmax with temperature, unnormalized scores); hand-built weight dicts; currency/rounding issues where 100 tiny weights sum to 1.00001 (below the 1e-5 tolerance usually, but marginal cases slip).

Related errors


AI-assisted analysis of microsoft/qlib@79633dd950 (2026-08-15). Data as JSON: /api/errors/cdcee389e8ce18b5. Report an issue: GitHub.