HKUDS/Vibe-Trading · error · ValueError

ts_std window must be >= 2, got {n}

Error message

ts_std window must be >= 2, got {n}

What it means

ts_std requires n >= 2 because it computes a sample standard deviation with ddof=1, which is undefined for a single observation; n < 2 raises. Warmup rows are NaN per min_periods=n.

Source

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

    y = _as_float(y)
    cols = x.columns.union(y.columns)
    xa = x.reindex(columns=cols)
    ya = y.reindex(columns=cols)
    cov = xa.rolling(window=n, min_periods=n).cov(ya)
    return cov.replace([np.inf, -np.inf], np.nan)


def ts_mean(df: pd.DataFrame, n: int) -> pd.DataFrame:
    """Rolling mean per column, warmup → NaN."""
    if n < 1:
        raise ValueError(f"ts_mean window must be >= 1, got {n}")
    return df.rolling(window=n, min_periods=n).mean()


def ts_std(df: pd.DataFrame, n: int) -> pd.DataFrame:
    """Rolling sample std (ddof=1) per column, warmup → NaN."""
    if n < 2:
        raise ValueError(f"ts_std window must be >= 2, got {n}")
    return df.rolling(window=n, min_periods=n).std(ddof=1)


def ts_max(df: pd.DataFrame, n: int) -> pd.DataFrame:
    """Rolling max per column, warmup → NaN."""
    if n < 1:
        raise ValueError(f"ts_max window must be >= 1, got {n}")
    return df.rolling(window=n, min_periods=n).max()


def ts_min(df: pd.DataFrame, n: int) -> pd.DataFrame:
    """Rolling min per column, warmup → NaN."""
    if n < 1:
        raise ValueError(f"ts_min window must be >= 1, got {n}")
    return df.rolling(window=n, min_periods=n).min()


def _argmax_last(arr: np.ndarray) -> float:

View on GitHub (pinned to 80ffdda44c)

Solutions

  1. Pass n >= 2 (need at least 2 points for sample std)
  2. If ddof=0 semantics with n=1 are acceptable, compute df.rolling(n).std(ddof=0) yourself instead of ts_std
  3. Validate each operator's minimum window in config validation

Example fix

# before
s = ts_std(df, n=1)

# after
s = ts_std(df, n=20)
Defensive patterns

Strategy: validation

Validate before calling

if not isinstance(n, int) or n < 2:
    raise ValueError(f'invalid ts_std window: {n!r} (sample std needs >= 2)')
s = ts_std(df, n)

Type guard

def is_valid_ts_std_window(n) -> bool:
    return isinstance(n, int) and n >= 2

Prevention

When it happens

Trigger: ts_std(df, 1), ts_std(df, 0), or negative n — often a window copied from ts_mean/ts_rank (which allow 1) without adjusting for the stricter minimum. Called from compute() and tests.

Common situations: Refactoring a pipeline from ts_mean to ts_std without changing n; short series with auto-scaled windows; config defaults of 1 used across all rolling operators.

Related errors


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