HKUDS/Vibe-Trading · error · ValueError
a return needs an opening and a closing valuation; got {len(
Error message
a return needs an opening and a closing valuation; got {len(raw_items)} What it means
Every return calculation needs at least a starting and an ending valuation. After normalisation, fewer than two usable (date, value) pairs means no period can be measured, so _normalize_valuations raises this error reporting how many items survived.
Source
Thrown at agent/src/quantlib/performance.py:321
raw_items: list[tuple[object, object]] = list(valuations.items())
else:
raw_items = []
for index, item in enumerate(valuations):
if isinstance(item, (str, bytes)) or not isinstance(item, Sequence):
raise ValueError(
f"valuations[{index}] must be a (date, value) pair, got "
f"{type(item).__name__}"
)
pair = tuple(item)
if len(pair) != 2:
raise ValueError(
f"valuations[{index}] must have exactly two elements "
f"(date, value), got {len(pair)}"
)
raw_items.append((pair[0], pair[1]))
if len(raw_items) < 2:
raise ValueError(
"a return needs an opening and a closing valuation; got "
f"{len(raw_items)}"
)
resolved: list[tuple[date, float]] = []
for raw_date, raw_value in raw_items:
when = normalize_date(raw_date, field_name="valuation date")
try:
value = float(raw_value)
except (TypeError, ValueError) as exc:
raise ValueError(
f"valuation on {when} must be numeric, got {raw_value!r}"
) from exc
if not math.isfinite(value):
raise ValueError(
f"valuation on {when} must be finite, got {raw_value!r}; a "
"missing mark must be fixed at the source, not carried as NaN"
)View on GitHub (pinned to 80ffdda44c)
Solutions
- Ensure at least two valuations spanning the period; for empty inputs, decide policy (raise is fine) and guard upstream.
- Check len(valuations) >= 2 before calling, and log the count in ingestion pipelines.
- For DataFrame input, confirm the date filter leaves >= 2 rows.
Example fix
# before
twr = time_weighted_return(account.valuations[-1:]) # one mark
# after
marks = account.valuations
if len(marks) < 2:
return None # or raise your own domain error
twr = time_weighted_return(marks) Defensive patterns
Strategy: validation
Validate before calling
if len(valuations) < 2:
return None # or raise your own domain-specific error
Type guard
def has_open_and_close(v) -> bool:
return len(list(v)) >= 2 Try / catch
try:
r = time_weighted_return(valuations)
except ValueError as e:
if 'opening and a closing valuation' in str(e):
return None # period not measurable
raise Prevention
- Guard len(valuations) >= 2 before calling.
- Check date filters leave >= 2 marks.
- Decide an explicit policy for new accounts with one mark.
When it happens
Trigger: Calling any of the three return functions with a single valuation, e.g. [('2024-12-31', 105.0)], or with an empty list/empty dict (the length check runs before date parsing, so even malformed single items count once parsed).
Common situations: Newly opened accounts with one mark; a date filter that accidentally trims the series to one point; passing the wrong variable (a single valuation instead of the series) after refactoring.
Related errors
- valuations[{index}] must be a (date, value) pair, got {type(
- valuations[{index}] must have exactly two elements (date, va
- valuation on {when} must be numeric, got {raw_value!r}
- valuation on {when} must be finite, got {raw_value!r}; a mis
- {model}: {name} must be a finite number, got {val!r}
AI-assisted analysis of HKUDS/Vibe-Trading@80ffdda44c (2026-08-28).
Data as JSON: /api/errors/247f11146a2236e7.
Report an issue: GitHub.