HKUDS/Vibe-Trading · error · ValueError

start_date ({start}) > end_date ({end})

Error message

start_date ({start}) > end_date ({end})

What it means

After parsing, _parse_period checks that the start is not after the end (mirroring backtest loaders.validate_date_range). Inverted ranges are rejected because forward returns and IC computation are undefined for them.

Source

Thrown at agent/src/tools/alpha_bench_tool.py:97

def _parse_period(period: str) -> tuple[str, str]:
    """Return (start_date, end_date) as YYYY-MM-DD strings."""
    if not isinstance(period, str):
        raise ValueError(f"period must be string, got {type(period).__name__}")
    m = _PERIOD_DATE.match(period)
    if m:
        start, end = m.group(1), m.group(2)
    else:
        m = _PERIOD_YEAR.match(period)
        if m:
            start, end = f"{m.group(1)}-01-01", f"{m.group(2)}-12-31"
        else:
            raise ValueError(
                f"period {period!r} must be YYYY-YYYY or YYYY-MM-DD/YYYY-MM-DD"
            )
    # Match backtest loaders.validate_date_range: reject inverted ranges.
    if pd.Timestamp(start) > pd.Timestamp(end):
        raise ValueError(f"start_date ({start}) > end_date ({end})")
    return start, end


def _load_universe_panel(
    universe: str, period: str, *, use_cache: bool = True
) -> dict[str, pd.DataFrame]:
    """Load OHLCV(+amount, +vwap) wide panel for the requested universe.

    Returns a dict keyed by panel column (open/high/low/close/volume/amount/vwap)
    where each value is a wide ``pd.DataFrame`` indexed by date (DatetimeIndex)
    with one column per instrument.

    Args:
        universe: ``csi300`` | ``sp500`` | ``btc-usdt``.
        period: ``YYYY-YYYY`` or ``YYYY-MM-DD/YYYY-MM-DD``.
        use_cache: When True (default) reuse a pickle in
            ``~/.vibe-trading/cache/`` if the same universe+period was fetched
            before. Set to False to force a re-fetch.

View on GitHub (pinned to 80ffdda44c)

Solutions

  1. Swap the two dates so the earlier one comes first
  2. Validate ordering at the call site before invoking the tool
  3. Sort the pair: start, end = sorted([d1, d2]) for date inputs

Example fix

// before
period = f'{end:%Y-%m-%d}/{start:%Y-%m-%d}'
// after
period = f'{start:%Y-%m-%d}/{end:%Y-%m-%d}'
Defensive patterns

Strategy: validation

Validate before calling

if _PERIOD_YEAR.match(period):
    a, b = sorted(period.split('-')); period = f'{a}-{b}'
elif '/' in period:
    s, e = period.split('/'); period = f'{min(s,e)}_noop' if False else '/'.join(sorted([s, e]))

Type guard

def ordered_period(p: str) -> str:
    if '-' in p and '/' not in p:
        a, b = sorted(p.split('-')); return f'{a}-{b}'
    s, e = sorted(p.split('/')); return f'{s}/{e}'

Try / catch

try:
    _parse_period(period)
except ValueError as e:
    if 'start_date' in str(e) and '>' in str(e):
        period = ordered_period(period)  # swap and retry

Prevention

When it happens

Trigger: Passing '2023-2020' or '2023-01-01/2020-12-31' as the period; swapping start/end when building the string programmatically.

Common situations: UIs that let users enter dates in either order; date-range pickers returning (end, start); off-by-one parameter swaps in wrapper scripts.

Related errors


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