HKUDS/Vibe-Trading · error · ValueError

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

Error message

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

What it means

decay_linear computes a linearly weighted moving average (weights n..1 normalized) via sliding_window_view + einsum with causal alignment. Window n must be >= 1; zero/negative windows make the weight vector empty and meaningless.

Source

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

    Lookahead ban: ``d >= 1`` strictly. Negative lag forbidden.
    """
    if d < 1:
        raise ValueError(f"delta lag must be >= 1 (lookahead ban), got {d}")
    return df - df.shift(d)


def decay_linear(df: pd.DataFrame, n: int) -> pd.DataFrame:
    """Linear decay-weighted moving average, weights ``n, n-1, ..., 1`` normalized.

    Warmup (first ``n-1`` rows) → NaN.

    Uses numpy ``sliding_window_view`` + ``einsum`` for vectorized computation
    (~40x faster than pandas rolling().apply()). Causal alignment is guaranteed:
    output[i] depends only on input[i-n+1:i+1].
    """
    if n < 1:
        raise ValueError(f"decay_linear window must be >= 1, got {n}")
    weights = np.arange(n, 0, -1, dtype=np.float64)
    weights /= weights.sum()

    def _apply(arr: np.ndarray) -> float:
        if np.isnan(arr).any():
            return np.nan
        return float(np.dot(arr, weights))

    arr = df.to_numpy(dtype=np.float64)
    T, C = arr.shape
    if T < n:
        return df.rolling(window=n, min_periods=n).apply(_apply, raw=True)

    windows = sliding_window_view(arr, window_shape=n, axis=0)  # (T-n+1, C, n)
    nan_mask = np.isnan(windows).any(axis=2)  # (T-n+1, C)
    weighted = np.where(nan_mask[..., np.newaxis], 0.0, windows)
    dot = np.einsum("ijk,k->ij", weighted, weights)

View on GitHub (pinned to 80ffdda44c)

Solutions

  1. Use n >= 1; for 'no decay' use n=1 (weights [1]) or skip the operator
  2. Validate config windows before compute()
  3. Clamp computed windows: max(1, n)

Example fix

// before
decay_linear(df, 0)
// after
decay_linear(df, 1)
Defensive patterns

Strategy: validation

Validate before calling

if not isinstance(n, int) or n < 1: raise ValueError(f'window must be int >= 1, got {n!r}')

Type guard

def is_valid_window(n: object) -> bool:
    return isinstance(n, int) and not isinstance(n, bool) and n >= 1

Prevention

When it happens

Trigger: Calling decay_linear(df, 0) or with a negative window; parameterized alphas with a bad decay window.

Common situations: Factor specs with decay: 0 intending 'no smoothing' (should just use raw factor), window sweeps including 0, or computed windows on short panels.

Related errors


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