HKUDS/Vibe-Trading · error · ValueError
find_hedge_ratio needs y and x sharing one index
Error message
find_hedge_ratio needs y and x sharing one index
What it means
find_hedge_ratio aligns y and x positionally via pd.concat on their indices; if the two inputs do not share the same index, concat produces a longer union frame and the length check fails. This guard prevents silently regressing misaligned observations.
Source
Thrown at agent/src/quantlib/timeseries.py:359
Returns:
Dict with keys ``hedge_ratio`` (β, float), ``intercept`` (α, float),
``spread_mean`` (float), ``spread_std`` (float, sample ddof=1) and
``half_life`` (float, in observation periods).
Raises:
ImportError: If ``statsmodels`` is not installed.
ValueError: If the series differ in length, carry different indices,
fewer than 3 aligned non-NaN observations remain, or ``x`` is
constant. A flat hedging leg is refused rather than fitted:
``sm.add_constant`` leaves an already-constant column alone, so the
design would silently collapse to one column and the β lookup would
be a bare ``IndexError``.
"""
sm = _require("statsmodels.api", "statsmodels", "find_hedge_ratio")
frame = pd.concat({"y": pd.Series(y, dtype=float), "x": pd.Series(x, dtype=float)}, axis=1)
if len(frame) != len(pd.Series(y)) or len(frame) != len(pd.Series(x)):
raise ValueError("find_hedge_ratio needs y and x sharing one index")
frame = frame.dropna()
if len(frame) < 3:
raise ValueError(f"find_hedge_ratio needs at least 3 aligned observations, got {len(frame)}")
if frame["x"].std(ddof=0) == 0:
raise ValueError("find_hedge_ratio needs an x that varies; this one is constant")
params = _ols_params(frame["y"], sm.add_constant(frame[["x"]]))
intercept, beta = float(params[0]), float(params[1])
spread = frame["y"] - beta * frame["x"]
return {
"hedge_ratio": beta,
"intercept": intercept,
"spread_mean": float(spread.mean()),
"spread_std": float(spread.std()),
"half_life": compute_half_life(spread),
}
View on GitHub (pinned to 80ffdda44c)
Solutions
- Align both inputs on a common index before calling: y, x = y.align(x, join='inner')
- Reset both to positional: pass .to_numpy() for both y and x
- Verify with (y.index == x.index).all() before the call
Example fix
# before ratio = find_hedge_ratio(prices_a, prices_b) # different calendars # after common = prices_a.index.intersection(prices_b.index) ratio = find_hedge_ratio(prices_a.loc[common], prices_b.loc[common])
Defensive patterns
Strategy: validation
Validate before calling
if isinstance(y, pd.Series) and isinstance(x, pd.Series):
assert y.index.equals(x.index), 'y and x must share one index'
else:
y = pd.Series(y, dtype=float)
x = pd.Series(x, dtype=float) Type guard
def share_index(y, x) -> bool:
if not (isinstance(y, pd.Series) and isinstance(x, pd.Series)):
return True # positional
return y.index.equals(x.index) Try / catch
try:
find_hedge_ratio(y, x)
except ValueError as e:
if 'sharing one index' in str(e):
y, x = y.align(x, join='inner')
return find_hedge_ratio(y, x)
raise Prevention
- Align series with .align(join='inner') before any bivariate call
- Convert both inputs to numpy arrays if you mean positional pairing
- Assert index equality in data-prep tests
When it happens
Trigger: Passing two pd.Series with different DatetimeIndexes (different dates or ranges), overlapping-but-not-identical indices, or mixing a Series with a plain list/array whose default RangeIndex differs from the other's index.
Common situations: Loading two price series from different sources with different trading calendars, reindexing one series but not the other, or passing y as a Series and x as a numpy array.
Related errors
- label_end_times is empty
- market_returns is missing {len(missing_market)} label(s) pre
- market_caps is missing {len(missing)} asset(s) present in va
- fit_ornstein_uhlenbeck needs a series that varies; this one
- find_hedge_ratio needs at least 3 aligned observations, got
AI-assisted analysis of HKUDS/Vibe-Trading@80ffdda44c (2026-08-28).
Data as JSON: /api/errors/9314f0b8465e1cf1.
Report an issue: GitHub.