HKUDS/Vibe-Trading · error · ValueError

ts_rank window must be >= 1, got {n}

Error message

ts_rank window must be >= 1, got {n}

What it means

ts_rank validates its rolling window n and requires n >= 1; smaller values (0 or negatives) raise immediately. A window of 1 is meaningful here (the single value is its own rank). The function uses numpy sliding_window_view for speed, with warmup positions returning NaN.

Source

Thrown at agent/src/factors/base.py:104

    """
    df = _as_float(df)
    abs_sum = df.abs().sum(axis=1, skipna=True)
    abs_sum = abs_sum.where(abs_sum > 0)  # zero → NaN
    return df.mul(a).div(abs_sum, axis=0)


def ts_rank(df: pd.DataFrame, n: int) -> pd.DataFrame:
    """Rolling rank (last value's rank within the n-window), per column.

    Warmup (first ``n-1`` rows per column) returns NaN. Result is a percentile
    in [0, 1] so it is compositionally compatible with cross-sectional rank.

    Uses numpy ``sliding_window_view`` for vectorized computation (~45x faster
    than pandas rolling().apply()). Note: ``bottleneck.move_rank`` computes
    Spearman rank correlation, not percentile rank, so it is not used here.
    """
    if n < 1:
        raise ValueError(f"ts_rank window must be >= 1, got {n}")

    def _last_rank(arr: np.ndarray) -> float:
        if np.isnan(arr).all():
            return np.nan
        last = arr[-1]
        if np.isnan(last):
            return np.nan
        valid = arr[~np.isnan(arr)]
        if valid.size == 0:
            return np.nan
        # average rank for ties; pct
        less = (valid < last).sum()
        eq = (valid == last).sum()
        rank_avg = less + 0.5 * (eq + 1)
        return float(rank_avg / valid.size)

    arr = df.to_numpy(dtype=np.float64)
    T, C = arr.shape

View on GitHub (pinned to 80ffdda44c)

Solutions

  1. Pass a positive integer window (>= 1)
  2. Validate/clamp computed windows: n = max(1, n) only if that is semantically correct, otherwise raise early with context
  3. Check config values for window parameters before running the factor pipeline

Example fix

# before
out = ts_rank(df, n=0)

# after
out = ts_rank(df, n=20)
Defensive patterns

Strategy: validation

Validate before calling

if not isinstance(n, int) or n < 1:
    raise ValueError(f'invalid ts_rank window: {n!r}')
out = ts_rank(df, n)

Type guard

def is_valid_ts_rank_window(n) -> bool:
    return isinstance(n, int) and n >= 1

Prevention

When it happens

Trigger: ts_rank(df, 0), ts_rank(df, -5), or a computed window that evaluates to 0, e.g. n = len(df) - lookback with lookback == len(df). Called from compute() in factor pipelines and directly in tests.

Common situations: Config-driven window sizes where a parameter is unset and defaults to 0; dynamic windows derived from data length that underflow on short series; passing a percentage (0.05) instead of a count.

Related errors


AI-assisted analysis of HKUDS/Vibe-Trading@80ffdda44c (2026-08-28). Data as JSON: /api/errors/e8057c1621a1e748. Report an issue: GitHub.