HKUDS/Vibe-Trading · error · ValueError
fit_ornstein_uhlenbeck needs a series that varies; this one
Error message
fit_ornstein_uhlenbeck needs a series that varies; this one is constant
What it means
fit_ornstein_uhlenbeck rejects input series whose lagged values have zero (ddof=0) standard deviation, i.e. a constant series. Mean-reversion estimation via OLS on lag pairs is degenerate when the regressor never varies, so the library raises instead of returning meaningless parameters.
Source
Thrown at agent/src/quantlib/timeseries.py:286
Raises:
ImportError: If ``statsmodels`` is not installed.
ValueError: If ``dt <= 0``, fewer than 3 valid lag pairs remain, or series is constant.
"""
if dt <= 0:
raise ValueError(f"dt must be strictly positive, got {dt}")
sm = _require("statsmodels.api", "statsmodels", "fit_ornstein_uhlenbeck")
s = pd.Series(series, dtype=float).dropna()
if not np.isfinite(s.values).all():
raise ValueError("series contains non-finite values")
lagged = s.shift(1)
frame = pd.concat({"curr": s, "lag": lagged}, axis=1).dropna()
if len(frame) < 3:
raise ValueError(f"fit_ornstein_uhlenbeck needs at least 3 lag pairs, got {len(frame)}")
if frame["lag"].std(ddof=0) == 0:
raise ValueError("fit_ornstein_uhlenbeck needs a series that varies; this one is constant")
exog = sm.add_constant(frame[["lag"]])
params = _ols_params(frame["curr"], exog)
a = float(params[0])
b = float(params[1])
residuals = frame["curr"] - (a + b * frame["lag"])
n = len(frame)
dof = max(1, n - 2)
sigma_eps_sq = float(np.sum(residuals**2) / dof)
sigma_eps = float(np.sqrt(sigma_eps_sq))
if 0.0 < b < 1.0:
theta = float(-np.log(b) / dt)
mu = float(a / (1.0 - b))
half_life = float(np.log(2.0) / theta)
one_minus_b2 = float(1.0 - b**2)
stat_var = float(sigma_eps_sq / one_minus_b2)View on GitHub (pinned to 80ffdda44c)
Solutions
- Check the series varies before calling: s.std(ddof=0) > 0
- Inspect upstream data ingestion for a stuck feed or repeated fill-forward values
- If constant data is legitimate, skip the OU fit or handle it as zero-volatility case
Example fix
# before
res = fit_ornstein_uhlenbeck(pd.Series([5.0] * 100))
# after
if s.std(ddof=0) == 0:
raise ValueError("series is constant; cannot fit OU")
res = fit_ornstein_uhlenbeck(s) Defensive patterns
Strategy: validation
Validate before calling
s = pd.Series(data, dtype=float).dropna()
if len(s) < 4 or s.shift(1).std(ddof=0) == 0:
raise ValueError('series must vary and have >= 3 lag pairs') Type guard
def is_fittable_ou(s: pd.Series) -> bool:
s = s.dropna()
return len(s) >= 4 and s.shift(1).dropna().std(ddof=0) > 0 Try / catch
try:
fit_ornstein_uhlenbeck(s)
except ValueError as e:
if 'series that varies' in str(e):
logger.warning('constant series; skipping OU fit: %s', e)
else:
raise Prevention
- Validate std(ddof=0) > 0 on the series and its lag before calling
- Log series statistics before fitting in batch pipelines
- Never feed fill-forward or placeholder data to mean-reversion estimators
When it happens
Trigger: Calling fit_ornstein_uhlenbeck with a series of identical values (e.g. np.full(100, 42.0)), or data that becomes constant after dropna of the lag frame (first N-1 values equal).
Common situations: Feeding prices from illiquid assets pinned at a fix, dummy/placeholder data in tests, or a mis-scaled series that rounds to a single value.
Related errors
- invalid alpha_id
- alpha_id not found
- invalid period: {exc}
- too many running benches; wait for one to finish
- invalid job_id
AI-assisted analysis of HKUDS/Vibe-Trading@80ffdda44c (2026-08-28).
Data as JSON: /api/errors/f7d837d1e26a95bc.
Report an issue: GitHub.