HKUDS/Vibe-Trading · error · ValueError

delta lag must be >= 1 (lookahead ban), got {d}

Error message

delta lag must be >= 1 (lookahead ban), got {d}

What it means

delta computes df - df.shift(d), the first difference at lag d. To enforce the lookahead ban (no negative shifts and no d=0 which is a no-op/identity), it requires d >= 1 strictly.

Source

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

    so we convert via ``(n - 1) - bn_result`` to get 0-based index from start.
    """
    if n < 1:
        raise ValueError(f"ts_argmin window must be >= 1, got {n}")
    if HAS_BOTTLENECK:
        arr = df.to_numpy(dtype=np.float64)
        raw = bn.move_argmin(arr, window=n, min_count=n, axis=0)
        corrected = (n - 1) - raw
        return pd.DataFrame(corrected, index=df.index, columns=df.columns)
    return df.rolling(window=n, min_periods=n).apply(_argmin_last, raw=True)


def delta(df: pd.DataFrame, d: int) -> pd.DataFrame:
    """First difference at lag ``d``: ``df - df.shift(d)``.

    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:

View on GitHub (pinned to 80ffdda44c)

Solutions

  1. Use d >= 1; for yesterday-vs-today diff use d=1
  2. If you truly want d=0 identity, skip delta and use df directly
  3. Validate lag parameters in config parsing

Example fix

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

Strategy: validation

Validate before calling

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

Type guard

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

Prevention

When it happens

Trigger: Calling delta(df, 0), delta(df, -1), or passing d=0 expecting current values.

Common situations: Translating 'change from today' semantics where 0 feels natural, off-by-one from other libraries where lag 0 is allowed, or user configs with lag: 0.

Related errors


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